Movatterモバイル変換


[0]ホーム

URL:


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

Sign up
Appearance settings

Commit562fbbd

Browse files
authored
Merge pull request#1409 from JohnVillalovos/jlvillal/untyped_defs
chore: mypy: Disallow untyped definitions
2 parentsb563cdc +6aef2da commit562fbbd

File tree

8 files changed

+78
-53
lines changed

8 files changed

+78
-53
lines changed

‎.mypy.ini

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,6 @@ files = gitlab/*.py
44
# disallow_incomplete_defs: This flag reports an error whenever it encounters a
55
# partly annotated function definition.
66
disallow_incomplete_defs = True
7+
# disallow_untyped_defs: This flag reports an error whenever it encounters a
8+
# function without type annotations or with incomplete type annotations.
9+
disallow_untyped_defs = True

‎gitlab/__main__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
importgitlab.cli
22

33

4-
__name__=="__main__"andgitlab.cli.main()
4+
if__name__=="__main__":
5+
gitlab.cli.main()

‎gitlab/base.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
importimportlib
1919
fromtypesimportModuleType
20-
fromtypingimportAny,Dict,NamedTuple,Optional,Tuple,Type
20+
fromtypingimportAny,Dict,Iterable,NamedTuple,Optional,Tuple,Type
2121

2222
from .clientimportGitlab,GitlabList
2323
fromgitlabimporttypesasg_types
@@ -133,8 +133,8 @@ def __ne__(self, other: object) -> bool:
133133
returnself.get_id()!=other.get_id()
134134
returnsuper(RESTObject,self)!=other
135135

136-
def__dir__(self):
137-
returnsuper(RESTObject,self).__dir__()|self.attributes.keys()
136+
def__dir__(self)->Iterable[str]:
137+
returnset(self.attributes).union(super(RESTObject,self).__dir__())
138138

139139
def__hash__(self)->int:
140140
ifnotself.get_id():
@@ -155,7 +155,7 @@ def _update_attrs(self, new_attrs: Dict[str, Any]) -> None:
155155
self.__dict__["_updated_attrs"]= {}
156156
self.__dict__["_attrs"]=new_attrs
157157

158-
defget_id(self):
158+
defget_id(self)->Any:
159159
"""Returns the id of the resource."""
160160
ifself._id_attrisNoneornothasattr(self,self._id_attr):
161161
returnNone
@@ -207,10 +207,10 @@ def __iter__(self) -> "RESTObjectList":
207207
def__len__(self)->int:
208208
returnlen(self._list)
209209

210-
def__next__(self):
210+
def__next__(self)->RESTObject:
211211
returnself.next()
212212

213-
defnext(self):
213+
defnext(self)->RESTObject:
214214
data=self._list.next()
215215
returnself._obj_cls(self.manager,data)
216216

‎gitlab/cli.py

Lines changed: 28 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
importfunctools
2222
importre
2323
importsys
24-
fromtypingimportAny,Callable,Dict,Optional,Tuple,Union
24+
fromtypingimportAny,Callable,cast,Dict,Optional,Tuple,TypeVar,Union
2525

2626
importgitlab.config# noqa: F401
2727

@@ -35,14 +35,21 @@
3535
custom_actions:Dict[str,Dict[str,Tuple[Tuple[str, ...],Tuple[str, ...],bool]]]= {}
3636

3737

38+
# For an explanation of how these type-hints work see:
39+
# https://mypy.readthedocs.io/en/stable/generics.html#declaring-decorators
40+
#
41+
# The goal here is that functions which get decorated will retain their types.
42+
__F=TypeVar("__F",bound=Callable[...,Any])
43+
44+
3845
defregister_custom_action(
3946
cls_names:Union[str,Tuple[str, ...]],
4047
mandatory:Tuple[str, ...]=tuple(),
4148
optional:Tuple[str, ...]=tuple(),
42-
)->Callable:
43-
defwrap(f:Callable)->Callable:
49+
)->Callable[[__F],__F]:
50+
defwrap(f:__F)->__F:
4451
@functools.wraps(f)
45-
defwrapped_f(*args,**kwargs):
52+
defwrapped_f(*args:Any,**kwargs:Any)->Any:
4653
returnf(*args,**kwargs)
4754

4855
# in_obj defines whether the method belongs to the obj or the manager
@@ -63,7 +70,7 @@ def wrapped_f(*args, **kwargs):
6370
action=f.__name__.replace("_","-")
6471
custom_actions[final_name][action]= (mandatory,optional,in_obj)
6572

66-
returnwrapped_f
73+
returncast(__F,wrapped_f)
6774

6875
returnwrap
6976

@@ -135,12 +142,16 @@ def _get_base_parser(add_help: bool = True) -> argparse.ArgumentParser:
135142
returnparser
136143

137144

138-
def_get_parser(cli_module):
145+
def_get_parser()->argparse.ArgumentParser:
146+
# NOTE: We must delay import of gitlab.v4.cli until now or
147+
# otherwise it will cause circular import errors
148+
importgitlab.v4.cli
149+
139150
parser=_get_base_parser()
140-
returncli_module.extend_parser(parser)
151+
returngitlab.v4.cli.extend_parser(parser)
141152

142153

143-
def_parse_value(v):
154+
def_parse_value(v:Any)->Any:
144155
ifisinstance(v,str)andv.startswith("@"):
145156
# If the user-provided value starts with @, we try to read the file
146157
# path provided after @ as the real value. Exit on any error.
@@ -162,18 +173,10 @@ def docs() -> argparse.ArgumentParser:
162173
if"sphinx"notinsys.modules:
163174
sys.exit("Docs parser is only intended for build_sphinx")
164175

165-
# NOTE: We must delay import of gitlab.v4.cli until now or
166-
# otherwise it will cause circular import errors
167-
importgitlab.v4.cli
168-
169-
return_get_parser(gitlab.v4.cli)
170-
176+
return_get_parser()
171177

172-
defmain():
173-
# NOTE: We must delay import of gitlab.v4.cli until now or
174-
# otherwise it will cause circular import errors
175-
importgitlab.v4.cli
176178

179+
defmain()->None:
177180
if"--version"insys.argv:
178181
print(gitlab.__version__)
179182
sys.exit(0)
@@ -183,7 +186,7 @@ def main():
183186
# This first parsing step is used to find the gitlab config to use, and
184187
# load the propermodule (v3 or v4) accordingly. At that point we don't have
185188
# any subparser setup
186-
(options,args)=parser.parse_known_args(sys.argv)
189+
(options,_)=parser.parse_known_args(sys.argv)
187190
try:
188191
config=gitlab.config.GitlabConfigParser(options.gitlab,options.config_file)
189192
exceptgitlab.config.ConfigErrorase:
@@ -196,14 +199,14 @@ def main():
196199
raiseModuleNotFoundError(name="gitlab.v%s.cli"%config.api_version)
197200

198201
# Now we build the entire set of subcommands and do the complete parsing
199-
parser=_get_parser(gitlab.v4.cli)
202+
parser=_get_parser()
200203
try:
201204
importargcomplete# type: ignore
202205

203206
argcomplete.autocomplete(parser)
204207
exceptException:
205208
pass
206-
args=parser.parse_args(sys.argv[1:])
209+
args=parser.parse_args()
207210

208211
config_files=args.config_file
209212
gitlab_id=args.gitlab
@@ -216,7 +219,7 @@ def main():
216219
action=args.whaction
217220
what=args.what
218221

219-
args=args.__dict__
222+
args_dict=vars(args)
220223
# Remove CLI behavior-related args
221224
foritemin (
222225
"gitlab",
@@ -228,8 +231,8 @@ def main():
228231
"version",
229232
"output",
230233
):
231-
args.pop(item)
232-
args= {k:_parse_value(v)fork,vinargs.items()ifvisnotNone}
234+
args_dict.pop(item)
235+
args_dict= {k:_parse_value(v)fork,vinargs_dict.items()ifvisnotNone}
233236

234237
try:
235238
gl=gitlab.Gitlab.from_config(gitlab_id,config_files)
@@ -241,6 +244,4 @@ def main():
241244
ifdebug:
242245
gl.enable_debug()
243246

244-
gitlab.v4.cli.run(gl,what,action,args,verbose,output,fields)
245-
246-
sys.exit(0)
247+
gitlab.v4.cli.run(gl,what,action,args_dict,verbose,output,fields)

‎gitlab/config.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ def __init__(
206206
exceptException:
207207
pass
208208

209-
def_get_values_from_helper(self):
209+
def_get_values_from_helper(self)->None:
210210
"""Update attributes that may get values from an external helper program"""
211211
forattrinHELPER_ATTRIBUTES:
212212
value=getattr(self,attr)

‎gitlab/exceptions.py

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,16 @@
1616
# along with this program. If not, see <http://www.gnu.org/licenses/>.
1717

1818
importfunctools
19+
fromtypingimportAny,Callable,cast,Optional,Type,TypeVar,TYPE_CHECKING,Union
1920

2021

2122
classGitlabError(Exception):
22-
def__init__(self,error_message="",response_code=None,response_body=None):
23+
def__init__(
24+
self,
25+
error_message:Union[str,bytes]="",
26+
response_code:Optional[int]=None,
27+
response_body:Optional[bytes]=None,
28+
)->None:
2329

2430
Exception.__init__(self,error_message)
2531
# Http status code
@@ -30,11 +36,15 @@ def __init__(self, error_message="", response_code=None, response_body=None):
3036
try:
3137
# if we receive str/bytes we try to convert to unicode/str to have
3238
# consistent message types (see #616)
39+
ifTYPE_CHECKING:
40+
assertisinstance(error_message,bytes)
3341
self.error_message=error_message.decode()
3442
exceptException:
43+
ifTYPE_CHECKING:
44+
assertisinstance(error_message,str)
3545
self.error_message=error_message
3646

37-
def__str__(self):
47+
def__str__(self)->str:
3848
ifself.response_codeisnotNone:
3949
return"{0}: {1}".format(self.response_code,self.error_message)
4050
else:
@@ -269,7 +279,14 @@ class GitlabUnfollowError(GitlabOperationError):
269279
pass
270280

271281

272-
defon_http_error(error):
282+
# For an explanation of how these type-hints work see:
283+
# https://mypy.readthedocs.io/en/stable/generics.html#declaring-decorators
284+
#
285+
# The goal here is that functions which get decorated will retain their types.
286+
__F=TypeVar("__F",bound=Callable[...,Any])
287+
288+
289+
defon_http_error(error:Type[Exception])->Callable[[__F],__F]:
273290
"""Manage GitlabHttpError exceptions.
274291
275292
This decorator function can be used to catch GitlabHttpError exceptions
@@ -280,14 +297,14 @@ def on_http_error(error):
280297
GitlabError
281298
"""
282299

283-
defwrap(f):
300+
defwrap(f:__F)->__F:
284301
@functools.wraps(f)
285-
defwrapped_f(*args,**kwargs):
302+
defwrapped_f(*args:Any,**kwargs:Any)->Any:
286303
try:
287304
returnf(*args,**kwargs)
288305
exceptGitlabHttpErrorase:
289306
raiseerror(e.error_message,e.response_code,e.response_body)frome
290307

291-
returnwrapped_f
308+
returncast(__F,wrapped_f)
292309

293310
returnwrap

‎gitlab/tests/test_cli.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
importpytest
2727

2828
fromgitlabimportcli
29-
importgitlab.v4.cli
3029

3130

3231
deftest_what_to_cls():
@@ -94,14 +93,14 @@ def test_base_parser():
9493

9594

9695
deftest_v4_parse_args():
97-
parser=cli._get_parser(gitlab.v4.cli)
96+
parser=cli._get_parser()
9897
args=parser.parse_args(["project","list"])
9998
assertargs.what=="project"
10099
assertargs.whaction=="list"
101100

102101

103102
deftest_v4_parser():
104-
parser=cli._get_parser(gitlab.v4.cli)
103+
parser=cli._get_parser()
105104
subparsers=next(
106105
action
107106
foractioninparser._actions

‎gitlab/types.py

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,46 +15,50 @@
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+
fromtypingimportAny,Optional,TYPE_CHECKING
19+
1820

1921
classGitlabAttribute(object):
20-
def__init__(self,value=None):
22+
def__init__(self,value:Any=None)->None:
2123
self._value=value
2224

23-
defget(self):
25+
defget(self)->Any:
2426
returnself._value
2527

26-
defset_from_cli(self,cli_value):
28+
defset_from_cli(self,cli_value:Any)->None:
2729
self._value=cli_value
2830

29-
defget_for_api(self):
31+
defget_for_api(self)->Any:
3032
returnself._value
3133

3234

3335
classListAttribute(GitlabAttribute):
34-
defset_from_cli(self,cli_value):
36+
defset_from_cli(self,cli_value:str)->None:
3537
ifnotcli_value.strip():
3638
self._value= []
3739
else:
3840
self._value= [item.strip()foritemincli_value.split(",")]
3941

40-
defget_for_api(self):
42+
defget_for_api(self)->str:
4143
# Do not comma-split single value passed as string
4244
ifisinstance(self._value,str):
4345
returnself._value
4446

47+
ifTYPE_CHECKING:
48+
assertisinstance(self._value,list)
4549
return",".join([str(x)forxinself._value])
4650

4751

4852
classLowercaseStringAttribute(GitlabAttribute):
49-
defget_for_api(self):
53+
defget_for_api(self)->str:
5054
returnstr(self._value).lower()
5155

5256

5357
classFileAttribute(GitlabAttribute):
54-
defget_file_name(self,attr_name=None):
58+
defget_file_name(self,attr_name:Optional[str]=None)->Optional[str]:
5559
returnattr_name
5660

5761

5862
classImageAttribute(FileAttribute):
59-
defget_file_name(self,attr_name=None):
63+
defget_file_name(self,attr_name:Optional[str]=None)->str:
6064
return"%s.png"%attr_nameifattr_nameelse"image.png"

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp