modelscope-hub 0.4.1__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.
Files changed (76) hide show
  1. {modelscope_hub-0.4.1/src/modelscope_hub.egg-info → modelscope_hub-0.4.2}/PKG-INFO +1 -1
  2. {modelscope_hub-0.4.1 → modelscope_hub-0.4.2}/src/modelscope_hub/api.py +66 -10
  3. {modelscope_hub-0.4.1 → modelscope_hub-0.4.2}/src/modelscope_hub/compat/hub_api.py +30 -0
  4. {modelscope_hub-0.4.1 → modelscope_hub-0.4.2}/src/modelscope_hub/version.py +1 -1
  5. {modelscope_hub-0.4.1 → modelscope_hub-0.4.2/src/modelscope_hub.egg-info}/PKG-INFO +1 -1
  6. {modelscope_hub-0.4.1 → modelscope_hub-0.4.2}/src/modelscope_hub.egg-info/SOURCES.txt +1 -0
  7. modelscope_hub-0.4.2/tests/test_compat_delete_files.py +54 -0
  8. {modelscope_hub-0.4.1 → modelscope_hub-0.4.2}/tests/test_upload_lfs_gate.py +55 -0
  9. {modelscope_hub-0.4.1 → modelscope_hub-0.4.2}/LICENSE +0 -0
  10. {modelscope_hub-0.4.1 → modelscope_hub-0.4.2}/README.md +0 -0
  11. {modelscope_hub-0.4.1 → modelscope_hub-0.4.2}/pyproject.toml +0 -0
  12. {modelscope_hub-0.4.1 → modelscope_hub-0.4.2}/setup.cfg +0 -0
  13. {modelscope_hub-0.4.1 → modelscope_hub-0.4.2}/src/modelscope_hub/__init__.py +0 -0
  14. {modelscope_hub-0.4.1 → modelscope_hub-0.4.2}/src/modelscope_hub/_cache_manager.py +0 -0
  15. {modelscope_hub-0.4.1 → modelscope_hub-0.4.2}/src/modelscope_hub/_download.py +0 -0
  16. {modelscope_hub-0.4.1 → modelscope_hub-0.4.2}/src/modelscope_hub/_git.py +0 -0
  17. {modelscope_hub-0.4.1 → modelscope_hub-0.4.2}/src/modelscope_hub/_legacy_api.py +0 -0
  18. {modelscope_hub-0.4.1 → modelscope_hub-0.4.2}/src/modelscope_hub/_openapi.py +0 -0
  19. {modelscope_hub-0.4.1 → modelscope_hub-0.4.2}/src/modelscope_hub/_repository.py +0 -0
  20. {modelscope_hub-0.4.1 → modelscope_hub-0.4.2}/src/modelscope_hub/_upload.py +0 -0
  21. {modelscope_hub-0.4.1 → modelscope_hub-0.4.2}/src/modelscope_hub/agent/__init__.py +0 -0
  22. {modelscope_hub-0.4.1 → modelscope_hub-0.4.2}/src/modelscope_hub/agent/_api.py +0 -0
  23. {modelscope_hub-0.4.1 → modelscope_hub-0.4.2}/src/modelscope_hub/agent_idp.py +0 -0
  24. {modelscope_hub-0.4.1 → modelscope_hub-0.4.2}/src/modelscope_hub/cli/__init__.py +0 -0
  25. {modelscope_hub-0.4.1 → modelscope_hub-0.4.2}/src/modelscope_hub/cli/agent.py +0 -0
  26. {modelscope_hub-0.4.1 → modelscope_hub-0.4.2}/src/modelscope_hub/cli/agent_idp.py +0 -0
  27. {modelscope_hub-0.4.1 → modelscope_hub-0.4.2}/src/modelscope_hub/cli/base.py +0 -0
  28. {modelscope_hub-0.4.1 → modelscope_hub-0.4.2}/src/modelscope_hub/cli/cache.py +0 -0
  29. {modelscope_hub-0.4.1 → modelscope_hub-0.4.2}/src/modelscope_hub/cli/compat.py +0 -0
  30. {modelscope_hub-0.4.1 → modelscope_hub-0.4.2}/src/modelscope_hub/cli/deploy.py +0 -0
  31. {modelscope_hub-0.4.1 → modelscope_hub-0.4.2}/src/modelscope_hub/cli/download.py +0 -0
  32. {modelscope_hub-0.4.1 → modelscope_hub-0.4.2}/src/modelscope_hub/cli/login.py +0 -0
  33. {modelscope_hub-0.4.1 → modelscope_hub-0.4.2}/src/modelscope_hub/cli/main.py +0 -0
  34. {modelscope_hub-0.4.1 → modelscope_hub-0.4.2}/src/modelscope_hub/cli/mcp.py +0 -0
  35. {modelscope_hub-0.4.1 → modelscope_hub-0.4.2}/src/modelscope_hub/cli/repo.py +0 -0
  36. {modelscope_hub-0.4.1 → modelscope_hub-0.4.2}/src/modelscope_hub/cli/secret.py +0 -0
  37. {modelscope_hub-0.4.1 → modelscope_hub-0.4.2}/src/modelscope_hub/cli/studio.py +0 -0
  38. {modelscope_hub-0.4.1 → modelscope_hub-0.4.2}/src/modelscope_hub/cli/upload.py +0 -0
  39. {modelscope_hub-0.4.1 → modelscope_hub-0.4.2}/src/modelscope_hub/compat/__init__.py +0 -0
  40. {modelscope_hub-0.4.1 → modelscope_hub-0.4.2}/src/modelscope_hub/compat/constants.py +0 -0
  41. {modelscope_hub-0.4.1 → modelscope_hub-0.4.2}/src/modelscope_hub/compat/file_download.py +0 -0
  42. {modelscope_hub-0.4.1 → modelscope_hub-0.4.2}/src/modelscope_hub/compat/snapshot_download.py +0 -0
  43. {modelscope_hub-0.4.1 → modelscope_hub-0.4.2}/src/modelscope_hub/config.py +0 -0
  44. {modelscope_hub-0.4.1 → modelscope_hub-0.4.2}/src/modelscope_hub/constants.py +0 -0
  45. {modelscope_hub-0.4.1 → modelscope_hub-0.4.2}/src/modelscope_hub/errors.py +0 -0
  46. {modelscope_hub-0.4.1 → modelscope_hub-0.4.2}/src/modelscope_hub/py.typed +0 -0
  47. {modelscope_hub-0.4.1 → modelscope_hub-0.4.2}/src/modelscope_hub/types.py +0 -0
  48. {modelscope_hub-0.4.1 → modelscope_hub-0.4.2}/src/modelscope_hub/utils/__init__.py +0 -0
  49. {modelscope_hub-0.4.1 → modelscope_hub-0.4.2}/src/modelscope_hub/utils/file_utils.py +0 -0
  50. {modelscope_hub-0.4.1 → modelscope_hub-0.4.2}/src/modelscope_hub/utils/format.py +0 -0
  51. {modelscope_hub-0.4.1 → modelscope_hub-0.4.2}/src/modelscope_hub/utils/logger.py +0 -0
  52. {modelscope_hub-0.4.1 → modelscope_hub-0.4.2}/src/modelscope_hub/utils/media.py +0 -0
  53. {modelscope_hub-0.4.1 → modelscope_hub-0.4.2}/src/modelscope_hub/utils/patterns.py +0 -0
  54. {modelscope_hub-0.4.1 → modelscope_hub-0.4.2}/src/modelscope_hub/utils/time_utils.py +0 -0
  55. {modelscope_hub-0.4.1 → modelscope_hub-0.4.2}/src/modelscope_hub.egg-info/dependency_links.txt +0 -0
  56. {modelscope_hub-0.4.1 → modelscope_hub-0.4.2}/src/modelscope_hub.egg-info/entry_points.txt +0 -0
  57. {modelscope_hub-0.4.1 → modelscope_hub-0.4.2}/src/modelscope_hub.egg-info/requires.txt +0 -0
  58. {modelscope_hub-0.4.1 → modelscope_hub-0.4.2}/src/modelscope_hub.egg-info/top_level.txt +0 -0
  59. {modelscope_hub-0.4.1 → modelscope_hub-0.4.2}/tests/test_agent_idp.py +0 -0
  60. {modelscope_hub-0.4.1 → modelscope_hub-0.4.2}/tests/test_agent_idp_keys.py +0 -0
  61. {modelscope_hub-0.4.1 → modelscope_hub-0.4.2}/tests/test_cache_verification.py +0 -0
  62. {modelscope_hub-0.4.1 → modelscope_hub-0.4.2}/tests/test_compat_get_model_files.py +0 -0
  63. {modelscope_hub-0.4.1 → modelscope_hub-0.4.2}/tests/test_compat_snapshot_download.py +0 -0
  64. {modelscope_hub-0.4.1 → modelscope_hub-0.4.2}/tests/test_compat_studio.py +0 -0
  65. {modelscope_hub-0.4.1 → modelscope_hub-0.4.2}/tests/test_config_token.py +0 -0
  66. {modelscope_hub-0.4.1 → modelscope_hub-0.4.2}/tests/test_credential_lifecycle.py +0 -0
  67. {modelscope_hub-0.4.1 → modelscope_hub-0.4.2}/tests/test_download_lock_path.py +0 -0
  68. {modelscope_hub-0.4.1 → modelscope_hub-0.4.2}/tests/test_errors_openapi_codes.py +0 -0
  69. {modelscope_hub-0.4.1 → modelscope_hub-0.4.2}/tests/test_legacy_cache_detection.py +0 -0
  70. {modelscope_hub-0.4.1 → modelscope_hub-0.4.2}/tests/test_login_failure_paths.py +0 -0
  71. {modelscope_hub-0.4.1 → modelscope_hub-0.4.2}/tests/test_login_scoped_token.py +0 -0
  72. {modelscope_hub-0.4.1 → modelscope_hub-0.4.2}/tests/test_openapi_coverage.py +0 -0
  73. {modelscope_hub-0.4.1 → modelscope_hub-0.4.2}/tests/test_repo_files_truncation.py +0 -0
  74. {modelscope_hub-0.4.1 → modelscope_hub-0.4.2}/tests/test_upload_config.py +0 -0
  75. {modelscope_hub-0.4.1 → modelscope_hub-0.4.2}/tests/test_user_info.py +0 -0
  76. {modelscope_hub-0.4.1 → modelscope_hub-0.4.2}/tests/test_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modelscope-hub
