Skip to content

Commit

Permalink
Fix circular import in login (#1930)
Browse files Browse the repository at this point in the history
* prepare for 0.21.0

* Fix circular import in login
  • Loading branch information
Wauplin committed Dec 20, 2023
1 parent 584b5c9 commit bbcfe42
Show file tree
Hide file tree
Showing 7 changed files with 130 additions and 105 deletions.
4 changes: 2 additions & 2 deletions src/huggingface_hub/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@
"InferenceEndpointType",
],
"_login": [
"get_token",
"interpreter_login",
"login",
"logout",
Expand Down Expand Up @@ -300,6 +299,7 @@
"configure_http_backend",
"dump_environment_info",
"get_session",
"get_token",
"logging",
"scan_cache_dir",
],
Expand Down Expand Up @@ -414,7 +414,6 @@ def __dir__():
InferenceEndpointType, # noqa: F401
)
from ._login import (
get_token, # noqa: F401
interpreter_login, # noqa: F401
login, # noqa: F401
logout, # noqa: F401
Expand Down Expand Up @@ -641,6 +640,7 @@ def __dir__():
configure_http_backend, # noqa: F401
dump_environment_info, # noqa: F401
get_session, # noqa: F401
get_token, # noqa: F401
logging, # noqa: F401
scan_cache_dir, # noqa: F401
)
Expand Down
112 changes: 12 additions & 100 deletions src/huggingface_hub/_login.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,25 @@
"""Contains methods to login to the Hub."""
import os
import subprocess
import warnings
from functools import partial
from getpass import getpass
from pathlib import Path
from typing import Optional

from . import constants
from .commands._cli_utils import ANSI
from .utils import logging
from .utils._git_credential import list_credential_helpers, set_git_credential, unset_git_credential
from .utils._runtime import is_google_colab, is_notebook
from .utils._subprocess import capture_output, run_subprocess
from .utils import (
capture_output,
get_token,
is_google_colab,
is_notebook,
list_credential_helpers,
logging,
run_subprocess,
set_git_credential,
unset_git_credential,
)
from .utils._token import _get_token_from_environment, _get_token_from_google_colab


logger = logging.get_logger(__name__)
Expand All @@ -38,8 +45,6 @@
_| _| _|_| _|_|_| _|_|_| _|_|_| _| _| _|_|_| _| _| _| _|_|_| _|_|_|_|
"""

_CHECK_GOOGLE_COLAB_SECRET = True


def login(
token: Optional[str] = None,
Expand Down Expand Up @@ -284,99 +289,6 @@ def login_token_event(t, write_permission: bool = False):
token_finish_button.on_click(partial(login_token_event, write_permission=write_permission))


###
# Token helpers
###


def get_token() -> Optional[str]:
"""
Get token if user is logged in.
Note: in most cases, you should use [`huggingface_hub.utils.build_hf_headers`] instead. This method is only useful
if you want to retrieve the token for other purposes than sending an HTTP request.
Token is retrieved in priority from the `HF_TOKEN` environment variable. Otherwise, we read the token file located
in the Hugging Face home folder. Returns None if user is not logged in. To log in, use [`login`] or
`huggingface-cli login`.
Returns:
`str` or `None`: The token, `None` if it doesn't exist.
"""
return _get_token_from_google_colab() or _get_token_from_environment() or _get_token_from_file()


def _get_token_from_google_colab() -> Optional[str]:
if not is_google_colab():
return None

global _CHECK_GOOGLE_COLAB_SECRET
if not _CHECK_GOOGLE_COLAB_SECRET: # request access only once
return None

try:
from google.colab import userdata
from google.colab.errors import Error as ColabError
except ImportError:
return None

try:
token = userdata.get("HF_TOKEN")
except userdata.NotebookAccessError:
# Means the user has a secret call `HF_TOKEN` and got a popup "please grand access to HF_TOKEN" and refused it
# => warn user but ignore error => do not re-request access to user
warnings.warn(
"\nAccess to the secret `HF_TOKEN` has not been granted on this notebook."
"\nYou will not be requested again."
"\nPlease restart the session if you want to be prompted again."
)
_CHECK_GOOGLE_COLAB_SECRET = False
return None
except userdata.SecretNotFoundError:
# Means the user did not define a `HF_TOKEN` secret => warn
warnings.warn(
"\nThe secret `HF_TOKEN` does not exist in your Colab secrets."
"\nTo authenticate with the Hugging Face Hub, create a token in your settings tab "
"(https://huggingface.co/settings/tokens), set it as secret in your Google Colab and restart your session."
"\nYou will be able to reuse this secret in all of your notebooks."
"\nPlease note that authentication is recommended but still optional to access public models or datasets."
)
return None
except ColabError as e:
# Something happen but we don't know what => recommend to open a GitHub issue
warnings.warn(
f"\nError while fetching `HF_TOKEN` secret value from your vault: '{str(e)}'."
"\nYou are not authenticated with the Hugging Face Hub in this notebook."
"\nIf the error persists, please let us know by opening an issue on GitHub "
"(https://github.com/huggingface/huggingface_hub/issues/new)."
)
return None

return _clean_token(token)


def _get_token_from_environment() -> Optional[str]:
# `HF_TOKEN` has priority (keep `HUGGING_FACE_HUB_TOKEN` for backward compatibility)
return _clean_token(os.environ.get("HF_TOKEN") or os.environ.get("HUGGING_FACE_HUB_TOKEN"))


def _get_token_from_file() -> Optional[str]:
try:
return _clean_token(Path(constants.HF_TOKEN_PATH).read_text())
except FileNotFoundError:
return None


def _clean_token(token: Optional[str]) -> Optional[str]:
"""Clean token by removing trailing and leading spaces and newlines.
If token is an empty string, return None.
"""
if token is None:
return None
return token.replace("\r", "").replace("\n", "").strip() or None


###
# Login private helpers
###
Expand Down
2 changes: 1 addition & 1 deletion src/huggingface_hub/commands/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,11 @@
NOTEBOOK_LOGIN_PASSWORD_HTML,
NOTEBOOK_LOGIN_TOKEN_HTML_END,
NOTEBOOK_LOGIN_TOKEN_HTML_START,
get_token,
login,
logout,
notebook_login,
)
from ..utils import get_token
from ._cli_utils import ANSI


Expand Down
2 changes: 1 addition & 1 deletion src/huggingface_hub/repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@
from huggingface_hub.constants import REPO_TYPES_URL_PREFIXES, REPOCARD_NAME
from huggingface_hub.repocard import metadata_load, metadata_save

from ._login import get_token
from .hf_api import HfApi, repo_type_and_id_from_hf_id
from .lfs import LFS_MULTIPART_UPLOAD_COMMAND
from .utils import (
SoftTemporaryDirectory,
get_token,
logging,
run_subprocess,
tqdm,
Expand Down
1 change: 1 addition & 0 deletions src/huggingface_hub/utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
RevisionNotFoundError,
hf_raise_for_status,
)
from ._token import get_token
from ._fixes import SoftTemporaryDirectory, yaml_dump
from ._git_credential import list_credential_helpers, set_git_credential, unset_git_credential
from ._headers import build_hf_headers, get_token_to_send, LocalTokenNotFoundError
Expand Down
2 changes: 1 addition & 1 deletion src/huggingface_hub/utils/_headers.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
from typing import Dict, Optional, Union

from .. import constants
from .._login import get_token
from ._runtime import (
get_fastai_version,
get_fastcore_version,
Expand All @@ -29,6 +28,7 @@
is_tf_available,
is_torch_available,
)
from ._token import get_token
from ._validators import validate_hf_hub_args


Expand Down
112 changes: 112 additions & 0 deletions src/huggingface_hub/utils/_token.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
# Copyright 2023 The HuggingFace Team. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Contains an helper to get the token from machine (env variable, secret or config file)."""
import os
import warnings
from pathlib import Path
from typing import Optional

