repo.py 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. # Copyright 2025 The HuggingFace Team. All rights reserved.
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License");
  4. # you may not use this file except in compliance with the License.
  5. # You may obtain a copy of the License at
  6. #
  7. # http://www.apache.org/licenses/LICENSE-2.0
  8. #
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS,
  11. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. # See the License for the specific language governing permissions and
  13. # limitations under the License.
  14. """Contains commands to interact with repositories on the Hugging Face Hub.
  15. Usage:
  16. # create a new dataset repo on the Hub
  17. hf repo create my-cool-dataset --repo-type=dataset
  18. # create a private model repo on the Hub
  19. hf repo create my-cool-model --private
  20. """
  21. import enum
  22. from typing import Annotated, Optional
  23. import typer
  24. from huggingface_hub.errors import HfHubHTTPError, RepositoryNotFoundError, RevisionNotFoundError
  25. from huggingface_hub.utils import ANSI
  26. from ._cli_utils import PrivateOpt, RepoIdArg, RepoType, RepoTypeOpt, RevisionOpt, TokenOpt, get_hf_api, typer_factory
  27. repo_cli = typer_factory(help="Manage repos on the Hub.")
  28. tag_cli = typer_factory(help="Manage tags for a repo on the Hub.")
  29. branch_cli = typer_factory(help="Manage branches for a repo on the Hub.")
  30. repo_cli.add_typer(tag_cli, name="tag")
  31. repo_cli.add_typer(branch_cli, name="branch")
  32. class GatedChoices(str, enum.Enum):
  33. auto = "auto"
  34. manual = "manual"
  35. false = "false"
  36. @repo_cli.command("create", help="Create a new repo on the Hub.")
  37. def repo_create(
  38. repo_id: RepoIdArg,
  39. repo_type: RepoTypeOpt = RepoType.model,
  40. space_sdk: Annotated[
  41. Optional[str],
  42. typer.Option(
  43. help="Hugging Face Spaces SDK type. Required when --type is set to 'space'.",
  44. ),
  45. ] = None,
  46. private: PrivateOpt = None,
  47. token: TokenOpt = None,
  48. exist_ok: Annotated[
  49. bool,
  50. typer.Option(
  51. help="Do not raise an error if repo already exists.",
  52. ),
  53. ] = False,
  54. resource_group_id: Annotated[
  55. Optional[str],
  56. typer.Option(
  57. help="Resource group in which to create the repo. Resource groups is only available for Enterprise Hub organizations.",
  58. ),
  59. ] = None,
  60. ) -> None:
  61. api = get_hf_api(token=token)
  62. repo_url = api.create_repo(
  63. repo_id=repo_id,
  64. repo_type=repo_type.value,
  65. private=private,
  66. token=token,
  67. exist_ok=exist_ok,
  68. resource_group_id=resource_group_id,
  69. space_sdk=space_sdk,
  70. )
  71. print(f"Successfully created {ANSI.bold(repo_url.repo_id)} on the Hub.")
  72. print(f"Your repo is now available at {ANSI.bold(repo_url)}")
  73. @repo_cli.command("delete", help="Delete a repo from the Hub. this is an irreversible operation.")
  74. def repo_delete(
  75. repo_id: RepoIdArg,
  76. repo_type: RepoTypeOpt = RepoType.model,
  77. token: TokenOpt = None,
  78. missing_ok: Annotated[
  79. bool,
  80. typer.Option(
  81. help="If set to True, do not raise an error if repo does not exist.",
  82. ),
  83. ] = False,
  84. ) -> None:
  85. api = get_hf_api(token=token)
  86. api.delete_repo(
  87. repo_id=repo_id,
  88. repo_type=repo_type.value,
  89. missing_ok=missing_ok,
  90. )
  91. print(f"Successfully deleted {ANSI.bold(repo_id)} on the Hub.")
  92. @repo_cli.command("move", help="Move a repository from a namespace to another namespace.")
  93. def repo_move(
  94. from_id: RepoIdArg,
  95. to_id: RepoIdArg,
  96. token: TokenOpt = None,
  97. repo_type: RepoTypeOpt = RepoType.model,
  98. ) -> None:
  99. api = get_hf_api(token=token)
  100. api.move_repo(
  101. from_id=from_id,
  102. to_id=to_id,
  103. repo_type=repo_type.value,
  104. )
  105. print(f"Successfully moved {ANSI.bold(from_id)} to {ANSI.bold(to_id)} on the Hub.")
  106. @repo_cli.command("settings", help="Update the settings of a repository.")
  107. def repo_settings(
  108. repo_id: RepoIdArg,
  109. gated: Annotated[
  110. Optional[GatedChoices],
  111. typer.Option(
  112. help="The gated status for the repository.",
  113. ),
  114. ] = None,
  115. private: Annotated[
  116. Optional[bool],
  117. typer.Option(
  118. help="Whether the repository should be private.",
  119. ),
  120. ] = None,
  121. token: TokenOpt = None,
  122. repo_type: RepoTypeOpt = RepoType.model,
  123. ) -> None:
  124. api = get_hf_api(token=token)
  125. api.update_repo_settings(
  126. repo_id=repo_id,
  127. gated=(gated.value if gated else None), # type: ignore [arg-type]
  128. private=private,
  129. repo_type=repo_type.value,
  130. )
  131. print(f"Successfully updated the settings of {ANSI.bold(repo_id)} on the Hub.")
  132. @branch_cli.command("create", help="Create a new branch for a repo on the Hub.")
  133. def branch_create(
  134. repo_id: RepoIdArg,
  135. branch: Annotated[
  136. str,
  137. typer.Argument(
  138. help="The name of the branch to create.",
  139. ),
  140. ],
  141. revision: RevisionOpt = None,
  142. token: TokenOpt = None,
  143. repo_type: RepoTypeOpt = RepoType.model,
  144. exist_ok: Annotated[
  145. bool,
  146. typer.Option(
  147. help="If set to True, do not raise an error if branch already exists.",
  148. ),
  149. ] = False,
  150. ) -> None:
  151. api = get_hf_api(token=token)
  152. api.create_branch(
  153. repo_id=repo_id,
  154. branch=branch,
  155. revision=revision,
  156. repo_type=repo_type.value,
  157. exist_ok=exist_ok,
  158. )
  159. print(f"Successfully created {ANSI.bold(branch)} branch on {repo_type.value} {ANSI.bold(repo_id)}")
  160. @branch_cli.command("delete", help="Delete a branch from a repo on the Hub.")
  161. def branch_delete(
  162. repo_id: RepoIdArg,
  163. branch: Annotated[
  164. str,
  165. typer.Argument(
  166. help="The name of the branch to delete.",
  167. ),
  168. ],
  169. token: TokenOpt = None,
  170. repo_type: RepoTypeOpt = RepoType.model,
  171. ) -> None:
  172. api = get_hf_api(token=token)
  173. api.delete_branch(
  174. repo_id=repo_id,
  175. branch=branch,
  176. repo_type=repo_type.value,
  177. )
  178. print(f"Successfully deleted {ANSI.bold(branch)} branch on {repo_type.value} {ANSI.bold(repo_id)}")
  179. @tag_cli.command("create", help="Create a tag for a repo.")
  180. def tag_create(
  181. repo_id: RepoIdArg,
  182. tag: Annotated[
  183. str,
  184. typer.Argument(
  185. help="The name of the tag to create.",
  186. ),
  187. ],
  188. message: Annotated[
  189. Optional[str],
  190. typer.Option(
  191. "-m",
  192. "--message",
  193. help="The description of the tag to create.",
  194. ),
  195. ] = None,
  196. revision: RevisionOpt = None,
  197. token: TokenOpt = None,
  198. repo_type: RepoTypeOpt = RepoType.model,
  199. ) -> None:
  200. repo_type_str = repo_type.value
  201. api = get_hf_api(token=token)
  202. print(f"You are about to create tag {ANSI.bold(tag)} on {repo_type_str} {ANSI.bold(repo_id)}")
  203. try:
  204. api.create_tag(repo_id=repo_id, tag=tag, tag_message=message, revision=revision, repo_type=repo_type_str)
  205. except RepositoryNotFoundError:
  206. print(f"{repo_type_str.capitalize()} {ANSI.bold(repo_id)} not found.")
  207. raise typer.Exit(code=1)
  208. except RevisionNotFoundError:
  209. print(f"Revision {ANSI.bold(str(revision))} not found.")
  210. raise typer.Exit(code=1)
  211. except HfHubHTTPError as e:
  212. if e.response.status_code == 409:
  213. print(f"Tag {ANSI.bold(tag)} already exists on {ANSI.bold(repo_id)}")
  214. raise typer.Exit(code=1)
  215. raise e
  216. print(f"Tag {ANSI.bold(tag)} created on {ANSI.bold(repo_id)}")
  217. @tag_cli.command("list", help="List tags for a repo.")
  218. def tag_list(
  219. repo_id: RepoIdArg,
  220. token: TokenOpt = None,
  221. repo_type: RepoTypeOpt = RepoType.model,
  222. ) -> None:
  223. repo_type_str = repo_type.value
  224. api = get_hf_api(token=token)
  225. try:
  226. refs = api.list_repo_refs(repo_id=repo_id, repo_type=repo_type_str)
  227. except RepositoryNotFoundError:
  228. print(f"{repo_type_str.capitalize()} {ANSI.bold(repo_id)} not found.")
  229. raise typer.Exit(code=1)
  230. except HfHubHTTPError as e:
  231. print(e)
  232. print(ANSI.red(e.response.text))
  233. raise typer.Exit(code=1)
  234. if len(refs.tags) == 0:
  235. print("No tags found")
  236. raise typer.Exit(code=0)
  237. print(f"Tags for {repo_type_str} {ANSI.bold(repo_id)}:")
  238. for t in refs.tags:
  239. print(t.name)
  240. @tag_cli.command("delete", help="Delete a tag for a repo.")
  241. def tag_delete(
  242. repo_id: RepoIdArg,
  243. tag: Annotated[
  244. str,
  245. typer.Argument(
  246. help="The name of the tag to delete.",
  247. ),
  248. ],
  249. yes: Annotated[
  250. bool,
  251. typer.Option(
  252. "-y",
  253. "--yes",
  254. help="Answer Yes to prompt automatically",
  255. ),
  256. ] = False,
  257. token: TokenOpt = None,
  258. repo_type: RepoTypeOpt = RepoType.model,
  259. ) -> None:
  260. repo_type_str = repo_type.value
  261. print(f"You are about to delete tag {ANSI.bold(tag)} on {repo_type_str} {ANSI.bold(repo_id)}")
  262. if not yes:
  263. choice = input("Proceed? [Y/n] ").lower()
  264. if choice not in ("", "y", "yes"):
  265. print("Abort")
  266. raise typer.Exit()
  267. api = get_hf_api(token=token)
  268. try:
  269. api.delete_tag(repo_id=repo_id, tag=tag, repo_type=repo_type_str)
  270. except RepositoryNotFoundError:
  271. print(f"{repo_type_str.capitalize()} {ANSI.bold(repo_id)} not found.")
  272. raise typer.Exit(code=1)
  273. except RevisionNotFoundError:
  274. print(f"Tag {ANSI.bold(tag)} not found on {ANSI.bold(repo_id)}")
  275. raise typer.Exit(code=1)
  276. print(f"Tag {ANSI.bold(tag)} deleted on {ANSI.bold(repo_id)}")