GeezerVison is showing github.com — refactor: deprecate accessing constants from top-level namespace · python-gitlab/python-gitlab@c0aa0e1
File treeExpand file treeCollapse file tree Open diff view settings Expand file treeCollapse file tree Open diff view settings Collapse file Copy file name to clipboardExpand all lines: gitlab/__init__.py +17-1Lines changed: 17 additions & 1 deletion | Original file line number | Diff line number | Diff line change |
|---|
| 17 | 17 | """Wrapper for the GitLab API.""" | 18 | 18 |
| 19 | 19 | import warnings | | 20 | +from typing import Any | 20 | 21 |
| 21 | 22 | import gitlab.config # noqa: F401 | 22 | 23 | from gitlab.__version__ import ( # noqa: F401 | | 28 | 29 | __version__, | 29 | 30 | ) | 30 | 31 | from gitlab.client import Gitlab, GitlabList # noqa: F401 | 31 | | -from gitlab.const import * # noqa: F401,F403 | 32 | 32 | from gitlab.exceptions import * # noqa: F401,F403 | 33 | 33 |
| 34 | 34 | warnings.filterwarnings("default", category=DeprecationWarning, module="^gitlab") | | 35 | + | | 36 | + | | 37 | +# NOTE(jlvillal): We are deprecating access to the gitlab.const values which | | 38 | +# were previously imported into this namespace by the | | 39 | +# 'from gitlab.const import *' statement. | | 40 | +def __getattr__(name: str) -> Any: | | 41 | + # Deprecate direct access to constants without namespace | | 42 | + if name in gitlab.const._DEPRECATED: | | 43 | + warnings.warn( | | 44 | + f"\nDirect access to 'gitlab.{name}' is deprecated and will be " | | 45 | + f"removed in a future major python-gitlab release. Please " | | 46 | + f"use 'gitlab.const.{name}' instead.", | | 47 | + DeprecationWarning, | | 48 | + ) | | 49 | + return getattr(gitlab.const, name) | | 50 | + raise AttributeError(f"module {__name__} has no attribute {name}") |
Collapse file Copy file name to clipboardExpand all lines: gitlab/const.py +35Lines changed: 35 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
| 17 | 17 |
| 18 | 18 | from gitlab.__version__ import __title__, __version__ | 19 | 19 |
| | 20 | +# NOTE(jlvillal): '_DEPRECATED' only affects users accessing constants via the | | 21 | +# top-level gitlab.* namespace. See 'gitlab/__init__.py:__getattr__()' for the | | 22 | +# consumer of '_DEPRECATED' For example 'x = gitlab.NO_ACCESS'. We want users | | 23 | +# to instead use constants by doing code like: gitlab.const.NO_ACCESS. | | 24 | +_DEPRECATED = [ | | 25 | + "DEFAULT_URL", | | 26 | + "DEVELOPER_ACCESS", | | 27 | + "GUEST_ACCESS", | | 28 | + "MAINTAINER_ACCESS", | | 29 | + "MINIMAL_ACCESS", | | 30 | + "NO_ACCESS", | | 31 | + "NOTIFICATION_LEVEL_CUSTOM", | | 32 | + "NOTIFICATION_LEVEL_DISABLED", | | 33 | + "NOTIFICATION_LEVEL_GLOBAL", | | 34 | + "NOTIFICATION_LEVEL_MENTION", | | 35 | + "NOTIFICATION_LEVEL_PARTICIPATING", | | 36 | + "NOTIFICATION_LEVEL_WATCH", | | 37 | + "OWNER_ACCESS", | | 38 | + "REPORTER_ACCESS", | | 39 | + "SEARCH_SCOPE_BLOBS", | | 40 | + "SEARCH_SCOPE_COMMITS", | | 41 | + "SEARCH_SCOPE_GLOBAL_SNIPPET_TITLES", | | 42 | + "SEARCH_SCOPE_ISSUES", | | 43 | + "SEARCH_SCOPE_MERGE_REQUESTS", | | 44 | + "SEARCH_SCOPE_MILESTONES", | | 45 | + "SEARCH_SCOPE_PROJECT_NOTES", | | 46 | + "SEARCH_SCOPE_PROJECTS", | | 47 | + "SEARCH_SCOPE_USERS", | | 48 | + "SEARCH_SCOPE_WIKI_BLOBS", | | 49 | + "USER_AGENT", | | 50 | + "VISIBILITY_INTERNAL", | | 51 | + "VISIBILITY_PRIVATE", | | 52 | + "VISIBILITY_PUBLIC", | | 53 | +] | | 54 | + | 20 | 55 | DEFAULT_URL: str = "https://gitlab.com" | 21 | 56 |
| 22 | 57 | NO_ACCESS: int = 0 | |
Collapse file Copy file name to clipboardExpand all lines: tests/unit/test_gitlab.py +31-16Lines changed: 31 additions & 16 deletions | Original file line number | Diff line number | Diff line change |
|---|
| 17 | 17 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | 18 | 18 |
| 19 | 19 | import pickle | | 20 | +import warnings | 20 | 21 |
| 21 | 22 | import pytest | 22 | 23 | from httmock import HTTMock, response, urlmatch, with_httmock # noqa | 23 | 24 |
| 24 | | -from gitlab import DEFAULT_URL, Gitlab, GitlabList, USER_AGENT | 25 | | -from gitlab.v4.objects import CurrentUser | | 25 | +import gitlab | 26 | 26 |
| 27 | 27 | localhost = "http://localhost" | 28 | 28 | username = "username" | @@ -94,7 +94,7 @@ def test_gitlab_build_list(gl): | 94 | 94 | @with_httmock(resp_page_1, resp_page_2) | 95 | 95 | def test_gitlab_all_omitted_when_as_list(gl): | 96 | 96 | result = gl.http_list("/tests", as_list=False, all=True) | 97 | | - assert isinstance(result, GitlabList) | | 97 | + assert isinstance(result, gitlab.GitlabList) | 98 | 98 |
| 99 | 99 |
| 100 | 100 | def test_gitlab_strip_base_url(gl_trailing): | @@ -114,7 +114,7 @@ def test_gitlab_pickability(gl): | 114 | 114 | original_gl_objects = gl._objects | 115 | 115 | pickled = pickle.dumps(gl) | 116 | 116 | unpickled = pickle.loads(pickled) | 117 | | - assert isinstance(unpickled, Gitlab) | | 117 | + assert isinstance(unpickled, gitlab.Gitlab) | 118 | 118 | assert hasattr(unpickled, "_objects") | 119 | 119 | assert unpickled._objects == original_gl_objects | 120 | 120 |
| @@ -124,24 +124,24 @@ def test_gitlab_token_auth(gl, callback=None): | 124 | 124 | gl.auth() | 125 | 125 | assert gl.user.username == username | 126 | 126 | assert gl.user.id == user_id | 127 | | - assert isinstance(gl.user, CurrentUser) | | 127 | + assert isinstance(gl.user, gitlab.v4.objects.CurrentUser) | 128 | 128 |
| 129 | 129 |
| 130 | 130 | def test_gitlab_default_url(): | 131 | | - gl = Gitlab() | 132 | | - assert gl.url == DEFAULT_URL | | 131 | + gl = gitlab.Gitlab() | | 132 | + assert gl.url == gitlab.DEFAULT_URL | 133 | 133 |
| 134 | 134 |
| 135 | 135 | @pytest.mark.parametrize( | 136 | 136 | "args, kwargs, expected_url, expected_private_token, expected_oauth_token", | 137 | 137 | [ | 138 | | - ([], {}, DEFAULT_URL, None, None), | 139 | | - ([None, token], {}, DEFAULT_URL, token, None), | | 138 | + ([], {}, gitlab.DEFAULT_URL, None, None), | | 139 | + ([None, token], {}, gitlab.DEFAULT_URL, token, None), | 140 | 140 | ([localhost], {}, localhost, None, None), | 141 | 141 | ([localhost, token], {}, localhost, token, None), | 142 | 142 | ([localhost, None, token], {}, localhost, None, token), | 143 | | - ([], {"private_token": token}, DEFAULT_URL, token, None), | 144 | | - ([], {"oauth_token": token}, DEFAULT_URL, None, token), | | 143 | + ([], {"private_token": token}, gitlab.DEFAULT_URL, token, None), | | 144 | + ([], {"oauth_token": token}, gitlab.DEFAULT_URL, None, token), | 145 | 145 | ([], {"url": localhost}, localhost, None, None), | 146 | 146 | ([], {"url": localhost, "private_token": token}, localhost, token, None), | 147 | 147 | ([], {"url": localhost, "oauth_token": token}, localhost, None, token), | @@ -162,19 +162,19 @@ def test_gitlab_default_url(): | 162 | 162 | def test_gitlab_args_kwargs( | 163 | 163 | args, kwargs, expected_url, expected_private_token, expected_oauth_token | 164 | 164 | ): | 165 | | - gl = Gitlab(*args, **kwargs) | | 165 | + gl = gitlab.Gitlab(*args, **kwargs) | 166 | 166 | assert gl.url == expected_url | 167 | 167 | assert gl.private_token == expected_private_token | 168 | 168 | assert gl.oauth_token == expected_oauth_token | 169 | 169 |
| 170 | 170 |
| 171 | 171 | def test_gitlab_from_config(default_config): | 172 | 172 | config_path = default_config | 173 | | - Gitlab.from_config("one", [config_path]) | | 173 | + gitlab.Gitlab.from_config("one", [config_path]) | 174 | 174 |
| 175 | 175 |
| 176 | 176 | def test_gitlab_subclass_from_config(default_config): | 177 | | - class MyGitlab(Gitlab): | | 177 | + class MyGitlab(gitlab.Gitlab): | 178 | 178 | pass | 179 | 179 |
| 180 | 180 | config_path = default_config | @@ -185,10 +185,25 @@ class MyGitlab(Gitlab): | 185 | 185 | @pytest.mark.parametrize( | 186 | 186 | "kwargs,expected_agent", | 187 | 187 | [ | 188 | | - ({}, USER_AGENT), | | 188 | + ({}, gitlab.USER_AGENT), | 189 | 189 | ({"user_agent": "my-package/1.0.0"}, "my-package/1.0.0"), | 190 | 190 | ], | 191 | 191 | ) | 192 | 192 | def test_gitlab_user_agent(kwargs, expected_agent): | 193 | | - gl = Gitlab("http://localhost", **kwargs) | | 193 | + gl = gitlab.Gitlab("http://localhost", **kwargs) | 194 | 194 | assert gl.headers["User-Agent"] == expected_agent | | 195 | + | | 196 | + | | 197 | +def test_gitlab_deprecated_const(): | | 198 | + with warnings.catch_warnings(record=True) as caught_warnings: | | 199 | + gitlab.NO_ACCESS | | 200 | + assert len(caught_warnings) == 1 | | 201 | + warning = caught_warnings[0] | | 202 | + assert isinstance(warning.message, DeprecationWarning) | | 203 | + message = str(caught_warnings[0].message) | | 204 | + assert "deprecated" in message | | 205 | + assert "gitlab.const.NO_ACCESS" in message | | 206 | + | | 207 | + with warnings.catch_warnings(record=True) as caught_warnings: | | 208 | + gitlab.const.NO_ACCESS | | 209 | + assert len(caught_warnings) == 0 |
|