codekingpro/portable-devtools
114k
1# Copyright 2026 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 at6#7# http://www.apache.org/licenses/LICENSE-2.08#9# Unless required by applicable law or agreed to in writing, software10# 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 and13# limitations under the License.14"""Contains commands to interact with models on the Hugging Face Hub.15 16Usage:17 # list models on the Hub18 hf models ls19 20 # list models with a search query21 hf models ls --search "llama"22 23 # get info about a model24 hf models info Lightricks/LTX-225"""26 27import enum28from typing import Annotated, get_args29 30import typer31 32from huggingface_hub.errors import CLIError, RepositoryNotFoundError, RevisionNotFoundError33from huggingface_hub.hf_api import ExpandModelProperty_T, ModelSort_T34from huggingface_hub.repocard import ModelCard35 36from ._cli_utils import (37 REPO_LIST_DEFAULT_LIMIT,38 AuthorOpt,39 FilterOpt,40 LimitOpt,41 RevisionOpt,42 SearchOpt,43 TokenOpt,44 api_object_to_dict,45 get_hf_api,46 make_expand_properties_parser,47 typer_factory,48)49from ._file_listing import list_repo_files_cmd50from ._output import out51 52 53_EXPAND_PROPERTIES = sorted(get_args(ExpandModelProperty_T))54_SORT_OPTIONS = get_args(ModelSort_T)55ModelSortEnum = enum.Enum("ModelSortEnum", {s: s for s in _SORT_OPTIONS}, type=str) # type: ignore[misc]56 57 58ExpandOpt = Annotated[59 str | None,60 typer.Option(61 help=f"Comma-separated properties to return. When used, only the listed properties (and id) are returned. Example: '--expand=downloads,likes,tags'. Valid: {', '.join(_EXPAND_PROPERTIES)}.",62 callback=make_expand_properties_parser(_EXPAND_PROPERTIES),63 ),64]65 66 67models_cli = typer_factory(help="Interact with models on the Hub.")68 69 70@models_cli.command(71 "list | ls",72 examples=[73 "hf models ls --sort downloads --limit 10",74 'hf models ls --search "llama" --author meta-llama',75 "hf models ls --num-parameters min:6B,max:128B --sort likes",76 "hf models ls meta-llama/Llama-3.2-1B-Instruct",77 "hf models ls meta-llama/Llama-3.2-1B-Instruct -R",78 "hf models ls meta-llama/Llama-3.2-1B-Instruct --tree -h",79 ],80)81def models_ls(82 repo_id: Annotated[83 str | None,84 typer.Argument(help="Model ID (e.g. `username/repo-name`) to list files from. If omitted, lists models."),85 ] = None,86 search: SearchOpt = None,87 author: AuthorOpt = None,88 filter: FilterOpt = None,89 num_parameters: Annotated[90 str | None,91 typer.Option(help="Filter by parameter count, e.g. 'min:6B,max:128B'."),92 ] = None,93 sort: Annotated[94 ModelSortEnum | None,95 typer.Option(help="Sort results."),96 ] = None,97 limit: LimitOpt = REPO_LIST_DEFAULT_LIMIT,98 expand: ExpandOpt = None,99 human_readable: Annotated[100 bool,101 typer.Option("--human-readable", "-h", help="Show sizes in human readable format (only for listing files)."),102 ] = False,103 as_tree: Annotated[104 bool,105 typer.Option("--tree", help="List files in tree format (only for listing files)."),106 ] = False,107 recursive: Annotated[108 bool,109 typer.Option("--recursive", "-R", help="List files recursively (only for listing files)."),110 ] = False,111 revision: RevisionOpt = None,112 token: TokenOpt = None,113) -> None:114 """List models on the Hub, or files in a model repo.115 116 When called with no argument, lists models on the Hub.117 When called with a model ID, lists files in that model repo.118 """119 if repo_id is not None:120 if search is not None:121 raise typer.BadParameter("Cannot use --search when listing files.")122 if author is not None:123 raise typer.BadParameter("Cannot use --author when listing files.")124 if filter is not None:125 raise typer.BadParameter("Cannot use --filter when listing files.")126 if num_parameters is not None:127 raise typer.BadParameter("Cannot use --num-parameters when listing files.")128 if sort is not None:129 raise typer.BadParameter("Cannot use --sort when listing files.")130 if limit != REPO_LIST_DEFAULT_LIMIT:131 raise typer.BadParameter("Cannot use --limit when listing files.")132 if expand is not None:133 raise typer.BadParameter("Cannot use --expand when listing files.")134 return list_repo_files_cmd(135 repo_id=repo_id,136 repo_type="model",137 human_readable=human_readable,138 as_tree=as_tree,139 recursive=recursive,140 revision=revision,141 token=token,142 )143 144 if as_tree:145 raise typer.BadParameter("Cannot use --tree when listing models.")146 if recursive:147 raise typer.BadParameter("Cannot use --recursive when listing models.")148 if human_readable:149 raise typer.BadParameter("Cannot use --human-readable when listing models.")150 if revision is not None:151 raise typer.BadParameter("Cannot use --revision when listing models.")152 api = get_hf_api(token=token)153 sort_key = sort.value if sort else None154 results = [155 api_object_to_dict(model_info)156 for model_info in api.list_models(157 filter=filter,158 author=author,159 search=search,160 num_parameters=num_parameters,161 sort=sort_key,162 limit=limit,163 expand=expand, # type: ignore164 )165 ]166 out.table(results)167 168 169@models_cli.command(170 "info",171 examples=[172 "hf models info meta-llama/Llama-3.2-1B-Instruct",173 "hf models info Qwen/Qwen3.5-9B --expand downloads,likes,tags",174 ],175)176def models_info(177 model_id: Annotated[str, typer.Argument(help="The model ID (e.g. `username/repo-name`).")],178 revision: RevisionOpt = None,179 expand: ExpandOpt = None,180 token: TokenOpt = None,181) -> None:182 """Get info about a model on the Hub."""183 api = get_hf_api(token=token)184 try:185 info = api.model_info(repo_id=model_id, revision=revision, expand=expand) # type: ignore186 except RepositoryNotFoundError as e:187 raise CLIError(f"Model '{model_id}' not found.") from e188 except RevisionNotFoundError as e:189 raise CLIError(f"Revision '{revision}' not found on '{model_id}'.") from e190 out.dict(info)191 192 193@models_cli.command(194 "card",195 examples=[196 "hf models card google/gemma-4-31B-it",197 "hf models card google/gemma-4-31B-it --metadata",198 "hf models card google/gemma-4-31B-it --metadata --format json",199 "hf models card google/gemma-4-31B-it --text",200 ],201)202def models_card(203 model_id: Annotated[str, typer.Argument(help="The model ID (e.g. `username/repo-name`).")],204 metadata: Annotated[bool, typer.Option("--metadata", help="Output only the metadata from the card.")] = False,205 text: Annotated[bool, typer.Option("--text", help="Output only the text body (no metadata).")] = False,206 token: TokenOpt = None,207) -> None:208 """Get the model card (README) for a model on the Hub."""209 if metadata and text:210 raise CLIError("--metadata and --text are mutually exclusive.")211 card = ModelCard.load(model_id, token=token)212 if metadata:213 out.dict(card.data.to_dict())214 elif text:215 out.text(card.text)216 else:217 out.text(card.content)218 out.hint(f"Use `hf models card {model_id} --metadata` to extract only the card metadata.")219 