11import base64
2+ from typing import Any ,Callable ,cast ,Dict ,List ,Optional ,TYPE_CHECKING
3+
4+ import requests
25
36from gitlab import cli
47from gitlab import exceptions as exc
2225class ProjectFile (SaveMixin ,ObjectDeleteMixin ,RESTObject ):
2326_id_attr = "file_path"
2427_short_print_attr = "file_path"
28+ file_path :str
29+ manager :"ProjectFileManager"
2530
2631def decode (self )-> bytes :
2732"""Returns the decoded content of the file.
@@ -31,7 +36,11 @@ def decode(self) -> bytes:
3136 """
3237return base64 .b64decode (self .content )
3338
34- def save (self ,branch ,commit_message ,** kwargs ):
39+ # NOTE(jlvillal): Signature doesn't match SaveMixin.save() so ignore
40+ # type error
41+ def save (# type: ignore
42+ self ,branch :str ,commit_message :str ,** kwargs :Any
43+ )-> None :
3544"""Save the changes made to the file to the server.
3645
3746 The object is updated to match what the server returns.
@@ -50,7 +59,12 @@ def save(self, branch, commit_message, **kwargs):
5059self .file_path = self .file_path .replace ("/" ,"%2F" )
5160super (ProjectFile ,self ).save (** kwargs )
5261
53- def delete (self ,branch ,commit_message ,** kwargs ):
62+ @exc .on_http_error (exc .GitlabDeleteError )
63+ # NOTE(jlvillal): Signature doesn't match DeleteMixin.delete() so ignore
64+ # type error
65+ def delete (# type: ignore
66+ self ,branch :str ,commit_message :str ,** kwargs :Any
67+ )-> None :
5468"""Delete the file from the server.
5569
5670 Args:
@@ -80,7 +94,11 @@ class ProjectFileManager(GetMixin, CreateMixin, UpdateMixin, DeleteMixin, RESTMa
8094 )
8195
8296@cli .register_custom_action ("ProjectFileManager" , ("file_path" ,"ref" ))
83- def get (self ,file_path ,ref ,** kwargs ):
97+ # NOTE(jlvillal): Signature doesn't match UpdateMixin.update() so ignore
98+ # type error
99+ def get (# type: ignore
100+ self ,file_path :str ,ref :str ,** kwargs :Any
101+ )-> ProjectFile :
84102"""Retrieve a single file.
85103
86104 Args:
@@ -95,15 +113,17 @@ def get(self, file_path, ref, **kwargs):
95113 Returns:
96114 object: The generated RESTObject
97115 """
98- return GetMixin .get (self ,file_path ,ref = ref ,** kwargs )
116+ return cast ( ProjectFile , GetMixin .get (self ,file_path ,ref = ref ,** kwargs ) )
99117
100118@cli .register_custom_action (
101119"ProjectFileManager" ,
102120 ("file_path" ,"branch" ,"content" ,"commit_message" ),
103121 ("encoding" ,"author_email" ,"author_name" ),
104122 )
105123@exc .on_http_error (exc .GitlabCreateError )
106- def create (self ,data ,** kwargs ):
124+ def create (
125+ self ,data :Optional [Dict [str ,Any ]]= None ,** kwargs :Any
126+ )-> ProjectFile :
107127"""Create a new object.
108128
109129 Args:
@@ -120,15 +140,23 @@ def create(self, data, **kwargs):
120140 GitlabCreateError: If the server cannot perform the request
121141 """
122142
143+ if TYPE_CHECKING :
144+ assert data is not None
123145self ._check_missing_create_attrs (data )
124146new_data = data .copy ()
125147file_path = new_data .pop ("file_path" ).replace ("/" ,"%2F" )
126148path = f"{ self .path } /{ file_path } "
127149server_data = self .gitlab .http_post (path ,post_data = new_data ,** kwargs )
150+ if TYPE_CHECKING :
151+ assert isinstance (server_data ,dict )
128152return self ._obj_cls (self ,server_data )
129153
130154@exc .on_http_error (exc .GitlabUpdateError )
131- def update (self ,file_path ,new_data = None ,** kwargs ):
155+ # NOTE(jlvillal): Signature doesn't match UpdateMixin.update() so ignore
156+ # type error
157+ def update (# type: ignore
158+ self ,file_path :str ,new_data :Optional [Dict [str ,Any ]]= None ,** kwargs :Any
159+ )-> Dict [str ,Any ]:
132160"""Update an object on the server.
133161
134162 Args:
@@ -149,13 +177,20 @@ def update(self, file_path, new_data=None, **kwargs):
149177data ["file_path" ]= file_path
150178path = f"{ self .path } /{ file_path } "
151179self ._check_missing_update_attrs (data )
152- return self .gitlab .http_put (path ,post_data = data ,** kwargs )
180+ result = self .gitlab .http_put (path ,post_data = data ,** kwargs )
181+ if TYPE_CHECKING :
182+ assert isinstance (result ,dict )
183+ return result
153184
154185@cli .register_custom_action (
155186"ProjectFileManager" , ("file_path" ,"branch" ,"commit_message" )
156187 )
157188@exc .on_http_error (exc .GitlabDeleteError )
158- def delete (self ,file_path ,branch ,commit_message ,** kwargs ):
189+ # NOTE(jlvillal): Signature doesn't match DeleteMixin.delete() so ignore
190+ # type error
191+ def delete (# type: ignore
192+ self ,file_path :str ,branch :str ,commit_message :str ,** kwargs :Any
193+ )-> None :
159194"""Delete a file on the server.
160195
161196 Args:
@@ -175,8 +210,14 @@ def delete(self, file_path, branch, commit_message, **kwargs):
175210@cli .register_custom_action ("ProjectFileManager" , ("file_path" ,"ref" ))
176211@exc .on_http_error (exc .GitlabGetError )
177212def raw (
178- self ,file_path ,ref ,streamed = False ,action = None ,chunk_size = 1024 ,** kwargs
179- ):
213+ self ,
214+ file_path :str ,
215+ ref :str ,
216+ streamed :bool = False ,
217+ action :Optional [Callable [...,Any ]]= None ,
218+ chunk_size :int = 1024 ,
219+ ** kwargs :Any ,
220+ )-> Optional [bytes ]:
180221"""Return the content of a file for a commit.
181222
182223 Args:
@@ -203,11 +244,13 @@ def raw(
203244result = self .gitlab .http_get (
204245path ,query_data = query_data ,streamed = streamed ,raw = True ,** kwargs
205246 )
247+ if TYPE_CHECKING :
248+ assert isinstance (result ,requests .Response )
206249return utils .response_content (result ,streamed ,action ,chunk_size )
207250
208251@cli .register_custom_action ("ProjectFileManager" , ("file_path" ,"ref" ))
209252@exc .on_http_error (exc .GitlabListError )
210- def blame (self ,file_path ,ref ,** kwargs ) :
253+ def blame (self ,file_path : str ,ref : str ,** kwargs : Any ) -> List [ Dict [ str , Any ]] :
211254"""Return the content of a file for a commit.
212255
213256 Args:
@@ -225,4 +268,7 @@ def blame(self, file_path, ref, **kwargs):
225268file_path = file_path .replace ("/" ,"%2F" ).replace ("." ,"%2E" )
226269path = f"{ self .path } /{ file_path } /blame"
227270query_data = {"ref" :ref }
228- return self .gitlab .http_list (path ,query_data ,** kwargs )
271+ result = self .gitlab .http_list (path ,query_data ,** kwargs )
272+ if TYPE_CHECKING :
273+ assert isinstance (result ,list )
274+ return result