Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 7802ade

Browse filesBrowse files
chore: create a custom warnings.warn wrapper
Create a custom `warnings.warn` wrapper that will walk the stack trace to find the first frame outside of the `gitlab/` path to print the warning against. This will make it easier for users to find where in their code the error is generated from
1 parent 5e19694 commit 7802ade
Copy full SHA for 7802ade

File tree

Expand file treeCollapse file tree

6 files changed

+95
-25
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

6 files changed

+95
-25
lines changed
Open diff view settings
Collapse file

‎docs/api-usage.rst‎

Copy file name to clipboardExpand all lines: docs/api-usage.rst
+13-5Lines changed: 13 additions & 5 deletions
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -93,20 +93,26 @@ Examples:
9393
.. code-block:: python
9494
9595
# list all the projects
96-
projects = gl.projects.list()
96+
projects = gl.projects.list(as_list=False)
9797
for project in projects:
9898
print(project)
9999
100100
# get the group with id == 2
101101
group = gl.groups.get(2)
102-
for project in group.projects.list():
102+
for project in group.projects.list(as_list=False):
103103
print(project)
104104
105105
# create a new user
106106
user_data = {'email': 'jen@foo.com', 'username': 'jen', 'name': 'Jen'}
107107
user = gl.users.create(user_data)
108108
print(user)
109109
110+
.. warning::
111+
Calling `list()` without any arguments will by default not return the complete list
112+
of items. Use either the `all=True` or `as_list=False` parameters to get all the
113+
items when using listing methods. See the :ref:`pagination` section for more
114+
information.
115+
110116
You can list the mandatory and optional attributes for object creation and
111117
update with the manager's ``get_create_attrs()`` and ``get_update_attrs()``
112118
methods. They return 2 tuples, the first one is the list of mandatory
@@ -133,7 +139,7 @@ Some objects also provide managers to access related GitLab resources:
133139
134140
# list the issues for a project
135141
project = gl.projects.get(1)
136-
issues = project.issues.list()
142+
issues = project.issues.list(all=True)
137143
138144
python-gitlab allows to send any data to the GitLab server when making queries.
139145
In case of invalid or missing arguments python-gitlab will raise an exception
@@ -150,9 +156,9 @@ conflict with python or python-gitlab when using them as kwargs:
150156

151157
.. code-block:: python
152158
153-
gl.user_activities.list(from='2019-01-01') ## invalid
159+
gl.user_activities.list(from='2019-01-01', as_list=False) ## invalid
154160
155-
gl.user_activities.list(query_parameters={'from': '2019-01-01'}) # OK
161+
gl.user_activities.list(query_parameters={'from': '2019-01-01'}, as_list=False) # OK
156162
157163
Gitlab Objects
158164
==============
@@ -222,6 +228,8 @@ a project (the previous example used 2 API calls):
222228
project = gl.projects.get(1, lazy=True) # no API call
223229
project.star() # API call
224230
231+
.. _pagination:
232+
225233
Pagination
226234
==========
227235

Collapse file

‎gitlab/__init__.py‎

Copy file name to clipboardExpand all lines: gitlab/__init__.py
+8-5Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
from typing import Any
2121