3
- Version: 0.4.1
3
+ Version: 0.4.2
4
4
  Summary: The official Python client to connect with ModelScope Hub.
5
5
  License: Apache-2.0
6
6
  Keywords: modelscope,hub,sdk,openapi,machine-learning
@@ -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
@@ -1669,16 +1670,18 @@ class HubApi:
1669
1670
  self,
1670
1671
  repo_id: str,
1671
1672
  repo_type: RepoTypeLike,
1672
- file_paths: Iterable[str],
1673
+ file_paths: Iterable[str] | str | None = None,
1673
1674
  *,
1675
+ delete_patterns: Iterable[str] | str | None = None,
1674
1676
  commit_message: str | None = None,
1675
1677
  revision: str | None = None,
1676
1678
  ) -> dict:
1677
- """Delete one or more files from a repository in a single commit.
1679
+ """Delete repository files selected by paths or glob patterns.
1678
1680
 
1679
1681
  The direct repository DELETE endpoints reject API-token authentication.
1680
- This method therefore sends commit ``delete`` actions through the same
1681
- supported write path as :meth:`upload_file` and :meth:`upload_folder`.
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`.
1682
1685
 
1683
1686
  Parameters
1684
1687
  ----------
@@ -1686,8 +1689,11 @@ class HubApi:
1686
1689
  Canonical ``owner/name`` identifier.
1687
1690
  repo_type : str or RepoType
1688
1691
  Repository type.
1689
- file_paths : iterable of str
1690
- Paths of files to remove. Empty entries are ignored.
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.
1691
1697
  commit_message : str, optional
1692
1698
  Message for the delete commit. Defaults to ``"Delete files"``.
1693
1699
  revision : str, optional
@@ -1696,18 +1702,68 @@ class HubApi:
1696
1702
  Returns
1697
1703
  -------
1698
1704
  dict
1699
- Summary with ``deleted_files`` and ``failed_files`` lists.
1705
+ Summary with ``deleted_files``, ``failed_files``, and ``total_files``.
1706
+ A pattern with no remote matches returns an empty successful summary.
1700
1707
  """
1701
1708
  rt = self._normalize_repo_type(repo_type)
1702
- paths = [file_paths] if isinstance(file_paths, str) else file_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))
1734
+ if not paths:
1735
+ return {
1736
+ "deleted_files": [],
1737
+ "failed_files": [],
1738
+ "total_files": 0,
1739
+ }
1740
+
1703
1741
  return self.uploader.delete_files(
1704
1742
  repo_id=repo_id,
1705
1743
  repo_type=str(rt),
1706
- file_paths=[path for path in paths if path],
1744
+ file_paths=paths,
1707
1745
  commit_message=commit_message or "Delete files",
1708
- revision=revision or "master",
1746
+ revision=resolved_revision,
1709
1747
  )
1710
1748
 
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
1766
+
1711
1767
  # ==================================================================
1712
1768
  # Versioning
1713
1769
  # ==================================================================
@@ -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,
@@ -1,3 +1,3 @@
1
1
  """Version information for modelscope_hub."""
2
2
 
3
- __version__ = "0.4.1"
3
+ __version__ = "0.4.2"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modelscope-hub
3
- Version: 0.4.1
3
+ Version: 0.4.2
4
4
  Summary: The official Python client to connect with ModelScope Hub.
5
5
  License: Apache-2.0
6
6
  Keywords: modelscope,hub,sdk,openapi,machine-learning
@@ -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,6 +4,7 @@ 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
 
9
10
  import pytest
@@ -112,6 +113,60 @@ def test_hub_api_delete_files_delegates_to_upload_manager(
112
113
  assert result == {"deleted_files": ["old.bin"]}
113
114
 
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
+
115
170
  def test_upload_file_normal_commits_inline_without_blob_api() -> None:
116
171
  manager, client = _make_manager()
117
172
 
File without changes
File without changes
File without changes