Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
_login.py495 linesDownload Raw Back to huggingface_hub
1# Copyright 2020 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 methods to log in to the Hub."""15 16import os17import subprocess18from getpass import getpass19from pathlib import Path20 21import typer22 23from . import constants24from .utils import (25    ANSI,26    capture_output,27    get_token,28    is_google_colab,29    is_notebook,30    list_credential_helpers,31    logging,32    run_subprocess,33    set_git_credential,34    unset_git_credential,35)36from .utils._auth import (37    _get_token_by_name,38    _get_token_from_environment,39    _get_token_from_file,40    _get_token_from_google_colab,41    _save_stored_tokens,42    _save_token,43    get_stored_tokens,44)45 46 47logger = logging.get_logger(__name__)48 49_HF_LOGO_ASCII = """50    _|    _|  _|    _|    _|_|_|    _|_|_|  _|_|_|  _|      _|    _|_|_|      _|_|_|_|    _|_|      _|_|_|  _|_|_|_|51    _|    _|  _|    _|  _|        _|          _|    _|_|    _|  _|            _|        _|    _|  _|        _|52    _|_|_|_|  _|    _|  _|  _|_|  _|  _|_|    _|    _|  _|  _|  _|  _|_|      _|_|_|    _|_|_|_|  _|        _|_|_|53    _|    _|  _|    _|  _|    _|  _|    _|    _|    _|    _|_|  _|    _|      _|        _|    _|  _|        _|54    _|    _|    _|_|      _|_|_|    _|_|_|  _|_|_|  _|      _|    _|_|_|      _|        _|    _|    _|_|_|  _|_|_|_|55"""56 57 58def login(59    token: str | None = None,60    *,61    add_to_git_credential: bool = False,62    skip_if_logged_in: bool = True,63) -> None:64    """Login the machine to access the Hub.65 66    The `token` is persisted in cache and set as a git credential. Once done, the machine67    is logged in and the access token will be available across all `huggingface_hub`68    components. If `token` is not provided, it will be prompted to the user either with69    a widget (in a notebook) or via the terminal.70 71    To log in from outside of a script, one can also use `hf auth login` which is72    a cli command that wraps [`login`].73 74    > [!TIP]75    > [`login`] is a drop-in replacement method for [`notebook_login`] as it wraps and76    > extends its capabilities.77 78    > [!TIP]79    > When the token is not passed, [`login`] will automatically detect if the script runs80    > in a notebook or not. However, this detection might not be accurate due to the81    > variety of notebooks that exists nowadays. If that is the case, you can always force82    > the UI by using [`notebook_login`] or [`interpreter_login`].83 84    Args:85        token (`str`, *optional*):86            User access token to generate from https://huggingface.co/settings/token.87        add_to_git_credential (`bool`, defaults to `False`):88            If `True`, token will be set as git credential. If no git credential helper89            is configured, a warning will be displayed to the user. If `token` is `None`,90            the value of `add_to_git_credential` is ignored and will be prompted again91            to the end user.92        skip_if_logged_in (`bool`, defaults to `True`):93            If `True`, do not prompt for token if user is already logged in.94            Set to `False` to force re-login. In CLI, use `--force` instead.95    Raises:96        [`ValueError`](https://docs.python.org/3/library/exceptions.html#ValueError)97            If an organization token is passed. Only personal account tokens are valid98            to log in.99        [`ValueError`](https://docs.python.org/3/library/exceptions.html#ValueError)100            If token is invalid.101        [`ImportError`](https://docs.python.org/3/library/exceptions.html#ImportError)102            If running in a notebook but `ipywidgets` is not installed.103    """104    if token is not None:105        if not add_to_git_credential:106            logger.info(107                "The token has not been saved to the git credentials helper. Pass "108                "`add_to_git_credential=True` in this function directly or "109                "`--add-to-git-credential` if using via `hf`CLI if "110                "you want to set the git credential as well."111            )112        _login(token, add_to_git_credential=add_to_git_credential)113    elif is_notebook():114        notebook_login(skip_if_logged_in=skip_if_logged_in)115    else:116        interpreter_login(skip_if_logged_in=skip_if_logged_in)117 118 119def logout(token_name: str | None = None) -> None:120    """Logout the machine from the Hub.121 122    Token is deleted from the machine and removed from git credential.123 124    Args:125        token_name (`str`, *optional*):126            Name of the access token to logout from. If `None`, will log out from all saved access tokens.127    Raises:128        [`ValueError`](https://docs.python.org/3/library/exceptions.html#ValueError):129            If the access token name is not found.130    """131    if get_token() is None and not get_stored_tokens():  # No active token and no saved access tokens132        logger.warning("Not logged in!")133        return134    if not token_name:135        # Delete all saved access tokens and token136        for file_path in (constants.HF_TOKEN_PATH, constants.HF_STORED_TOKENS_PATH):137            try:138                Path(file_path).unlink()139            except FileNotFoundError:140                pass141        logger.info("Successfully logged out from all access tokens.")142    else:143        _logout_from_token(token_name)144        logger.info(f"Successfully logged out from access token: {token_name}.")145 146    unset_git_credential()147 148    # Check if still logged in149    if _get_token_from_google_colab() is not None:150        raise OSError(151            "You are automatically logged in using a Google Colab secret.\n"152            "To log out, you must unset the `HF_TOKEN` secret in your Colab settings."153        )154    if _get_token_from_environment() is not None:155        raise OSError(156            "Token has been deleted from your machine but you are still logged in.\n"157            "To log out, you must clear out both `HF_TOKEN` and `HUGGING_FACE_HUB_TOKEN` environment variables."158        )159 160 161def auth_switch(token_name: str, add_to_git_credential: bool = False) -> None:162    """Switch to a different access token.163 164    Args:165        token_name (`str`):166            Name of the access token to switch to.167        add_to_git_credential (`bool`, defaults to `False`):168            If `True`, token will be set as git credential. If no git credential helper169            is configured, a warning will be displayed to the user. If `token` is `None`,170            the value of `add_to_git_credential` is ignored and will be prompted again171            to the end user.172 173    Raises:174        [`ValueError`](https://docs.python.org/3/library/exceptions.html#ValueError):175            If the access token name is not found.176    """177    token = _get_token_by_name(token_name)178    if not token:179        raise ValueError(f"Access token {token_name} not found in {constants.HF_STORED_TOKENS_PATH}")180    # Write token to HF_TOKEN_PATH181    _set_active_token(token_name, add_to_git_credential)182    logger.info(f"The current active token is: {token_name}")183    token_from_environment = _get_token_from_environment()184    if token_from_environment is not None and token_from_environment != token:185        logger.warning(186            "The environment variable `HF_TOKEN` is set and will override the access token you've just switched to."187        )188 189 190def auth_list() -> None:191    """List all stored access tokens."""192    tokens = get_stored_tokens()193 194    if not tokens:195        if _get_token_from_environment():196            logger.info("No stored access tokens found.")197            logger.warning("Note: Environment variable `HF_TOKEN` is set and is the current active token.")198        else:199            logger.info("No access tokens found.")200        return201    # Find current token202    current_token = get_token()203    current_token_name = None204    for token_name in tokens:205        if tokens.get(token_name) == current_token:206            current_token_name = token_name207    # Print header208    max_offset = max(len("token"), max(len(token) for token in tokens)) + 2209    print(f"  {{:<{max_offset}}}| {{:<15}}".format("name", "token"))210    print("-" * (max_offset + 2) + "|" + "-" * 15)211 212    # Print saved access tokens213    for token_name in tokens:214        token = tokens.get(token_name, "<not set>")215        masked_token = f"{token[:3]}****{token[-4:]}" if token != "<not set>" else token216        is_current = "*" if token == current_token else " "217 218        print(f"{is_current} {{:<{max_offset}}}| {{:<15}}".format(token_name, masked_token))219 220    if _get_token_from_environment():221        logger.warning(222            "\nNote: Environment variable `HF_TOKEN` is set and is the current active token independently from the stored tokens listed above."223        )224    elif current_token_name is None:225        logger.warning(226            "\nNote: No active token is set and no environment variable `HF_TOKEN` is found. Use `hf auth login` to log in."227        )228 229 230###231# Interpreter-based login (text)232###233 234 235def interpreter_login(*, skip_if_logged_in: bool = True) -> None:236    """237    Displays a prompt to log in to the HF website and store the token.238 239    This is equivalent to [`login`] without passing a token when not run in a notebook.240    [`interpreter_login`] is useful if you want to force the use of the terminal prompt241    instead of a notebook widget.242 243    For more details, see [`login`].244 245    Args:246        skip_if_logged_in (`bool`, defaults to `True`):247            If `True`, do not prompt for token if user is already logged in.248            Set to `False` to force re-login. In CLI, use `--force` instead.249    """250    if skip_if_logged_in and get_token() is not None:251        logger.info("User is already logged in. Use `hf auth login --force` to force re-login.")252        return253 254    print(_HF_LOGO_ASCII)255    if get_token() is not None:256        logger.info(257            "    A token is already saved on your machine. Run `hf auth whoami`"258            " to get more information or `hf auth logout` if you want"259            " to log out."260        )261        logger.info("    Setting a new token will erase the existing one.")262 263    logger.info(264        "    To log in, `huggingface_hub` requires a token generated from https://huggingface.co/settings/tokens ."265    )266    if os.name == "nt":267        logger.info("Token can be pasted using 'Right-Click'.")268    token = getpass("Enter your token (input will not be visible): ")269    add_to_git_credential = typer.confirm("Add token as git credential?")270 271    _login(token=token, add_to_git_credential=add_to_git_credential)272 273 274###275# Notebook-based login (widget)276###277 278NOTEBOOK_LOGIN_PASSWORD_HTML = """<center> <img279src=https://huggingface.co/front/assets/huggingface_logo-noborder.svg280alt='Hugging Face'> <br> Immediately click login after typing your password or281it might be stored in plain text in this notebook file. </center>"""282 283 284NOTEBOOK_LOGIN_TOKEN_HTML_START = """<center> <img285src=https://huggingface.co/front/assets/huggingface_logo-noborder.svg286alt='Hugging Face'> <br> Copy a token from <a287href="https://huggingface.co/settings/tokens" target="_blank">your Hugging Face288tokens page</a> and paste it below. <br> Immediately click login after copying289your token or it might be stored in plain text in this notebook file. </center>"""290 291 292NOTEBOOK_LOGIN_TOKEN_HTML_END = """293<b>Pro Tip:</b> If you don't already have one, you can create a dedicated294'notebooks' token with 'write' access, that you can then easily reuse for all295notebooks. </center>"""296 297 298def notebook_login(*, skip_if_logged_in: bool = True) -> None:299    """300    Displays a widget to log in to the HF website and store the token.301 302    This is equivalent to [`login`] without passing a token when run in a notebook.303    [`notebook_login`] is useful if you want to force the use of the notebook widget304    instead of a prompt in the terminal.305 306    For more details, see [`login`].307 308    Args:309        skip_if_logged_in (`bool`, defaults to `True`):310            If `True`, do not prompt for token if user is already logged in.311            Set to `False` to force re-login. In CLI, use `--force` instead.312    """313    try:314        import ipywidgets.widgets as widgets  # type: ignore315        from IPython.display import display  # type: ignore316    except ImportError:317        raise ImportError(318            "The `notebook_login` function can only be used in a notebook (Jupyter or"319            " Colab) and you need the `ipywidgets` module: `pip install ipywidgets`."320        )321    if skip_if_logged_in and get_token() is not None:322        logger.info("User is already logged in. Use `hf auth login --force` to force re-login.")323        return324 325    box_layout = widgets.Layout(display="flex", flex_flow="column", align_items="center", width="50%")326 327    token_widget = widgets.Password(description="Token:")328    git_checkbox_widget = widgets.Checkbox(value=True, description="Add token as git credential?")329    token_finish_button = widgets.Button(description="Login")330 331    login_token_widget = widgets.VBox(332        [333            widgets.HTML(NOTEBOOK_LOGIN_TOKEN_HTML_START),334            token_widget,335            git_checkbox_widget,336            token_finish_button,337            widgets.HTML(NOTEBOOK_LOGIN_TOKEN_HTML_END),338        ],339        layout=box_layout,340    )341    display(login_token_widget)342 343    # On click events344    def login_token_event(t):345        """Event handler for the login button."""346        token = token_widget.value347        add_to_git_credential = git_checkbox_widget.value348        # Erase token and clear value to make sure it's not saved in the notebook.349        token_widget.value = ""350        # Hide inputs351        login_token_widget.children = [widgets.Label("Connecting...")]352        try:353            with capture_output() as captured:354                _login(token, add_to_git_credential=add_to_git_credential)355            message = captured.getvalue()356        except Exception as error:357            message = str(error)358        # Print result (success message or error)359        login_token_widget.children = [widgets.Label(line) for line in message.split("\n") if line.strip()]360 361    token_finish_button.on_click(login_token_event)362 363 364###365# Login private helpers366###367 368 369def _login(370    token: str,371    add_to_git_credential: bool,372) -> None:373    from .hf_api import whoami  # avoid circular import374 375    if token.startswith("api_org"):376        raise ValueError("You must use your personal account token, not an organization token.")377 378    token_info = whoami(token)379    permission = token_info["auth"]["accessToken"]["role"]380    logger.info(f"Token is valid (permission: {permission}).")381 382    token_name = token_info["auth"]["accessToken"]["displayName"]383    # Store token locally384    _save_token(token=token, token_name=token_name)385    # Set active token386    _set_active_token(token_name=token_name, add_to_git_credential=add_to_git_credential)387    logger.info("Login successful.")388    if _get_token_from_environment():389        logger.warning(390            "Note: Environment variable`HF_TOKEN` is set and is the current active token independently from the token you've just configured."391        )392    else:393        logger.info(f"The current active token is: `{token_name}`")394 395 396def _logout_from_token(token_name: str) -> None:397    """Logout from a specific access token.398 399    Args:400        token_name (`str`):401            The name of the access token to logout from.402    Raises:403        [`ValueError`](https://docs.python.org/3/library/exceptions.html#ValueError):404            If the access token name is not found.405    """406    stored_tokens = get_stored_tokens()407    # If there is no access tokens saved or the access token name is not found, do nothing408    if not stored_tokens or token_name not in stored_tokens:409        return410 411    token = stored_tokens.pop(token_name)412    _save_stored_tokens(stored_tokens)413 414    if token == _get_token_from_file():415        logger.warning(f"Active token '{token_name}' has been deleted.")416        Path(constants.HF_TOKEN_PATH).unlink(missing_ok=True)417 418 419def _set_active_token(420    token_name: str,421    add_to_git_credential: bool,422) -> None:423    """Set the active access token.424 425    Args:426        token_name (`str`):427            The name of the token to set as active.428    """429    token = _get_token_by_name(token_name)430    if not token:431        raise ValueError(f"Token {token_name} not found in {constants.HF_STORED_TOKENS_PATH}")432    if add_to_git_credential:433        if _is_git_credential_helper_configured():434            set_git_credential(token)435            logger.info(436                "Your token has been saved in your configured git credential helpers"437                + f" ({','.join(list_credential_helpers())})."438            )439        else:440            logger.warning("Token has not been saved to git credential helper.")441    # Write token to HF_TOKEN_PATH442    path = Path(constants.HF_TOKEN_PATH)443    path.parent.mkdir(parents=True, exist_ok=True)444    path.write_text(token)445    logger.info(f"Your token has been saved to {constants.HF_TOKEN_PATH}")446 447 448def _is_git_credential_helper_configured() -> bool:449    """Check if a git credential helper is configured.450 451    Warns user if not the case (except for Google Colab where "store" is set by default452    by `huggingface_hub`).453    """454    helpers = list_credential_helpers()455    if len(helpers) > 0:456        return True  # Do not warn: at least 1 helper is set457 458    # Only in Google Colab to avoid the warning message459    # See https://github.com/huggingface/huggingface_hub/issues/1043#issuecomment-1247010710460    if is_google_colab():461        _set_store_as_git_credential_helper_globally()462        return True  # Do not warn: "store" is used by default in Google Colab463 464    # Otherwise, warn user465    print(466        ANSI.red(467            "Cannot authenticate through git-credential as no helper is defined on your"468            " machine.\nYou might have to re-authenticate when pushing to the Hugging"469            " Face Hub.\nRun the following command in your terminal in case you want to"470            " set the 'store' credential helper as default.\n\ngit config --global"471            " credential.helper store\n\nRead"472            " https://git-scm.com/book/en/v2/Git-Tools-Credential-Storage for more"473            " details."474        )475    )476    return False477 478 479def _set_store_as_git_credential_helper_globally() -> None:480    """Set globally the credential.helper to `store`.481 482    To be used only in Google Colab as we assume the user doesn't care about the git483    credential config. It is the only particular case where we don't want to display the484    warning message in [`notebook_login()`].485 486    Related:487    - https://github.com/huggingface/huggingface_hub/issues/1043488    - https://github.com/huggingface/huggingface_hub/issues/1051489    - https://git-scm.com/docs/git-credential-store490    """491    try:492        run_subprocess("git config --global credential.helper store")493    except subprocess.CalledProcessError as exc:494        raise OSError(exc.stderr)495 
codekingpro/portable-devtools · Team Ai