2222
import gitlab.config # noqa: F401
23+
from gitlab import utils as _utils
2324
from gitlab._version import ( # noqa: F401
2425
__author__,
2526
__copyright__,
@@ -40,11 +41,13 @@
4041
def __getattr__(name: str) -> Any:
4142
# Deprecate direct access to constants without namespace
4243
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,
44+
_utils.warn(
45+
message=(
46+
f"\nDirect access to 'gitlab.{name}' is deprecated and will be "
47+
f"removed in a future major python-gitlab release. Please "
48+
f"use 'gitlab.const.{name}' instead."
49+
),
50+
category=DeprecationWarning,
4851
)
4952
return getattr(gitlab.const, name)
5053
raise AttributeError(f"module {__name__} has no attribute {name}")
Collapse file

‎gitlab/utils.py‎

Copy file name to clipboardExpand all lines: gitlab/utils.py
+37-1Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,11 @@
1515
# You should have received a copy of the GNU Lesser General Public License
1616
# along with this program. If not, see <http://www.gnu.org/licenses/>.
1717

18+
import pathlib
19+
import traceback
1820
import urllib.parse
19-
from typing import Any, Callable, Dict, Optional, Union
21+
import warnings
22+
from typing import Any, Callable, Dict, Optional, Type, Union
2023

2124
import requests
2225

@@ -90,3 +93,36 @@ def __new__( # type: ignore
9093

9194
def remove_none_from_dict(data: Dict[str, Any]) -> Dict[str, Any]:
9295
return {k: v for k, v in data.items() if v is not None}
96+
97+
98+
def warn(
99+
message: str,
100+
*,
101+
category: Optional[Type] = None,
102+
source: Optional[Any] = None,
103+
) -> None:
104+
"""This `warnings.warn` wrapper function attempts to show the location causing the
105+
warning in the user code that called the library.
106+
107+
It does this by walking up the stack trace to find the first frame located outside
108+
the `gitlab/` directory. This is helpful to users as it shows them their code that
109+
is causing the warning.
110+
"""
111+
# Get `stacklevel` for user code so we indicate where issue is in
112+
# their code.
113+
pg_dir = pathlib.Path(__file__).parent.resolve()
114+
stack = traceback.extract_stack()
115+
stacklevel = 1
116+
warning_from = ""
117+
for stacklevel, frame in enumerate(reversed(stack), start=1):
118+
if stacklevel == 2:
119+
warning_from = f" (python-gitlab: {frame.filename}:{frame.lineno})"
120+
frame_dir = str(pathlib.Path(frame.filename).parent.resolve())
121+
if not frame_dir.startswith(str(pg_dir)):
122+
break
123+
warnings.warn(
124+
message=message + warning_from,
125+
category=category,
126+
stacklevel=stacklevel,
127+
source=source,
128+
)
Collapse file

‎gitlab/v4/objects/artifacts.py‎

Copy file name to clipboardExpand all lines: gitlab/v4/objects/artifacts.py
+6-5Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
GitLab API:
33
https://docs.gitlab.com/ee/api/job_artifacts.html
44
"""
5-
import warnings
65
from typing import Any, Callable, Optional, TYPE_CHECKING
76

87
import requests
@@ -34,10 +33,12 @@ def __call__(
3433
*args: Any,
3534
**kwargs: Any,
3635
) -> Optional[bytes]:
37-
warnings.warn(
38-
"The project.artifacts() method is deprecated and will be "
39-
"removed in a future version. Use project.artifacts.download() instead.\n",
40-
DeprecationWarning,
36+
utils.warn(
37+
message=(
38+
"The project.artifacts() method is deprecated and will be removed in a "
39+
"future version. Use project.artifacts.download() instead.\n"
40+
),
41+
category=DeprecationWarning,
4142
)
4243
return self.download(
4344
*args,
Collapse file

‎gitlab/v4/objects/projects.py‎

Copy file name to clipboardExpand all lines: gitlab/v4/objects/projects.py
+12-9Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import warnings
21
from typing import Any, Callable, cast, Dict, List, Optional, TYPE_CHECKING, Union
32

43
import requests
@@ -548,10 +547,12 @@ def transfer(self, to_namespace: Union[int, str], **kwargs: Any) -> None:
548547

549548
@cli.register_custom_action("Project", ("to_namespace",))
550549
def transfer_project(self, *args: Any, **kwargs: Any) -> None:
551-
warnings.warn(
552-
"The project.transfer_project() method is deprecated and will be "
553-
"removed in a future version. Use project.transfer() instead.",
554-
DeprecationWarning,
550+
utils.warn(
551+
message=(
552+
"The project.transfer_project() method is deprecated and will be "
553+
"removed in a future version. Use project.transfer() instead."
554+
),
555+
category=DeprecationWarning,
555556
)
556557
return self.transfer(*args, **kwargs)
557558

@@ -562,10 +563,12 @@ def artifact(
562563
*args: Any,
563564
**kwargs: Any,
564565
) -> Optional[bytes]:
565-
warnings.warn(
566-
"The project.artifact() method is deprecated and will be "
567-
"removed in a future version. Use project.artifacts.raw() instead.",
568-
DeprecationWarning,
566+
utils.warn(
567+
message=(
568+
"The project.artifact() method is deprecated and will be "
569+
"removed in a future version. Use project.artifacts.raw() instead."
570+
),
571+
category=DeprecationWarning,
569572
)
570573
return self.artifacts.raw(*args, **kwargs)
571574

Collapse file

‎tests/unit/test_utils.py‎

Copy file name to clipboardExpand all lines: tests/unit/test_utils.py
+19Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
# along with this program. If not, see <http://www.gnu.org/licenses/>.
1717

1818
import json
19+
import warnings
1920

2021
from gitlab import utils
2122

@@ -76,3 +77,21 @@ def test_json_serializable(self):
7677

7778
obj = utils.EncodedId("we got/a/path")
7879
assert '"we%20got%2Fa%2Fpath"' == json.dumps(obj)
80+
81+
82+
class TestWarningsWrapper:
83+
def test_warn(self):
84+
warn_message = "short and stout"
85+
warn_source = "teapot"
86+
87+
with warnings.catch_warnings(record=True) as caught_warnings:
88+
utils.warn(message=warn_message, category=UserWarning, source=warn_source)
89+
assert len(caught_warnings) == 1
90+
warning = caught_warnings[0]
91+
# File name is this file as it is the first file outside of the `gitlab/` path.
92+
assert __file__ == warning.filename
93+
assert warning.category == UserWarning
94+
assert isinstance(warning.message, UserWarning)
95+
assert warn_message in str(warning.message)
96+
assert __file__ in str(warning.message)
97+
assert warn_source == warning.source

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.