comparison sat/plugins/plugin_misc_file.py @ 4037:524856bd7b19

massive refactoring to switch from camelCase to snake_case: historically, Libervia (SàT before) was using camelCase as allowed by PEP8 when using a pre-PEP8 code, to use the same coding style as in Twisted. However, snake_case is more readable and it's better to follow PEP8 best practices, so it has been decided to move on full snake_case. Because Libervia has a huge codebase, this ended with a ugly mix of camelCase and snake_case. To fix that, this patch does a big refactoring by renaming every function and method (including bridge) that are not coming from Twisted or Wokkel, to use fully snake_case. This is a massive change, and may result in some bugs.
author Goffi <goffi@goffi.org>
date Sat, 08 Apr 2023 13:54:42 +0200
parents 4c3361e2bf55
children 877145b4ba01
comparison
equal deleted inserted replaced
4036:c4464d7ae97b 4037:524856bd7b19
67 File = stream.SatFile 67 File = stream.SatFile
68 68
69 def __init__(self, host): 69 def __init__(self, host):
70 log.info(_("plugin File initialization")) 70 log.info(_("plugin File initialization"))
71 self.host = host 71 self.host = host
72 host.bridge.addMethod( 72 host.bridge.add_method(
73 "fileSend", 73 "file_send",
74 ".plugin", 74 ".plugin",
75 in_sign="ssssss", 75 in_sign="ssssss",
76 out_sign="a{ss}", 76 out_sign="a{ss}",
77 method=self._fileSend, 77 method=self._file_send,
78 async_=True, 78 async_=True,
79 ) 79 )
80 self._file_managers = [] 80 self._file_managers = []
81 host.importMenu( 81 host.import_menu(
82 (D_("Action"), D_("send file")), 82 (D_("Action"), D_("send file")),
83 self._fileSendMenu, 83 self._file_send_menu,
84 security_limit=10, 84 security_limit=10,
85 help_string=D_("Send a file"), 85 help_string=D_("Send a file"),
86 type_=C.MENU_SINGLE, 86 type_=C.MENU_SINGLE,
87 ) 87 )
88 88
89 def _fileSend( 89 def _file_send(
90 self, 90 self,
91 peer_jid_s: str, 91 peer_jid_s: str,
92 filepath: str, 92 filepath: str,
93 name: str, 93 name: str,
94 file_desc: str, 94 file_desc: str,
95 extra_s: str, 95 extra_s: str,
96 profile: str = C.PROF_KEY_NONE 96 profile: str = C.PROF_KEY_NONE
97 ) -> defer.Deferred: 97 ) -> defer.Deferred:
98 client = self.host.getClient(profile) 98 client = self.host.get_client(profile)
99 return defer.ensureDeferred(self.fileSend( 99 return defer.ensureDeferred(self.file_send(
100 client, jid.JID(peer_jid_s), filepath, name or None, file_desc or None, 100 client, jid.JID(peer_jid_s), filepath, name or None, file_desc or None,
101 data_format.deserialise(extra_s) 101 data_format.deserialise(extra_s)
102 )) 102 ))
103 103
104 async def fileSend( 104 async def file_send(
105 self, client, peer_jid, filepath, filename=None, file_desc=None, extra=None 105 self, client, peer_jid, filepath, filename=None, file_desc=None, extra=None
106 ): 106 ):
107 """Send a file using best available method 107 """Send a file using best available method
108 108
109 @param peer_jid(jid.JID): jid of the destinee 109 @param peer_jid(jid.JID): jid of the destinee
117 if not os.path.isfile(filepath): 117 if not os.path.isfile(filepath):
118 raise exceptions.DataError("The given path doesn't link to a file") 118 raise exceptions.DataError("The given path doesn't link to a file")
119 if not filename: 119 if not filename:
120 filename = os.path.basename(filepath) or "_" 120 filename = os.path.basename(filepath) or "_"
121 for manager, priority in self._file_managers: 121 for manager, priority in self._file_managers:
122 if await utils.asDeferred(manager.canHandleFileSend, 122 if await utils.as_deferred(manager.can_handle_file_send,
123 client, peer_jid, filepath): 123 client, peer_jid, filepath):
124 try: 124 try:
125 method_name = manager.name 125 method_name = manager.name
126 except AttributeError: 126 except AttributeError:
127 method_name = manager.__class__.__name__ 127 method_name = manager.__class__.__name__
129 _("{name} method will be used to send the file").format( 129 _("{name} method will be used to send the file").format(
130 name=method_name 130 name=method_name
131 ) 131 )
132 ) 132 )
133 try: 133 try:
134 progress_id = await utils.asDeferred( 134 progress_id = await utils.as_deferred(
135 manager.fileSend, client, peer_jid, filepath, filename, file_desc, 135 manager.file_send, client, peer_jid, filepath, filename, file_desc,
136 extra 136 extra
137 ) 137 )
138 except Exception as e: 138 except Exception as e:
139 log.warning( 139 log.warning(
140 _("Can't send {filepath} to {peer_jid} with {method_name}: " 140 _("Can't send {filepath} to {peer_jid} with {method_name}: "
153 "xmlui": xml_tools.note( 153 "xmlui": xml_tools.note(
154 "Can't transfer file", msg, C.XMLUI_DATA_LVL_WARNING 154 "Can't transfer file", msg, C.XMLUI_DATA_LVL_WARNING
155 ).toXml() 155 ).toXml()
156 } 156 }
157 157
158 def _onFileChoosed(self, peer_jid, data, profile): 158 def _on_file_choosed(self, peer_jid, data, profile):
159 client = self.host.getClient(profile) 159 client = self.host.get_client(profile)
160 cancelled = C.bool(data.get("cancelled", C.BOOL_FALSE)) 160 cancelled = C.bool(data.get("cancelled", C.BOOL_FALSE))
161 if cancelled: 161 if cancelled:
162 return 162 return
163 path = data["path"] 163 path = data["path"]
164 return self.fileSend(client, peer_jid, path) 164 return self.file_send(client, peer_jid, path)
165 165
166 def _fileSendMenu(self, data, profile): 166 def _file_send_menu(self, data, profile):
167 """ XMLUI activated by menu: return file sending UI 167 """ XMLUI activated by menu: return file sending UI
168 168
169 @param profile: %(doc_profile)s 169 @param profile: %(doc_profile)s
170 """ 170 """
171 try: 171 try:
172 jid_ = jid.JID(data["jid"]) 172 jid_ = jid.JID(data["jid"])
173 except RuntimeError: 173 except RuntimeError:
174 raise exceptions.DataError(_("Invalid JID")) 174 raise exceptions.DataError(_("Invalid JID"))
175 175
176 file_choosed_id = self.host.registerCallback( 176 file_choosed_id = self.host.register_callback(
177 partial(self._onFileChoosed, jid_), 177 partial(self._on_file_choosed, jid_),
178 with_data=True, 178 with_data=True,
179 one_shot=True, 179 one_shot=True,
180 ) 180 )
181 xml_ui = xml_tools.XMLUI( 181 xml_ui = xml_tools.XMLUI(
182 C.XMLUI_DIALOG, 182 C.XMLUI_DIALOG,
191 return {"xmlui": xml_ui.toXml()} 191 return {"xmlui": xml_ui.toXml()}
192 192
193 def register(self, manager, priority: int = 0) -> None: 193 def register(self, manager, priority: int = 0) -> None:
194 """Register a fileSending manager 194 """Register a fileSending manager
195 195
196 @param manager: object implementing canHandleFileSend, and fileSend methods 196 @param manager: object implementing can_handle_file_send, and file_send methods
197 @param priority: pririoty of this manager, the higher available will be used 197 @param priority: pririoty of this manager, the higher available will be used
198 """ 198 """
199 m_data = (manager, priority) 199 m_data = (manager, priority)
200 if m_data in self._file_managers: 200 if m_data in self._file_managers:
201 raise exceptions.ConflictError( 201 raise exceptions.ConflictError(
202 f"Manager {manager} is already registered" 202 f"Manager {manager} is already registered"
203 ) 203 )
204 if not hasattr(manager, "canHandleFileSend") or not hasattr(manager, "fileSend"): 204 if not hasattr(manager, "can_handle_file_send") or not hasattr(manager, "file_send"):
205 raise ValueError( 205 raise ValueError(
206 f'{manager} must have both "canHandleFileSend" and "fileSend" methods to ' 206 f'{manager} must have both "can_handle_file_send" and "file_send" methods to '
207 'be registered') 207 'be registered')
208 self._file_managers.append(m_data) 208 self._file_managers.append(m_data)
209 self._file_managers.sort(key=lambda m: m[1], reverse=True) 209 self._file_managers.sort(key=lambda m: m[1], reverse=True)
210 210
211 def unregister(self, manager): 211 def unregister(self, manager):
217 del self._file_managers[idx] 217 del self._file_managers[idx]
218 218
219 # Dialogs with user 219 # Dialogs with user
220 # the overwrite check is done here 220 # the overwrite check is done here
221 221
222 def openFileWrite(self, client, file_path, transfer_data, file_data, stream_object): 222 def open_file_write(self, client, file_path, transfer_data, file_data, stream_object):
223 """create SatFile or FileStremaObject for the requested file and fill suitable data 223 """create SatFile or FileStremaObject for the requested file and fill suitable data
224 """ 224 """
225 if stream_object: 225 if stream_object:
226 assert "stream_object" not in transfer_data 226 assert "stream_object" not in transfer_data
227 transfer_data["stream_object"] = stream.FileStreamObject( 227 transfer_data["stream_object"] = stream.FileStreamObject(
243 uid=file_data[PROGRESS_ID_KEY], 243 uid=file_data[PROGRESS_ID_KEY],
244 size=file_data["size"], 244 size=file_data["size"],
245 data_cb=file_data.get("data_cb"), 245 data_cb=file_data.get("data_cb"),
246 ) 246 )
247 247
248 async def _gotConfirmation( 248 async def _got_confirmation(
249 self, client, data, peer_jid, transfer_data, file_data, stream_object 249 self, client, data, peer_jid, transfer_data, file_data, stream_object
250 ): 250 ):
251 """Called when the permission and dest path have been received 251 """Called when the permission and dest path have been received
252 252
253 @param peer_jid(jid.JID): jid of the file sender 253 @param peer_jid(jid.JID): jid of the file sender
254 @param transfer_data(dict): same as for [self.getDestDir] 254 @param transfer_data(dict): same as for [self.get_dest_dir]
255 @param file_data(dict): same as for [self.getDestDir] 255 @param file_data(dict): same as for [self.get_dest_dir]
256 @param stream_object(bool): same as for [self.getDestDir] 256 @param stream_object(bool): same as for [self.get_dest_dir]
257 return (bool): True if copy is wanted and OK 257 return (bool): True if copy is wanted and OK
258 False if user wants to cancel 258 False if user wants to cancel
259 if file exists ask confirmation and call again self._getDestDir if needed 259 if file exists ask confirmation and call again self._getDestDir if needed
260 """ 260 """
261 if data.get("cancelled", False): 261 if data.get("cancelled", False):
264 file_data["file_path"] = file_path = os.path.join(path, file_data["name"]) 264 file_data["file_path"] = file_path = os.path.join(path, file_data["name"])
265 log.debug("destination file path set to {}".format(file_path)) 265 log.debug("destination file path set to {}".format(file_path))
266 266
267 # we manage case where file already exists 267 # we manage case where file already exists
268 if os.path.exists(file_path): 268 if os.path.exists(file_path):
269 overwrite = await xml_tools.deferConfirm( 269 overwrite = await xml_tools.defer_confirm(
270 self.host, 270 self.host,
271 _(CONFIRM_OVERWRITE).format(file_path), 271 _(CONFIRM_OVERWRITE).format(file_path),
272 _(CONFIRM_OVERWRITE_TITLE), 272 _(CONFIRM_OVERWRITE_TITLE),
273 action_extra={ 273 action_extra={
274 "meta_from_jid": peer_jid.full(), 274 "meta_from_jid": peer_jid.full(),
278 security_limit=SECURITY_LIMIT, 278 security_limit=SECURITY_LIMIT,
279 profile=client.profile, 279 profile=client.profile,
280 ) 280 )
281 281
282 if not overwrite: 282 if not overwrite:
283 return await self.getDestDir(client, peer_jid, transfer_data, file_data) 283 return await self.get_dest_dir(client, peer_jid, transfer_data, file_data)
284 284
285 self.openFileWrite(client, file_path, transfer_data, file_data, stream_object) 285 self.open_file_write(client, file_path, transfer_data, file_data, stream_object)
286 return True 286 return True
287 287
288 async def getDestDir( 288 async def get_dest_dir(
289 self, client, peer_jid, transfer_data, file_data, stream_object=False 289 self, client, peer_jid, transfer_data, file_data, stream_object=False
290 ): 290 ):
291 """Request confirmation and destination dir to user 291 """Request confirmation and destination dir to user
292 292
293 Overwrite confirmation is managed. 293 Overwrite confirmation is managed.
294 if transfer is confirmed, 'file_obj' is added to transfer_data 294 if transfer is confirmed, 'file_obj' is added to transfer_data
295 @param peer_jid(jid.JID): jid of the file sender 295 @param peer_jid(jid.JID): jid of the file sender
296 @param filename(unicode): name of the file 296 @param filename(unicode): name of the file
297 @param transfer_data(dict): data of the transfer session, 297 @param transfer_data(dict): data of the transfer session,
298 it will be only used to store the file_obj. 298 it will be only used to store the file_obj.
299 "file_obj" (or "stream_object") key *MUST NOT* exist before using getDestDir 299 "file_obj" (or "stream_object") key *MUST NOT* exist before using get_dest_dir
300 @param file_data(dict): information about the file to be transfered 300 @param file_data(dict): information about the file to be transfered
301 It MUST contain the following keys: 301 It MUST contain the following keys:
302 - peer_jid (jid.JID): other peer jid 302 - peer_jid (jid.JID): other peer jid
303 - name (unicode): name of the file to trasnsfer 303 - name (unicode): name of the file to trasnsfer
304 the name must not be empty or contain a "/" character 304 the name must not be empty or contain a "/" character
312 "size_human" will also be added with human readable file size 312 "size_human" will also be added with human readable file size
313 @param stream_object(bool): if True, a stream_object will be used instead of file_obj 313 @param stream_object(bool): if True, a stream_object will be used instead of file_obj
314 a stream.FileStreamObject will be used 314 a stream.FileStreamObject will be used
315 return: True if transfer is accepted 315 return: True if transfer is accepted
316 """ 316 """
317 cont, ret_value = await self.host.trigger.asyncReturnPoint( 317 cont, ret_value = await self.host.trigger.async_return_point(
318 "FILE_getDestDir", client, peer_jid, transfer_data, file_data, stream_object 318 "FILE_getDestDir", client, peer_jid, transfer_data, file_data, stream_object
319 ) 319 )
320 if not cont: 320 if not cont:
321 return ret_value 321 return ret_value
322 filename = file_data["name"] 322 filename = file_data["name"]
323 assert filename and not "/" in filename 323 assert filename and not "/" in filename
324 assert PROGRESS_ID_KEY in file_data 324 assert PROGRESS_ID_KEY in file_data
325 # human readable size 325 # human readable size
326 file_data["size_human"] = common_utils.getHumanSize(file_data["size"]) 326 file_data["size_human"] = common_utils.get_human_size(file_data["size"])
327 resp_data = await xml_tools.deferDialog( 327 resp_data = await xml_tools.defer_dialog(
328 self.host, 328 self.host,
329 _(CONFIRM).format(peer=peer_jid.full(), **file_data), 329 _(CONFIRM).format(peer=peer_jid.full(), **file_data),
330 _(CONFIRM_TITLE), 330 _(CONFIRM_TITLE),
331 type_=C.XMLUI_DIALOG_FILE, 331 type_=C.XMLUI_DIALOG_FILE,
332 options={C.XMLUI_DATA_FILETYPE: C.XMLUI_DATA_FILETYPE_DIR}, 332 options={C.XMLUI_DATA_FILETYPE: C.XMLUI_DATA_FILETYPE_DIR},
337 }, 337 },
338 security_limit=SECURITY_LIMIT, 338 security_limit=SECURITY_LIMIT,
339 profile=client.profile, 339 profile=client.profile,
340 ) 340 )
341 341
342 accepted = await self._gotConfirmation( 342 accepted = await self._got_confirmation(
343 client, 343 client,
344 resp_data, 344 resp_data,
345 peer_jid, 345 peer_jid,
346 transfer_data, 346 transfer_data,
347 file_data, 347 file_data,