from .. import constants
from ._runtime import is_google_colab


_CHECK_GOOGLE_COLAB_SECRET = True


def get_token() -> Optional[str]:
"""
Get token if user is logged in.
Note: in most cases, you should use [`huggingface_hub.utils.build_hf_headers`] instead. This method is only useful
if you want to retrieve the token for other purposes than sending an HTTP request.
Token is retrieved in priority from the `HF_TOKEN` environment variable. Otherwise, we read the token file located
in the Hugging Face home folder. Returns None if user is not logged in. To log in, use [`login`] or
`huggingface-cli login`.
Returns:
`str` or `None`: The token, `None` if it doesn't exist.
"""
return _get_token_from_google_colab() or _get_token_from_environment() or _get_token_from_file()


def _get_token_from_google_colab() -> Optional[str]:
if not is_google_colab():
return None

global _CHECK_GOOGLE_COLAB_SECRET
if not _CHECK_GOOGLE_COLAB_SECRET: # request access only once
return None

try:
from google.colab import userdata
from google.colab.errors import Error as ColabError
except ImportError:
return None

try:
token = userdata.get("HF_TOKEN")
except userdata.NotebookAccessError:
# Means the user has a secret call `HF_TOKEN` and got a popup "please grand access to HF_TOKEN" and refused it
# => warn user but ignore error => do not re-request access to user
warnings.warn(
"\nAccess to the secret `HF_TOKEN` has not been granted on this notebook."
"\nYou will not be requested again."
"\nPlease restart the session if you want to be prompted again."
)
_CHECK_GOOGLE_COLAB_SECRET = False
return None
except userdata.SecretNotFoundError:
# Means the user did not define a `HF_TOKEN` secret => warn
warnings.warn(
"\nThe secret `HF_TOKEN` does not exist in your Colab secrets."
"\nTo authenticate with the Hugging Face Hub, create a token in your settings tab "
"(https://huggingface.co/settings/tokens), set it as secret in your Google Colab and restart your session."
"\nYou will be able to reuse this secret in all of your notebooks."
"\nPlease note that authentication is recommended but still optional to access public models or datasets."
)
return None
except ColabError as e:
# Something happen but we don't know what => recommend to open a GitHub issue
warnings.warn(
f"\nError while fetching `HF_TOKEN` secret value from your vault: '{str(e)}'."
"\nYou are not authenticated with the Hugging Face Hub in this notebook."
"\nIf the error persists, please let us know by opening an issue on GitHub "
"(https://github.com/huggingface/huggingface_hub/issues/new)."
)
return None

return _clean_token(token)


def _get_token_from_environment() -> Optional[str]:
# `HF_TOKEN` has priority (keep `HUGGING_FACE_HUB_TOKEN` for backward compatibility)
return _clean_token(os.environ.get("HF_TOKEN") or os.environ.get("HUGGING_FACE_HUB_TOKEN"))


def _get_token_from_file() -> Optional[str]:
try:
return _clean_token(Path(constants.HF_TOKEN_PATH).read_text())
except FileNotFoundError:
return None


def _clean_token(token: Optional[str]) -> Optional[str]:
"""Clean token by removing trailing and leading spaces and newlines.
If token is an empty string, return None.
"""
if token is None:
return None
return token.replace("\r", "").replace("\n", "").strip() or None

0 comments on commit bbcfe42

Please sign in to comment.