From de6794cd867b49bdc71bec906dc6998580cf4ac9 Mon Sep 17 00:00:00 2001 From: Swapnil Jikar <112884653+WizKnight@users.noreply.github.com> Date: Sat, 14 Sep 2024 14:17:22 +0530 Subject: [PATCH 1/6] Enhance `update_repo_settings` to manage repo visibility --- docs/source/en/guides/repository.md | 17 +++++-------- src/huggingface_hub/hf_api.py | 28 +++++++++++++++------ src/huggingface_hub/utils/__init__.py | 1 + tests/test_hf_api.py | 36 +++++++++++++-------------- 4 files changed, 46 insertions(+), 36 deletions(-) diff --git a/docs/source/en/guides/repository.md b/docs/source/en/guides/repository.md index 77bf797e61..e0dd20a888 100644 --- a/docs/source/en/guides/repository.md +++ b/docs/source/en/guides/repository.md @@ -146,26 +146,21 @@ an organization). In this section, we will see the settings that you can also co Some settings are specific to Spaces (hardware, environment variables,...). To configure those, please refer to our [Manage your Spaces](../guides/manage-spaces) guide. -### Update visibility +### Setup gated access and visibility -A repository can be public or private. A private repository is only visible to you or members of the organization in which the repository is located. Change a repository to private as shown in the following: +To enhance control over how repos are utilized, the Hub empowers repo authors to enable **access requests** for their repos, and to set the visibility of the repo to **private**. -```py ->>> from huggingface_hub import update_repo_visibility ->>> update_repo_visibility(repo_id=repo_id, private=True) -``` - -### Setup gated access +When **access requests** are enabled, users must agree to share their contact information (username and email address) with the repo authors to gain access to the files. A repo with access requests enabled is referred to as a **gated repo**. -To give more control over how repos are used, the Hub allows repo authors to enable **access requests** for their repos. User must agree to share their contact information (username and email address) with the repo authors to access the files when enabled. A repo with access requests enabled is called a **gated repo**. +And a repository can be public or private. A private repository is only visible to you or members of the organization in which the repository is located. -You can set a repo as gated using [`update_repo_settings`]: +You can configure these settings using [`update_repo_settings`]: ```py >>> from huggingface_hub import HfApi >>> api = HfApi() ->>> api.update_repo_settings(repo_id=repo_id, gated="auto") # Set automatic gating for a model +>>> api.update_repo_settings(repo_id=repo_id, gated="auto", private=True) # Set automatic gating and visibility for a model ``` ### Rename your repository diff --git a/src/huggingface_hub/hf_api.py b/src/huggingface_hub/hf_api.py index 50643fa626..aa66235177 100644 --- a/src/huggingface_hub/hf_api.py +++ b/src/huggingface_hub/hf_api.py @@ -124,6 +124,7 @@ SafetensorsParsingError, SafetensorsRepoMetadata, TensorInfo, + _deprecate_method, build_hf_headers, experimental, filter_repo_objects, @@ -3512,7 +3513,9 @@ def delete_repo( if not missing_ok: raise - @validate_hf_hub_args + @_deprecate_method( + version="0.29.x", message="This method will be removed in v0.29.x. Please use `update_repo_settings` instead." + ) def update_repo_visibility( self, repo_id: str, @@ -3521,7 +3524,7 @@ def update_repo_visibility( token: Union[str, bool, None] = None, repo_type: Optional[str] = None, ) -> Dict[str, bool]: - """Update the visibility setting of a repository. + """(Deprecated) Update the visibility setting of a repository. Args: repo_id (`str`, *optional*): @@ -3569,13 +3572,16 @@ def update_repo_settings( self, repo_id: str, *, - gated: Literal["auto", "manual", False] = False, + gated: Optional[Literal["auto", "manual", False]] = False, + private: Optional[bool] = False, token: Union[str, bool, None] = None, repo_type: Optional[str] = None, ) -> None: """ - Update the gated settings of a repository. - To give more control over how repos are used, the Hub allows repo authors to enable **access requests** for their repos. + Update the settings of a repository, including gated access and visibility. + + To give more control over how repos are used, the Hub allows repo authors to enable + access requests for their repos, and also to set the visibility of the repo to private. Args: repo_id (`str`): @@ -3585,6 +3591,8 @@ def update_repo_settings( * "auto": The repository is gated, and access requests are automatically approved or denied based on predefined criteria. * "manual": The repository is gated, and access requests require manual approval. * False (default): The repository is not gated, and anyone can access it. + private (`bool`, *optional*, defaults to `False`): + Whether the model repo should be private. token (`Union[str, bool, None]`, *optional*): A valid user access token (string). Defaults to the locally saved token, which is the recommended method for authentication (see @@ -3601,8 +3609,11 @@ def update_repo_settings( If repo_type is not one of the values in constants.REPO_TYPES. [`~utils.HfHubHTTPError`]: If the request to the Hugging Face Hub API fails. + [`~utils.RepositoryNotFoundError`] + If the repository to download from cannot be found. This may be because it doesn't exist, + or because it is set to `private` and you do not have access. """ - if gated not in ["auto", "manual", False]: + if gated is not None and gated not in ["auto", "manual", False]: raise ValueError(f"Invalid gated status, must be one of 'auto', 'manual', or False. Got '{gated}'.") if repo_type not in constants.REPO_TYPES: @@ -3613,10 +3624,13 @@ def update_repo_settings( # Build headers headers = self._build_hf_headers(token=token) + # Preparing the JSON payload for the PUT request + payload = {"gated": gated, "private": private} + r = get_session().put( url=f"{self.endpoint}/api/{repo_type}s/{repo_id}/settings", headers=headers, - json={"gated": gated}, + json={key: value for key, value in payload.items() if value is not None}, ) hf_raise_for_status(r) diff --git a/src/huggingface_hub/utils/__init__.py b/src/huggingface_hub/utils/__init__.py index 4efea4e253..c44129bcca 100644 --- a/src/huggingface_hub/utils/__init__.py +++ b/src/huggingface_hub/utils/__init__.py @@ -46,6 +46,7 @@ ) from ._chunk_utils import chunk_iterable from ._datetime import parse_datetime +from ._deprecation import _deprecate_method from ._experimental import experimental from ._fixes import SoftTemporaryDirectory, WeakFileLock, yaml_dump from ._git_credential import list_credential_helpers, set_git_credential, unset_git_credential diff --git a/tests/test_hf_api.py b/tests/test_hf_api.py index 44e228871f..097e73faec 100644 --- a/tests/test_hf_api.py +++ b/tests/test_hf_api.py @@ -126,12 +126,12 @@ def setUpClass(cls): def test_repo_id_no_warning(): # tests that passing repo_id as positional arg doesn't raise any warnings - # for {create, delete}_repo and update_repo_visibility + # for {create, delete}_repo and update_repo_settings api = HfApi(endpoint=ENDPOINT_STAGING, token=TOKEN) with warnings.catch_warnings(record=True) as record: repo_id = api.create_repo(repo_name()).repo_id - api.update_repo_visibility(repo_id, private=True) + api.update_repo_settings(repo_id, gated="auto", private=True) api.delete_repo(repo_id) assert not len(record) @@ -212,26 +212,26 @@ def test_delete_repo_missing_ok(self) -> None: def test_create_update_and_delete_repo(self): repo_id = self._api.create_repo(repo_id=repo_name()).repo_id - res = self._api.update_repo_visibility(repo_id=repo_id, private=True) - assert res["private"] - res = self._api.update_repo_visibility(repo_id=repo_id, private=False) - assert not res["private"] + self._api.update_repo_settings(repo_id=repo_id, private=True) + info = self._api.repo_info(repo_id) + if info is not None: + assert info.private self._api.delete_repo(repo_id=repo_id) def test_create_update_and_delete_model_repo(self): repo_id = self._api.create_repo(repo_id=repo_name(), repo_type=constants.REPO_TYPE_MODEL).repo_id - res = self._api.update_repo_visibility(repo_id=repo_id, private=True, repo_type=constants.REPO_TYPE_MODEL) - assert res["private"] - res = self._api.update_repo_visibility(repo_id=repo_id, private=False, repo_type=constants.REPO_TYPE_MODEL) - assert not res["private"] + self._api.update_repo_settings(repo_id=repo_id, private=True, repo_type=constants.REPO_TYPE_MODEL) + info = self._api.model_info(repo_id) + if info is not None: + assert info.private self._api.delete_repo(repo_id=repo_id, repo_type=constants.REPO_TYPE_MODEL) def test_create_update_and_delete_dataset_repo(self): repo_id = self._api.create_repo(repo_id=repo_name(), repo_type=constants.REPO_TYPE_DATASET).repo_id - res = self._api.update_repo_visibility(repo_id=repo_id, private=True, repo_type=constants.REPO_TYPE_DATASET) - assert res["private"] - res = self._api.update_repo_visibility(repo_id=repo_id, private=False, repo_type=constants.REPO_TYPE_DATASET) - assert not res["private"] + self._api.update_repo_settings(repo_id=repo_id, private=True, repo_type=constants.REPO_TYPE_DATASET) + info = self._api.dataset_info(repo_id) + if info is not None: + assert info.private self._api.delete_repo(repo_id=repo_id, repo_type=constants.REPO_TYPE_DATASET) def test_create_update_and_delete_space_repo(self): @@ -244,10 +244,10 @@ def test_create_update_and_delete_space_repo(self): repo_id = self._api.create_repo( repo_id=repo_name(), repo_type=constants.REPO_TYPE_SPACE, space_sdk=sdk ).repo_id - res = self._api.update_repo_visibility(repo_id=repo_id, private=True, repo_type=constants.REPO_TYPE_SPACE) - assert res["private"] - res = self._api.update_repo_visibility(repo_id=repo_id, private=False, repo_type=constants.REPO_TYPE_SPACE) - assert not res["private"] + self._api.update_repo_settings(repo_id=repo_id, private=True, repo_type=constants.REPO_TYPE_SPACE) + info = self._api.space_info(repo_id) + if info is not None: + assert info.private self._api.delete_repo(repo_id=repo_id, repo_type=constants.REPO_TYPE_SPACE) def test_move_repo_normal_usage(self): From e169e96cbc25df3a51d30bc8b8b305f3a76de94a Mon Sep 17 00:00:00 2001 From: Swapnil Jikar <112884653+WizKnight@users.noreply.github.com> Date: Thu, 19 Sep 2024 21:17:52 +0530 Subject: [PATCH 2/6] Enhance `update_repo_settings` to manage repo visibility --- src/huggingface_hub/hf_api.py | 9 +++------ src/huggingface_hub/utils/__init__.py | 1 - 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/huggingface_hub/hf_api.py b/src/huggingface_hub/hf_api.py index 52bf1a6a88..62a192cac3 100644 --- a/src/huggingface_hub/hf_api.py +++ b/src/huggingface_hub/hf_api.py @@ -124,7 +124,6 @@ SafetensorsParsingError, SafetensorsRepoMetadata, TensorInfo, - _deprecate_method, build_hf_headers, experimental, filter_repo_objects, @@ -3525,9 +3524,7 @@ def delete_repo( if not missing_ok: raise - @_deprecate_method( - version="0.29.x", message="This method will be removed in v0.29.x. Please use `update_repo_settings` instead." - ) + @_deprecate_method(version="0.29", message="Please use `update_repo_settings` instead.") def update_repo_visibility( self, repo_id: str, @@ -3584,8 +3581,8 @@ def update_repo_settings( self, repo_id: str, *, - gated: Optional[Literal["auto", "manual", False]] = False, - private: Optional[bool] = False, + gated: Optional[Literal["auto", "manual", False]] = None, + private: Optional[bool] = None, token: Union[str, bool, None] = None, repo_type: Optional[str] = None, ) -> None: diff --git a/src/huggingface_hub/utils/__init__.py b/src/huggingface_hub/utils/__init__.py index c44129bcca..4efea4e253 100644 --- a/src/huggingface_hub/utils/__init__.py +++ b/src/huggingface_hub/utils/__init__.py @@ -46,7 +46,6 @@ ) from ._chunk_utils import chunk_iterable from ._datetime import parse_datetime -from ._deprecation import _deprecate_method from ._experimental import experimental from ._fixes import SoftTemporaryDirectory, WeakFileLock, yaml_dump from ._git_credential import list_credential_helpers, set_git_credential, unset_git_credential From 06e31db641c2f323877c3afe3cd45fc17c8fb281 Mon Sep 17 00:00:00 2001 From: Swapnil Jikar <112884653+WizKnight@users.noreply.github.com> Date: Sat, 21 Sep 2024 01:37:11 +0530 Subject: [PATCH 3/6] Enhance `update_repo_settings` to manage repo visibility --- docs/source/en/guides/repository.md | 19 ++++++---- src/huggingface_hub/hf_api.py | 31 +++++++++++----- tests/test_file_download.py | 1 + tests/test_hf_api.py | 55 +++++++++++++++++------------ tests/test_snapshot_download.py | 3 +- 5 files changed, 71 insertions(+), 38 deletions(-) diff --git a/docs/source/en/guides/repository.md b/docs/source/en/guides/repository.md index e0dd20a888..c3c059fc93 100644 --- a/docs/source/en/guides/repository.md +++ b/docs/source/en/guides/repository.md @@ -146,21 +146,28 @@ an organization). In this section, we will see the settings that you can also co Some settings are specific to Spaces (hardware, environment variables,...). To configure those, please refer to our [Manage your Spaces](../guides/manage-spaces) guide. -### Setup gated access and visibility +### Update Visibility -To enhance control over how repos are utilized, the Hub empowers repo authors to enable **access requests** for their repos, and to set the visibility of the repo to **private**. +A repository can be public or private. A private repository is only visible to you or members of the organization in which the repository is located. Change a repository to private as shown in the following: -When **access requests** are enabled, users must agree to share their contact information (username and email address) with the repo authors to gain access to the files. A repo with access requests enabled is referred to as a **gated repo**. +```py +>>> from huggingface_hub import HfApi + +>>> api = HfApi() +>>> api.update_repo_settings(repo_id=repo_id, private=True) +``` + +### Setup gated access -And a repository can be public or private. A private repository is only visible to you or members of the organization in which the repository is located. +To give more control over how repos are used, the Hub allows repo authors to enable access requests for their repos. User must agree to share their contact information (username and email address) with the repo authors to access the files when enabled. A repo with access requests enabled is called a gated repo. -You can configure these settings using [`update_repo_settings`]: +You can set a repo as gated using [`update_repo_settings`]: ```py >>> from huggingface_hub import HfApi >>> api = HfApi() ->>> api.update_repo_settings(repo_id=repo_id, gated="auto", private=True) # Set automatic gating and visibility for a model +>>> api.update_repo_settings(repo_id=repo_id, gated="auto") # Set automatic gating for a model ``` ### Rename your repository diff --git a/src/huggingface_hub/hf_api.py b/src/huggingface_hub/hf_api.py index 62a192cac3..318bc3f66f 100644 --- a/src/huggingface_hub/hf_api.py +++ b/src/huggingface_hub/hf_api.py @@ -3525,6 +3525,7 @@ def delete_repo( raise @_deprecate_method(version="0.29", message="Please use `update_repo_settings` instead.") + @validate_hf_hub_args def update_repo_visibility( self, repo_id: str, @@ -3533,7 +3534,9 @@ def update_repo_visibility( token: Union[str, bool, None] = None, repo_type: Optional[str] = None, ) -> Dict[str, bool]: - """(Deprecated) Update the visibility setting of a repository. + """Update the visibility setting of a repository. + + Deprecated. Use `update_repo_settings` instead. Args: repo_id (`str`, *optional*): @@ -3599,8 +3602,8 @@ def update_repo_settings( The gated release status for the repository. * "auto": The repository is gated, and access requests are automatically approved or denied based on predefined criteria. * "manual": The repository is gated, and access requests require manual approval. - * False (default): The repository is not gated, and anyone can access it. - private (`bool`, *optional*, defaults to `False`): + * False : The gated status for the repository. If set to `None` (default), the `gated` setting of the repository won't be updated. + private (`bool`, *optional*): Whether the model repo should be private. token (`Union[str, bool, None]`, *optional*): A valid user access token (string). Defaults to the locally saved token, @@ -3608,7 +3611,7 @@ def update_repo_settings( https://huggingface.co/docs/huggingface_hub/quick-start#authentication). To disable authentication, pass False. repo_type (`str`, *optional*): - The type of the repository to update settings from (`"model"`, `"dataset"` or `"space"`. + The type of the repository to update settings from (`"model"`, `"dataset"` or `"space"`). Defaults to `"model"`. Raises: @@ -3622,24 +3625,34 @@ def update_repo_settings( If the repository to download from cannot be found. This may be because it doesn't exist, or because it is set to `private` and you do not have access. """ - if gated is not None and gated not in ["auto", "manual", False]: - raise ValueError(f"Invalid gated status, must be one of 'auto', 'manual', or False. Got '{gated}'.") if repo_type not in constants.REPO_TYPES: raise ValueError(f"Invalid repo type, must be one of {constants.REPO_TYPES}") if repo_type is None: repo_type = constants.REPO_TYPE_MODEL # default repo type + # Check if both gated and private are None + if gated is None and private is None: + raise ValueError("At least one of 'gated' or 'private' must be provided.") + # Build headers headers = self._build_hf_headers(token=token) - # Preparing the JSON payload for the PUT request - payload = {"gated": gated, "private": private} + # Prepare the JSON payload for the PUT request + payload: Dict = {} + + if gated is not None: + if gated not in ["auto", "manual", False]: + raise ValueError(f"Invalid gated status, must be one of 'auto', 'manual', or False. Got '{gated}'.") + payload["gated"] = gated + + if private is not None: + payload["private"] = private r = get_session().put( url=f"{self.endpoint}/api/{repo_type}s/{repo_id}/settings", headers=headers, - json={key: value for key, value in payload.items() if value is not None}, + json=payload, ) hf_raise_for_status(r) diff --git a/tests/test_file_download.py b/tests/test_file_download.py index 3496f82349..9e265f4b5d 100644 --- a/tests/test_file_download.py +++ b/tests/test_file_download.py @@ -161,6 +161,7 @@ def test_download_from_a_gated_repo_with_hf_hub_download(self, repo_url: RepoUrl repo_id=repo_url.repo_id, filename=".gitattributes", token=OTHER_TOKEN, cache_dir=tmpdir ) + @expect_deprecation("update_repo_visibility") @use_tmp_repo() def test_download_regular_file_from_private_renamed_repo(self, repo_url: RepoUrl) -> None: """Regression test for #1999. diff --git a/tests/test_hf_api.py b/tests/test_hf_api.py index f6f8d1e08b..536f0a65d9 100644 --- a/tests/test_hf_api.py +++ b/tests/test_hf_api.py @@ -93,6 +93,7 @@ DUMMY_MODEL_ID_REVISION_ONE_SPECIFIC_COMMIT, ENDPOINT_PRODUCTION, SAMPLE_DATASET_IDENTIFIER, + expect_deprecation, repo_name, require_git_lfs, rmtree_with_retry, @@ -210,30 +211,34 @@ def test_delete_repo_error_message(self): def test_delete_repo_missing_ok(self) -> None: self._api.delete_repo("repo-that-does-not-exist", missing_ok=True) + @expect_deprecation("update_repo_visibility") def test_create_update_and_delete_repo(self): repo_id = self._api.create_repo(repo_id=repo_name()).repo_id - self._api.update_repo_settings(repo_id=repo_id, private=True) - info = self._api.repo_info(repo_id) - if info is not None: - assert info.private + res = self._api.update_repo_visibility(repo_id=repo_id, private=True) + assert res["private"] + res = self._api.update_repo_visibility(repo_id=repo_id, private=False) + assert not res["private"] self._api.delete_repo(repo_id=repo_id) + @expect_deprecation("update_repo_visibility") def test_create_update_and_delete_model_repo(self): repo_id = self._api.create_repo(repo_id=repo_name(), repo_type=constants.REPO_TYPE_MODEL).repo_id - self._api.update_repo_settings(repo_id=repo_id, private=True, repo_type=constants.REPO_TYPE_MODEL) - info = self._api.model_info(repo_id) - if info is not None: - assert info.private + res = self._api.update_repo_visibility(repo_id=repo_id, private=True, repo_type=constants.REPO_TYPE_MODEL) + assert res["private"] + res = self._api.update_repo_visibility(repo_id=repo_id, private=False, repo_type=constants.REPO_TYPE_MODEL) + assert not res["private"] self._api.delete_repo(repo_id=repo_id, repo_type=constants.REPO_TYPE_MODEL) + @expect_deprecation("update_repo_visibility") def test_create_update_and_delete_dataset_repo(self): repo_id = self._api.create_repo(repo_id=repo_name(), repo_type=constants.REPO_TYPE_DATASET).repo_id - self._api.update_repo_settings(repo_id=repo_id, private=True, repo_type=constants.REPO_TYPE_DATASET) - info = self._api.dataset_info(repo_id) - if info is not None: - assert info.private + res = self._api.update_repo_visibility(repo_id=repo_id, private=True, repo_type=constants.REPO_TYPE_DATASET) + assert res["private"] + res = self._api.update_repo_visibility(repo_id=repo_id, private=False, repo_type=constants.REPO_TYPE_DATASET) + assert not res["private"] self._api.delete_repo(repo_id=repo_id, repo_type=constants.REPO_TYPE_DATASET) + @expect_deprecation("update_repo_visibility") def test_create_update_and_delete_space_repo(self): with pytest.raises(ValueError, match=r"No space_sdk provided.*"): self._api.create_repo(repo_id=repo_name(), repo_type=constants.REPO_TYPE_SPACE, space_sdk=None) @@ -244,10 +249,10 @@ def test_create_update_and_delete_space_repo(self): repo_id = self._api.create_repo( repo_id=repo_name(), repo_type=constants.REPO_TYPE_SPACE, space_sdk=sdk ).repo_id - self._api.update_repo_settings(repo_id=repo_id, private=True, repo_type=constants.REPO_TYPE_SPACE) - info = self._api.space_info(repo_id) - if info is not None: - assert info.private + res = self._api.update_repo_visibility(repo_id=repo_id, private=True, repo_type=constants.REPO_TYPE_SPACE) + assert res["private"] + res = self._api.update_repo_visibility(repo_id=repo_id, private=False, repo_type=constants.REPO_TYPE_SPACE) + assert not res["private"] self._api.delete_repo(repo_id=repo_id, repo_type=constants.REPO_TYPE_SPACE) def test_move_repo_normal_usage(self): @@ -286,9 +291,11 @@ def test_update_repo_settings(self, repo_url: RepoUrl): repo_id = repo_url.repo_id for gated_value in ["auto", "manual", False]: - self._api.update_repo_settings(repo_id=repo_id, gated=gated_value) - info = self._api.model_info(repo_id, expand="gated") - assert info.gated == gated_value + for private_value in [True, False]: # Test both private and public settings + self._api.update_repo_settings(repo_id=repo_id, gated=gated_value, private=private_value) + info = self._api.model_info(repo_id) + assert info.gated == gated_value + assert info.private == private_value # Verify the private setting @use_tmp_repo(repo_type="dataset") def test_update_dataset_repo_settings(self, repo_url: RepoUrl): @@ -296,9 +303,13 @@ def test_update_dataset_repo_settings(self, repo_url: RepoUrl): repo_type = repo_url.repo_type for gated_value in ["auto", "manual", False]: - self._api.update_repo_settings(repo_id=repo_id, repo_type=repo_type, gated=gated_value) - info = self._api.dataset_info(repo_id, expand="gated") - assert info.gated == gated_value + for private_value in [True, False]: + self._api.update_repo_settings( + repo_id=repo_id, repo_type=repo_type, gated=gated_value, private=private_value + ) + info = self._api.dataset_info(repo_id) + assert info.gated == gated_value + assert info.private == private_value class CommitApiTest(HfApiCommonTest): diff --git a/tests/test_snapshot_download.py b/tests/test_snapshot_download.py index 17f4c561b3..641e7980ab 100644 --- a/tests/test_snapshot_download.py +++ b/tests/test_snapshot_download.py @@ -8,7 +8,7 @@ from huggingface_hub.utils import SoftTemporaryDirectory from .testing_constants import TOKEN -from .testing_utils import OfflineSimulationMode, offline, repo_name +from .testing_utils import OfflineSimulationMode, expect_deprecation, offline, repo_name class SnapshotDownloadTests(unittest.TestCase): @@ -95,6 +95,7 @@ def test_download_model(self): # folder name contains the revision's commit sha. self.assertTrue(self.first_commit_hash in storage_folder) + @expect_deprecation("update_repo_visibility") def test_download_private_model(self): self.api.update_repo_visibility(repo_id=self.repo_id, private=True) From b06e6b453b7756e4435ca29a3617c35703acb6f2 Mon Sep 17 00:00:00 2001 From: Swapnil Jikar <112884653+WizKnight@users.noreply.github.com> Date: Sat, 21 Sep 2024 01:43:04 +0530 Subject: [PATCH 4/6] Enhance `update_repo_settings` to manage repo visibility --- tests/test_hf_api.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/test_hf_api.py b/tests/test_hf_api.py index 536f0a65d9..cb1ba44aee 100644 --- a/tests/test_hf_api.py +++ b/tests/test_hf_api.py @@ -125,14 +125,15 @@ def setUpClass(cls): cls._api = HfApi(endpoint=ENDPOINT_STAGING, token=TOKEN) +@expect_deprecation("update_repo_visibility") def test_repo_id_no_warning(): # tests that passing repo_id as positional arg doesn't raise any warnings - # for {create, delete}_repo and update_repo_settings + # for {create, delete}_repo and update_repo_visibility api = HfApi(endpoint=ENDPOINT_STAGING, token=TOKEN) with warnings.catch_warnings(record=True) as record: repo_id = api.create_repo(repo_name()).repo_id - api.update_repo_settings(repo_id, gated="auto", private=True) + api.update_repo_visibility(repo_id, private=True) api.delete_repo(repo_id) assert not len(record) From e68280c04e1fa6a7651db0f89ac3adc04c5bfaad Mon Sep 17 00:00:00 2001 From: Swapnil Jikar <112884653+WizKnight@users.noreply.github.com> Date: Thu, 26 Sep 2024 16:38:17 +0530 Subject: [PATCH 5/6] Enhance `update_repo_settings` to manage repo visibility --- src/huggingface_hub/hf_api.py | 4 ++-- tests/test_hf_api.py | 14 -------------- 2 files changed, 2 insertions(+), 16 deletions(-) diff --git a/src/huggingface_hub/hf_api.py b/src/huggingface_hub/hf_api.py index 318bc3f66f..98d556de42 100644 --- a/src/huggingface_hub/hf_api.py +++ b/src/huggingface_hub/hf_api.py @@ -3599,10 +3599,10 @@ def update_repo_settings( repo_id (`str`): A namespace (user or an organization) and a repo name separated by a /. gated (`Literal["auto", "manual", False]`, *optional*): - The gated release status for the repository. + The gated status for the repository. If set to `None` (default), the `gated` setting of the repository won't be updated. * "auto": The repository is gated, and access requests are automatically approved or denied based on predefined criteria. * "manual": The repository is gated, and access requests require manual approval. - * False : The gated status for the repository. If set to `None` (default), the `gated` setting of the repository won't be updated. + * False : The repository is not gated, and anyone can access it. private (`bool`, *optional*): Whether the model repo should be private. token (`Union[str, bool, None]`, *optional*): diff --git a/tests/test_hf_api.py b/tests/test_hf_api.py index cb1ba44aee..a028066847 100644 --- a/tests/test_hf_api.py +++ b/tests/test_hf_api.py @@ -20,7 +20,6 @@ import types import unittest import uuid -import warnings from collections.abc import Iterable from concurrent.futures import Future from dataclasses import fields @@ -125,19 +124,6 @@ def setUpClass(cls): cls._api = HfApi(endpoint=ENDPOINT_STAGING, token=TOKEN) -@expect_deprecation("update_repo_visibility") -def test_repo_id_no_warning(): - # tests that passing repo_id as positional arg doesn't raise any warnings - # for {create, delete}_repo and update_repo_visibility - api = HfApi(endpoint=ENDPOINT_STAGING, token=TOKEN) - - with warnings.catch_warnings(record=True) as record: - repo_id = api.create_repo(repo_name()).repo_id - api.update_repo_visibility(repo_id, private=True) - api.delete_repo(repo_id) - assert not len(record) - - class HfApiRepoFileExistsTest(HfApiCommonTest): def setUp(self) -> None: super().setUp() From 8b13d083895a59ac788ee5431c2f3438c309ed08 Mon Sep 17 00:00:00 2001 From: Lucain Date: Thu, 26 Sep 2024 15:39:05 +0200 Subject: [PATCH 6/6] Apply suggestions from code review --- docs/source/en/guides/repository.md | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/docs/source/en/guides/repository.md b/docs/source/en/guides/repository.md index c3c059fc93..adfc881298 100644 --- a/docs/source/en/guides/repository.md +++ b/docs/source/en/guides/repository.md @@ -146,20 +146,18 @@ an organization). In this section, we will see the settings that you can also co Some settings are specific to Spaces (hardware, environment variables,...). To configure those, please refer to our [Manage your Spaces](../guides/manage-spaces) guide. -### Update Visibility +### Update visibility A repository can be public or private. A private repository is only visible to you or members of the organization in which the repository is located. Change a repository to private as shown in the following: ```py ->>> from huggingface_hub import HfApi - ->>> api = HfApi() ->>> api.update_repo_settings(repo_id=repo_id, private=True) +>>> from huggingface_hub import update_repo_settings +>>> update_repo_settings(repo_id=repo_id, private=True) ``` ### Setup gated access -To give more control over how repos are used, the Hub allows repo authors to enable access requests for their repos. User must agree to share their contact information (username and email address) with the repo authors to access the files when enabled. A repo with access requests enabled is called a gated repo. +To give more control over how repos are used, the Hub allows repo authors to enable **access requests** for their repos. User must agree to share their contact information (username and email address) with the repo authors to access the files when enabled. A repo with access requests enabled is called a **gated repo**. You can set a repo as gated using [`update_repo_settings`]: