modelscope-hub 0.4.0__tar.gz → 0.4.2__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.
- {modelscope_hub-0.4.0/src/modelscope_hub.egg-info → modelscope_hub-0.4.2}/PKG-INFO +1 -1
- {modelscope_hub-0.4.0 → modelscope_hub-0.4.2}/src/modelscope_hub/_upload.py +36 -0
- {modelscope_hub-0.4.0 → modelscope_hub-0.4.2}/src/modelscope_hub/api.py +70 -42
- {modelscope_hub-0.4.0 → modelscope_hub-0.4.2}/src/modelscope_hub/compat/hub_api.py +30 -0
- {modelscope_hub-0.4.0 → modelscope_hub-0.4.2}/src/modelscope_hub/version.py +1 -1
- {modelscope_hub-0.4.0 → modelscope_hub-0.4.2/src/modelscope_hub.egg-info}/PKG-INFO +1 -1
- {modelscope_hub-0.4.0 → modelscope_hub-0.4.2}/src/modelscope_hub.egg-info/SOURCES.txt +1 -0
- modelscope_hub-0.4.2/tests/test_compat_delete_files.py +54 -0
- {modelscope_hub-0.4.0 → modelscope_hub-0.4.2}/tests/test_upload_lfs_gate.py +141 -1
- {modelscope_hub-0.4.0 → modelscope_hub-0.4.2}/LICENSE +0 -0
- {modelscope_hub-0.4.0 → modelscope_hub-0.4.2}/README.md +0 -0
- {modelscope_hub-0.4.0 → modelscope_hub-0.4.2}/pyproject.toml +0 -0
- {modelscope_hub-0.4.0 → modelscope_hub-0.4.2}/setup.cfg +0 -0
- {modelscope_hub-0.4.0 → modelscope_hub-0.4.2}/src/modelscope_hub/__init__.py +0 -0
- {modelscope_hub-0.4.0 → modelscope_hub-0.4.2}/src/modelscope_hub/_cache_manager.py +0 -0
- {modelscope_hub-0.4.0 → modelscope_hub-0.4.2}/src/modelscope_hub/_download.py +0 -0
- {modelscope_hub-0.4.0 → modelscope_hub-0.4.2}/src/modelscope_hub/_git.py +0 -0
- {modelscope_hub-0.4.0 → modelscope_hub-0.4.2}/src/modelscope_hub/_legacy_api.py +0 -0
- {modelscope_hub-0.4.0 → modelscope_hub-0.4.2}/src/modelscope_hub/_openapi.py +0 -0
- {modelscope_hub-0.4.0 → modelscope_hub-0.4.2}/src/modelscope_hub/_repository.py +0 -0
- {modelscope_hub-0.4.0 → modelscope_hub-0.4.2}/src/modelscope_hub/agent/__init__.py +0 -0
- {modelscope_hub-0.4.0 → modelscope_hub-0.4.2}/src/modelscope_hub/agent/_api.py +0 -0
- {modelscope_hub-0.4.0 → modelscope_hub-0.4.2}/src/modelscope_hub/agent_idp.py +0 -0
- {modelscope_hub-0.4.0 → modelscope_hub-0.4.2}/src/modelscope_hub/cli/__init__.py +0 -0
- {modelscope_hub-0.4.0 → modelscope_hub-0.4.2}/src/modelscope_hub/cli/agent.py +0 -0
- {modelscope_hub-0.4.0 → modelscope_hub-0.4.2}/src/modelscope_hub/cli/agent_idp.py +0 -0
- {modelscope_hub-0.4.0 → modelscope_hub-0.4.2}/src/modelscope_hub/cli/base.py +0 -0
- {modelscope_hub-0.4.0 → modelscope_hub-0.4.2}/src/modelscope_hub/cli/cache.py +0 -0
- {modelscope_hub-0.4.0 → modelscope_hub-0.4.2}/src/modelscope_hub/cli/compat.py +0 -0
- {modelscope_hub-0.4.0 → modelscope_hub-0.4.2}/src/modelscope_hub/cli/deploy.py +0 -0
- {modelscope_hub-0.4.0 → modelscope_hub-0.4.2}/src/modelscope_hub/cli/download.py +0 -0
- {modelscope_hub-0.4.0 → modelscope_hub-0.4.2}/src/modelscope_hub/cli/login.py +0 -0
- {modelscope_hub-0.4.0 → modelscope_hub-0.4.2}/src/modelscope_hub/cli/main.py +0 -0
- {modelscope_hub-0.4.0 → modelscope_hub-0.4.2}/src/modelscope_hub/cli/mcp.py +0 -0
- {modelscope_hub-0.4.0 → modelscope_hub-0.4.2}/src/modelscope_hub/cli/repo.py +0 -0
- {modelscope_hub-0.4.0 → modelscope_hub-0.4.2}/src/modelscope_hub/cli/secret.py +0 -0
- {modelscope_hub-0.4.0 → modelscope_hub-0.4.2}/src/modelscope_hub/cli/studio.py +0 -0
- {modelscope_hub-0.4.0 → modelscope_hub-0.4.2}/src/modelscope_hub/cli/upload.py +0 -0
- {modelscope_hub-0.4.0 → modelscope_hub-0.4.2}/src/modelscope_hub/compat/__init__.py +0 -0
- {modelscope_hub-0.4.0 → modelscope_hub-0.4.2}/src/modelscope_hub/compat/constants.py +0 -0
- {modelscope_hub-0.4.0 → modelscope_hub-0.4.2}/src/modelscope_hub/compat/file_download.py +0 -0
- {modelscope_hub-0.4.0 → modelscope_hub-0.4.2}/src/modelscope_hub/compat/snapshot_download.py +0 -0
- {modelscope_hub-0.4.0 → modelscope_hub-0.4.2}/src/modelscope_hub/config.py +0 -0
- {modelscope_hub-0.4.0 → modelscope_hub-0.4.2}/src/modelscope_hub/constants.py +0 -0
- {modelscope_hub-0.4.0 → modelscope_hub-0.4.2}/src/modelscope_hub/errors.py +0 -0
- {modelscope_hub-0.4.0 → modelscope_hub-0.4.2}/src/modelscope_hub/py.typed +0 -0
- {modelscope_hub-0.4.0 → modelscope_hub-0.4.2}/src/modelscope_hub/types.py +0 -0
- {modelscope_hub-0.4.0 → modelscope_hub-0.4.2}/src/modelscope_hub/utils/__init__.py +0 -0
- {modelscope_hub-0.4.0 → modelscope_hub-0.4.2}/src/modelscope_hub/utils/file_utils.py +0 -0
- {modelscope_hub-0.4.0 → modelscope_hub-0.4.2}/src/modelscope_hub/utils/format.py +0 -0
- {modelscope_hub-0.4.0 → modelscope_hub-0.4.2}/src/modelscope_hub/utils/logger.py +0 -0
- {modelscope_hub-0.4.0 → modelscope_hub-0.4.2}/src/modelscope_hub/utils/media.py +0 -0
- {modelscope_hub-0.4.0 → modelscope_hub-0.4.2}/src/modelscope_hub/utils/patterns.py +0 -0
- {modelscope_hub-0.4.0 → modelscope_hub-0.4.2}/src/modelscope_hub/utils/time_utils.py +0 -0
- {modelscope_hub-0.4.0 → modelscope_hub-0.4.2}/src/modelscope_hub.egg-info/dependency_links.txt +0 -0
- {modelscope_hub-0.4.0 → modelscope_hub-0.4.2}/src/modelscope_hub.egg-info/entry_points.txt +0 -0
- {modelscope_hub-0.4.0 → modelscope_hub-0.4.2}/src/modelscope_hub.egg-info/requires.txt +0 -0
- {modelscope_hub-0.4.0 → modelscope_hub-0.4.2}/src/modelscope_hub.egg-info/top_level.txt +0 -0
- {modelscope_hub-0.4.0 → modelscope_hub-0.4.2}/tests/test_agent_idp.py +0 -0
- {modelscope_hub-0.4.0 → modelscope_hub-0.4.2}/tests/test_agent_idp_keys.py +0 -0
- {modelscope_hub-0.4.0 → modelscope_hub-0.4.2}/tests/test_cache_verification.py +0 -0
- {modelscope_hub-0.4.0 → modelscope_hub-0.4.2}/tests/test_compat_get_model_files.py +0 -0
- {modelscope_hub-0.4.0 → modelscope_hub-0.4.2}/tests/test_compat_snapshot_download.py +0 -0
- {modelscope_hub-0.4.0 → modelscope_hub-0.4.2}/tests/test_compat_studio.py +0 -0
- {modelscope_hub-0.4.0 → modelscope_hub-0.4.2}/tests/test_config_token.py +0 -0
- {modelscope_hub-0.4.0 → modelscope_hub-0.4.2}/tests/test_credential_lifecycle.py +0 -0
- {modelscope_hub-0.4.0 → modelscope_hub-0.4.2}/tests/test_download_lock_path.py +0 -0
- {modelscope_hub-0.4.0 → modelscope_hub-0.4.2}/tests/test_errors_openapi_codes.py +0 -0
- {modelscope_hub-0.4.0 → modelscope_hub-0.4.2}/tests/test_legacy_cache_detection.py +0 -0
- {modelscope_hub-0.4.0 → modelscope_hub-0.4.2}/tests/test_login_failure_paths.py +0 -0
- {modelscope_hub-0.4.0 → modelscope_hub-0.4.2}/tests/test_login_scoped_token.py +0 -0
- {modelscope_hub-0.4.0 → modelscope_hub-0.4.2}/tests/test_openapi_coverage.py +0 -0
- {modelscope_hub-0.4.0 → modelscope_hub-0.4.2}/tests/test_repo_files_truncation.py +0 -0
- {modelscope_hub-0.4.0 → modelscope_hub-0.4.2}/tests/test_upload_config.py +0 -0
- {modelscope_hub-0.4.0 → modelscope_hub-0.4.2}/tests/test_user_info.py +0 -0
- {modelscope_hub-0.4.0 → modelscope_hub-0.4.2}/tests/test_utils.py +0 -0
|
@@ -635,6 +635,42 @@ class UploadManager:
|
|
|
635
635
|
revision=revision,
|
|
636
636
|
)
|
|
637
637
|
|
|
638
|
+
# ------------------------------------------------------------------
|
|
639
|
+
# Public: delete_files
|
|
640
|
+
# ------------------------------------------------------------------
|
|
641
|
+
def delete_files(
|
|
642
|
+
self,
|
|
643
|
+
repo_id: str,
|
|
644
|
+
repo_type: str,
|
|
645
|
+
file_paths: list[str],
|
|
646
|
+
*,
|
|
647
|
+
commit_message: str = "Delete files",
|
|
648
|
+
revision: str = "master",
|
|
649
|
+
) -> dict:
|
|
650
|
+
"""Delete repository files through a commit operation.
|
|
651
|
+
|
|
652
|
+
The direct repository DELETE endpoints reject API-token authentication.
|
|
653
|
+
Commit ``delete`` actions use the same supported write path as uploads
|
|
654
|
+
and are applied atomically in a single commit.
|
|
655
|
+
"""
|
|
656
|
+
paths = list(dict.fromkeys(path for path in file_paths if path))
|
|
657
|
+
if not paths:
|
|
658
|
+
raise InvalidParameter(
|
|
659
|
+
"file_paths must contain at least one non-empty path.")
|
|
660
|
+
|
|
661
|
+
self._commit_with_retry(
|
|
662
|
+
repo_id=repo_id,
|
|
663
|
+
repo_type=repo_type,
|
|
664
|
+
operations=self._build_delete_operations(paths),
|
|
665
|
+
commit_message=commit_message,
|
|
666
|
+
revision=revision,
|
|
667
|
+
)
|
|
668
|
+
return {
|
|
669
|
+
"deleted_files": paths,
|
|
670
|
+
"failed_files": [],
|
|
671
|
+
"total_files": len(paths),
|
|
672
|
+
}
|
|
673
|
+
|
|
638
674
|
# ------------------------------------------------------------------
|
|
639
675
|
# Public: upload_folder
|
|
640
676
|
# ------------------------------------------------------------------
|
|
@@ -23,6 +23,7 @@ Design principles
|
|
|
23
23
|
|
|
24
24
|
from __future__ import annotations
|
|
25
25
|
|
|
26
|
+
import fnmatch
|
|
26
27
|
import time
|
|
27
28
|
from collections.abc import Iterable, Mapping
|
|
28
29
|
from pathlib import Path
|
|
@@ -46,7 +47,6 @@ from .errors import (
|
|
|
46
47
|
AuthenticationError,
|
|
47
48
|
HubError,
|
|
48
49
|
InvalidParameter,
|
|
49
|
-
NetworkError,
|
|
50
50
|
NotExistError,
|
|
51
51
|
NotSupportedError,
|
|
52
52
|
PermissionDeniedError,
|
|
@@ -1670,17 +1670,18 @@ class HubApi:
|
|
|
1670
1670
|
self,
|
|
1671
1671
|
repo_id: str,
|
|
1672
1672
|
repo_type: RepoTypeLike,
|
|
1673
|
-
file_paths: Iterable[str],
|
|
1673
|
+
file_paths: Iterable[str] | str | None = None,
|
|
1674
1674
|
*,
|
|
1675
|
+
delete_patterns: Iterable[str] | str | None = None,
|
|
1675
1676
|
commit_message: str | None = None,
|
|
1676
1677
|
revision: str | None = None,
|
|
1677
1678
|
) -> dict:
|
|
1678
|
-
"""Delete
|
|
1679
|
+
"""Delete repository files selected by paths or glob patterns.
|
|
1679
1680
|
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1681
|
+
The direct repository DELETE endpoints reject API-token authentication.
|
|
1682
|
+
This method resolves optional glob patterns against the remote file list,
|
|
1683
|
+
then sends commit ``delete`` actions through the same supported write
|
|
1684
|
+
path as :meth:`upload_file` and :meth:`upload_folder`.
|
|
1684
1685
|
|
|
1685
1686
|
Parameters
|
|
1686
1687
|
----------
|
|
@@ -1688,53 +1689,80 @@ class HubApi:
|
|
|
1688
1689
|
Canonical ``owner/name`` identifier.
|
|
1689
1690
|
repo_type : str or RepoType
|
|
1690
1691
|
Repository type.
|
|
1691
|
-
file_paths : iterable of str
|
|
1692
|
-
|
|
1692
|
+
file_paths : iterable of str or str, optional
|
|
1693
|
+
Explicit repository-relative paths to remove.
|
|
1694
|
+
delete_patterns : iterable of str or str, optional
|
|
1695
|
+
Glob patterns matched against remote file paths. For example,
|
|
1696
|
+
``"*.json"`` matches JSON files at any repository depth.
|
|
1693
1697
|
commit_message : str, optional
|
|
1694
|
-
|
|
1698
|
+
Message for the delete commit. Defaults to ``"Delete files"``.
|
|
1695
1699
|
revision : str, optional
|
|
1696
1700
|
Branch to delete from. Defaults to ``"master"``.
|
|
1697
1701
|
|
|
1698
1702
|
Returns
|
|
1699
1703
|
-------
|
|
1700
1704
|
dict
|
|
1701
|
-
Summary with ``deleted_files`` and ``
|
|
1702
|
-
|
|
1703
|
-
Raises
|
|
1704
|
-
------
|
|
1705
|
-
InvalidParameter
|
|
1706
|
-
When ``file_paths`` resolves to an empty list.
|
|
1707
|
-
|
|
1708
|
-
Examples
|
|
1709
|
-
--------
|
|
1710
|
-
>>> api.delete_files(
|
|
1711
|
-
... "alice/llama-7b",
|
|
1712
|
-
... "model",
|
|
1713
|
-
... ["old_weights.bin", "deprecated/config.json"],
|
|
1714
|
-
... )
|
|
1705
|
+
Summary with ``deleted_files``, ``failed_files``, and ``total_files``.
|
|
1706
|
+
A pattern with no remote matches returns an empty successful summary.
|
|
1715
1707
|
"""
|
|
1716
1708
|
rt = self._normalize_repo_type(repo_type)
|
|
1717
|
-
paths =
|
|
1709
|
+
paths = self._normalize_delete_values(file_paths, "file_paths")
|
|
1710
|
+
patterns = self._normalize_delete_values(
|
|
1711
|
+
delete_patterns, "delete_patterns")
|
|
1712
|
+
if not paths and not patterns:
|
|
1713
|
+
raise InvalidParameter(
|
|
1714
|
+
"Provide at least one file path or delete pattern.")
|
|
1715
|
+
|
|
1716
|
+
resolved_revision = revision or "master"
|
|
1717
|
+
if patterns:
|
|
1718
|
+
remote_paths = [
|
|
1719
|
+
file.path
|
|
1720
|
+
for file in self.list_repo_files(
|
|
1721
|
+
repo_id,
|
|
1722
|
+
rt,
|
|
1723
|
+
revision=resolved_revision,
|
|
1724
|
+
recursive=True,
|
|
1725
|
+
)
|
|
1726
|
+
if file.path and file.type != "tree"
|
|
1727
|
+
]
|
|
1728
|
+
paths.extend(
|
|
1729
|
+
path for path in remote_paths
|
|
1730
|
+
if any(fnmatch.fnmatchcase(path, pattern)
|
|
1731
|
+
for pattern in patterns))
|
|
1732
|
+
|
|
1733
|
+
paths = list(dict.fromkeys(paths))
|
|
1718
1734
|
if not paths:
|
|
1719
|
-
|
|
1735
|
+
return {
|
|
1736
|
+
"deleted_files": [],
|
|
1737
|
+
"failed_files": [],
|
|
1738
|
+
"total_files": 0,
|
|
1739
|
+
}
|
|
1720
1740
|
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
revision=revision or "master",
|
|
1729
|
-
)
|
|
1730
|
-
deleted.append(p)
|
|
1731
|
-
except (AuthenticationError, NetworkError):
|
|
1732
|
-
failed.append(p)
|
|
1733
|
-
raise
|
|
1734
|
-
except Exception:
|
|
1735
|
-
failed.append(p)
|
|
1741
|
+
return self.uploader.delete_files(
|
|
1742
|
+
repo_id=repo_id,
|
|
1743
|
+
repo_type=str(rt),
|
|
1744
|
+
file_paths=paths,
|
|
1745
|
+
commit_message=commit_message or "Delete files",
|
|
1746
|
+
revision=resolved_revision,
|
|
1747
|
+
)
|
|
1736
1748
|
|
|
1737
|
-
|
|
1749
|
+
@staticmethod
|
|
1750
|
+
def _normalize_delete_values(
|
|
1751
|
+
values: Iterable[str] | str | None,
|
|
1752
|
+
parameter_name: str,
|
|
1753
|
+
) -> list[str]:
|
|
1754
|
+
"""Normalize a delete path or glob-pattern argument."""
|
|
1755
|
+
if values is None:
|
|
1756
|
+
return []
|
|
1757
|
+
raw_values = [values] if isinstance(values, str) else list(values)
|
|
1758
|
+
normalized: list[str] = []
|
|
1759
|
+
for value in raw_values:
|
|
1760
|
+
if not isinstance(value, str):
|
|
1761
|
+
raise InvalidParameter(
|
|
1762
|
+
f"{parameter_name} must contain only strings.")
|
|
1763
|
+
if value:
|
|
1764
|
+
normalized.append(value)
|
|
1765
|
+
return normalized
|
|
1738
1766
|
|
|
1739
1767
|
# ==================================================================
|
|
1740
1768
|
# Versioning
|
|
@@ -195,6 +195,36 @@ class LegacyHubApi:
|
|
|
195
195
|
result = [f for f in result if f["Path"] == prefix or str(f["Path"]).startswith(prefix + "/")]
|
|
196
196
|
return result
|
|
197
197
|
|
|
198
|
+
def delete_files(
|
|
199
|
+
self,
|
|
200
|
+
repo_id: str,
|
|
201
|
+
repo_type: str | RepoType = RepoType.MODEL,
|
|
202
|
+
delete_patterns: str | list[str] | None = None,
|
|
203
|
+
*,
|
|
204
|
+
file_paths: str | list[str] | None = None,
|
|
205
|
+
revision: str | None = DEFAULT_DATASET_REVISION,
|
|
206
|
+
commit_message: str | None = None,
|
|
207
|
+
endpoint: str | None = None,
|
|
208
|
+
token: str | None = None,
|
|
209
|
+
) -> dict:
|
|
210
|
+
"""Delete files selected by legacy glob patterns or explicit paths.
|
|
211
|
+
|
|
212
|
+
``delete_patterns`` preserves the historical ``modelscope.hub.api``
|
|
213
|
+
contract. Patterns are resolved against the remote repository by the
|
|
214
|
+
modelscope-hub facade before it commits atomic delete actions.
|
|
215
|
+
"""
|
|
216
|
+
api = self._api
|
|
217
|
+
if token or endpoint:
|
|
218
|
+
api = HubApi(endpoint=endpoint or self._endpoint, token=token)
|
|
219
|
+
return api.delete_files(
|
|
220
|
+
repo_id,
|
|
221
|
+
repo_type,
|
|
222
|
+
file_paths=file_paths,
|
|
223
|
+
delete_patterns=delete_patterns,
|
|
224
|
+
commit_message=commit_message,
|
|
225
|
+
revision=revision,
|
|
226
|
+
)
|
|
227
|
+
|
|
198
228
|
def create_repo(
|
|
199
229
|
self,
|
|
200
230
|
repo_id: str,
|
|
@@ -55,6 +55,7 @@ src/modelscope_hub/utils/time_utils.py
|
|
|
55
55
|
tests/test_agent_idp.py
|
|
56
56
|
tests/test_agent_idp_keys.py
|
|
57
57
|
tests/test_cache_verification.py
|
|
58
|
+
tests/test_compat_delete_files.py
|
|
58
59
|
tests/test_compat_get_model_files.py
|
|
59
60
|
tests/test_compat_snapshot_download.py
|
|
60
61
|
tests/test_compat_studio.py
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from unittest import mock
|
|
4
|
+
|
|
5
|
+
from modelscope_hub.compat import LegacyHubApi
|
|
6
|
+
from modelscope_hub.constants import RepoType
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def test_legacy_hub_api_preserves_delete_patterns_contract() -> None:
|
|
10
|
+
api = LegacyHubApi(endpoint="https://modelscope.cn", token="test-token")
|
|
11
|
+
expected = {
|
|
12
|
+
"deleted_files": ["config.json"],
|
|
13
|
+
"failed_files": [],
|
|
14
|
+
"total_files": 1,
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
with mock.patch.object(api._api, "delete_files", return_value=expected) as delete_files:
|
|
18
|
+
result = api.delete_files(
|
|
19
|
+
repo_id="owner/repo",
|
|
20
|
+
repo_type=RepoType.MODEL,
|
|
21
|
+
delete_patterns="*.json",
|
|
22
|
+
revision="main",
|
|
23
|
+
commit_message="Delete JSON files",
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
delete_files.assert_called_once_with(
|
|
27
|
+
"owner/repo",
|
|
28
|
+
RepoType.MODEL,
|
|
29
|
+
file_paths=None,
|
|
30
|
+
delete_patterns="*.json",
|
|
31
|
+
commit_message="Delete JSON files",
|
|
32
|
+
revision="main",
|
|
33
|
+
)
|
|
34
|
+
assert result == expected
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def test_legacy_hub_api_delete_files_supports_explicit_paths() -> None:
|
|
38
|
+
api = LegacyHubApi(token="test-token")
|
|
39
|
+
|
|
40
|
+
with mock.patch.object(api._api, "delete_files", return_value={}) as delete_files:
|
|
41
|
+
api.delete_files(
|
|
42
|
+
"owner/repo",
|
|
43
|
+
repo_type="dataset",
|
|
44
|
+
file_paths=["data/old.json"],
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
delete_files.assert_called_once_with(
|
|
48
|
+
"owner/repo",
|
|
49
|
+
"dataset",
|
|
50
|
+
file_paths=["data/old.json"],
|
|
51
|
+
delete_patterns=None,
|
|
52
|
+
commit_message=None,
|
|
53
|
+
revision="master",
|
|
54
|
+
)
|
|
@@ -4,11 +4,15 @@ import base64
|
|
|
4
4
|
import hashlib
|
|
5
5
|
import json
|
|
6
6
|
from pathlib import Path
|
|
7
|
+
from types import SimpleNamespace
|
|
7
8
|
from unittest.mock import MagicMock
|
|
8
9
|
|
|
10
|
+
import pytest
|
|
11
|
+
|
|
9
12
|
import modelscope_hub._upload as upload_module
|
|
13
|
+
from modelscope_hub import HubApi
|
|
10
14
|
from modelscope_hub._upload import UploadManager
|
|
11
|
-
from modelscope_hub.errors import NetworkError
|
|
15
|
+
from modelscope_hub.errors import InvalidParameter, NetworkError
|
|
12
16
|
|
|
13
17
|
|
|
14
18
|
def _make_manager() -> tuple[UploadManager, MagicMock]:
|
|
@@ -27,6 +31,142 @@ def _make_manager() -> tuple[UploadManager, MagicMock]:
|
|
|
27
31
|
return UploadManager(client, MagicMock()), client
|
|
28
32
|
|
|
29
33
|
|
|
34
|
+
@pytest.mark.parametrize("repo_type", ["model", "dataset"])
|
|
35
|
+
def test_delete_files_commits_atomic_delete_actions(repo_type: str) -> None:
|
|
36
|
+
manager, client = _make_manager()
|
|
37
|
+
|
|
38
|
+
result = manager.delete_files(
|
|
39
|
+
repo_id="owner/repo",
|
|
40
|
+
repo_type=repo_type,
|
|
41
|
+
file_paths=["old.bin", "nested/deprecated.json", "old.bin"],
|
|
42
|
+
commit_message="Remove obsolete files",
|
|
43
|
+
revision="main",
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
client.create_commit.assert_called_once_with(
|
|
47
|
+
repo_id="owner/repo",
|
|
48
|
+
repo_type=repo_type,
|
|
49
|
+
operations=[
|
|
50
|
+
{
|
|
51
|
+
"action": "delete",
|
|
52
|
+
"path": "old.bin",
|
|
53
|
+
"type": "normal",
|
|
54
|
+
"size": 0,
|
|
55
|
+
"sha256": "",
|
|
56
|
+
"content": "",
|
|
57
|
+
"encoding": "",
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"action": "delete",
|
|
61
|
+
"path": "nested/deprecated.json",
|
|
62
|
+
"type": "normal",
|
|
63
|
+
"size": 0,
|
|
64
|
+
"sha256": "",
|
|
65
|
+
"content": "",
|
|
66
|
+
"encoding": "",
|
|
67
|
+
},
|
|
68
|
+
],
|
|
69
|
+
commit_message="Remove obsolete files",
|
|
70
|
+
revision="main",
|
|
71
|
+
)
|
|
72
|
+
assert result == {
|
|
73
|
+
"deleted_files": ["old.bin", "nested/deprecated.json"],
|
|
74
|
+
"failed_files": [],
|
|
75
|
+
"total_files": 2,
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def test_delete_files_rejects_empty_paths() -> None:
|
|
80
|
+
manager, client = _make_manager()
|
|
81
|
+
|
|
82
|
+
with pytest.raises(InvalidParameter, match="at least one"):
|
|
83
|
+
manager.delete_files(
|
|
84
|
+
repo_id="owner/repo", repo_type="model", file_paths=["", ""])
|
|
85
|
+
|
|
86
|
+
client.create_commit.assert_not_called()
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
@pytest.mark.parametrize("repo_type", ["model", "dataset"])
|
|
90
|
+
@pytest.mark.parametrize("file_paths", [["", "old.bin"], "old.bin"])
|
|
91
|
+
def test_hub_api_delete_files_delegates_to_upload_manager(
|
|
92
|
+
repo_type: str, file_paths: list[str] | str
|
|
93
|
+
) -> None:
|
|
94
|
+
api = HubApi(token="test-token")
|
|
95
|
+
api._uploader = MagicMock()
|
|
96
|
+
api._uploader.delete_files.return_value = {"deleted_files": ["old.bin"]}
|
|
97
|
+
|
|
98
|
+
result = api.delete_files(
|
|
99
|
+
"owner/repo",
|
|
100
|
+
repo_type,
|
|
101
|
+
file_paths,
|
|
102
|
+
commit_message="Remove obsolete files",
|
|
103
|
+
revision="main",
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
api._uploader.delete_files.assert_called_once_with(
|
|
107
|
+
repo_id="owner/repo",
|
|
108
|
+
repo_type=repo_type,
|
|
109
|
+
file_paths=["old.bin"],
|
|
110
|
+
commit_message="Remove obsolete files",
|
|
111
|
+
revision="main",
|
|
112
|
+
)
|
|
113
|
+
assert result == {"deleted_files": ["old.bin"]}
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
@pytest.mark.parametrize("repo_type", ["model", "dataset"])
|
|
117
|
+
def test_hub_api_delete_patterns_resolve_remote_paths(repo_type: str) -> None:
|
|
118
|
+
api = HubApi(token="test-token")
|
|
119
|
+
api._uploader = MagicMock()
|
|
120
|
+
api._uploader.delete_files.return_value = {
|
|
121
|
+
"deleted_files": ["config.json", "nested/metadata.json"],
|
|
122
|
+
"failed_files": [],
|
|
123
|
+
"total_files": 2,
|
|
124
|
+
}
|
|
125
|
+
api.list_repo_files = MagicMock(
|
|
126
|
+
return_value=[
|
|
127
|
+
SimpleNamespace(path="config.json", type="blob"),
|
|
128
|
+
SimpleNamespace(path="nested/metadata.json", type="blob"),
|
|
129
|
+
SimpleNamespace(path="weights.bin", type="blob"),
|
|
130
|
+
SimpleNamespace(path="nested", type="tree"),
|
|
131
|
+
])
|
|
132
|
+
|
|
133
|
+
result = api.delete_files(
|
|
134
|
+
"owner/repo",
|
|
135
|
+
repo_type,
|
|
136
|
+
delete_patterns="*.json",
|
|
137
|
+
commit_message="Remove JSON files",
|
|
138
|
+
revision="main",
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
api.list_repo_files.assert_called_once_with(
|
|
142
|
+
"owner/repo", repo_type, revision="main", recursive=True)
|
|
143
|
+
api._uploader.delete_files.assert_called_once_with(
|
|
144
|
+
repo_id="owner/repo",
|
|
145
|
+
repo_type=repo_type,
|
|
146
|
+
file_paths=["config.json", "nested/metadata.json"],
|
|
147
|
+
commit_message="Remove JSON files",
|
|
148
|
+
revision="main",
|
|
149
|
+
)
|
|
150
|
+
assert result["total_files"] == 2
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def test_hub_api_delete_patterns_with_no_match_is_noop() -> None:
|
|
154
|
+
api = HubApi(token="test-token")
|
|
155
|
+
api._uploader = MagicMock()
|
|
156
|
+
api.list_repo_files = MagicMock(
|
|
157
|
+
return_value=[SimpleNamespace(path="weights.bin", type="blob")])
|
|
158
|
+
|
|
159
|
+
result = api.delete_files(
|
|
160
|
+
"owner/repo", "model", delete_patterns="*.json")
|
|
161
|
+
|
|
162
|
+
api._uploader.delete_files.assert_not_called()
|
|
163
|
+
assert result == {
|
|
164
|
+
"deleted_files": [],
|
|
165
|
+
"failed_files": [],
|
|
166
|
+
"total_files": 0,
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
|
|
30
170
|
def test_upload_file_normal_commits_inline_without_blob_api() -> None:
|
|
31
171
|
manager, client = _make_manager()
|
|
32
172
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{modelscope_hub-0.4.0 → modelscope_hub-0.4.2}/src/modelscope_hub/compat/snapshot_download.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{modelscope_hub-0.4.0 → modelscope_hub-0.4.2}/src/modelscope_hub.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|