diff --git a/deluge/core/core.py b/deluge/core/core.py index 1e5774ff1..1090b0f2a 100644 --- a/deluge/core/core.py +++ b/deluge/core/core.py @@ -14,7 +14,6 @@ import shutil import tempfile import threading from base64 import b64decode, b64encode -from typing import Any, Dict, List, Optional, Tuple, Union from urllib.request import URLError, urlopen from twisted.internet import defer, reactor, task @@ -241,12 +240,13 @@ class Core(component.Component): """Apply libtorrent session settings. Args: - settings: A dict of lt session settings to apply. + settings (dict): A dict of lt session settings to apply. + """ self.session.apply_settings(settings) @staticmethod - def _create_peer_id(version: str) -> str: + def _create_peer_id(version): """Create a peer_id fingerprint. This creates the peer_id and modifies the release char to identify @@ -261,10 +261,11 @@ class Core(component.Component): ``--DE201b--`` (beta pre-release of v2.0.1) Args: - version: The version string in PEP440 dotted notation. + version (str): The version string in PEP440 dotted notation. Returns: - The formatted peer_id with Deluge prefix e.g. '--DE200s--' + str: The formatted peer_id with Deluge prefix e.g. '--DE200s--' + """ split = deluge.common.VersionSplit(version) # Fill list with zeros to length of 4 and use lt to create fingerprint. @@ -313,11 +314,12 @@ class Core(component.Component): log.info('Restoring backup of %s from: %s', filename, filepath_bak) shutil.move(filepath_bak, filepath) - def _load_session_state(self) -> dict: + def _load_session_state(self): """Loads the libtorrent session state Returns: - A libtorrent sesion state, empty dict if unable to load it. + dict: A libtorrent sesion state, empty dict if unable to load it. + """ filename = 'session.state' filepath = get_config_dir(filename) @@ -399,19 +401,18 @@ class Core(component.Component): # Exported Methods @export - def add_torrent_file_async( - self, filename: str, filedump: str, options: dict, save_state: bool = True - ) -> defer.Deferred[Optional[str]]: + def add_torrent_file_async(self, filename, filedump, options, save_state=True): """Adds a torrent file to the session asynchronously. Args: - filename: The filename of the torrent. - filedump: A base64 encoded string of torrent file contents. - options: The options to apply to the torrent upon adding. - save_state: If the state should be saved after adding the file. + filename (str): The filename of the torrent. + filedump (str): A base64 encoded string of torrent file contents. + options (dict): The options to apply to the torrent upon adding. + save_state (bool): If the state should be saved after adding the file. Returns: - The torrent ID or None. + Deferred: The torrent ID or None. + """ try: filedump = b64decode(filedump) @@ -432,9 +433,7 @@ class Core(component.Component): return d @export - def prefetch_magnet_metadata( - self, magnet: str, timeout: int = 30 - ) -> defer.Deferred[Tuple[str, bytes]]: + def prefetch_magnet_metadata(self, magnet, timeout=30): """Download magnet metadata without adding to Deluge session. Used by UIs to get magnet files for selection before adding to session. @@ -442,11 +441,12 @@ class Core(component.Component): The metadata is bencoded and for transfer base64 encoded. Args: - magnet: The magnet URI. - timeout: Number of seconds to wait before canceling request. + magnet (str): The magnet URI. + timeout (int): Number of seconds to wait before canceling request. Returns: - A tuple of (torrent_id (str), metadata (str)) for the magnet. + Deferred: A tuple of (torrent_id (str), metadata (str)) for the magnet. + """ def on_metadata(result, result_d): @@ -461,18 +461,16 @@ class Core(component.Component): return result_d @export - def add_torrent_file( - self, filename: str, filedump: Union[str, bytes], options: dict - ) -> Optional[str]: + def add_torrent_file(self, filename, filedump, options): """Adds a torrent file to the session. Args: - filename: The filename of the torrent. - filedump: A base64 encoded string of the torrent file contents. - options: The options to apply to the torrent upon adding. + filename (str): The filename of the torrent. + filedump (str): A base64 encoded string of the torrent file contents. + options (dict): The options to apply to the torrent upon adding. Returns: - The torrent_id or None. + str: The torrent_id or None. """ try: filedump = b64decode(filedump) @@ -488,17 +486,16 @@ class Core(component.Component): raise @export - def add_torrent_files( - self, torrent_files: List[Tuple[str, Union[str, bytes], dict]] - ) -> defer.Deferred[List[AddTorrentError]]: + def add_torrent_files(self, torrent_files): """Adds multiple torrent files to the session asynchronously. Args: - torrent_files: Torrent files as tuple of - ``(filename, filedump, options)``. + torrent_files (list of tuples): Torrent files as tuple of + ``(filename, filedump, options)``. Returns: - A list of errors (if there were any) + Deferred + """ @defer.inlineCallbacks @@ -518,19 +515,19 @@ class Core(component.Component): return task.deferLater(reactor, 0, add_torrents) @export - def add_torrent_url( - self, url: str, options: dict, headers: dict = None - ) -> defer.Deferred[Optional[str]]: - """Adds a torrent from a URL. Deluge will attempt to fetch the torrent + def add_torrent_url(self, url, options, headers=None): + """ + Adds a torrent from a URL. Deluge will attempt to fetch the torrent from the URL prior to adding it to the session. - Args: - url: the URL pointing to the torrent file - options: the options to apply to the torrent on add - headers: any optional headers to send + :param url: the URL pointing to the torrent file + :type url: string + :param options: the options to apply to the torrent on add + :type options: dict + :param headers: any optional headers to send + :type headers: dict - Returns: - a Deferred which returns the torrent_id as a str or None + :returns: a Deferred which returns the torrent_id as a str or None """ log.info('Attempting to add URL %s', url) @@ -556,52 +553,55 @@ class Core(component.Component): return d @export - def add_torrent_magnet(self, uri: str, options: dict) -> str: - """Adds a torrent from a magnet link. + def add_torrent_magnet(self, uri, options): + """ + Adds a torrent from a magnet link. - Args: - uri: the magnet link - options: the options to apply to the torrent on add + :param uri: the magnet link + :type uri: string + :param options: the options to apply to the torrent on add + :type options: dict + + :returns: the torrent_id + :rtype: string - Returns: - the torrent_id """ log.debug('Attempting to add by magnet URI: %s', uri) return self.torrentmanager.add(magnet=uri, options=options) @export - def remove_torrent(self, torrent_id: str, remove_data: bool) -> bool: + def remove_torrent(self, torrent_id, remove_data): """Removes a single torrent from the session. Args: - torrent_id: The torrent ID to remove. - remove_data: If True, also remove the downloaded data. + torrent_id (str): The torrent ID to remove. + remove_data (bool): If True, also remove the downloaded data. Returns: - True if removed successfully. + bool: True if removed successfully. Raises: InvalidTorrentError: If the torrent ID does not exist in the session. + """ log.debug('Removing torrent %s from the core.', torrent_id) return self.torrentmanager.remove(torrent_id, remove_data) @export - def remove_torrents( - self, torrent_ids: List[str], remove_data: bool - ) -> defer.Deferred[List[Tuple[str, str]]]: + def remove_torrents(self, torrent_ids, remove_data): """Remove multiple torrents from the session. Args: - torrent_ids: The torrent IDs to remove. - remove_data: If True, also remove the downloaded data. + torrent_ids (list): The torrent IDs to remove. + remove_data (bool): If True, also remove the downloaded data. Returns: - An empty list if no errors occurred otherwise the list contains - tuples of strings, a torrent ID and an error message. For example: + list: An empty list if no errors occurred otherwise the list contains + tuples of strings, a torrent ID and an error message. For example: + + [('', 'Error removing torrent')] - [('', 'Error removing torrent')] """ log.info('Removing %d torrents from core.', len(torrent_ids)) @@ -625,17 +625,17 @@ class Core(component.Component): return task.deferLater(reactor, 0, do_remove_torrents) @export - def get_session_status(self, keys: List[str]) -> Dict[str, Union[int, float]]: + def get_session_status(self, keys): """Gets the session status values for 'keys', these keys are taking from libtorrent's session status. See: http://www.rasterbar.com/products/libtorrent/manual.html#status - Args: - keys: the keys for which we want values + :param keys: the keys for which we want values + :type keys: list + :returns: a dictionary of {key: value, ...} + :rtype: dict - Returns: - a dictionary of {key: value, ...} """ if not keys: return self.session_status @@ -656,13 +656,13 @@ class Core(component.Component): return status @export - def force_reannounce(self, torrent_ids: List[str]) -> None: + def force_reannounce(self, torrent_ids): log.debug('Forcing reannouncment to: %s', torrent_ids) for torrent_id in torrent_ids: self.torrentmanager[torrent_id].force_reannounce() @export - def pause_torrent(self, torrent_id: str) -> None: + def pause_torrent(self, torrent_id): """Pauses a torrent""" log.debug('Pausing: %s', torrent_id) if not isinstance(torrent_id, str): @@ -671,7 +671,7 @@ class Core(component.Component): self.torrentmanager[torrent_id].pause() @export - def pause_torrents(self, torrent_ids: List[str] = None) -> None: + def pause_torrents(self, torrent_ids=None): """Pauses a list of torrents""" if not torrent_ids: torrent_ids = self.torrentmanager.get_torrent_list() @@ -679,27 +679,27 @@ class Core(component.Component): self.pause_torrent(torrent_id) @export - def connect_peer(self, torrent_id: str, ip: str, port: int): + def connect_peer(self, torrent_id, ip, port): log.debug('adding peer %s to %s', ip, torrent_id) if not self.torrentmanager[torrent_id].connect_peer(ip, port): log.warning('Error adding peer %s:%s to %s', ip, port, torrent_id) @export - def move_storage(self, torrent_ids: List[str], dest: str): + def move_storage(self, torrent_ids, dest): log.debug('Moving storage %s to %s', torrent_ids, dest) for torrent_id in torrent_ids: if not self.torrentmanager[torrent_id].move_storage(dest): log.warning('Error moving torrent %s to %s', torrent_id, dest) @export - def pause_session(self) -> None: + def pause_session(self): """Pause the entire session""" if not self.session.is_paused(): self.session.pause() component.get('EventManager').emit(SessionPausedEvent()) @export - def resume_session(self) -> None: + def resume_session(self): """Resume the entire session""" if self.session.is_paused(): self.session.resume() @@ -708,12 +708,12 @@ class Core(component.Component): component.get('EventManager').emit(SessionResumedEvent()) @export - def is_session_paused(self) -> bool: + def is_session_paused(self): """Returns the activity of the session""" return self.session.is_paused() @export - def resume_torrent(self, torrent_id: str) -> None: + def resume_torrent(self, torrent_id): """Resumes a torrent""" log.debug('Resuming: %s', torrent_id) if not isinstance(torrent_id, str): @@ -722,7 +722,7 @@ class Core(component.Component): self.torrentmanager[torrent_id].resume() @export - def resume_torrents(self, torrent_ids: List[str] = None) -> None: + def resume_torrents(self, torrent_ids=None): """Resumes a list of torrents""" if not torrent_ids: torrent_ids = self.torrentmanager.get_torrent_list() @@ -755,9 +755,7 @@ class Core(component.Component): return status @export - def get_torrent_status( - self, torrent_id: str, keys: List[str], diff: bool = False - ) -> dict: + def get_torrent_status(self, torrent_id, keys, diff=False): torrent_keys, plugin_keys = self.torrentmanager.separate_keys( keys, [torrent_id] ) @@ -772,10 +770,10 @@ class Core(component.Component): @export @defer.inlineCallbacks - def get_torrents_status( - self, filter_dict: dict, keys: List[str], diff: bool = False - ) -> dict: - """returns all torrents , optionally filtered by filter_dict.""" + def get_torrents_status(self, filter_dict, keys, diff=False): + """ + returns all torrents , optionally filtered by filter_dict. + """ all_keys = not keys torrent_ids = self.filtermanager.filter_torrent_ids(filter_dict) status_dict, plugin_keys = yield self.torrentmanager.torrents_status_update( @@ -788,37 +786,36 @@ class Core(component.Component): return status_dict @export - def get_filter_tree( - self, show_zero_hits: bool = True, hide_cat: List[str] = None - ) -> Dict: - """returns {field: [(value,count)] } + def get_filter_tree(self, show_zero_hits=True, hide_cat=None): + """ + returns {field: [(value,count)] } for use in sidebar(s) """ return self.filtermanager.get_filter_tree(show_zero_hits, hide_cat) @export - def get_session_state(self) -> List[str]: + def get_session_state(self): """Returns a list of torrent_ids in the session.""" # Get the torrent list from the TorrentManager return self.torrentmanager.get_torrent_list() @export - def get_config(self) -> dict: + def get_config(self): """Get all the preferences as a dictionary""" return self.config.config @export - def get_config_value(self, key: str) -> Any: + def get_config_value(self, key): """Get the config value for key""" return self.config.get(key) @export - def get_config_values(self, keys: List[str]) -> Dict[str, Any]: + def get_config_values(self, keys): """Get the config values for the entered keys""" return {key: self.config.get(key) for key in keys} @export - def set_config(self, config: Dict[str, Any]): + def set_config(self, config): """Set the config with values from dictionary""" # Load all the values into the configuration for key in config: @@ -827,20 +824,21 @@ class Core(component.Component): self.config[key] = config[key] @export - def get_listen_port(self) -> int: + def get_listen_port(self): """Returns the active listen port""" return self.session.listen_port() @export - def get_proxy(self) -> Dict[str, Any]: + def get_proxy(self): """Returns the proxy settings Returns: - Proxy settings. + dict: Contains proxy settings. Notes: Proxy type names: 0: None, 1: Socks4, 2: Socks5, 3: Socks5 w Auth, 4: HTTP, 5: HTTP w Auth, 6: I2P + """ settings = self.session.get_settings() @@ -863,38 +861,36 @@ class Core(component.Component): return proxy_dict @export - def get_available_plugins(self) -> List[str]: + def get_available_plugins(self): """Returns a list of plugins available in the core""" return self.pluginmanager.get_available_plugins() @export - def get_enabled_plugins(self) -> List[str]: + def get_enabled_plugins(self): """Returns a list of enabled plugins in the core""" return self.pluginmanager.get_enabled_plugins() @export - def enable_plugin(self, plugin: str) -> defer.Deferred[bool]: + def enable_plugin(self, plugin): return self.pluginmanager.enable_plugin(plugin) @export - def disable_plugin(self, plugin: str) -> defer.Deferred[bool]: + def disable_plugin(self, plugin): return self.pluginmanager.disable_plugin(plugin) @export - def force_recheck(self, torrent_ids: List[str]) -> None: + def force_recheck(self, torrent_ids): """Forces a data recheck on torrent_ids""" for torrent_id in torrent_ids: self.torrentmanager[torrent_id].force_recheck() @export - def set_torrent_options( - self, torrent_ids: List[str], options: Dict[str, Any] - ) -> None: + def set_torrent_options(self, torrent_ids, options): """Sets the torrent options for torrent_ids Args: - torrent_ids: A list of torrent_ids to set the options for. - options: A dict of torrent options to set. See + torrent_ids (list): A list of torrent_ids to set the options for. + options (dict): A dict of torrent options to set. See ``torrent.TorrentOptions`` class for valid keys. """ if 'owner' in options and not self.authmanager.has_account(options['owner']): @@ -907,14 +903,12 @@ class Core(component.Component): self.torrentmanager[torrent_id].set_options(options) @export - def set_torrent_trackers( - self, torrent_id: str, trackers: List[Dict[str, Any]] - ) -> None: + def set_torrent_trackers(self, torrent_id, trackers): """Sets a torrents tracker list. trackers will be ``[{"url", "tier"}]``""" return self.torrentmanager[torrent_id].set_trackers(trackers) @export - def get_magnet_uri(self, torrent_id: str) -> str: + def get_magnet_uri(self, torrent_id): return self.torrentmanager[torrent_id].get_magnet_uri() @deprecated @@ -1062,7 +1056,7 @@ class Core(component.Component): self.add_torrent_file(os.path.split(target)[1], filedump, options) @export - def upload_plugin(self, filename: str, filedump: Union[str, bytes]) -> None: + def upload_plugin(self, filename, filedump): """This method is used to upload new plugins to the daemon. It is used when connecting to the daemon remotely and installing a new plugin on the client side. ``plugin_data`` is a ``xmlrpc.Binary`` object of the file data, @@ -1080,24 +1074,26 @@ class Core(component.Component): component.get('CorePluginManager').scan_for_plugins() @export - def rescan_plugins(self) -> None: - """Re-scans the plugin folders for new plugins""" + def rescan_plugins(self): + """ + Re-scans the plugin folders for new plugins + """ component.get('CorePluginManager').scan_for_plugins() @export - def rename_files( - self, torrent_id: str, filenames: List[Tuple[int, str]] - ) -> defer.Deferred: - """Rename files in ``torrent_id``. Since this is an asynchronous operation by + def rename_files(self, torrent_id, filenames): + """ + Rename files in ``torrent_id``. Since this is an asynchronous operation by libtorrent, watch for the TorrentFileRenamedEvent to know when the files have been renamed. - Args: - torrent_id: the torrent_id to rename files - filenames: a list of index, filename pairs + :param torrent_id: the torrent_id to rename files + :type torrent_id: string + :param filenames: a list of index, filename pairs + :type filenames: ((index, filename), ...) + + :raises InvalidTorrentError: if torrent_id is invalid - Raises: - InvalidTorrentError: if torrent_id is invalid """ if torrent_id not in self.torrentmanager.torrents: raise InvalidTorrentError('torrent_id is not in session') @@ -1108,20 +1104,21 @@ class Core(component.Component): return task.deferLater(reactor, 0, rename) @export - def rename_folder( - self, torrent_id: str, folder: str, new_folder: str - ) -> defer.Deferred: - """Renames the 'folder' to 'new_folder' in 'torrent_id'. Watch for the + def rename_folder(self, torrent_id, folder, new_folder): + """ + Renames the 'folder' to 'new_folder' in 'torrent_id'. Watch for the TorrentFolderRenamedEvent which is emitted when the folder has been renamed successfully. - Args: - torrent_id: the torrent to rename folder in - folder: the folder to rename - new_folder: the new folder name + :param torrent_id: the torrent to rename folder in + :type torrent_id: string + :param folder: the folder to rename + :type folder: string + :param new_folder: the new folder name + :type new_folder: string + + :raises InvalidTorrentError: if the torrent_id is invalid - Raises: - InvalidTorrentError: if the torrent_id is invalid """ if torrent_id not in self.torrentmanager.torrents: raise InvalidTorrentError('torrent_id is not in session') @@ -1129,7 +1126,7 @@ class Core(component.Component): return self.torrentmanager[torrent_id].rename_folder(folder, new_folder) @export - def queue_top(self, torrent_ids: List[str]) -> None: + def queue_top(self, torrent_ids): log.debug('Attempting to queue %s to top', torrent_ids) # torrent_ids must be sorted in reverse before moving to preserve order for torrent_id in sorted( @@ -1143,7 +1140,7 @@ class Core(component.Component): log.warning('torrent_id: %s does not exist in the queue', torrent_id) @export - def queue_up(self, torrent_ids: List[str]) -> None: + def queue_up(self, torrent_ids): log.debug('Attempting to queue %s to up', torrent_ids) torrents = ( (self.torrentmanager.get_queue_position(torrent_id), torrent_id) @@ -1168,7 +1165,7 @@ class Core(component.Component): prev_queue_position = queue_position @export - def queue_down(self, torrent_ids: List[str]) -> None: + def queue_down(self, torrent_ids): log.debug('Attempting to queue %s to down', torrent_ids) torrents = ( (self.torrentmanager.get_queue_position(torrent_id), torrent_id) @@ -1193,7 +1190,7 @@ class Core(component.Component): prev_queue_position = queue_position @export - def queue_bottom(self, torrent_ids: List[str]) -> None: + def queue_bottom(self, torrent_ids): log.debug('Attempting to queue %s to bottom', torrent_ids) # torrent_ids must be sorted before moving to preserve order for torrent_id in sorted( @@ -1207,15 +1204,17 @@ class Core(component.Component): log.warning('torrent_id: %s does not exist in the queue', torrent_id) @export - def glob(self, path: str) -> List[str]: + def glob(self, path): return glob.glob(path) @export - def test_listen_port(self) -> defer.Deferred[Optional[bool]]: - """Checks if the active port is open + def test_listen_port(self): + """ + Checks if the active port is open + + :returns: True if the port is open, False if not + :rtype: bool - Returns: - True if the port is open, False if not """ port = self.get_listen_port() url = 'https://deluge-torrent.org/test_port.php?port=%s' % port @@ -1234,17 +1233,18 @@ class Core(component.Component): return d @export - def get_free_space(self, path: str = None) -> int: - """Returns the number of free bytes at path + def get_free_space(self, path=None): + """ + Returns the number of free bytes at path - Args: - path: the path to check free space at, if None, use the default download location + :param path: the path to check free space at, if None, use the default download location + :type path: string - Returns: - the number of free bytes at path + :returns: the number of free bytes at path + :rtype: int + + :raises InvalidPathError: if the path is invalid - Raises: - InvalidPathError: if the path is invalid """ if not path: path = self.config['download_location'] @@ -1257,40 +1257,46 @@ class Core(component.Component): self.external_ip = external_ip @export - def get_external_ip(self) -> str: - """Returns the external IP address received from libtorrent.""" + def get_external_ip(self): + """ + Returns the external IP address received from libtorrent. + """ return self.external_ip @export - def get_libtorrent_version(self) -> str: - """Returns the libtorrent version. + def get_libtorrent_version(self): + """ + Returns the libtorrent version. + + :returns: the version + :rtype: string - Returns: - the version """ return LT_VERSION @export - def get_completion_paths(self, args: Dict[str, Any]) -> Dict[str, Any]: - """Returns the available path completions for the input value.""" + def get_completion_paths(self, args): + """ + Returns the available path completions for the input value. + """ return path_chooser_common.get_completion_paths(args) @export(AUTH_LEVEL_ADMIN) - def get_known_accounts(self) -> List[Dict[str, Any]]: + def get_known_accounts(self): return self.authmanager.get_known_accounts() @export(AUTH_LEVEL_NONE) - def get_auth_levels_mappings(self) -> Tuple[Dict[str, int], Dict[int, str]]: + def get_auth_levels_mappings(self): return (AUTH_LEVELS_MAPPING, AUTH_LEVELS_MAPPING_REVERSE) @export(AUTH_LEVEL_ADMIN) - def create_account(self, username: str, password: str, authlevel: str) -> bool: + def create_account(self, username, password, authlevel): return self.authmanager.create_account(username, password, authlevel) @export(AUTH_LEVEL_ADMIN) - def update_account(self, username: str, password: str, authlevel: str) -> bool: + def update_account(self, username, password, authlevel): return self.authmanager.update_account(username, password, authlevel) @export(AUTH_LEVEL_ADMIN) - def remove_account(self, username: str) -> bool: + def remove_account(self, username): return self.authmanager.remove_account(username) diff --git a/deluge/path_chooser_common.py b/deluge/path_chooser_common.py index 0ea92341c..858f7c2da 100644 --- a/deluge/path_chooser_common.py +++ b/deluge/path_chooser_common.py @@ -40,7 +40,7 @@ def get_completion_paths(args): :param args: options :type args: dict :returns: the args argument containing the available completions for the completion_text - :rtype: dict + :rtype: list """ args['paths'] = [] diff --git a/docs/requirements.txt b/docs/requirements.txt index 70739640a..18ef4fe47 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -2,4 +2,3 @@ sphinx==4.* myst-parser sphinx_rtd_theme sphinxcontrib-spelling==7.3.0 -sphinx-autodoc-typehints diff --git a/docs/source/conf.py b/docs/source/conf.py index 9c5853c73..f04653e03 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -48,7 +48,6 @@ extensions = [ 'sphinx.ext.coverage', 'sphinxcontrib.spelling', 'myst_parser', - 'sphinx_autodoc_typehints', ] napoleon_include_init_with_doc = True