[Docs] Add spellchecking with pyenchant

- Use sphinxcontrib.spelling with custom wordlist.
- Skip the checking of the modules documents as they raise
false-positives.
- Add a setup.py spellcheck_docs command.
- Fix spelling and other issues.
- Add a doc favicon.
This commit is contained in:
Calum Lind 2019-06-15 19:44:33 +01:00
commit 8b62e50eb8
28 changed files with 191 additions and 134 deletions

View file

@ -53,6 +53,8 @@ addons:
- python3.6 - python3.6
# Intall python3-venv to provide ensurepip module for tox. # Intall python3-venv to provide ensurepip module for tox.
- python3-venv - python3-venv
# Spellchecking
- enchant
# Install dependencies # Install dependencies
install: install:

View file

@ -31,13 +31,13 @@
### Core ### Core
- Fix Python 2 compatiblity issue with SimpleNamespace. - Fix Python 2 compatibility issue with SimpleNamespace.
## 2.0.1 (2019-06-07) ## 2.0.1 (2019-06-07)
### Packaging ### Packaging
- Fix setup.py build error without git installed. - Fix `setup.py` build error without git installed.
## 2.0.0 (2019-06-06) ## 2.0.0 (2019-06-06)
@ -55,16 +55,16 @@
there to allow acting upon them. there to allow acting upon them.
- Updated SSL/TLS Protocol parameters for better security. - Updated SSL/TLS Protocol parameters for better security.
- Make the distinction between adding to the session new unmanaged torrents - Make the distinction between adding to the session new unmanaged torrents
and torrents loaded from state. This will break backwards compatability. and torrents loaded from state. This will break backwards compatibility.
- Pass a copy of an event instead of passing the event arguments to the - Pass a copy of an event instead of passing the event arguments to the
event handlers. This will break backwards compatability. event handlers. This will break backwards compatibility.
- Allow changing ownership of torrents. - Allow changing ownership of torrents.
- File modifications on the auth file are now detected and when they happen, - File modifications on the auth file are now detected and when they happen,
the file is reloaded. Upon finding an old auth file with an old format, an the file is reloaded. Upon finding an old auth file with an old format, an
upgrade to the new format is made, file saved, and reloaded. upgrade to the new format is made, file saved, and reloaded.
- Authentication no longer requires a username/password. If one or both of - Authentication no longer requires a username/password. If one or both of
these is missing, an authentication error will be sent to the client these is missing, an authentication error will be sent to the client
which sould then ask the username/password to the user. which should then ask the username/password to the user.
- Implemented sequential downloads. - Implemented sequential downloads.
- Provide information about a torrent's pieces states - Provide information about a torrent's pieces states
- Add Option To Specify Outgoing Connection Interface. - Add Option To Specify Outgoing Connection Interface.
@ -77,13 +77,13 @@
- Host entries in the Connection Manager UI are now editable. - Host entries in the Connection Manager UI are now editable.
- Implemented sequential downloads UI handling. - Implemented sequential downloads UI handling.
- Add optional pieces bar instead of a regular progress bar in torrent status tab. - Add optional pieces bar instead of a regular progress bar in torrent status tab.
- Make torrent opening compatible with all unicode paths. - Make torrent opening compatible with all Unicode paths.
- Fix magnet association button on Windows. - Fix magnet association button on Windows.
- Add keyboard shortcuts for changing queue position: - Add keyboard shortcuts for changing queue position:
- Up: Ctrl+Alt+Up - Up: `Ctrl+Alt+Up`
- Down: Ctrl+Alt+Down - Down: `Ctrl+Alt+Down`
- Top: Ctrl+Alt+Shift+Up - Top: `Ctrl+Alt+Shift+Up`
- Bottom: Ctrl+Alt+Shift+Down - Bottom: `Ctrl+Alt+Shift+Down`
### Web UI ### Web UI
@ -93,7 +93,7 @@
### Blocklist Plugin ### Blocklist Plugin
- Implemented whitelist support to both core and GTK UI. - Implemented whitelist support to both core and GTK UI.
- Implemented ip filter cleaning before each update. Restarting the deluge - Implemented IP filter cleaning before each update. Restarting the deluge
daemon is no longer needed. daemon is no longer needed.
- If "check_after_days" is 0(zero), the timer is not started anymore. It - If "check_after_days" is 0(zero), the timer is not started anymore. It
would keep updating one call after the other. If the value changed, the would keep updating one call after the other. If the value changed, the

View file

