hfms-bridge 0.4.0__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,19 @@
1
+ name: tests
2
+ on: [push, pull_request]
3
+ jobs:
4
+ test:
5
+ strategy:
6
+ fail-fast: false
7
+ matrix:
8
+ os: [ubuntu-latest, macos-latest, windows-latest]
9
+ python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14']
10
+ runs-on: ${{ matrix.os }}
11
+ steps:
12
+ - uses: actions/checkout@v4
13
+ - uses: astral-sh/setup-uv@v6
14
+ with:
15
+ python-version: ${{ matrix.python }}
16
+ - run: uv sync --locked
17
+ - run: uv run ruff check .
18
+ - run: uv run pytest
19
+ - run: uv build
@@ -0,0 +1,15 @@
1
+ .venv/
2
+ .hfms-bridge/
3
+ __pycache__/
4
+ *.py[cod]
5
+ .pytest_cache/
6
+ .ruff_cache/
7
+ dist/
8
+ *.egg-info/
9
+ .env
10
+
11
+ # OS
12
+ .DS_Store
13
+
14
+ # IDE
15
+ .vscode
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 hfms-bridge contributors
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,99 @@
1
+ Metadata-Version: 2.4
2
+ Name: hfms-bridge
3
+ Version: 0.4.0
4
+ Summary: Stream models and datasets between HuggingFace and ModelScope
5
+ Project-URL: Homepage, https://github.com/feixyz10/hfms-bridge/
6
+ Project-URL: Source, https://github.com/feixyz10/hfms-bridge/
7
+ Project-URL: Issues, https://github.com/feixyz10/hfms-bridge/issues
8
+ Author: ExcitingMe
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: cli,datasets,huggingface,models,modelscope,streaming,transfer
12
+ Classifier: Environment :: Console
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3 :: Only
17
+ Classifier: Programming Language :: Python :: 3.9
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Programming Language :: Python :: 3.14
23
+ Classifier: Topic :: Utilities
24
+ Requires-Python: >=3.9
25
+ Requires-Dist: filelock<4,>=3.16
26
+ Requires-Dist: requests<3,>=2.32.3
27
+ Requires-Dist: tqdm<5,>=4.66
28
+ Description-Content-Type: text/markdown
29
+
30
+ # hfms-bridge
31
+
32
+ Transfer models and datasets between **Hugging Face and ModelScope** with minimal local disk usage. File contents stream directly between services; only small metadata checkpoints are saved locally.
33
+
34
+ - Both directions: `hfms-bridge hf2ms` and `hfms-bridge ms2hf`.
35
+ - Parallel file transfers with overall and per-file progress bars.
36
+ - Automatic destination creation and incremental updates.
37
+ - File-level resume and recovery from interrupted source downloads.
38
+ - Python 3.9+, Linux, macOS and Windows.
39
+
40
+ ## Install
41
+
42
+ ```bash
43
+ pip install hfms-bridge
44
+ # Or install as an isolated command:
45
+ uv tool install hfms-bridge
46
+ ```
47
+
48
+ ## Transfer
49
+
50
+ From Hugging Face to ModelScope:
51
+
52
+ ```bash
53
+ hfms-bridge hf2ms org/source user/destination --ms-token "$MODELSCOPE_API_TOKEN"
54
+ ```
55
+
56
+ From ModelScope to Hugging Face:
57
+
58
+ ```bash
59
+ hfms-bridge ms2hf org/source user/destination --hf-token "$HF_TOKEN"
60
+ ```
61
+
62
+ The destination token is required explicitly and needs write/create permission. Public sources normally need no token. For private sources, pass `--hf-token` or `--ms-token`, or set the source token environment variable (`HF_TOKEN` or `MODELSCOPE_API_TOKEN`).
63
+
64
+ In PowerShell, use `$env:HF_TOKEN` or `$env:MODELSCOPE_API_TOKEN` instead of the shell variables above.
65
+
66
+ ## Common options
67
+
68
+ ```bash
69
+ # Preview without downloading payloads or modifying repositories/cache
70
+ hfms-bridge ms2hf org/source user/destination --hf-token "$HF_TOKEN" --dry-run
71
+
72
+ # Select files and concurrency
73
+ hfms-bridge hf2ms org/source user/destination --ms-token "$MODELSCOPE_API_TOKEN" \
74
+ --workers 4 --include '*.safetensors' '*.json' --exclude 'original/*'
75
+
76
+ hfms-bridge hf2ms --help
77
+ hfms-bridge ms2hf --help
78
+ ```
79
+
80
+ `--repo-type auto` checks the source's model and dataset namespaces and selects the unique accessible match. If both exist, choose `--repo-type model` or `--repo-type dataset` explicitly. The destination uses the same type.
81
+
82
+ `--hf-revision` defaults to `main`; `--ms-revision` defaults to `master`. Source revisions can be selected independently. A missing destination is created on its default branch; other destination branches must already exist. `--visibility auto|public|private` controls new repositories; auto creates private destinations for private, gated or unknown-visibility sources.
83
+
84
+ Existing identical files are skipped; different content is overwritten by default. Choose `--on-conflict error` or `--on-conflict skip` to change that behavior. Files unrelated to the transfer are not deleted.
85
+
86
+ ## Resume and resource usage
87
+
88
+ If `HF_ENDPOINT` or `--hf-endpoint` is `https://hf-mirror.com`, `ms2hf` sends destination requests directly to official HF (`https://huggingface.co`) to avoid upload redirects. Official HF must be reachable. Existing tasks can resume using the same command and cache; `hf2ms` downloads still use the mirror.
89
+
90
+ Run the same command again after an error or interruption. Completed files are compared and skipped when identical. Source file versions are pinned for unfinished tasks. Changing `--workers` or `--progress` does not discard progress. `--restart` resolves the source again; it does not force identical remote blobs to upload again.
91
+
92
+ No payload is cached on disk. Metadata checkpoints default to `~/.cache/hfms-bridge`, with a `256MiB` budget; change this with `--cache-dir` and `--cache-max-size`. Old completed tasks are evicted first, and active tasks are protected. Memory scales mainly with worker count and read buffers (`--chunk-size`, default `1MiB`).
93
+
94
+ Interrupted source reads can continue through HTTP Range while the process is running. MS supports this path for LFS files; ordinary MS files restart their read. HF uploads can use server-negotiated multipart uploads, with each part streamed directly. **Destination upload failures and process restarts do not support file-internal resume:** unfinished files may restart from byte zero. Complete remote blobs may still be reused.
95
+
96
+ For ordinary HF destination files, checking equality may require another source read. Large ordinary files are committed using streaming Base64. MS repository metadata files have a 1MiB inline limit. Network, permission, service file-size and rate limits still apply.
97
+
98
+
99
+ Source and developer documentation: [English](https://github.com/feixyz10/hfms-bridge/blob/main/README.md), [简体中文](https://github.com/feixyz10/hfms-bridge/blob/main/README_CN.md).
@@ -0,0 +1,100 @@
1
+ # hfms-bridge
2
+
3
+ [User guide](docs/README.md) | **English** | [简体中文](README_CN.md)
4
+
5
+ Stream models and datasets between HuggingsFace (HF) and ModelScope (MS), without saving file payloads to disk. Python 3.9+, Linux, macOS and Windows.
6
+
7
+ ## Development quick start
8
+
9
+ ```bash
10
+ uv sync --locked
11
+ uv run hfms-bridge hf2ms org/source user/destination --ms-token "$MODELSCOPE_API_TOKEN"
12
+ uv run hfms-bridge ms2hf org/source user/destination --hf-token "$HF_TOKEN"
13
+ uv run hfms-bridge ms2hf --help
14
+ ```
15
+
16
+ The destination token must be explicit. Optional source tokens default to `HF_TOKEN` or `MODELSCOPE_API_TOKEN`. Private or gated sources require authorized read access.
17
+
18
+
19
+ ## Options and behavior
20
+
21
+ Both directions share these options:
22
+
23
+ | Option | Default / behavior |
24
+ | -------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
25
+ | `SOURCE DESTINATION` | Required `owner/repository` IDs |
26
+ | `--repo-type auto\|model\|dataset` | Probe the source model and dataset namespaces; select the unique accessible match; require an explicit choice when ambiguous |
27
+ | `--hf-token TOKEN` | Required for `ms2hf`; otherwise optional, defaults to `HF_TOKEN` |
28
+ | `--ms-token TOKEN` | Required for `hf2ms`; otherwise optional, defaults to `MODELSCOPE_API_TOKEN` |
29
+ | `--hf-revision REV` | `main`; source revision or existing destination branch |
30
+ | `--ms-revision REV` | `master`; source revision or existing destination branch |
31
+ | `--visibility auto\|public\|private` | New destination only; auto mirrors public sources, otherwise private |
32
+ | `--include GLOB [GLOB ...]` | Repeatable case-sensitive repository-relative globs |
33
+ | `--exclude GLOB [GLOB ...]` | Repeatable, takes precedence over include |
34
+ | `--on-conflict overwrite\|error\|skip` | `overwrite`; different or unverifiable destination content |
35
+ | `--workers N` | `4`; concurrent file transfers, `1` for serial |
36
+ | `--attempts N` | `3`; maximum attempts per operation, including the first |
37
+ | `--chunk-size SIZE` | `1MiB`; streaming buffer per active file |
38
+ | `--timeout SECONDS` | `120`; socket timeout |
39
+ | `--progress auto\|on\|off` | `auto`; enabled on terminal stderr |
40
+ | `--cache-dir PATH` | `~/.cache/hfms-bridge` |
41
+ | `--cache-max-size SIZE` | `256MiB`; minimum `64KiB`, oldest completed tasks evicted first |
42
+ | `--restart` | Ignore local progress and resolve the source again; identical remote data can still be reused |
43
+ | `--dry-run` | Read-only plan, no payload downloads, remote writes or checkpoint changes |
44
+ | `--hf-endpoint URL` | `HF_ENDPOINT` or `https://huggingface.co` |
45
+ | `--ms-endpoint URL` | `MODELSCOPE_ENDPOINT` or `https://modelscope.cn` |
46
+
47
+ Use `hfms-bridge --version` for the version. Sizes accept bytes, KiB/MiB/GiB or KB/MB/GB. Quote globs and place positional arguments before multi-value filters. A missing/inaccessible source produces an error; auto detection cannot discover repositories hidden from the current token.
48
+
49
+ Missing destinations are created automatically on their platform's default branch. Other destination branches must already exist. Existing repositories are updated through per-file commits; unrelated destination files are not deleted. Visibility is only set on creation. MS creation uses the source license when available, otherwise `Other`; license and README files are transferred normally. HF repository creation does not synthesize a license card.
50
+
51
+ Identical destination content is skipped using SHA-256 or, for ordinary HF files, Git blob SHA-1. Ordinary HF comparisons may require reading the source again. Dry runs do not download data to establish missing hashes, so some equality checks remain unknown. `--on-conflict error` checks all selected paths before remote writes; it does not provide an atomic transaction against concurrent external writers.
52
+
53
+ ## Architecture and recovery
54
+
55
+ For `ms2hf`, configuring `https://hf-mirror.com` as the HF endpoint routes destination requests directly to `https://huggingface.co`. This avoids replaying streamed commits after a mirror redirect and requires access to official HF. The configured endpoint remains part of the checkpoint identity, so existing mirror-configured tasks resume with the same command. `hf2ms` source downloads still use the configured mirror.
56
+
57
+ `hubs/hf.py` and `hubs/ms.py` implement source and destination adapters. `transfer.py`, `http.py`, `progress.py`, and `state.py` share scheduling, retry, checked streaming, progress and checkpoint logic across both directions.
58
+
59
+ HF sources pin a commit. MS sources store a SQLite manifest containing each file's immutable revision, size and digest; the root listing marker is checked before and after enumeration. An unfinished run reuses this manifest even when the source branch changes. This is a file-revision snapshot, not a server-side atomic repository snapshot. No file payload is stored locally. Metadata disk usage grows with the number of files; the cache budget protects active tasks from eviction and fails if they cannot fit.
60
+
61
+ Large payloads pass through bounded buffers. SHA-256 is computed while reading and validated against available source metadata before completion is recorded. Missing digests may require an extra source pass. HF preupload determines ordinary/LFS storage; ordinary file commits stream Base64 NDJSON, while LFS uses basic PUT or server-negotiated multipart upload. MS uses its existing LFS PUT/commit protocol. MS repository metadata files have a 1 MiB inline limit.
62
+
63
+ Source connection loss can resume inside a running upload using a strict HTTP 206 Range response. MS Range recovery is enabled only for LFS files; ordinary MS files restart their read because their Range behavior is unreliable. The extension (`.pt`, `.jsonl`, etc.) does not decide this: the server's LFS metadata does.
64
+
65
+ A destination upload failure retries the file. HF multipart parts are streamed sequentially, without buffering a whole part or persisting upload sessions; failed parts are not resumed independently. **Process exit or Ctrl-C resumes at file granularity, not within an unfinished file.** Completed blobs may be reused if the destination reports them present. Run the same command without `--restart` to continue; workers and progress settings can change without changing task identity.
66
+
67
+ Threads overlap network I/O with isolated HTTP sessions. Only commits and short checkpoint operations serialize. Progress has one overall file counter and a temporary row per active file. Byte counts reflect bytes consumed by the uploader, not server acknowledgements. Source Range recovery preserves progress; a whole-file retry resets it. Exhausted retries stop scheduling new files while active workers finish. Ctrl-C waits for active network calls to return or time out before releasing resources.
68
+
69
+ Credentials are excluded from checkpoints and stripped from cross-origin download redirects. Metadata redirects are restricted to trusted origins; streamed uploads and commits are not blindly replayed on redirects.
70
+
71
+ ## Python API
72
+
73
+ ```python
74
+ import os
75
+ from hfms_bridge import Transfer, TransferOptions
76
+
77
+ result = Transfer(
78
+ TransferOptions(
79
+ source="org/source",
80
+ destination="user/destination",
81
+ direction="ms2hf", # or "hf2ms"
82
+ workers=4,
83
+ ),
84
+ hf_token=os.environ["HF_TOKEN"],
85
+ ms_token=os.getenv("MODELSCOPE_API_TOKEN"),
86
+ ).run()
87
+ ```
88
+
89
+ ## Validation and build
90
+
91
+ ```bash
92
+ uv sync --locked
93
+ uv run ruff check .
94
+ uv run pytest
95
+ uv build
96
+ ```
97
+
98
+ Tests use local HTTP servers for both directions, actual streaming requests, multipart completion, Range recovery, pinned-manifest recovery, conflict handling, cache limits, cancellation and progress. CI covers Python 3.9–3.14 on Linux/macOS/Windows. Public MS model/dataset downloads and HF metadata endpoints are checked separately; local server tests do not replace authenticated end-to-end service validation.
99
+
100
+ Protocol references: [HF LFS implementation](https://github.com/huggingface/huggingface_hub/blob/main/src/huggingface_hub/lfs.py), [HF commits](https://github.com/huggingface/huggingface_hub/blob/main/src/huggingface_hub/_commit_api.py), [ModelScope REST/LFS](https://github.com/modelscope/modelscope_hub/blob/main/src/modelscope_hub/_legacy_api.py).
@@ -0,0 +1,93 @@
1
+ # hfms-bridge
2
+
3
+ [用户指南(英文)](docs/README.md) | [English](README.md) | **简体中文**
4
+
5
+ 在 HuggingFace(HF)与 ModelScope(MS)之间流式传输模型和数据集,不把文件内容保存到本地。支持 Python 3.9+、Linux、macOS 和 Windows。
6
+
7
+ ## 开发环境与使用
8
+
9
+ ```bash
10
+ uv sync --locked
11
+ uv run hfms-bridge hf2ms org/source user/destination --ms-token "$MODELSCOPE_API_TOKEN"
12
+ uv run hfms-bridge ms2hf org/source user/destination --hf-token "$HF_TOKEN"
13
+ uv run hfms-bridge ms2hf --help
14
+ ```
15
+
16
+ 目标端 token 必须显式传入。源端 token 可选,默认读取 `HF_TOKEN` 或 `MODELSCOPE_API_TOKEN`;私有或受限源仓库需要具备读取权限的 token。
17
+
18
+
19
+ ## 参数与仓库行为
20
+
21
+ | 参数 | 默认值 / 行为 |
22
+ | -------------------------------------- | --------------------------------------------------------------------------------------- |
23
+ | `SOURCE DESTINATION` | 必填,均为 `owner/repository` |
24
+ | `--repo-type auto\|model\|dataset` | auto 检查源端模型和数据集命名空间;只有一个可访问结果时选用它,两个均存在则要求显式指定 |
25
+ | `--hf-token TOKEN` | ms2hf 必填;hf2ms 可选,默认读取 `HF_TOKEN` |
26
+ | `--ms-token TOKEN` | hf2ms 必填;ms2hf 可选,默认读取 `MODELSCOPE_API_TOKEN` |
27
+ | `--hf-revision REV` | `main`;源端版本或已存在的目标分支 |
28
+ | `--ms-revision REV` | `master`;源端版本或已存在的目标分支 |
29
+ | `--visibility auto\|public\|private` | 仅新仓库;auto 对公开源创建公开目标,其余创建私有目标 |
30
+ | `--include GLOB [GLOB ...]` | 可重复,匹配仓库相对路径,区分大小写 |
31
+ | `--exclude GLOB [GLOB ...]` | 可重复,优先于 include |
32
+ | `--on-conflict overwrite\|error\|skip` | `overwrite`;处理内容不同或无法确认相同的目标文件 |
33
+ | `--workers N` | `4`;文件并行数,设为 1 即串行 |
34
+ | `--attempts N` | `3`;每项操作尝试次数,包含首次 |
35
+ | `--chunk-size SIZE` | `1MiB`;每个活动文件的读取缓冲 |
36
+ | `--timeout SECONDS` | `120`;网络超时 |
37
+ | `--progress auto\|on\|off` | `auto`;终端 stderr 显示进度 |
38
+ | `--cache-dir PATH` | `~/.cache/hfms-bridge` |
39
+ | `--cache-max-size SIZE` | `256MiB`;最小 64KiB,优先清理最久未使用的已完成任务 |
40
+ | `--restart` | 忽略本地进度并重新解析源版本,仍可复用远端相同内容 |
41
+ | `--dry-run` | 只读预览,不下载文件内容、不写远端、不更改缓存 |
42
+ | `--hf-endpoint URL` | `HF_ENDPOINT` 或 `https://huggingface.co` |
43
+ | `--ms-endpoint URL` | `MODELSCOPE_ENDPOINT` 或 `https://modelscope.cn` |
44
+
45
+ 版本查看使用 `hfms-bridge --version`。大小支持字节及 KiB/MiB/GiB、KB/MB/GB。请给 glob 加引号,并将源和目标位置参数放在多值筛选参数前。自动识别只针对当前 token 可见的仓库。
46
+
47
+ 目标仓库不存在时自动创建,使用该平台默认分支;其他目标分支必须提前创建。已有仓库逐文件提交更新,不删除目标上的其他文件。可见性只在创建时设置。创建 MS 仓库时采用源许可证,缺失时使用 `Other`;HF 不自动生成许可证卡片,许可证文件和 README 正常传输。
48
+
49
+ 通过 SHA-256 或 HF 普通文件的 Git blob SHA-1 比较相同内容并跳过。后者可能需要再次读取源文件。dry-run 不为比较下载内容,因此部分结果为未知。`--on-conflict error` 在远端写入前检查所选路径,但不能对其他客户端的并发修改提供事务保证。
50
+
51
+ ## 实现与恢复语义
52
+
53
+ `ms2hf` 配置 `https://hf-mirror.com` 时,目标端请求直接使用 `https://huggingface.co`,避免镜像跳转后重放已消耗的提交流,因此仍需能访问 HF 官方站点。检查点身份保留原始 endpoint 配置,已有任务使用原命令即可恢复。`hf2ms` 源端下载仍使用配置的镜像。
54
+
55
+ `hubs/hf.py`、`hubs/ms.py` 提供平台适配器,调度、重试、流校验、进度和检查点由公共引擎复用。
56
+
57
+ HF 源固定到 commit;MS 源把每个文件的不可变 revision、大小和摘要写入 SQLite 清单,枚举前后检查根列表标记。未完成任务恢复时复用清单,即使源分支已变化也保持文件版本。它是文件版本快照,不是服务端原子仓库快照。本地只保存元数据,不保存文件内容;元数据空间随文件数增长。缓存预算不会淘汰活动任务,放不下时会报错。
58
+
59
+ 文件内容通过有限缓冲传输,并在完成前校验可用的 SHA-256。缺少摘要可能增加一次读取。HF 由 preupload 接口决定普通/LFS 存储;普通文件使用流式 Base64 NDJSON 提交,LFS 使用单次 PUT 或服务端协商的分片上传。MS 使用现有 LFS PUT/commit 协议,仓库元数据文件有 1MiB 内联限制。
60
+
61
+ 源端断线可在当前上传过程中通过严格校验的 HTTP 206 Range 响应续读。MS 仅对 LFS 文件启用 Range,普通文件的 Range 行为不可靠,需重新读取。是否使用 LFS 取决于服务端元数据,与 `.pt`、`.jsonl` 等扩展名无关。
62
+
63
+ 目标端上传失败仍按文件重试。HF 分片顺序流式发送,不缓存整片,也不持久化分片会话;不单独续传失败分片。**进程退出或 Ctrl-C 后,只保证文件级恢复,未完成文件不能从中间字节继续。** 若目标端已保存完整 blob,则可协商复用。保持原命令、不加 `--restart` 即可恢复;修改 workers 或 progress 不影响任务身份。
64
+
65
+ 并行采用线程和独立 HTTP 会话,仅提交和短暂的 SQLite 操作串行。总进度统计完成或跳过文件,活动文件各有临时进度行。字节进度代表上传器读取量,不是服务端确认量;源端 Range 恢复不清零,整文件重试会清零。重试耗尽后停止派发新文件,等待活动任务完成。Ctrl-C 清理需等待正在执行的网络调用返回或超时。
66
+
67
+ token 不写入检查点,跨域下载跳转会移除认证信息。元数据跳转限于受信任来源,不自动重放已消耗的上传或提交流。
68
+
69
+ ## Python API
70
+
71
+ ```python
72
+ import os
73
+ from hfms_bridge import Transfer, TransferOptions
74
+
75
+ result = Transfer(
76
+ TransferOptions("org/source", "user/destination", direction="ms2hf", workers=4),
77
+ hf_token=os.environ["HF_TOKEN"],
78
+ ms_token=os.getenv("MODELSCOPE_API_TOKEN"),
79
+ ).run()
80
+ ```
81
+
82
+ ## 验证与构建
83
+
84
+ ```bash
85
+ uv sync --locked
86
+ uv run ruff check .
87
+ uv run pytest
88
+ uv build
89
+ ```
90
+
91
+ 本地 HTTP 服务测试覆盖双向流式请求、分片完成、Range 恢复、固定清单恢复、冲突处理、缓存限制、取消和进度。CI 配置 Python 3.9–3.14 与 Linux/macOS/Windows。公开 MS 模型/数据集下载和 HF 元数据接口另行只读验证;本地测试不能替代真实鉴权上传的端到端验证。
92
+
93
+ 协议参考:[HF LFS](https://github.com/huggingface/huggingface_hub/blob/main/src/huggingface_hub/lfs.py)、[HF commit](https://github.com/huggingface/huggingface_hub/blob/main/src/huggingface_hub/_commit_api.py)、[MS REST/LFS](https://github.com/modelscope/modelscope_hub/blob/main/src/modelscope_hub/_legacy_api.py)。
@@ -0,0 +1,70 @@
1
+ # hfms-bridge
2
+
3
+ Transfer models and datasets between **Hugging Face and ModelScope** with minimal local disk usage. File contents stream directly between services; only small metadata checkpoints are saved locally.
4
+
5
+ - Both directions: `hfms-bridge hf2ms` and `hfms-bridge ms2hf`.
6
+ - Parallel file transfers with overall and per-file progress bars.
7
+ - Automatic destination creation and incremental updates.
8
+ - File-level resume and recovery from interrupted source downloads.
9
+ - Python 3.9+, Linux, macOS and Windows.
10
+
11
+ ## Install
12
+
13
+ ```bash
14
+ pip install hfms-bridge
15
+ # Or install as an isolated command:
16
+ uv tool install hfms-bridge
17
+ ```
18
+
19
+ ## Transfer
20
+
21
+ From Hugging Face to ModelScope:
22
+
23
+ ```bash
24
+ hfms-bridge hf2ms org/source user/destination --ms-token "$MODELSCOPE_API_TOKEN"
25
+ ```
26
+
27
+ From ModelScope to Hugging Face:
28
+
29
+ ```bash
30
+ hfms-bridge ms2hf org/source user/destination --hf-token "$HF_TOKEN"
31
+ ```
32
+
33
+ The destination token is required explicitly and needs write/create permission. Public sources normally need no token. For private sources, pass `--hf-token` or `--ms-token`, or set the source token environment variable (`HF_TOKEN` or `MODELSCOPE_API_TOKEN`).
34
+
35
+ In PowerShell, use `$env:HF_TOKEN` or `$env:MODELSCOPE_API_TOKEN` instead of the shell variables above.
36
+
37
+ ## Common options
38
+
39
+ ```bash
40
+ # Preview without downloading payloads or modifying repositories/cache
41
+ hfms-bridge ms2hf org/source user/destination --hf-token "$HF_TOKEN" --dry-run
42
+
43
+ # Select files and concurrency
44
+ hfms-bridge hf2ms org/source user/destination --ms-token "$MODELSCOPE_API_TOKEN" \
45
+ --workers 4 --include '*.safetensors' '*.json' --exclude 'original/*'
46
+
47
+ hfms-bridge hf2ms --help
48
+ hfms-bridge ms2hf --help
49
+ ```
50
+
51
+ `--repo-type auto` checks the source's model and dataset namespaces and selects the unique accessible match. If both exist, choose `--repo-type model` or `--repo-type dataset` explicitly. The destination uses the same type.
52
+
53
+ `--hf-revision` defaults to `main`; `--ms-revision` defaults to `master`. Source revisions can be selected independently. A missing destination is created on its default branch; other destination branches must already exist. `--visibility auto|public|private` controls new repositories; auto creates private destinations for private, gated or unknown-visibility sources.
54
+
55
+ Existing identical files are skipped; different content is overwritten by default. Choose `--on-conflict error` or `--on-conflict skip` to change that behavior. Files unrelated to the transfer are not deleted.
56
+
57
+ ## Resume and resource usage
58
+
59
+ If `HF_ENDPOINT` or `--hf-endpoint` is `https://hf-mirror.com`, `ms2hf` sends destination requests directly to official HF (`https://huggingface.co`) to avoid upload redirects. Official HF must be reachable. Existing tasks can resume using the same command and cache; `hf2ms` downloads still use the mirror.
60
+
61
+ Run the same command again after an error or interruption. Completed files are compared and skipped when identical. Source file versions are pinned for unfinished tasks. Changing `--workers` or `--progress` does not discard progress. `--restart` resolves the source again; it does not force identical remote blobs to upload again.
62
+
63
+ No payload is cached on disk. Metadata checkpoints default to `~/.cache/hfms-bridge`, with a `256MiB` budget; change this with `--cache-dir` and `--cache-max-size`. Old completed tasks are evicted first, and active tasks are protected. Memory scales mainly with worker count and read buffers (`--chunk-size`, default `1MiB`).
64
+
65
+ Interrupted source reads can continue through HTTP Range while the process is running. MS supports this path for LFS files; ordinary MS files restart their read. HF uploads can use server-negotiated multipart uploads, with each part streamed directly. **Destination upload failures and process restarts do not support file-internal resume:** unfinished files may restart from byte zero. Complete remote blobs may still be reused.
66
+
67
+ For ordinary HF destination files, checking equality may require another source read. Large ordinary files are committed using streaming Base64. MS repository metadata files have a 1MiB inline limit. Network, permission, service file-size and rate limits still apply.
68
+
69
+
70
+ Source and developer documentation: [English](https://github.com/feixyz10/hfms-bridge/blob/main/README.md), [简体中文](https://github.com/feixyz10/hfms-bridge/blob/main/README_CN.md).
@@ -0,0 +1,63 @@
1
+ [build-system]
2
+ requires = ["hatchling>=1.27,<2"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "hfms-bridge"
7
+ version = "0.4.0"
8
+ description = "Stream models and datasets between HuggingFace and ModelScope"
9
+ readme = "docs/README.md"
10
+ authors = [{ name = "ExcitingMe" }]
11
+ requires-python = ">=3.9"
12
+ license = "MIT"
13
+ license-files = ["LICENSE"]
14
+ keywords = ["huggingface", "modelscope", "datasets", "models", "streaming", "transfer", "cli"]
15
+ dependencies = ["requests>=2.32.3,<3", "filelock>=3.16,<4", "tqdm>=4.66,<5"]
16
+ classifiers = [
17
+ "Environment :: Console",
18
+ "Intended Audience :: Developers",
19
+ "Topic :: Utilities",
20
+ "Programming Language :: Python :: 3 :: Only",
21
+ "Operating System :: OS Independent",
22
+ "Programming Language :: Python :: 3",
23
+ "Programming Language :: Python :: 3.9",
24
+ "Programming Language :: Python :: 3.10",
25
+ "Programming Language :: Python :: 3.11",
26
+ "Programming Language :: Python :: 3.12",
27
+ "Programming Language :: Python :: 3.13",
28
+ "Programming Language :: Python :: 3.14",
29
+ ]
30
+
31
+ [project.urls]
32
+ Homepage = "https://github.com/feixyz10/hfms-bridge/"
33
+ Source = "https://github.com/feixyz10/hfms-bridge/"
34
+ Issues = "https://github.com/feixyz10/hfms-bridge/issues"
35
+
36
+ [project.scripts]
37
+ hfms-bridge = "hfms_bridge.cli:main"
38
+
39
+ [dependency-groups]
40
+ dev = ["pytest>=8,<9", "ruff>=0.11,<1"]
41
+
42
+ [[tool.uv.index]]
43
+ name = "pypi"
44
+ url = "https://pypi.org/simple"
45
+ default = true
46
+
47
+ [tool.ruff]
48
+ target-version = "py39"
49
+ line-length = 100
50
+
51
+ [tool.ruff.lint]
52
+ select = ["E4", "E7", "E9", "F", "B"]
53
+
54
+ [tool.pytest.ini_options]
55
+ testpaths = ["tests"]
56
+
57
+ # Keep release metadata compatible with Twine 6 validation.
58
+ [tool.hatch.build.targets.wheel]
59
+ packages = ["src/hfms_bridge"]
60
+ core-metadata-version = "2.4"
61
+
62
+ [tool.hatch.build.targets.sdist]
63
+ core-metadata-version = "2.4"
@@ -0,0 +1,6 @@
1
+ """Streaming repository transfer without storing payloads on disk."""
2
+
3
+ from .transfer import Transfer, TransferOptions
4
+
5
+ __all__ = ["Transfer", "TransferOptions"]
6
+ __version__ = "0.4.0"
@@ -0,0 +1,3 @@
1
+ from .cli import main
2
+
3
+ raise SystemExit(main())