diff --git a/.github/workflows/marin-libs-wheels.yaml b/.github/workflows/marin-libs-wheels.yaml new file mode 100644 index 0000000000..25cc61fb8c --- /dev/null +++ b/.github/workflows/marin-libs-wheels.yaml @@ -0,0 +1,100 @@ +name: marin-libs - Build Wheels + +on: + workflow_dispatch: + inputs: + mode: + description: "Build mode" + type: choice + options: [nightly, manual] + default: manual + schedule: + - cron: "0 6 * * *" # 06:00 UTC daily + push: + tags: + - "marin-libs-v*" + pull_request: + paths: + - "lib/**" + - "scripts/python_libs_package.py" + - ".github/workflows/marin-libs-wheels.yaml" + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: false # don't kill an in-flight nightly mid-publish + +permissions: + contents: write # creating GH releases + pull-requests: read + +jobs: + resolve: + runs-on: ubuntu-latest + outputs: + mode: ${{ steps.pick.outputs.mode }} + version: ${{ steps.pick.outputs.version }} + steps: + - id: pick + run: | + set -euo pipefail + if [[ "${GITHUB_EVENT_NAME}" == "push" && "${GITHUB_REF}" == refs/tags/marin-libs-v* ]]; then + echo "mode=stable" >> "$GITHUB_OUTPUT" + echo "version=${GITHUB_REF_NAME#marin-libs-v}" >> "$GITHUB_OUTPUT" + elif [[ "${GITHUB_EVENT_NAME}" == "schedule" ]]; then + echo "mode=nightly" >> "$GITHUB_OUTPUT" + echo "version=" >> "$GITHUB_OUTPUT" + elif [[ "${GITHUB_EVENT_NAME}" == "workflow_dispatch" ]]; then + echo "mode=${{ github.event.inputs.mode }}" >> "$GITHUB_OUTPUT" + echo "version=" >> "$GITHUB_OUTPUT" + else + # pull_request: build-only smoke test + echo "mode=manual" >> "$GITHUB_OUTPUT" + echo "version=" >> "$GITHUB_OUTPUT" + fi + + build: + needs: resolve + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 # for git rev-parse in manual mode + - uses: astral-sh/setup-uv@v7 + + - name: Build wheels + run: | + uv run python scripts/python_libs_package.py \ + --mode "${{ needs.resolve.outputs.mode }}" \ + ${{ needs.resolve.outputs.version && format('--version {0}', needs.resolve.outputs.version) || '' }} \ + --skip-publish + + - uses: actions/upload-artifact@v4 + with: + name: marin-libs-wheels + # BUILD_INFO.json travels with the wheels so the publish job uses + # the same resolved version the build job stamped in, instead of + # re-computing it (which would drift across midnight UTC). + path: | + dist/*.whl + dist/BUILD_INFO.json + retention-days: 14 + + publish: + needs: [resolve, build] + if: github.event_name != 'pull_request' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: astral-sh/setup-uv@v7 + - uses: actions/download-artifact@v4 + with: + name: marin-libs-wheels + path: dist + - name: Publish releases and prune nightlies + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + uv run python scripts/python_libs_package.py \ + --mode "${{ needs.resolve.outputs.mode }}" \ + ${{ needs.resolve.outputs.version && format('--version {0}', needs.resolve.outputs.version) || '' }} \ + --publish-only diff --git a/lib/fray/pyproject.toml b/lib/fray/pyproject.toml index 339ee1b459..f73c606168 100644 --- a/lib/fray/pyproject.toml +++ b/lib/fray/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "hatchling.build" [project] name = "marin-fray" -version = "0.1.0" +version = "0.99" requires-python = ">=3.11,<3.13" dependencies = [ "click>=8.0", diff --git a/lib/haliax/src/haliax/__about__.py b/lib/haliax/src/haliax/__about__.py index f1b75e00ec..7d4731fee1 100644 --- a/lib/haliax/src/haliax/__about__.py +++ b/lib/haliax/src/haliax/__about__.py @@ -2,4 +2,4 @@ # # SPDX-License-Identifier: Apache-2.0 -__version__ = "1.4" +__version__ = "0.99" diff --git a/lib/iris/pyproject.toml b/lib/iris/pyproject.toml index fdd5383cf4..cbe17fee04 100644 --- a/lib/iris/pyproject.toml +++ b/lib/iris/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "hatchling.build" [project] name = "marin-iris" -version = "0.1.0" +version = "0.99" requires-python = ">=3.11,<3.13" dependencies = [ "marin-rigging", diff --git a/lib/levanter/pyproject.toml b/lib/levanter/pyproject.toml index cc6b8877df..88d1ab23a5 100644 --- a/lib/levanter/pyproject.toml +++ b/lib/levanter/pyproject.toml @@ -10,7 +10,7 @@ module-name = "levanter" [project] name = "marin-levanter" -version = "1.2" +version = "0.99" description = "Scalable Training for Foundation Models with Named Tensors and JAX" readme = "README.md" requires-python = ">=3.11" @@ -34,7 +34,7 @@ classifiers = [ ] dependencies = [ - "marin-haliax>=1.4.dev450", + "marin-haliax", "equinox>=0.11.7,!=0.12.0", "jax>=0.8.0", "marin-fray", diff --git a/lib/marin/pyproject.toml b/lib/marin/pyproject.toml index be799b444e..df48799239 100644 --- a/lib/marin/pyproject.toml +++ b/lib/marin/pyproject.toml @@ -5,7 +5,7 @@ requires-python = ">=3.11,<3.13" [project] name = "marin" -version = "0.1.0" +version = "0.99" requires-python = ">=3.11" dependencies = [ diff --git a/lib/rigging/pyproject.toml b/lib/rigging/pyproject.toml index 9cc66eb52b..a33152caa1 100644 --- a/lib/rigging/pyproject.toml +++ b/lib/rigging/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "hatchling.build" [project] name = "marin-rigging" -version = "0.1.0" +version = "0.99" requires-python = ">=3.11,<3.13" dependencies = [ "fsspec>=2024.0.0", diff --git a/lib/zephyr/pyproject.toml b/lib/zephyr/pyproject.toml index 88c45d9cf3..5e1deb29f8 100644 --- a/lib/zephyr/pyproject.toml +++ b/lib/zephyr/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "hatchling.build" [project] name = "marin-zephyr" -version = "0.1.0" +version = "0.99" description = "Lightweight dataset library for distributed data processing" readme = "README.md" requires-python = ">=3.11,<3.13" diff --git a/scripts/python_libs_package.py b/scripts/python_libs_package.py new file mode 100644 index 0000000000..f1f1e7926e --- /dev/null +++ b/scripts/python_libs_package.py @@ -0,0 +1,447 @@ +#!/usr/bin/env python3 +# Copyright The Marin Authors +# SPDX-License-Identifier: Apache-2.0 + +"""Build and publish marin-* lib wheels. + +Builds the seven pure-Python marin-* lib packages (marin, marin-iris, +marin-fray, marin-haliax, marin-levanter, marin-rigging, marin-zephyr) into +dist/, then optionally publishes them as GitHub Releases. + +Four modes: + nightly -- version becomes .dev; overwrites the rolling + marin--latest tag in place. No dated history is kept; + reproducibility comes from stable tags, not historical nightlies. + stable -- version is taken from --version; creates marin--v + and overwrites marin--stable. + manual -- version becomes +manual.; build only (no publish). + Useful for inspecting wheels from a workflow_dispatch run. + vendor -- version becomes .dev; copy wheels to a + local directory (no GH publish). For local-iteration loops + where a marin worktree feeds wheels into an experiment repo's + find-links. The timestamp guarantees rebuilt wheels beat any + nightly already published earlier the same day. + +Usage: + python scripts/python_libs_package.py --mode nightly + python scripts/python_libs_package.py --mode stable --version 1.0.0 + python scripts/python_libs_package.py --mode nightly --skip-publish + python scripts/python_libs_package.py --skip-build --publish-only + python scripts/python_libs_package.py --mode vendor --vendor ../tiny-tpu/vendor + +The build is done from a temporary in-place patch of each package's version +file plus a cross-pin rewrite of every sibling dependency. Mutations are +reverted on exit (success OR failure) so the working tree stays clean. +After building, dist/BUILD_INFO.json records the resolved version so that a +subsequent --publish-only call (typically the publish job in CI) uses the +exact version the build job produced, even if the run straddles midnight UTC. +""" + +import argparse +import json +import re +import shutil +import subprocess +import sys +from contextlib import contextmanager +from datetime import datetime, timezone +from pathlib import Path + +REPO_ROOT = Path(__file__).resolve().parent.parent +DIST_DIR = REPO_ROOT / "dist" +REPO = "marin-community/marin" + + +# Each entry: (dist name, lib subdir, version-file path relative to lib subdir, version-file kind) +# kind = "pyproject" -> patch version = "..." in pyproject.toml +# kind = "about_py" -> patch __version__ = "..." in src//__about__.py +PACKAGES: dict[str, dict[str, str]] = { + "marin": {"path": "lib/marin", "version_file": "pyproject.toml", "kind": "pyproject"}, + "marin-iris": {"path": "lib/iris", "version_file": "pyproject.toml", "kind": "pyproject"}, + "marin-fray": {"path": "lib/fray", "version_file": "pyproject.toml", "kind": "pyproject"}, + "marin-rigging": {"path": "lib/rigging", "version_file": "pyproject.toml", "kind": "pyproject"}, + "marin-zephyr": {"path": "lib/zephyr", "version_file": "pyproject.toml", "kind": "pyproject"}, + "marin-levanter": {"path": "lib/levanter", "version_file": "pyproject.toml", "kind": "pyproject"}, + "marin-haliax": {"path": "lib/haliax", "version_file": "src/haliax/__about__.py", "kind": "about_py"}, +} + +SIBLING_NAMES = sorted(PACKAGES.keys(), key=len, reverse=True) + + +# ---------- helpers ---------------------------------------------------------- + + +def _check_tool(name: str, install_hint: str) -> None: + if shutil.which(name) is None: + print(f"ERROR: '{name}' not found. Install with: {install_hint}", file=sys.stderr) + sys.exit(1) + + +def _git_short_sha() -> str: + return subprocess.check_output(["git", "rev-parse", "--short", "HEAD"], text=True, cwd=REPO_ROOT).strip() + + +def _read_base_version(pkg: str) -> str: + info = PACKAGES[pkg] + path = REPO_ROOT / info["path"] / info["version_file"] + text = path.read_text() + if info["kind"] == "pyproject": + m = re.search(r'^version\s*=\s*"([^"]+)"', text, re.MULTILINE) + else: + m = re.search(r'^__version__\s*=\s*"([^"]+)"', text, re.MULTILINE) + if not m: + raise RuntimeError(f"Could not read version from {path}") + return m.group(1) + + +def _set_version(text: str, kind: str, new_version: str) -> str: + if kind == "pyproject": + new_text, count = re.subn( + r'^version\s*=\s*"[^"]+"', + f'version = "{new_version}"', + text, + count=1, + flags=re.MULTILINE, + ) + else: + new_text, count = re.subn( + r'^__version__\s*=\s*"[^"]+"', + f'__version__ = "{new_version}"', + text, + count=1, + flags=re.MULTILINE, + ) + if count != 1: + raise RuntimeError(f"Failed to patch version (kind={kind})") + return new_text + + +# Match dependency list items: lines that are indented and start with a quoted +# sibling name. Anchored on `^\s+"` so we never touch metadata lines like +# `name = "marin"` (no leading whitespace) or single-line `gpu = ["..."]` +# entries (no marin siblings appear in those today; verified by grep). +_SIBLING_ALT = "|".join(re.escape(s) for s in sorted(PACKAGES, key=len, reverse=True)) +_SIBLING_ITEM_RE = re.compile( + rf'^(?P\s+)"(?P{_SIBLING_ALT})(?![-\w])(?P\[[^\]]*\])?[^"]*"(?P.*)$', + re.MULTILINE, +) + + +def _rewrite_sibling_pins(text: str, version: str) -> str: + """Pin every sibling marin-* package in dependency list items to ==.""" + return _SIBLING_ITEM_RE.sub( + lambda m: (f'{m.group("indent")}"{m.group("name")}{m.group("extras") or ""}=={version}"{m.group("tail")}'), + text, + ) + + +@contextmanager +def patched_tree(version: str): + """Patch every package's version file and sibling pins; revert on exit. + + Captures the original text of each path exactly once, before any mutation, + so the finally block restores the truly-original content even if multiple + patches touched the same file. + """ + originals: dict[Path, str] = {} + try: + for info in PACKAGES.values(): + pyproject_path = REPO_ROOT / info["path"] / "pyproject.toml" + version_path = REPO_ROOT / info["path"] / info["version_file"] + + if pyproject_path not in originals: + originals[pyproject_path] = pyproject_path.read_text() + if version_path not in originals: + originals[version_path] = version_path.read_text() + + # Apply version patch first; for haliax this writes __about__.py + # (separate file from pyproject), for the rest it overwrites the + # pyproject we just snapshotted above. + patched_version = _set_version(originals[version_path], info["kind"], version) + version_path.write_text(patched_version) + + # Then sibling-pin rewrite always targets pyproject.toml. Re-read + # in case version patch already wrote pyproject. + current_pyproject = pyproject_path.read_text() + new_pyproject = _rewrite_sibling_pins(current_pyproject, version) + if new_pyproject != current_pyproject: + pyproject_path.write_text(new_pyproject) + yield + finally: + for path, text in originals.items(): + path.write_text(text) + + +# ---------- build ------------------------------------------------------------ + + +def _highest_base_version() -> str: + """Return the highest version currently declared across the seven libs. + + All seven packages share one synthetic version per build so cross-pins + resolve cleanly. Picking the max keeps the synthetic version above the + most recent stable so uv prefers it. + """ + bases = [_read_base_version(p) for p in PACKAGES] + return max(bases, key=lambda v: tuple(int(p) if p.isdigit() else 0 for p in re.split(r"[.\-+]", v))) + + +def resolve_version(mode: str, explicit: str | None) -> str: + """Return the build version for the requested mode. + + nightly -> .dev + stable -> + manual -> +manual. + vendor -> .dev + """ + if mode == "stable": + if not explicit: + raise SystemExit("--version is required for --mode stable") + return explicit + if mode == "nightly": + date = datetime.now(timezone.utc).strftime("%Y%m%d") + return f"{_highest_base_version()}.dev{date}" + if mode == "manual": + sha = _git_short_sha() + return f"{_highest_base_version()}+manual.{sha}" + if mode == "vendor": + # Second-precision timestamp guarantees the freshly-built wheel beats + # any nightly built earlier today, so `uv sync` in the consumer always + # picks up the local copy without cache games. + ts = datetime.now(timezone.utc).strftime("%Y%m%d%H%M%S") + return f"{_highest_base_version()}.dev{ts}" + raise SystemExit(f"Unknown mode: {mode}") + + +# Path inside dist/ where build_wheels persists the resolved version + mode. +# Publish reads this instead of re-resolving so a workflow that straddles +# midnight UTC can't compute a different date in build vs publish. +BUILD_INFO_PATH = DIST_DIR / "BUILD_INFO.json" + + +def write_build_info(version: str, mode: str) -> None: + BUILD_INFO_PATH.write_text(json.dumps({"version": version, "mode": mode}, indent=2)) + + +def read_build_info() -> dict[str, str] | None: + if not BUILD_INFO_PATH.is_file(): + return None + return json.loads(BUILD_INFO_PATH.read_text()) + + +def build_wheels(version: str, mode: str) -> None: + """Build all seven marin-* wheels into DIST_DIR with version patched in. + + Persists BUILD_INFO.json next to the wheels so the publish step (which + runs in a separate job and downloads dist/ as an artifact) can read the + exact version this build used instead of re-resolving it. That guarantees + a workflow run straddling midnight UTC produces a consistent version + across build and publish. + """ + _check_tool("uv", "https://docs.astral.sh/uv/") + + if DIST_DIR.exists(): + shutil.rmtree(DIST_DIR) + DIST_DIR.mkdir() + + with patched_tree(version): + for name, info in PACKAGES.items(): + pkg_dir = REPO_ROOT / info["path"] + print(f"\n--- Building {name} ({version}) ---") + subprocess.run( + ["uv", "build", "--wheel", "--out-dir", str(DIST_DIR), str(pkg_dir)], + check=True, + cwd=REPO_ROOT, + ) + + wheels = sorted(DIST_DIR.glob("*.whl")) + print(f"\nBuilt {len(wheels)} wheel(s):") + for w in wheels: + print(f" {w.name}") + if len(wheels) != len(PACKAGES): + raise RuntimeError(f"Expected {len(PACKAGES)} wheels, got {len(wheels)}") + + write_build_info(version, mode) + + +# ---------- vendor ----------------------------------------------------------- + + +def vendor_copy(target: Path) -> None: + """Drop freshly-built wheels into target/, replacing any prior marin-* wheels. + + Cleans only files matching marin*-*.whl so unrelated files in the target + directory (e.g. .gitkeep, README) are left alone. Used by --mode vendor + to feed local wheels into a downstream experiment's find-links. + """ + target.mkdir(parents=True, exist_ok=True) + stale = sorted(target.glob("marin*-*.whl")) + for s in stale: + s.unlink() + if stale: + print(f"\nRemoved {len(stale)} stale marin-* wheel(s) from {target}") + print(f"\nCopying wheels to {target}:") + for wheel in sorted(DIST_DIR.glob("*.whl")): + dest = target / wheel.name + shutil.copy2(wheel, dest) + print(f" -> {dest.name}") + + +def lock_consumer(project_dir: Path) -> None: + """Re-lock the consumer project so it picks up the freshly-vendored wheels. + + uv lock preserves existing resolutions when constraints are already + satisfied, so a plain `uv lock` after vendoring keeps the old version. + --upgrade-package for each marin-* package forces re-resolution against + the new wheels in the vendor find-links directory. + """ + upgrade_flags: list[str] = [] + for pkg in PACKAGES: + upgrade_flags += ["--upgrade-package", pkg] + print(f"\nRe-locking {project_dir} ...") + subprocess.run(["uv", "lock", *upgrade_flags], check=True, cwd=project_dir) + + +# ---------- publish ---------------------------------------------------------- + + +def _wheel_for(pkg: str) -> Path: + """Return the dist/ wheel matching pkg (uv normalises hyphens to underscores).""" + stem = pkg.replace("-", "_") + candidates = list(DIST_DIR.glob(f"{stem}-*.whl")) + if not candidates: + raise FileNotFoundError(f"No wheel for {pkg} in {DIST_DIR}") + if len(candidates) > 1: + raise RuntimeError(f"Multiple wheels for {pkg}: {[c.name for c in candidates]}") + return candidates[0] + + +def _gh_release_replace(tag: str, files: list[Path], title: str, notes: str, prerelease: bool) -> None: + """Idempotently (re)create a GitHub release with the given assets.""" + subprocess.run( + ["gh", "release", "delete", tag, "--yes", "--cleanup-tag", "--repo", REPO], + check=False, + capture_output=True, + ) + cmd = [ + "gh", + "release", + "create", + tag, + *[str(f) for f in files], + "--repo", + REPO, + "--title", + title, + "--notes", + notes, + ] + if prerelease: + cmd.append("--prerelease") + subprocess.run(cmd, check=True) + + +def publish_releases(version: str, mode: str) -> None: + """Per-package GH release. + + nightly -> overwrite the rolling marin--latest tag in place. No dated + tags are kept; consumers point find-links at the rolling URL + and always get the most recent build. Reproducibility comes + from stable tags, not from historical nightlies. + stable -> create marin--v and overwrite marin--stable. + """ + _check_tool("gh", "https://cli.github.com/") + + if mode == "nightly": + for pkg in PACKAGES: + wheel = _wheel_for(pkg) + tag = f"{pkg}-latest" + print(f"\n--- Publishing {tag} ({version}) ---") + _gh_release_replace( + tag=tag, + files=[wheel], + title=f"{pkg} (latest)", + notes=f"Rolling nightly. Currently pointing at {version}.", + prerelease=True, + ) + return + + if mode == "stable": + for pkg in PACKAGES: + wheel = _wheel_for(pkg) + for tag, label in ((f"{pkg}-v{version}", "stable"), (f"{pkg}-stable", "rolling stable")): + print(f"\n--- Publishing {tag} ---") + _gh_release_replace( + tag=tag, + files=[wheel], + title=f"{pkg} {version}", + notes=f"{pkg} {version} ({label})", + prerelease=False, + ) + return + + raise SystemExit(f"publish_releases called with unsupported mode: {mode}") + + +# ---------- main ------------------------------------------------------------- + + +def main() -> None: + parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) + parser.add_argument("--mode", choices=["nightly", "stable", "manual", "vendor"], default="nightly") + parser.add_argument("--version", default=None, help="Required for --mode stable") + parser.add_argument( + "--vendor", + type=Path, + default=None, + help="Target directory to drop wheels into (required for --mode vendor)", + ) + parser.add_argument("--skip-build", action="store_true", help="Reuse existing dist/") + parser.add_argument("--skip-publish", action="store_true", help="Build only") + parser.add_argument("--publish-only", action="store_true", help="Same as --skip-build") + args = parser.parse_args() + + if args.publish_only: + args.skip_build = True + + if args.mode == "vendor": + if args.vendor is None: + raise SystemExit("--vendor PATH is required for --mode vendor") + version = resolve_version(args.mode, args.version) + print(f"Mode: {args.mode}\nVersion: {version}") + build_wheels(version, args.mode) + vendor_target = args.vendor.expanduser().resolve() + vendor_copy(vendor_target) + lock_consumer(vendor_target.parent) + print("\nDone.") + return + + if not args.skip_build: + version = resolve_version(args.mode, args.version) + print(f"Mode: {args.mode}\nVersion: {version}") + build_wheels(version, args.mode) + else: + if not DIST_DIR.exists() or not list(DIST_DIR.glob("*.whl")): + raise SystemExit(f"No wheels in {DIST_DIR}; remove --skip-build/--publish-only or build first.") + info = read_build_info() + if info is not None: + version = info["version"] + print(f"Mode: {args.mode}\nVersion: {version} (from BUILD_INFO.json)") + else: + # Legacy path: dist/ has wheels but no BUILD_INFO.json. Fall back + # to re-resolving; this is the only branch where the midnight-drift + # bug could resurface. + version = resolve_version(args.mode, args.version) + print(f"Mode: {args.mode}\nVersion: {version} (re-resolved; no BUILD_INFO.json)") + + if args.skip_publish or args.mode == "manual": + print(f"\nBuild complete. Wheels in {DIST_DIR}/") + return + + publish_releases(version, args.mode) + + print("\nDone.") + + +if __name__ == "__main__": + main() diff --git a/uv.lock b/uv.lock index 5c07f42571..c46033215c 100644 --- a/uv.lock +++ b/uv.lock @@ -4638,7 +4638,7 @@ wheels = [ [[package]] name = "marin" -version = "0.1.0" +version = "0.99" source = { editable = "lib/marin" } dependencies = [ { name = "braceexpand" }, @@ -4959,7 +4959,7 @@ test = [ [[package]] name = "marin-fray" -version = "0.1.0" +version = "0.99" source = { editable = "lib/fray" } dependencies = [ { name = "click" }, @@ -5113,7 +5113,7 @@ dev = [ [[package]] name = "marin-iris" -version = "0.1.0" +version = "0.99" source = { editable = "lib/iris" } dependencies = [ { name = "click" }, @@ -5225,11 +5225,12 @@ examples = [ [[package]] name = "marin-levanter" -version = "1.2" +version = "0.99" source = { editable = "lib/levanter" } dependencies = [ { name = "async-lru" }, { name = "braceexpand" }, + { name = "chex" }, { name = "dataclasses-json" }, { name = "datasets" }, { name = "deepdiff" }, @@ -5346,6 +5347,7 @@ test = [ requires-dist = [ { name = "async-lru", specifier = "~=2.0" }, { name = "braceexpand", specifier = ">=0.1.7" }, + { name = "chex", specifier = ">=0.1.86" }, { name = "dataclasses-json", specifier = "~=0.6.4" }, { name = "datasets", specifier = ">=3.1.0,<5.0" }, { name = "deepdiff" }, @@ -5436,7 +5438,7 @@ test = [ [[package]] name = "marin-rigging" -version = "0.1.0" +version = "0.99" source = { editable = "lib/rigging" } dependencies = [ { name = "fsspec" }, @@ -5494,7 +5496,7 @@ requires-dist = [ [[package]] name = "marin-zephyr" -version = "0.1.0" +version = "0.99" source = { editable = "lib/zephyr" } dependencies = [ { name = "braceexpand" }, @@ -6053,13 +6055,13 @@ name = "mlx-lm" version = "0.29.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "jinja2", marker = "sys_platform == 'darwin' or (sys_platform != 'linux' and extra == 'extra-5-marin-gpu') or (extra == 'extra-14-marin-levanter-gpu' and extra == 'extra-14-marin-levanter-tpu') or (extra == 'extra-5-marin-gpu' and extra == 'extra-5-marin-tpu') or (extra != 'extra-5-marin-gpu' and extra != 'extra-5-marin-tpu')" }, + { name = "jinja2", marker = "sys_platform == 'darwin' or (extra == 'extra-14-marin-levanter-gpu' and extra == 'extra-14-marin-levanter-tpu') or (extra == 'extra-5-marin-gpu' and extra == 'extra-5-marin-tpu')" }, { name = "mlx", marker = "sys_platform == 'darwin' or (extra == 'extra-14-marin-levanter-gpu' and extra == 'extra-14-marin-levanter-tpu') or (extra == 'extra-5-marin-gpu' and extra == 'extra-5-marin-tpu')" }, - { name = "numpy", marker = "sys_platform == 'darwin' or (sys_platform != 'linux' and extra == 'extra-5-marin-gpu') or (extra == 'extra-14-marin-levanter-gpu' and extra == 'extra-14-marin-levanter-tpu') or (extra == 'extra-5-marin-gpu' and extra == 'extra-5-marin-tpu') or (extra != 'extra-5-marin-gpu' and extra != 'extra-5-marin-tpu')" }, - { name = "protobuf", marker = "sys_platform == 'darwin' or (sys_platform != 'linux' and extra == 'extra-5-marin-gpu') or (extra == 'extra-14-marin-levanter-gpu' and extra == 'extra-14-marin-levanter-tpu') or (extra == 'extra-5-marin-gpu' and extra == 'extra-5-marin-tpu') or (extra != 'extra-5-marin-gpu' and extra != 'extra-5-marin-tpu')" }, - { name = "pyyaml", marker = "sys_platform == 'darwin' or (sys_platform != 'linux' and extra == 'extra-5-marin-gpu') or (extra == 'extra-14-marin-levanter-gpu' and extra == 'extra-14-marin-levanter-tpu') or (extra == 'extra-5-marin-gpu' and extra == 'extra-5-marin-tpu') or (extra != 'extra-5-marin-gpu' and extra != 'extra-5-marin-tpu')" }, - { name = "sentencepiece", marker = "sys_platform == 'darwin' or (sys_platform != 'linux' and extra == 'extra-5-marin-gpu') or (extra == 'extra-14-marin-levanter-gpu' and extra == 'extra-14-marin-levanter-tpu') or (extra == 'extra-5-marin-gpu' and extra == 'extra-5-marin-tpu') or (extra != 'extra-5-marin-gpu' and extra != 'extra-5-marin-tpu')" }, - { name = "transformers", marker = "sys_platform == 'darwin' or (sys_platform != 'linux' and extra == 'extra-5-marin-gpu') or (extra == 'extra-14-marin-levanter-gpu' and extra == 'extra-14-marin-levanter-tpu') or (extra == 'extra-5-marin-gpu' and extra == 'extra-5-marin-tpu') or (extra != 'extra-5-marin-gpu' and extra != 'extra-5-marin-tpu')" }, + { name = "numpy", marker = "sys_platform == 'darwin' or (extra == 'extra-14-marin-levanter-gpu' and extra == 'extra-14-marin-levanter-tpu') or (extra == 'extra-5-marin-gpu' and extra == 'extra-5-marin-tpu')" }, + { name = "protobuf", marker = "sys_platform == 'darwin' or (extra == 'extra-14-marin-levanter-gpu' and extra == 'extra-14-marin-levanter-tpu') or (extra == 'extra-5-marin-gpu' and extra == 'extra-5-marin-tpu')" }, + { name = "pyyaml", marker = "sys_platform == 'darwin' or (extra == 'extra-14-marin-levanter-gpu' and extra == 'extra-14-marin-levanter-tpu') or (extra == 'extra-5-marin-gpu' and extra == 'extra-5-marin-tpu')" }, + { name = "sentencepiece", marker = "sys_platform == 'darwin' or (extra == 'extra-14-marin-levanter-gpu' and extra == 'extra-14-marin-levanter-tpu') or (extra == 'extra-5-marin-gpu' and extra == 'extra-5-marin-tpu')" }, + { name = "transformers", marker = "sys_platform == 'darwin' or (extra == 'extra-14-marin-levanter-gpu' and extra == 'extra-14-marin-levanter-tpu') or (extra == 'extra-5-marin-gpu' and extra == 'extra-5-marin-tpu')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/e3/62/f46e1355256a114808517947f8e83ad6be310c7288c551db0fa678f47923/mlx_lm-0.29.1.tar.gz", hash = "sha256:b99180d8f33d33a077b814e550bfb2d8a59ae003d668fd1f4b3fff62a381d34b", size = 232302, upload-time = "2025-12-16T16:58:27.959Z" } wheels = [