@ -373,9 +373,9 @@ def show_file(path, timestamp=None):
def open_url_in_browser(url): def open_url_in_browser(url):
""" """
Opens a url in the desktop's default browser Opens a URL in the desktop's default browser
:param url: the url to open :param url: the URL to open
:type url: string :type url: string
""" """
@ -695,7 +695,7 @@ def is_url(url):
""" """
A simple test to check if the URL is valid A simple test to check if the URL is valid
:param url: the url to test :param url: the URL to test
:type url: string :type url: string
:returns: True or False :returns: True or False
:rtype: bool :rtype: bool
@ -731,9 +731,9 @@ TR_PARAM = 'tr='
def is_magnet(uri): def is_magnet(uri):
""" """
A check to determine if a uri is a valid bittorrent magnet uri A check to determine if a URI is a valid bittorrent magnet URI
:param uri: the uri to check :param uri: the URI to check
:type uri: string :type uri: string
:returns: True or False :returns: True or False
:rtype: bool :rtype: bool
@ -819,7 +819,7 @@ def get_magnet_info(uri):
def create_magnet_uri(infohash, name=None, trackers=None): def create_magnet_uri(infohash, name=None, trackers=None):
"""Creates a magnet uri """Creates a magnet URI
Args: Args:
infohash (str): The info-hash of the torrent. infohash (str): The info-hash of the torrent.
@ -827,7 +827,7 @@ def create_magnet_uri(infohash, name=None, trackers=None):
trackers (list or dict, optional): A list of trackers or dict or {tracker: tier} pairs. trackers (list or dict, optional): A list of trackers or dict or {tracker: tier} pairs.
Returns: Returns:
str: A magnet uri string. str: A magnet URI string.
""" """
try: try:
@ -1175,7 +1175,7 @@ def create_localclient_account(append=False):
def get_localhost_auth(): def get_localhost_auth():
"""Grabs the localclient auth line from the 'auth' file and creates a localhost uri. """Grabs the localclient auth line from the 'auth' file and creates a localhost URI.
Returns: Returns:
tuple: With the username and password to login as. tuple: With the username and password to login as.

View file

@ -405,7 +405,7 @@ class Core(component.Component):
# Exported Methods # Exported Methods
@export @export
def add_torrent_file_async(self, filename, filedump, options, save_state=True): def add_torrent_file_async(self, filename, filedump, options, save_state=True):
"""Adds a torrent file to the session asynchonously. """Adds a torrent file to the session asynchronously.
Args: Args:
filename (str): The filename of the torrent. filename (str): The filename of the torrent.
@ -442,8 +442,8 @@ class Core(component.Component):
Used by UIs to get magnet files for selection before adding to session. Used by UIs to get magnet files for selection before adding to session.
Args: Args:
magnet (str): The magnet uri. magnet (str): The magnet URI.
timeout (int): Number of seconds to wait before cancelling request. timeout (int): Number of seconds to wait before canceling request.
Returns: Returns:
Deferred: A tuple of (torrent_id (str), metadata (dict)) for the magnet. Deferred: A tuple of (torrent_id (str), metadata (dict)) for the magnet.
@ -488,10 +488,11 @@ class Core(component.Component):
@export @export
def add_torrent_files(self, torrent_files): def add_torrent_files(self, torrent_files):
"""Adds multiple torrent files to the session asynchonously. """Adds multiple torrent files to the session asynchronously.
Args: Args:
torrent_files (list of tuples): Torrent files as tuple of (filename, filedump, options). torrent_files (list of tuples): Torrent files as tuple of
``(filename, filedump, options)``.
Returns: Returns:
Deferred Deferred
@ -517,10 +518,10 @@ class Core(component.Component):
@export @export
def add_torrent_url(self, url, options, headers=None): def add_torrent_url(self, url, options, headers=None):
""" """
Adds a torrent from a url. Deluge will attempt to fetch the torrent Adds a torrent from a URL. Deluge will attempt to fetch the torrent
from url prior to adding it to the session. from the URL prior to adding it to the session.
:param url: the url pointing to the torrent file :param url: the URL pointing to the torrent file
:type url: string :type url: string
:param options: the options to apply to the torrent on add :param options: the options to apply to the torrent on add
:type options: dict :type options: dict
@ -529,7 +530,7 @@ class Core(component.Component):
: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) log.info('Attempting to add URL %s', url)
def on_download_success(filename): def on_download_success(filename):
# We got the file, so add it to the session # We got the file, so add it to the session
@ -543,7 +544,7 @@ class Core(component.Component):
def on_download_fail(failure): def on_download_fail(failure):
# Log the error and pass the failure onto the client # Log the error and pass the failure onto the client
log.error('Failed to add torrent from url %s', url) log.error('Failed to add torrent from URL %s', url)
return failure return failure
tmp_fd, tmp_file = tempfile.mkstemp(prefix='deluge_url.', suffix='.torrent') tmp_fd, tmp_file = tempfile.mkstemp(prefix='deluge_url.', suffix='.torrent')
@ -566,7 +567,7 @@ class Core(component.Component):
:rtype: string :rtype: string
""" """
log.debug('Attempting to add by magnet uri: %s', uri) log.debug('Attempting to add by magnet URI: %s', uri)
return self.torrentmanager.add(magnet=uri, options=options) return self.torrentmanager.add(magnet=uri, options=options)
@ -894,7 +895,8 @@ class Core(component.Component):
Args: Args:
torrent_ids (list): A list of torrent_ids to set the options for. 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. 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']): if 'owner' in options and not self.authmanager.has_account(options['owner']):
raise DelugeError('Username "%s" is not known.' % options['owner']) raise DelugeError('Username "%s" is not known.' % options['owner'])
@ -907,7 +909,7 @@ class Core(component.Component):
@export @export
def set_torrent_trackers(self, torrent_id, trackers): def set_torrent_trackers(self, torrent_id, trackers):
"""Sets a torrents tracker list. trackers will be [{"url", "tier"}]""" """Sets a torrents tracker list. trackers will be ``[{"url", "tier"}]``"""
return self.torrentmanager[torrent_id].set_trackers(trackers) return self.torrentmanager[torrent_id].set_trackers(trackers)
@deprecated @deprecated
@ -985,7 +987,7 @@ class Core(component.Component):
@export @export
def get_path_size(self, path): def get_path_size(self, path):
"""Returns the size of the file or folder 'path' and -1 if the path is """Returns the size of the file or folder 'path' and -1 if the path is
unaccessible (non-existent or insufficient privs)""" inaccessible (non-existent or insufficient privileges)"""
return deluge.common.get_path_size(path) return deluge.common.get_path_size(path)
@export @export
@ -1058,8 +1060,8 @@ class Core(component.Component):
def upload_plugin(self, filename, filedump): def upload_plugin(self, filename, filedump):
"""This method is used to upload new plugins to the daemon. It is used """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 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, the client side. ``plugin_data`` is a ``xmlrpc.Binary`` object of the file data,
ie, plugin_file.read()""" i.e. ``plugin_file.read()``"""
try: try:
filedump = b64decode(filedump) filedump = b64decode(filedump)
@ -1075,14 +1077,14 @@ class Core(component.Component):
@export @export
def rescan_plugins(self): def rescan_plugins(self):
""" """
Rescans the plugin folders for new plugins Re-scans the plugin folders for new plugins
""" """
component.get('CorePluginManager').scan_for_plugins() component.get('CorePluginManager').scan_for_plugins()
@export @export
def rename_files(self, torrent_id, filenames): def rename_files(self, torrent_id, filenames):
""" """
Rename files in torrent_id. Since this is an asynchronous operation by Rename files in ``torrent_id``. Since this is an asynchronous operation by
libtorrent, watch for the TorrentFileRenamedEvent to know when the libtorrent, watch for the TorrentFileRenamedEvent to know when the
files have been renamed. files have been renamed.
@ -1258,7 +1260,7 @@ class Core(component.Component):
@export @export
def get_external_ip(self): def get_external_ip(self):
""" """
Returns the external ip address recieved from libtorrent. Returns the external IP address received from libtorrent.
""" """
return self.external_ip return self.external_ip

View file

@ -206,12 +206,12 @@ class Torrent(object):
options (dict): The torrent options. options (dict): The torrent options.
state (TorrentState): The torrent state. state (TorrentState): The torrent state.
filename (str): The filename of the torrent file. filename (str): The filename of the torrent file.
magnet (str): The magnet uri. magnet (str): The magnet URI.
Attributes: Attributes:
torrent_id (str): The torrent_id for this torrent torrent_id (str): The torrent_id for this torrent
handle: Holds the libtorrent torrent handle handle: Holds the libtorrent torrent handle
magnet (str): The magnet uri used to add this torrent (if available). magnet (str): The magnet URI used to add this torrent (if available).
status: Holds status info so that we don"t need to keep getting it from libtorrent. status: Holds status info so that we don"t need to keep getting it from libtorrent.
torrent_info: store the torrent info. torrent_info: store the torrent info.
has_metadata (bool): True if the metadata for the torrent is available, False otherwise. has_metadata (bool): True if the metadata for the torrent is available, False otherwise.
@ -913,7 +913,7 @@ class Torrent(object):
return '' return ''
def get_magnet_uri(self): def get_magnet_uri(self):
"""Returns a magnet uri for this torrent""" """Returns a magnet URI for this torrent"""
return lt.make_magnet_uri(self.handle) return lt.make_magnet_uri(self.handle)
def get_name(self): def get_name(self):

View file

@ -340,11 +340,11 @@ class TorrentManager(component.Component):
return torrent_info return torrent_info
def prefetch_metadata(self, magnet, timeout): def prefetch_metadata(self, magnet, timeout):
"""Download the metadata for a magnet uri. """Download the metadata for a magnet URI.
Args: Args:
magnet (str): A magnet uri to download the metadata for. magnet (str): A magnet URI to download the metadata for.
timeout (int): Number of seconds to wait before cancelling. timeout (int): Number of seconds to wait before canceling.
Returns: Returns:
Deferred: A tuple of (torrent_id (str), metadata (dict)) Deferred: A tuple of (torrent_id (str), metadata (dict))
@ -509,7 +509,7 @@ class TorrentManager(component.Component):
save_state (bool, optional): If True save the session state after adding torrent, defaults to True. save_state (bool, optional): If True save the session state after adding torrent, defaults to True.
filedump (str, optional): bencoded filedump of a torrent file. filedump (str, optional): bencoded filedump of a torrent file.
filename (str, optional): The filename of the torrent file. filename (str, optional): The filename of the torrent file.
magnet (str, optional): The magnet uri. magnet (str, optional): The magnet URI.
resume_data (lt.entry, optional): libtorrent fast resume data. resume_data (lt.entry, optional): libtorrent fast resume data.
Returns: Returns:
@ -574,7 +574,7 @@ class TorrentManager(component.Component):
save_state (bool, optional): If True save the session state after adding torrent, defaults to True. save_state (bool, optional): If True save the session state after adding torrent, defaults to True.
filedump (str, optional): bencoded filedump of a torrent file. filedump (str, optional): bencoded filedump of a torrent file.
filename (str, optional): The filename of the torrent file. filename (str, optional): The filename of the torrent file.
magnet (str, optional): The magnet uri. magnet (str, optional): The magnet URI.
resume_data (lt.entry, optional): libtorrent fast resume data. resume_data (lt.entry, optional): libtorrent fast resume data.
Returns: Returns:

View file

@ -81,7 +81,7 @@ class Command(BaseCommand):
continue continue
if deluge.common.is_url(torrent): if deluge.common.is_url(torrent):
self.console.write( self.console.write(
'{!info!}Attempting to add torrent from url: %s' % torrent '{!info!}Attempting to add torrent from URL: %s' % torrent
) )
deferreds.append( deferreds.append(
client.core.add_torrent_url(torrent, t_options) client.core.add_torrent_url(torrent, t_options)
@ -90,7 +90,7 @@ class Command(BaseCommand):
) )
elif deluge.common.is_magnet(torrent): elif deluge.common.is_magnet(torrent):
self.console.write( self.console.write(
'{!info!}Attempting to add torrent from magnet uri: %s' % torrent '{!info!}Attempting to add torrent from magnet URI: %s' % torrent
) )
deferreds.append( deferreds.append(
client.core.add_torrent_magnet(torrent, t_options) client.core.add_torrent_magnet(torrent, t_options)

View file

@ -301,7 +301,7 @@ class AddTorrentDialog(component.Component):
self.builder.get_object('prefetch_hbox').hide() self.builder.get_object('prefetch_hbox').hide()
def add_from_magnets(self, uris): def add_from_magnets(self, uris):
"""Add a list of magnet uris to torrent_liststore.""" """Add a list of magnet URIs to torrent_liststore."""
already_added = 0 already_added = 0
for uri in uris: for uri in uris:
@ -853,11 +853,11 @@ class AddTorrentDialog(component.Component):
log.debug('Create torrent tracker lines: %s', trackers_text) log.debug('Create torrent tracker lines: %s', trackers_text)
trackers = list(trackers_tiers_from_text(trackers_text).keys()) trackers = list(trackers_tiers_from_text(trackers_text).keys())
# Convert the information to a magnet uri, this is just easier to # Convert the information to a magnet URI, this is just easier to
# handle this way. # handle this way.
log.debug('trackers: %s', trackers) log.debug('trackers: %s', trackers)
magnet = create_magnet_uri(infohash, infohash, trackers) magnet = create_magnet_uri(infohash, infohash, trackers)
log.debug('magnet uri: %s', magnet) log.debug('magnet URI: %s', magnet)
self.add_from_magnets([magnet]) self.add_from_magnets([magnet])
entry.set_text('') entry.set_text('')

View file

@ -267,7 +267,7 @@ def associate_magnet_links(overwrite=False):
from gi.repository import GConf from gi.repository import GConf
except ValueError: except ValueError:
log.debug( log.debug(
'gconf not available, so will not attempt to register magnet uri handler' 'gconf not available, so will not attempt to register magnet URI handler'
) )
return False return False
else: else:
@ -282,11 +282,11 @@ def associate_magnet_links(overwrite=False):
gconf_client.set_bool( gconf_client.set_bool(
'/desktop/gnome/url-handlers/magnet/enabled', True '/desktop/gnome/url-handlers/magnet/enabled', True
) )
log.info('Deluge registered as default magnet uri handler!') log.info('Deluge registered as default magnet URI handler!')
return True return True
else: else:
log.error( log.error(
'Unable to register Deluge as default magnet uri handler.' 'Unable to register Deluge as default magnet URI handler.'
) )
return False return False
return False return False

View file

@ -472,7 +472,7 @@ class WebApi(JSONComponent):
The current connection state. The current connection state.
:returns: True if the client is connected :returns: True if the client is connected
:rtype: booleon :rtype: boolean
""" """
return client.connected() return client.connected()
@ -498,7 +498,7 @@ class WebApi(JSONComponent):
:type keys: list :type keys: list
:param filter_dict: the filters to apply when selecting torrents. :param filter_dict: the filters to apply when selecting torrents.
:type filter_dict: dictionary :type filter_dict: dictionary
:returns: The torrent and ui information. :returns: The torrent and UI information.
:rtype: dictionary :rtype: dictionary
""" """
d = Deferred() d = Deferred()
@ -659,9 +659,9 @@ class WebApi(JSONComponent):
@export @export
def download_torrent_from_url(self, url, cookie=None): def download_torrent_from_url(self, url, cookie=None):
""" """
Download a torrent file from a url to a temporary directory. Download a torrent file from a URL to a temporary directory.
:param url: the url of the torrent :param url: the URL of the torrent
:type url: string :type url: string
:returns: the temporary file name of the torrent file :returns: the temporary file name of the torrent file
:rtype: string :rtype: string
@ -829,7 +829,7 @@ class WebApi(JSONComponent):
password (str): The password to login to the daemon with. password (str): The password to login to the daemon with.
Returns: Returns:
bool: True if succesful, False otherwise. bool: True if successful, False otherwise.
""" """
return self.hostlist.update_host(host_id, host, port, username, password) return self.hostlist.update_host(host_id, host, port, username, password)
@ -842,7 +842,7 @@ class WebApi(JSONComponent):
host_id (str): The host identifying hash. host_id (str): The host identifying hash.
Returns: Returns:
bool: True if succesful, False otherwise. bool: True if successful, False otherwise.
""" """
return self.hostlist.remove_host(host_id) return self.hostlist.remove_host(host_id)
@ -1002,7 +1002,7 @@ class WebApi(JSONComponent):
class WebUtils(JSONComponent): class WebUtils(JSONComponent):
""" """
Utility functions for the webui that do not fit in the WebApi. Utility functions for the Web UI that do not fit in the WebApi.
""" """
def __init__(self): def __init__(self):
@ -1014,6 +1014,6 @@ class WebUtils(JSONComponent):
Get the available translated languages Get the available translated languages
Returns: Returns:
list: of tuples [(lang-id, language-name), ...] list: of tuples ``[(lang-id, language-name), ...]``
""" """
return get_languages() return get_languages()

View file

@ -1,3 +1,4 @@
sphinx==2.0.* sphinx==2.0.*
recommonmark==0.4.* recommonmark==0.4.*
sphinx_rtd_theme sphinx_rtd_theme
sphinxcontrib-spelling

View file

@ -49,6 +49,7 @@ extensions = [
'sphinx.ext.doctest', 'sphinx.ext.doctest',
'sphinx.ext.napoleon', 'sphinx.ext.napoleon',
'sphinx.ext.coverage', 'sphinx.ext.coverage',
'sphinxcontrib.spelling',
] ]
napoleon_include_init_with_doc = True napoleon_include_init_with_doc = True
@ -85,8 +86,7 @@ today_fmt = '%B %d, %Y'
# List of directories, relative to source directories, that shouldn't be searched # List of directories, relative to source directories, that shouldn't be searched
# for source files. # for source files.
# exclude_dirs = [] exclude_patterns = []
# exclude_patterns = []
# The reST default role (used for this markup: `text`) to use for all documents. # The reST default role (used for this markup: `text`) to use for all documents.
# default_role = None # default_role = None
@ -106,6 +106,14 @@ today_fmt = '%B %d, %Y'
pygments_style = 'sphinx' pygments_style = 'sphinx'
# Options for spelling
# --------------------
spelling_show_suggestions = True
spelling_word_list_filename = '../spelling_wordlist.txt'
# Skip Deluge module rst files
if 'spelling' in sys.argv or 'spellcheck_docs' in sys.argv:
exclude_patterns += ['modules']
# Options for HTML output # Options for HTML output
# ----------------------- # -----------------------
html_theme = 'sphinx_rtd_theme' html_theme = 'sphinx_rtd_theme'
@ -132,7 +140,7 @@ html_css_files = [
# The name of an image file (within the static path) to use as favicon of the # The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large. # pixels large.
# html_favicon = None html_favicon = '../../deluge/ui/data/pixmaps/deluge.ico'
# Add any paths that contain custom static files (such as style sheets) here, # Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files, # relative to this directory. They are copied after the builtin static files,

View file

@ -5,13 +5,13 @@
- A [new ticket](http://dev.deluge-torrent.org/newticket) is required for bugs - A [new ticket](http://dev.deluge-torrent.org/newticket) is required for bugs
or features. Search the ticket system first, to avoid filing a duplicate. or features. Search the ticket system first, to avoid filing a duplicate.
- Ensure code follows the [syntax and conventions](#syntax-and-conventions). - Ensure code follows the [syntax and conventions](#syntax-and-conventions).
- Code must pass tests. See [testing.md] for - Code must pass tests. See [testing](testing.md) document for
information on how to run and write unit tests. information on how to run and write unit tests.
- Commit messages are informative. - Commit messages are informative.
## Pull request process: ## Pull request process:
- Fork us on [github](https://github.com/deluge-torrent/deluge). - Fork us on [GitHub](https://github.com/deluge-torrent/deluge).
- Clone your repository. - Clone your repository.
- Create a feature branch for your issue. - Create a feature branch for your issue.
- Apply your changes: - Apply your changes:
@ -19,16 +19,16 @@
- Run the tests until they pass. - Run the tests until they pass.
- When you feel you are finished, rebase your commits to ensure a simple - When you feel you are finished, rebase your commits to ensure a simple
and informative commit log. and informative commit log.
- Create a pull request on github from your forked repository. - Create a pull request on GitHub from your forked repository.
- Verify that the tests run by [Travis-ci](https://travis-ci.org/deluge-torrent/deluge) - Verify that the tests run by [Travis-ci](https://travis-ci.org/deluge-torrent/deluge)
are passing. are passing.
## Syntax and conventions ## Syntax and conventions
### Code formatters ### Code formatting
We use two applications to automatically format the code to save development We use two applications to automatically format the code to save development
time. They are both run with pre-commit. time. They are both run with [pre-commit].
#### Black #### Black
@ -36,7 +36,7 @@ time. They are both run with pre-commit.
#### Prettier #### Prettier
- Javascript - JavaScript
- CSS - CSS
- YAML - YAML
- Markdown - Markdown
@ -51,32 +51,32 @@ time. They are both run with pre-commit.
We follow [PEP8](http://www.python.org/dev/peps/pep-0008/) and We follow [PEP8](http://www.python.org/dev/peps/pep-0008/) and
[Python Code Style](http://docs.python-guide.org/en/latest/writing/style/) [Python Code Style](http://docs.python-guide.org/en/latest/writing/style/)
which is adhered to with Black formatter. which is adhered to with [Black].
- Code '''must''' pass [flake8](https://pypi.python.org/pypi/flake8) (w/[https://pypi.python.org/pypi/flake8-quotes flake8-quotes]), [https://pypi.python.org/pypi/isort isort] and [http://www.pylint.org/ Pylint] source code checkers. - Code '''must''' pass [Black], [flake8] and [isort] source code checkers.
(Optionally [Pylint])
flake8 deluge flake8 deluge
isort -rc -df deluge isort -rc -df deluge
pylint deluge pylint deluge
pylint deluge/plugins/\*/deluge/ pylint deluge/plugins/\*/deluge/
- Using the [http://pre-commit.com/ pre-commit] app can aid in picking up - Using the [pre-commit] app can aid in identifying issues while creating git commits.
issues before creating git commits.
#### Strings and bytes #### Strings and bytes
To prevent bugs or errors in the code byte strings (`str`) must be decoded to To prevent bugs or errors in the code byte strings (`str`) must be decoded to
strings (unicode strings, `unicode`) on input and then encoded on output. strings (Unicode text strings, `unicode`) on input and then encoded on output.
_Notes:_ _Notes:_
- PyGTK/GTK+ will accept `str` (utf8 encoded) or `unicode` but will only return - PyGTK/GTK+ will accept `str` (UTF-8 encoded) or `unicode` but will only return
`str`. See [http://python-gtk-3-tutorial.readthedocs.org/en/latest/unicode.html GTK+ Unicode] docs. `str`. See [GTK3 Unicode] docs.
- There is a `bytearray` type which enables in-place modification of a string. - There is a `bytearray` type which enables in-place modification of a string.
See [Python Bytearrays](http://stackoverflow.com/a/9099337/175584) See [Python Bytearrays](http://stackoverflow.com/a/9099337/175584)
- Python 3 renames `unicode` to `str` type and byte strings become `bytes` type. - Python 3 renames `unicode` to `str` type and byte strings become `bytes` type.
### Javascript ### JavaScript
- Classes should follow the Ext coding style. - Classes should follow the Ext coding style.
- Class names should be in !CamelCase - Class names should be in !CamelCase
@ -108,8 +108,16 @@ Google Style example:
""" """
return return
See complete list of [http://www.sphinx-doc.org/en/master/usage/extensions/napoleon.html#docstring-sections supported headers]. See complete list of [supported headers][napoleon sections].
Verify that the documentation parses correctly with: Verify that the documentation parses correctly with:
python setup.py build_docs python setup.py build_docs
[pre-commit]: http://pre-commit.com/
[flake8]: https://pypi.python.org/pypi/flake8
[isort]: https://pypi.python.org/pypi/isort
[pylint]: http://www.pylint.org/
[black]: https://github.com/python/black/
[gtk3 unicode]: http://python-gtk-3-tutorial.readthedocs.org/en/latest/unicode.html
[napoleon sections]: http://www.sphinx-doc.org/en/master/usage/extensions/napoleon.html#docstring-sections

View file

@ -36,7 +36,7 @@ Running the tests for a specific plugin (requires [pytest](https://pypi.python.o
## Tox ## Tox
All the tests for Deluge can be run using [tox](https://pypi.python.org/pypi/tox) All the tests for Deluge can be run using [Tox](https://pypi.python.org/pypi/tox)
#### See available targets: #### See available targets:
@ -54,10 +54,10 @@ All the tests for Deluge can be run using [tox](https://pypi.python.org/pypi/tox
tox -e lint tox -e lint
## Travis-ci ## Travis CI
Deluge develop branch is tested automatically by [Travis]. Deluge develop branch is tested automatically by [Travis].
When creating a pull request (PR) on [github], Travis will be automatically run When creating a pull request (PR) on [GitHub], Travis will be automatically run
the unit tests with the code in the PR. the unit tests with the code in the PR.
[travis]: https://travis-ci.org/deluge-torrent/deluge [travis]: https://travis-ci.org/deluge-torrent/deluge

View file

@ -16,7 +16,7 @@ For GTK the text can also be marked translatable in the `glade/*.ui` files:
<property name="label" translatable="yes">Max Upload Speed:</property> <property name="label" translatable="yes">Max Upload Speed:</property>
For more details see: [http://docs.python.org/library/gettext.html Python Gettext] For more details see: [Python Gettext]
## Translation process ## Translation process
@ -40,8 +40,8 @@ To enable WebUI to use translations update `gettext.js` by running `gen_gettext.
## Useful applications ## Useful applications
- [podiff](http://puszcza.gnu.org.ua/projects/podiff/) - Compare textual information in two PO files - [podiff](http://puszcza.gnu.org.ua/projects/podiff/) - Compare textual information in two PO files
- [gtranslator](http://projects.gnome.org/gtranslator/) - GUI po file editor - [gtranslator](http://projects.gnome.org/gtranslator/) - GUI PO file editor
- [Poedit](http://www.poedit.net/) - GUI po file editor - [Poedit](http://www.poedit.net/) - GUI PO file editor
## Testing translation ## Testing translation
@ -63,3 +63,4 @@ will only translate based on the `MO` files for Deluge so some GTK
text/button strings will remain in English. text/button strings will remain in English.
[launchpad translations]: https://translations.launchpad.net/deluge/ [launchpad translations]: https://translations.launchpad.net/deluge/
[python gettext]: http://docs.python.org/library/gettext.html

View file

@ -1,8 +1,8 @@
# How to connect to JSON-RPC with curl # How to connect to JSON-RPC with curl
Before continuing make sure deluge-web or webui plugin is running. Before continuing make sure `deluge-web` or Web UI plugin is running.
## Create a curl config ## Create a curl configuration file
To save a lot of typing and to keep the curl command short we shall create To save a lot of typing and to keep the curl command short we shall create
a `curl.cfg` files and put the following contents in it: a `curl.cfg` files and put the following contents in it:
@ -16,7 +16,7 @@ a `curl.cfg` files and put the following contents in it:
url = "http://localhost:8112/json" url = "http://localhost:8112/json"
write-out = "\n" write-out = "\n"
To pretty-print the JSON result see: https://stackoverflow.com/q/352098/175584 To pretty-print the JSON result see: <https://stackoverflow.com/q/352098/175584>
## Login to Web UI ## Login to Web UI
@ -43,7 +43,7 @@ Check the contents of the cookie file to verify session ID created.
## Check connected to deluged ## Check connected to deluged
Use the `web.connected` method to get a boolean response if the webui is Use the `web.connected` method to get a boolean response if the Web UI is
connected to a deluged host: connected to a deluged host:
curl -d '{"method": "web.connected", "params": [], "id": 1}' -K curl.cfg curl -d '{"method": "web.connected", "params": [], "id": 1}' -K curl.cfg
@ -101,7 +101,7 @@ To connect to deluged with `<hostID>`:
curl -d '{"method": "web.connect", \ curl -d '{"method": "web.connect", \
"params": ["<hostID>"], "id": 1}' -K curl.cfg "params": ["<hostID>"], "id": 1}' -K curl.cfg
The result contains the full list of avaiable host methods: The result contains the full list of available host methods:
{ {
"error": null, "error": null,
@ -148,7 +148,7 @@ A successful result:
{"error": null, "result": null, "id": 1} {"error": null, "result": null, "id": 1}
## Useful curl config options ## Useful curl configuration options
For full list of options see man page `man curl` or help `curl --help`: For full list of options see man page `man curl` or help `curl --help`:

View file

@ -27,7 +27,7 @@ Use [six] to assist with compatibility.
### Unicode literals ### Unicode literals
Add the following to files to ensure strings and bytes separatation so there Add the following to files to ensure strings and bytes separation so there
are no surprises when running on Python 3. are no surprises when running on Python 3.
from __future__ import unicode_literals from __future__ import unicode_literals
@ -49,7 +49,7 @@ GtkBuilder `.ui` files and the Python code updated.
See the official [Migrating to GtkBuilder][migrate-gtkbuilder] document for more details. See the official [Migrating to GtkBuilder][migrate-gtkbuilder] document for more details.
#### gtk-builder-convert #### GtkBuilder conversion script
Install the `gtk-builder-convert` converter on Ubuntu with: Install the `gtk-builder-convert` converter on Ubuntu with:
@ -103,7 +103,7 @@ If you open and save the file it will update with the new requirement header:
<requires lib="gtk+" version="3.10"/> <requires lib="gtk+" version="3.10"/>
You can fix deprecated widgets but keep the minimum GTK version to <= 3.10 for You can fix deprecated widgets but keep the minimum GTK version to <= 3.10 for
desktop compatiblity. desktop compatibility.
An example of migrating a Deluge plugin to GtkBuilder: [AutoAdd GtkBuilder] An example of migrating a Deluge plugin to GtkBuilder: [AutoAdd GtkBuilder]
@ -111,7 +111,7 @@ An example of migrating a Deluge plugin to GtkBuilder: [AutoAdd GtkBuilder]
Move from PyGTK to GTK3 using Python bindings. Move from PyGTK to GTK3 using Python bindings.
https://pygobject.readthedocs.io/en/latest/guide/porting.html <https://pygobject.readthedocs.io/en/latest/guide/porting.html>
wget https://gitlab.gnome.org/GNOME/pygobject/raw/master/tools/pygi-convert.sh wget https://gitlab.gnome.org/GNOME/pygobject/raw/master/tools/pygi-convert.sh
cp gtkui.py gtk3ui.py cp gtkui.py gtk3ui.py

View file

@ -1,15 +1,15 @@
# Launchpad recipe # Launchpad recipe
The launchpad build recipes are for build from source automatically to provide The launchpad build recipes are for build from source automatically to provide
ubuntu packages. They are used to create daily builds of a git repo branch. Ubuntu packages. They are used to create daily builds of a Deluge git branch.
Note these don't have the same control as a creating a publishing to PPA. Note these don't have the same control as a creating a publishing to PPA.
Main reference: https://help.launchpad.net/Packaging/SourceBuilds/Recipes Main reference: <https://help.launchpad.net/Packaging/SourceBuilds/Recipes>
## Deluge launchpad build recipes ## Deluge Launchpad build recipes
Recipe configuration: https://code.launchpad.net/~deluge-team/+recipes Recipe configuration: <https://code.launchpad.net/~deluge-team/+recipes>
An example for building the develop branch: An example for building the develop branch:

View file

@ -1,6 +1,6 @@
# Release Checklist # Release Checklist
## Pre-Release ## Pre-release
- Update [translation] `po` files from [Launchpad] account. - Update [translation] `po` files from [Launchpad] account.
- Changelog is updated with relevant commits and release date is added. - Changelog is updated with relevant commits and release date is added.
@ -30,9 +30,9 @@
- Change release version in `version` files. - Change release version in `version` files.
- Run `trigger-deluge` to sync OSUOSL ftp site. - Run `trigger-deluge` to sync OSUOSL ftp site.
- Create packages (Ubuntu, Windows, OSX). - Create packages (Ubuntu, Windows, OSX).
- Ubuntu: https://code.launchpad.net/~deluge-team/+recipe/stable-releases - Ubuntu: <https://code.launchpad.net/~deluge-team/+recipe/stable-releases>
## Post-Release ## Post-release
- Update with version, hashes and release notes: - Update with version, hashes and release notes:
- Publish docs on [ReadTheDocs]. - Publish docs on [ReadTheDocs].

View file

@ -1,11 +1,11 @@
# How to set Deluge as default torrent application # How to set Deluge as default torrent application
## Check registered mime types ## Check registered MIME types
gio mime application/x-bittorrent gio mime application/x-bittorrent
gio mime x-scheme-handler/magnet gio mime x-scheme-handler/magnet
## Set Deluge as default mime ## Set Deluge as default for MIME types
gio mime x-scheme-handler/magnet deluge.desktop gio mime x-scheme-handler/magnet deluge.desktop
gio mime application/x-bittorrent deluge.desktop gio mime application/x-bittorrent deluge.desktop
@ -21,4 +21,4 @@ xdg-mime query default x-scheme-handler/magnet
## References ## References
https://help.gnome.org/admin/system-admin-guide/stable/mime-types-custom-user.html.en <https://help.gnome.org/admin/system-admin-guide/stable/mime-types-custom-user.html.en>

View file

@ -24,14 +24,14 @@ Install with pip:
## <i class="fa fa-windows"></i> Windows ## <i class="fa fa-windows"></i> Windows
Unfortuately due to move to GTK3 and Python 3 there is no installer package currently Unfortunately due to move to GTK3 and Python 3 there is no installer package currently
available for Windows. available for Windows.
Intrepid users can install Deluge from seperate packages as detailed in [issue #3201]. Intrepid users can install Deluge from separate packages as detailed in [issue #3201].
## <i class="fa fa-apple"></i> macOS ## <i class="fa fa-apple"></i> macOS
There is no `.app` package currently for macOS, but can try Deluge with homebrew. There is no `.app` package currently for macOS, but can try Deluge with [Homebrew].
1. Install [Homebrew] 1. Install [Homebrew]
2. Open a terminal. 2. Open a terminal.

View file

@ -5,8 +5,8 @@ Message Formats
--------------- ---------------
DelugeRPC is a protocol used for daemon/client communication. There are four DelugeRPC is a protocol used for daemon/client communication. There are four
types of messages involved in the protocol: RPC Request, RPC Response, types of messages involved in the protocol: RPC Request, RPC Response,
RPC Error and Event. All messages are zlib compressed rencoded strings and RPC Error and Event. All messages are zlib compressed with rencode encoded strings
their data formats are detailed below. and their data formats are detailed below.
""""""""""" """""""""""
RPC Request RPC Request

View file

@ -30,8 +30,8 @@ There are two ways to enable SSL encryption in the webserver:
## Enable Development mode ## Enable Development mode
Add `?dev=true` to the webui url to enable development mode, uses the source js files Append `?dev=true` to the Web UI URL to enable development mode, uses the source
(if available) rather than compressed versions: JavaScript files (if available) rather than compressed versions:
http://127.0.0.1:8112/?dev=true http://127.0.0.1:8112/?dev=true

View file

@ -26,7 +26,7 @@ Some of the highlights since the last major release.
As well as the usual source tarball available for [download] we now have published As well as the usual source tarball available for [download] we now have published
Deluge on the PyPi software repository. Deluge on the PyPi software repository.
- https://pypi.org/project/deluge/ - <https://pypi.org/project/deluge/>
### Windows and MacOS ### Windows and MacOS

View file

@ -0,0 +1,28 @@
Changelog
tooltip
Gtk
libglade
Wayland
macOS
codebase
unmanaged
rebase
formatter
camelCase
docstring
docstrings
Pytest
Tox
pre
Blocklist
boolean
daemonizes
daemonize
config
Trac
runtime
codec
auth
hostlist
hostname
filesystem

View file

@ -7,6 +7,11 @@ build-dir = docs/build
all_files = true all_files = true
fresh-env = true fresh-env = true
[spellcheck_docs]
source-dir = docs/source
build-dir = docs/build
builder = spelling
[py2app] [py2app]
app = ['deluge/ui/ui_entry.py'] app = ['deluge/ui/ui_entry.py']
arch = x86_64 arch = x86_64

View file

@ -443,6 +443,7 @@ cmdclass = {
'build_trans': BuildTranslations, 'build_trans': BuildTranslations,
'build_plugins': BuildPlugins, 'build_plugins': BuildPlugins,
'build_docs': BuildDoc, 'build_docs': BuildDoc,
'spellcheck_docs': BuildDoc,
'install_data': InstallData, 'install_data': InstallData,
'clean_plugins': CleanPlugins, 'clean_plugins': CleanPlugins,
'clean_trans': CleanTranslations, 'clean_trans': CleanTranslations,

View file

@ -152,7 +152,8 @@ sitepackages = False
deps = {[basedocs]deps} deps = {[basedocs]deps}
commands = commands =
python setup.py clean_docs python setup.py clean_docs
sphinx-build -v -j auto -E -T -b html -d docs/build/doctrees docs/source docs/build/html sphinx-build -v -j auto -E -b html -d docs/build/doctrees docs/source docs/build/html
sphinx-build -v -j auto -b spelling -d docs/build/doctrees docs/source docs/build/spelling
[testenv:docscoverage] [testenv:docscoverage]
sitepackages = False sitepackages = False