Skip to content

Commit 5fc3bae

Browse files
wip: start of a decorator to warn about non-keyword arg usage
1 parent acc5c39 commit 5fc3bae

File tree

1 file changed

+66
-1
lines changed

1 file changed

+66
-1
lines changed

gitlab/utils.py

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,24 @@
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 functools
19+
import inspect
1820
import pathlib
1921
import traceback
2022
import urllib.parse
2123
import warnings
22-
from typing import Any, Callable, Dict, Iterator, Optional, Tuple, Type, Union
24+
from typing import (
25+
Any,
26+
Callable,
27+
Dict,
28+
Iterator,
29+
Optional,
30+
Tuple,
31+
Type,
32+
Union,
33+
TypeVar,
34+
cast,
35+
)
2336

2437
import requests
2538

@@ -163,3 +176,55 @@ def warn(
163176
stacklevel=stacklevel,
164177
source=source,
165178
)
179+
180+
181+
__F = TypeVar("__F", bound=Callable[..., Any])
182+
183+
def non_kwarg_deprecation(*, allowed_args: int) -> Callable[[__F], __F]:
184+
def decorate(function: __F) -> __F:
185+
signature = inspect.signature(function)
186+
187+
@functools.wraps(function)
188+
def wrapper(*args: Any, **kwargs: Any) -> Any:
189+
if len(args) > allowed_args:
190+
message = (
191+
f"Too many non-keyword arguments. Only {allowed_args} non-keyword "
192+
f"argument(s) will be allowed starting in python-gitlab version "
193+
f"4.0.0. Then it will be required to be called using keyword "
194+
f"arguments. For example: "
195+
)
196+
message += f"{function.__name__}("
197+
for index, (arg_name, arg_value) in enumerate(
198+
zip(signature.parameters, args), start=1
199+
):
200+
if index > allowed_args:
201+
message += f"{arg_name}={arg_value!r}, "
202+
else:
203+
message += f"{arg_value!r}, "
204+
message = message[:-2]
205+
message += ")"
206+
# Get `stacklevel` for user code so we indicate where issue is in
207+
# their code.
208+
pg_dir = pathlib.Path(__file__).parent.resolve()
209+
stack = traceback.extract_stack()
210+
stacklevel = 1
211+
warning_from = ""
212+
for stacklevel, frame in enumerate(reversed(stack), start=1):
213+
if stacklevel == 2:
214+
warning_from = (
215+
f" (python-gitlab: {frame.filename}:{frame.lineno})"
216+
)
217+
frame_dir = str(pathlib.Path(frame.filename).parent.resolve())
218+
if not frame_dir.startswith(str(pg_dir)):
219+
break
220+
warnings.warn(
221+
message=message + warning_from,
222+
category=DeprecationWarning,
223+
stacklevel=stacklevel,
224+
)
225+
226+
return function(*args, **kwargs)
227+
228+
return cast(__F, wrapper)
229+
230+
return decorate

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy