Review fixes
This commit is contained in:
parent
b840b8066b
commit
932e7a9ab9
@ -18,7 +18,6 @@ include tox.ini
|
|||||||
include qutebrowser.py
|
include qutebrowser.py
|
||||||
include misc/cheatsheet.svg
|
include misc/cheatsheet.svg
|
||||||
include qutebrowser/config/configdata.yml
|
include qutebrowser/config/configdata.yml
|
||||||
include qutebrowser/browser/webengine/langs.tsv
|
|
||||||
|
|
||||||
prune www
|
prune www
|
||||||
prune scripts/dev
|
prune scripts/dev
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
# This file is automatically generated by scripts/dev/recompile_requirements.py
|
# This file is automatically generated by scripts/dev/recompile_requirements.py
|
||||||
|
|
||||||
certifi==2017.4.17
|
certifi==2017.7.27.1
|
||||||
chardet==3.0.4
|
chardet==3.0.4
|
||||||
codecov==2.0.9
|
codecov==2.0.9
|
||||||
coverage==4.4.1
|
coverage==4.4.1
|
||||||
idna==2.5
|
idna==2.6
|
||||||
requests==2.18.1
|
requests==2.18.4
|
||||||
urllib3==1.21.1
|
urllib3==1.22
|
||||||
|
@ -1,42 +0,0 @@
|
|||||||
af-ZA Afrikaans (South Africa) af-ZA-3-0.bdic
|
|
||||||
bg-BG Bulgarian (Bulgaria) bg-BG-3-0.bdic
|
|
||||||
ca-ES Catalan (Spain) ca-ES-3-0.bdic
|
|
||||||
cs-CZ Czech (Czech Republic) cs-CZ-3-0.bdic
|
|
||||||
da-DK Danish (Denmark) da-DK-3-0.bdic
|
|
||||||
de-DE German (Germany) de-DE-3-0.bdic
|
|
||||||
el-GR Greek (Greece) el-GR-3-0.bdic
|
|
||||||
en-CA English (Canada) en-CA-7-1.bdic
|
|
||||||
en-GB English (United Kingdom) en-GB-7-1.bdic
|
|
||||||
en-US English (United States) en-US-7-1.bdic
|
|
||||||
es-ES Spanish (Spain) es-ES-3-0.bdic
|
|
||||||
et-EE Estonian (Estonia) et-EE-3-0.bdic
|
|
||||||
fa-IR Farsi (Iran) fa-IR-7-0.bdic
|
|
||||||
fo-FO Faroese (Faroe Islands) fo-FO-3-0.bdic
|
|
||||||
fr-FR French (France) fr-FR-3-0.bdic
|
|
||||||
he-IL Hebrew (Israel) he-IL-3-0.bdic
|
|
||||||
hi-IN Hindi (India) hi-IN-3-0.bdic
|
|
||||||
hr-HR Croatian (Croatia) hr-HR-3-0.bdic
|
|
||||||
hu-HU Hungarian (Hungary) hu-HU-3-0.bdic
|
|
||||||
id-ID Indonesian (Indonesia) id-ID-3-0.bdic
|
|
||||||
it-IT Italian (Italy) it-IT-3-0.bdic
|
|
||||||
ko Korean ko-3-0.bdic
|
|
||||||
lt-LT Lithuanian (Lithuania) lt-LT-3-0.bdic
|
|
||||||
lv-LV Latvian (Latvia) lv-LV-3-0.bdic
|
|
||||||
nb-NO Norwegian (Norway) nb-NO-3-0.bdic
|
|
||||||
nl-NL Dutch (Netherlands) nl-NL-3-0.bdic
|
|
||||||
pl-PL Polish (Poland) pl-PL-3-0.bdic
|
|
||||||
pt-BR Portuguese (Brazil) pt-BR-3-0.bdic
|
|
||||||
pt-PT Portuguese (Portugal) pt-PT-3-0.bdic
|
|
||||||
ro-RO Romanian (Romania) ro-RO-3-0.bdic
|
|
||||||
ru-RU Russian (Russia) ru-RU-3-0.bdic
|
|
||||||
sh Serbo-Croatian sh-3-0.bdic
|
|
||||||
sk-SK Slovak (Slovakia) sk-SK-3-0.bdic
|
|
||||||
sl-SI Slovenian (Slovenia) sl-SI-3-0.bdic
|
|
||||||
sq Albanian sq-3-0.bdic
|
|
||||||
sr Serbian sr-3-0.bdic
|
|
||||||
sv-SE Swedish (Sweden) sv-SE-3-0.bdic
|
|
||||||
ta-IN Tamil (India) ta-IN-3-0.bdic
|
|
||||||
tg-TG Tajik (Tajikistan) tg-TG-5-0.bdic
|
|
||||||
tr-TR Turkish (Turkey) tr-TR-4-0.bdic
|
|
||||||
uk-UA Ukrainian (Ukraine) uk-UA-3-0.bdic
|
|
||||||
vi-VN Vietnamese (Viet Nam) vi-VN-3-0.bdic
|
|
|
@ -19,132 +19,29 @@
|
|||||||
|
|
||||||
"""Installing and configuring spell-checking for QtWebEngine."""
|
"""Installing and configuring spell-checking for QtWebEngine."""
|
||||||
|
|
||||||
|
import glob
|
||||||
import os
|
import os
|
||||||
from urllib.parse import urljoin
|
|
||||||
from urllib.request import urlretrieve
|
|
||||||
|
|
||||||
from PyQt5.QtCore import QLibraryInfo
|
from PyQt5.QtCore import QLibraryInfo
|
||||||
|
|
||||||
repository_url = 'https://redirector.gvt1.com/edgedl/chrome/dict/'
|
|
||||||
|
def dictionary_dir():
|
||||||
|
"""Return the path (str) to the QtWebEngine's dictionaries directory."""
|
||||||
|
datapath = QLibraryInfo.location(QLibraryInfo.DataPath)
|
||||||
|
return os.path.join(datapath, 'qtwebengine_dictionaries')
|
||||||
|
|
||||||
|
|
||||||
class Language:
|
def installed_file(code):
|
||||||
|
"""Return the installed dictionary for the given code.
|
||||||
|
|
||||||
"""Dictionary language specs."""
|
Return the filename of the installed dictionary or None
|
||||||
|
if the dictionary is not installed.
|
||||||
def __init__(self, code, name, file):
|
|
||||||
self.code = code
|
|
||||||
self.name = name
|
|
||||||
self.file = file
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def from_array(lang_array):
|
|
||||||
"""Create Language object from an array.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
lang_array: an array of strings containing
|
|
||||||
the specs of the language in the following format:
|
|
||||||
[code, name, file]
|
|
||||||
"""
|
"""
|
||||||
return Language.from_tuple(tuple(lang_array))
|
pathname = os.path.join(dictionary_dir(), '{}*.bdic'.format(code))
|
||||||
|
print(pathname)
|
||||||
@staticmethod
|
matching_dicts = glob.glob(pathname)
|
||||||
def from_tuple(lang_tuple):
|
if matching_dicts:
|
||||||
"""Create Language object from a tuple.
|
with_extension = os.path.basename(matching_dicts[0])
|
||||||
|
return os.path.splitext(with_extension)[0]
|
||||||
Args:
|
else:
|
||||||
lang_tuple: a tuple of strings containing
|
return None
|
||||||
the specs of the language in the following format:
|
|
||||||
(code, name, file)
|
|
||||||
"""
|
|
||||||
code, name, file = lang_tuple
|
|
||||||
return Language(code, name, file)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def from_tsv_string(tsv_string):
|
|
||||||
"""Create Language object from a string in tab-separated values format.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
tsv_string: a string containing
|
|
||||||
the specs of the language in the following format:
|
|
||||||
"code name file"
|
|
||||||
"""
|
|
||||||
lang_array = tsv_string.split('\t')
|
|
||||||
return Language.from_array(lang_array)
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
return 'Language({}, {}, {})'.format(self.code, self.name, self.file)
|
|
||||||
|
|
||||||
|
|
||||||
def get_dictionary_dir():
|
|
||||||
"""Return the path to the QtWebEngine's dictionaries directory."""
|
|
||||||
return os.path.join(QLibraryInfo.location(QLibraryInfo.DataPath),
|
|
||||||
'qtwebengine_dictionaries')
|
|
||||||
|
|
||||||
|
|
||||||
def get_language_list_file():
|
|
||||||
"""Return the path to the file with the list of all available languages."""
|
|
||||||
package_dir = os.path.dirname(os.path.abspath(__file__))
|
|
||||||
return os.path.join(package_dir, 'langs.tsv')
|
|
||||||
|
|
||||||
|
|
||||||
def get_available_languages():
|
|
||||||
"""Return a list of Language objects of all available languages."""
|
|
||||||
with open(get_language_list_file(), 'r', encoding='UTF-8') as file:
|
|
||||||
return [Language.from_tsv_string(line[:-1]) for line in file]
|
|
||||||
|
|
||||||
|
|
||||||
def get_installed_languages():
|
|
||||||
"""Return a list of Language objects of all installed languages."""
|
|
||||||
if not os.path.isdir(get_dictionary_dir()):
|
|
||||||
return []
|
|
||||||
installed_files = [os.path.basename(file)
|
|
||||||
for file in os.listdir(get_dictionary_dir())]
|
|
||||||
all_languages = get_available_languages()
|
|
||||||
return filter_languages(all_languages, installed_files,
|
|
||||||
by=lambda lang: lang.file,
|
|
||||||
fail_on_unknown=False)
|
|
||||||
|
|
||||||
|
|
||||||
def filter_languages(languages, selected, by=lambda lang: lang.code,
|
|
||||||
fail_on_unknown=True):
|
|
||||||
"""Filter a list of languages based on an inclusion list.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
languages: a list of languages to filter
|
|
||||||
selected: a list of keys to select
|
|
||||||
by: a function returning the selection key (code by default)
|
|
||||||
fail_on_unknown: whether to raise an error if there is an unknown
|
|
||||||
key in selected
|
|
||||||
"""
|
|
||||||
filtered_languages = []
|
|
||||||
for language in languages:
|
|
||||||
if by(language) in selected:
|
|
||||||
filtered_languages.append(language)
|
|
||||||
selected.remove(by(language))
|
|
||||||
if fail_on_unknown and selected:
|
|
||||||
unknown = ', '.join(selected)
|
|
||||||
raise ValueError('unknown languages found: {}'.format(unknown))
|
|
||||||
return filtered_languages
|
|
||||||
|
|
||||||
|
|
||||||
def download_dictionary(url, dest):
|
|
||||||
urlretrieve(url, dest)
|
|
||||||
|
|
||||||
|
|
||||||
def install(languages):
|
|
||||||
"""Install languages."""
|
|
||||||
for lang in languages:
|
|
||||||
try:
|
|
||||||
print('Installing {}: {}'.format(lang.code, lang.name))
|
|
||||||
lang_url = urljoin(repository_url, lang.file)
|
|
||||||
if not os.path.isdir(get_dictionary_dir()):
|
|
||||||
print('WARN: {} does not exist, creating the directory'.format(
|
|
||||||
get_dictionary_dir()))
|
|
||||||
os.makedirs(get_dictionary_dir())
|
|
||||||
print('Downloading {}'.format(lang_url))
|
|
||||||
download_dictionary(lang_url, os.path.join(get_dictionary_dir(),
|
|
||||||
lang.file))
|
|
||||||
print('Done.')
|
|
||||||
except PermissionError as e:
|
|
||||||
print(e)
|
|
||||||
|
@ -36,7 +36,7 @@ from PyQt5.QtWebEngineWidgets import (QWebEngineSettings, QWebEngineProfile,
|
|||||||
QWebEngineScript)
|
QWebEngineScript)
|
||||||
|
|
||||||
from qutebrowser.browser import shared
|
from qutebrowser.browser import shared
|
||||||
from qutebrowser.browser.webengine.spell import get_installed_languages
|
from qutebrowser.browser.webengine import spell
|
||||||
from qutebrowser.config import config, websettings
|
from qutebrowser.config import config, websettings
|
||||||
from qutebrowser.utils import utils, standarddir, javascript, qtutils, message
|
from qutebrowser.utils import utils, standarddir, javascript, qtutils, message
|
||||||
|
|
||||||
@ -134,20 +134,18 @@ class DictionaryLanguageSetter(DefaultProfileSetter):
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__('setSpellCheckLanguages', default=[])
|
super().__init__('setSpellCheckLanguages', default=[])
|
||||||
|
|
||||||
|
def _find_installed(self, code):
|
||||||
|
installed_file = spell.installed_file(code)
|
||||||
|
if not installed_file:
|
||||||
|
message.warning('Language {} is not installed.'.format(code))
|
||||||
|
return installed_file
|
||||||
|
|
||||||
def _set(self, value, settings=None):
|
def _set(self, value, settings=None):
|
||||||
if settings is not None:
|
if settings is not None:
|
||||||
raise ValueError("'settings' may not be set with "
|
raise ValueError("'settings' may not be set with "
|
||||||
"DictionaryLanguageSetter!")
|
"DictionaryLanguageSetter!")
|
||||||
installed_langs = dict([(lang.code, lang.file)
|
filenames = [self._find_installed(code) for code in value]
|
||||||
for lang in get_installed_languages()])
|
super()._set([f for f in filenames if f], settings)
|
||||||
lang_files = []
|
|
||||||
for lang_code in value:
|
|
||||||
if lang_code in installed_langs:
|
|
||||||
lang_files.append(installed_langs[lang_code][:-5])
|
|
||||||
else:
|
|
||||||
message.warning('Language {} is not installed.'
|
|
||||||
.format(lang_code))
|
|
||||||
super()._set(lang_files, settings)
|
|
||||||
|
|
||||||
|
|
||||||
def _init_stylesheet(profile):
|
def _init_stylesheet(profile):
|
||||||
@ -322,7 +320,6 @@ MAPPINGS = {
|
|||||||
|
|
||||||
'scrolling.smooth':
|
'scrolling.smooth':
|
||||||
Attribute(QWebEngineSettings.ScrollAnimatorEnabled),
|
Attribute(QWebEngineSettings.ScrollAnimatorEnabled),
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -334,8 +331,9 @@ except AttributeError:
|
|||||||
|
|
||||||
|
|
||||||
if qtutils.version_check('5.8'):
|
if qtutils.version_check('5.8'):
|
||||||
MAPPINGS['spell'] = DefaultProfileSetter('setSpellCheckEnabled')
|
spellcheck_setter = DefaultProfileSetter('setSpellCheckEnabled')
|
||||||
MAPPINGS['spell_languages'] = DictionaryLanguageSetter()
|
MAPPINGS['spellcheck.enabled'] = spellcheck_setter
|
||||||
|
MAPPINGS['spellcheck.languages'] = DictionaryLanguageSetter()
|
||||||
|
|
||||||
|
|
||||||
if qtutils.version_check('5.9'):
|
if qtutils.version_check('5.9'):
|
||||||
|
@ -977,7 +977,7 @@ scrolling.smooth:
|
|||||||
|
|
||||||
## spell
|
## spell
|
||||||
|
|
||||||
spell:
|
spellcheck.enabled:
|
||||||
type: Bool
|
type: Bool
|
||||||
default: true
|
default: true
|
||||||
desc: Enable spell checking.
|
desc: Enable spell checking.
|
||||||
@ -985,7 +985,7 @@ spell:
|
|||||||
QtWebKit: false
|
QtWebKit: false
|
||||||
QtWebEngine: Qt 5.8
|
QtWebEngine: Qt 5.8
|
||||||
|
|
||||||
spell_languages:
|
spellcheck.languages:
|
||||||
type:
|
type:
|
||||||
name: List
|
name: List
|
||||||
valtype:
|
valtype:
|
||||||
@ -1035,7 +1035,11 @@ spell_languages:
|
|||||||
- vi-VN: Vietnamese (Viet Nam)
|
- vi-VN: Vietnamese (Viet Nam)
|
||||||
none_ok: true
|
none_ok: true
|
||||||
default:
|
default:
|
||||||
desc: Spell checking languages.
|
desc: >-
|
||||||
|
Spell checking languages.
|
||||||
|
|
||||||
|
You can check for available languages and install dictionaries using
|
||||||
|
scripts/install_dict.py. Run the script with -h/--help for instructions.
|
||||||
backend:
|
backend:
|
||||||
QtWebKit: false
|
QtWebKit: false
|
||||||
QtWebEngine: Qt 5.8
|
QtWebEngine: Qt 5.8
|
||||||
|
@ -33,7 +33,6 @@ import sip
|
|||||||
from PyQt5.QtCore import QUrl
|
from PyQt5.QtCore import QUrl
|
||||||
# so it's available for :debug-pyeval
|
# so it's available for :debug-pyeval
|
||||||
from PyQt5.QtWidgets import QApplication # pylint: disable=unused-import
|
from PyQt5.QtWidgets import QApplication # pylint: disable=unused-import
|
||||||
from PyQt5.QtWebEngineWidgets import QWebEngineProfile # pylint: disable=unused-import
|
|
||||||
|
|
||||||
from qutebrowser.browser import qutescheme
|
from qutebrowser.browser import qutescheme
|
||||||
from qutebrowser.utils import log, objreg, usertypes, message, debug, utils
|
from qutebrowser.utils import log, objreg, usertypes, message, debug, utils
|
||||||
|
@ -27,6 +27,7 @@ import urllib.error
|
|||||||
import shutil
|
import shutil
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
def get_latest_pdfjs_url():
|
def get_latest_pdfjs_url():
|
||||||
@ -110,7 +111,25 @@ def update_ace():
|
|||||||
urllib.request.urlcleanup()
|
urllib.request.urlcleanup()
|
||||||
|
|
||||||
|
|
||||||
def run(ace=False, pdfjs=True, fancy_dmg=False, pdfjs_version=None):
|
def test_dicts():
|
||||||
|
"""Test available dictionaries."""
|
||||||
|
sys.path.insert(0, os.curdir)
|
||||||
|
from scripts import install_dict
|
||||||
|
from qutebrowser.config import configdata
|
||||||
|
configdata.init()
|
||||||
|
for lang in install_dict.available_languages():
|
||||||
|
sys.stdout.write('Testing dictionary {}... '.format(lang.code))
|
||||||
|
lang_url = urllib.parse.urljoin(install_dict.API_URL, lang.file_path)
|
||||||
|
request = urllib.request.Request(lang_url, method='HEAD')
|
||||||
|
response = urllib.request.urlopen(request)
|
||||||
|
if response.status == 200:
|
||||||
|
print('OK')
|
||||||
|
else:
|
||||||
|
print('ERROR: {}'.format(response.status))
|
||||||
|
|
||||||
|
|
||||||
|
def run(ace=False, pdfjs=True, fancy_dmg=False, pdfjs_version=None,
|
||||||
|
dicts=None):
|
||||||
"""Update components based on the given arguments."""
|
"""Update components based on the given arguments."""
|
||||||
if pdfjs:
|
if pdfjs:
|
||||||
update_pdfjs(pdfjs_version)
|
update_pdfjs(pdfjs_version)
|
||||||
@ -118,6 +137,8 @@ def run(ace=False, pdfjs=True, fancy_dmg=False, pdfjs_version=None):
|
|||||||
update_ace()
|
update_ace()
|
||||||
if fancy_dmg:
|
if fancy_dmg:
|
||||||
update_dmg_makefile()
|
update_dmg_makefile()
|
||||||
|
if dicts:
|
||||||
|
test_dicts()
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
@ -129,9 +150,14 @@ def main():
|
|||||||
required=False, metavar='VERSION')
|
required=False, metavar='VERSION')
|
||||||
parser.add_argument('--fancy-dmg', help="Update fancy-dmg Makefile",
|
parser.add_argument('--fancy-dmg', help="Update fancy-dmg Makefile",
|
||||||
action='store_true')
|
action='store_true')
|
||||||
|
parser.add_argument(
|
||||||
|
'--dicts', '-d',
|
||||||
|
help='Test whether all available dictionaries '
|
||||||
|
'can be reached at the remote repository.',
|
||||||
|
required=False, action='store_true')
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
run(ace=True, pdfjs=True, fancy_dmg=args.fancy_dmg,
|
run(ace=True, pdfjs=True, fancy_dmg=args.fancy_dmg,
|
||||||
pdfjs_version=args.pdfjs)
|
pdfjs_version=args.pdfjs, dicts=args.dicts)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
@ -24,9 +24,34 @@ Use: python -m scripts.install_dict [--list] [lang [lang [...]]]
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
import base64
|
||||||
|
import json
|
||||||
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
import re
|
||||||
|
import urllib.parse
|
||||||
|
import urllib.request
|
||||||
|
import attr
|
||||||
|
|
||||||
from qutebrowser.browser.webengine import spell
|
from qutebrowser.browser.webengine import spell
|
||||||
|
from qutebrowser.config import configdata
|
||||||
|
|
||||||
|
|
||||||
|
API_URL = 'https://chromium.googlesource.com/chromium/deps/hunspell_dictionaries.git/+/master/'
|
||||||
|
|
||||||
|
|
||||||
|
@attr.s
|
||||||
|
class Language:
|
||||||
|
"""Dictionary language specs."""
|
||||||
|
|
||||||
|
code = attr.ib(None)
|
||||||
|
name = attr.ib(None)
|
||||||
|
file_basename = attr.ib(None)
|
||||||
|
file_extension = attr.ib('bdic')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def file_path(self):
|
||||||
|
return '.'.join([self.file_basename, self.file_extension])
|
||||||
|
|
||||||
|
|
||||||
def get_argparser():
|
def get_argparser():
|
||||||
@ -46,18 +71,105 @@ def print_list(languages):
|
|||||||
print('{1}\t{0}'.format(lang.name, lang.code))
|
print('{1}\t{0}'.format(lang.name, lang.code))
|
||||||
|
|
||||||
|
|
||||||
|
def valid_languages():
|
||||||
|
"""Return a mapping from valid language codes to their names."""
|
||||||
|
option = configdata.DATA['spellcheck.languages']
|
||||||
|
return option.typ.valtype.valid_values.descriptions
|
||||||
|
|
||||||
|
|
||||||
|
def language_list_from_api():
|
||||||
|
"""Return a JSON with a list of available languages from Google API."""
|
||||||
|
listurl = urllib.parse.urljoin(API_URL, '?format=JSON')
|
||||||
|
response = urllib.request.urlopen(listurl)
|
||||||
|
# TODO: what's up with the first 4 characters?
|
||||||
|
entries = json.loads(response.read().decode('utf-8')[4:])['entries']
|
||||||
|
return entries
|
||||||
|
|
||||||
|
|
||||||
|
def available_languages():
|
||||||
|
"""Return a list of Language objects of all available languages."""
|
||||||
|
lang_map = valid_languages()
|
||||||
|
api_list = language_list_from_api()
|
||||||
|
dict_re = re.compile(r"""
|
||||||
|
(?P<filename>(?P<dict>[a-z]{2}(-[A-Z]{2})?).*)\.bdic
|
||||||
|
""", re.VERBOSE)
|
||||||
|
code2file = {}
|
||||||
|
for lang in api_list:
|
||||||
|
match = dict_re.match(lang['name'])
|
||||||
|
if match is not None:
|
||||||
|
code2file[match.group('dict')] = match.group('filename')
|
||||||
|
return [
|
||||||
|
Language(code, name, code2file[code])
|
||||||
|
for code, name in lang_map.items()
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def download_dictionary(url, dest):
|
||||||
|
"""Download a decoded dictionary file."""
|
||||||
|
response = urllib.request.urlopen(url)
|
||||||
|
decoded = base64.decodebytes(response.read())
|
||||||
|
with open(dest, 'bw') as dict_file:
|
||||||
|
dict_file.write(decoded)
|
||||||
|
|
||||||
|
|
||||||
|
def filter_languages(languages, selected):
|
||||||
|
"""Filter a list of languages based on an inclusion list.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
languages: a list of languages to filter
|
||||||
|
selected: a list of keys to select
|
||||||
|
by: a function returning the selection key (code by default)
|
||||||
|
fail_on_unknown: whether to raise an error if there is an unknown
|
||||||
|
key in selected
|
||||||
|
"""
|
||||||
|
filtered_languages = []
|
||||||
|
for language in languages:
|
||||||
|
if language.code in selected:
|
||||||
|
filtered_languages.append(language)
|
||||||
|
selected.remove(language.code)
|
||||||
|
if selected:
|
||||||
|
unknown = ', '.join(selected)
|
||||||
|
raise ValueError('unknown languages found: {}'.format(unknown))
|
||||||
|
return filtered_languages
|
||||||
|
|
||||||
|
|
||||||
|
def install_lang(lang):
|
||||||
|
"""Install a single lang given by the argument."""
|
||||||
|
print('Installing {}: {}'.format(lang.code, lang.name))
|
||||||
|
lang_url = urllib.parse.urljoin(API_URL, lang.file_path, '?format=TEXT')
|
||||||
|
if not os.path.isdir(spell.dictionary_dir()):
|
||||||
|
warn_msg = 'WARN: {} does not exist, creating the directory'
|
||||||
|
print(warn_msg.format(spell.dictionary_dir()))
|
||||||
|
os.makedirs(spell.dictionary_dir())
|
||||||
|
print('Downloading {}'.format(lang_url))
|
||||||
|
dest = os.path.join(spell.dictionary_dir(), lang.file_path)
|
||||||
|
download_dictionary(lang_url, dest)
|
||||||
|
print('Done.')
|
||||||
|
|
||||||
|
|
||||||
|
def install(languages):
|
||||||
|
"""Install languages."""
|
||||||
|
for lang in languages:
|
||||||
|
try:
|
||||||
|
install_lang(lang)
|
||||||
|
except PermissionError as e:
|
||||||
|
print(e)
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
if configdata.DATA is None:
|
||||||
|
configdata.init()
|
||||||
parser = get_argparser()
|
parser = get_argparser()
|
||||||
argv = sys.argv[1:]
|
argv = sys.argv[1:]
|
||||||
args = parser.parse_args(argv)
|
args = parser.parse_args(argv)
|
||||||
languages = spell.get_available_languages()
|
languages = available_languages()
|
||||||
if args.list:
|
if args.list:
|
||||||
print_list(languages)
|
print_list(languages)
|
||||||
elif not args.languages:
|
elif not args.languages:
|
||||||
parser.print_usage()
|
parser.print_usage()
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
spell.install(spell.filter_languages(languages, args.languages))
|
install(filter_languages(languages, args.languages))
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
print(e)
|
print(e)
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ import pstats
|
|||||||
import os.path
|
import os.path
|
||||||
import operator
|
import operator
|
||||||
|
|
||||||
from qutebrowser.browser.webengine.spell import get_installed_languages
|
from qutebrowser.browser.webengine import spell
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from PyQt5.QtCore import PYQT_VERSION
|
from PyQt5.QtCore import PYQT_VERSION
|
||||||
@ -120,18 +120,17 @@ def _get_backend_tag(tag):
|
|||||||
|
|
||||||
def _get_dictionary_tag(tag):
|
def _get_dictionary_tag(tag):
|
||||||
"""Handle tags like must_have_dict=en-US for BDD tests."""
|
"""Handle tags like must_have_dict=en-US for BDD tests."""
|
||||||
version_re = re.compile(r"""
|
dict_re = re.compile(r"""
|
||||||
(?P<event>must_have_dict|cannot_have_dict)=(?P<dict>[a-z]{2}-[A-Z]{2})
|
(?P<event>must_have_dict|cannot_have_dict)=(?P<dict>[a-z]{2}-[A-Z]{2})
|
||||||
""", re.VERBOSE)
|
""", re.VERBOSE)
|
||||||
|
|
||||||
match = version_re.match(tag)
|
match = dict_re.match(tag)
|
||||||
if not match:
|
if not match:
|
||||||
#return pytest.mark.skip
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
event = match.group('event')
|
event = match.group('event')
|
||||||
dictionary = match.group('dict')
|
dictionary = match.group('dict')
|
||||||
has_dict = dictionary in [lang.code for lang in get_installed_languages()]
|
has_dict = spell.installed_file(dictionary) is not None
|
||||||
if event == 'must_have_dict':
|
if event == 'must_have_dict':
|
||||||
return pytest.mark.skipif(not has_dict, reason=tag)
|
return pytest.mark.skipif(not has_dict, reason=tag)
|
||||||
elif event == 'cannot_have_dict':
|
elif event == 'cannot_have_dict':
|
||||||
|
@ -2,37 +2,29 @@
|
|||||||
|
|
||||||
Feature: Setting spell checking for QtWebEngine
|
Feature: Setting spell checking for QtWebEngine
|
||||||
|
|
||||||
Background:
|
|
||||||
Given spell check languages are []
|
|
||||||
|
|
||||||
@qtwebkit_skip @qt>=5.8
|
@qtwebkit_skip @qt>=5.8
|
||||||
Scenario: Turn spell check on
|
Scenario: Turn spell check on
|
||||||
Given spell check is off
|
Given I set spellcheck.enabled to false
|
||||||
When I run :set spell true
|
When I run :set spellcheck.enabled true
|
||||||
Then the option spell should be set to true
|
Then the option spellcheck.enabled should be set to true
|
||||||
Then spell check is on
|
|
||||||
|
|
||||||
@qtwebkit_skip @qt>=5.8
|
@qtwebkit_skip @qt>=5.8
|
||||||
Scenario: Turn spell check off
|
Scenario: Turn spell check off
|
||||||
Given spell check is on
|
Given I set spellcheck.enabled to true
|
||||||
When I run :set spell false
|
When I run :set spellcheck.enabled false
|
||||||
Then the option spell should be set to false
|
Then the option spellcheck.enabled should be set to false
|
||||||
Then spell check is off
|
|
||||||
|
|
||||||
@qtwebkit_skip @qt>=5.8
|
@qtwebkit_skip @qt>=5.8
|
||||||
Scenario: Set an invalid language
|
Scenario: Set an invalid language
|
||||||
When I run :set spell_languages ['invalid-language'] (invalid command)
|
When I run :set spellcheck.languages ['invalid-language'] (invalid command)
|
||||||
Then the error "set: Invalid value 'invalid-language' *" should be shown
|
Then the error "set: Invalid value 'invalid-language' *" should be shown
|
||||||
Then actual spell check languages are []
|
|
||||||
|
|
||||||
@qtwebkit_skip @qt>=5.8 @cannot_have_dict=af-ZA
|
@qtwebkit_skip @qt>=5.8 @cannot_have_dict=af-ZA
|
||||||
Scenario: Set valid but not installed language
|
Scenario: Set valid but not installed language
|
||||||
When I run :set spell_languages ['af-ZA']
|
When I run :set spellcheck.languages ['af-ZA']
|
||||||
Then the warning "Language af-ZA is not installed." should be shown
|
Then the warning "Language af-ZA is not installed." should be shown
|
||||||
Then actual spell check languages are []
|
|
||||||
|
|
||||||
@qtwebkit_skip @qt>=5.8 @must_have_dict=en-US
|
@qtwebkit_skip @qt>=5.8 @must_have_dict=en-US
|
||||||
Scenario: Set valid and installed language
|
Scenario: Set valid and installed language
|
||||||
When I run :set spell_languages ["en-US"]
|
When I run :set spellcheck.languages ["en-US"]
|
||||||
Then the option spell_languages should be set to ["en-US"]
|
Then the option spellcheck.languages should be set to ["en-US"]
|
||||||
Then actual spell check languages are ['en-US-7-1']
|
|
||||||
|
@ -20,39 +20,3 @@
|
|||||||
import pytest_bdd as bdd
|
import pytest_bdd as bdd
|
||||||
|
|
||||||
bdd.scenarios('spell.feature')
|
bdd.scenarios('spell.feature')
|
||||||
|
|
||||||
|
|
||||||
@bdd.given(bdd.parsers.parse("spell check is {val}"))
|
|
||||||
def spellcheck_enabled_given(quteproc, val):
|
|
||||||
enabled = val == 'on'
|
|
||||||
quteproc.send_cmd(':debug-pyeval QWebEngineProfile.defaultProfile()' +
|
|
||||||
'.setSpellCheckEnabled({})'.format(enabled))
|
|
||||||
quteproc.wait_for_load_finished('qute://pyeval')
|
|
||||||
|
|
||||||
|
|
||||||
@bdd.given(bdd.parsers.parse("spell check languages are {langs}"))
|
|
||||||
def spellcheck_langs_given(quteproc, langs):
|
|
||||||
quteproc.send_cmd(':debug-pyeval QWebEngineProfile.defaultProfile()' +
|
|
||||||
'.setSpellCheckLanguages({})'.format(langs))
|
|
||||||
quteproc.wait_for_load_finished('qute://pyeval')
|
|
||||||
|
|
||||||
|
|
||||||
@bdd.then(bdd.parsers.parse("spell check is {val}"))
|
|
||||||
def spellcheck_enabled_then(quteproc, val):
|
|
||||||
quteproc.send_cmd(':debug-pyeval QWebEngineProfile.defaultProfile()' +
|
|
||||||
'.isSpellCheckEnabled()')
|
|
||||||
quteproc.wait_for_load_finished('qute://pyeval')
|
|
||||||
content = quteproc.get_content().strip()
|
|
||||||
if val == 'on':
|
|
||||||
assert content == 'True'
|
|
||||||
else:
|
|
||||||
assert content == 'False'
|
|
||||||
|
|
||||||
|
|
||||||
@bdd.then(bdd.parsers.parse("actual spell check languages are {langs}"))
|
|
||||||
def spellcheck_langs_then(quteproc, langs):
|
|
||||||
quteproc.send_cmd(':debug-pyeval QWebEngineProfile.defaultProfile()' +
|
|
||||||
'.spellCheckLanguages()')
|
|
||||||
quteproc.wait_for_load_finished('qute://pyeval')
|
|
||||||
actual_langs = quteproc.get_content().strip()
|
|
||||||
assert actual_langs == langs
|
|
||||||
|
@ -18,78 +18,23 @@
|
|||||||
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
|
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|
||||||
from os.path import basename, join
|
|
||||||
|
|
||||||
import pytest
|
|
||||||
|
|
||||||
from qutebrowser.browser.webengine import spell
|
from qutebrowser.browser.webengine import spell
|
||||||
|
|
||||||
AFRIKAANS = spell.Language('af-ZA',
|
|
||||||
'Afrikaans (South Africa)',
|
|
||||||
'af-ZA-3-0.bdic')
|
|
||||||
ENGLISH = spell.Language('en-US',
|
|
||||||
'English (United States)',
|
|
||||||
'en-US-7-1.bdic')
|
|
||||||
POLISH = spell.Language('pl-PL',
|
|
||||||
'Polish (Poland)',
|
|
||||||
'pl-PL-3-0.bdic')
|
|
||||||
|
|
||||||
LANGUAGE_LIST = [AFRIKAANS, ENGLISH, POLISH]
|
def test_installed_file_dictionary_does_not_exist(tmpdir, monkeypatch):
|
||||||
|
monkeypatch.setattr(
|
||||||
|
spell, 'dictionary_dir', lambda: '/some-non-existing-dir')
|
||||||
|
assert not spell.installed_file('en-US')
|
||||||
|
|
||||||
|
|
||||||
def test_get_installed_languages_empty(tmpdir, mocker):
|
def test_installed_file_dictionary_not_installed(tmpdir, monkeypatch):
|
||||||
mocker.patch('qutebrowser.browser.webengine.spell.get_dictionary_dir',
|
monkeypatch.setattr(spell, 'dictionary_dir', lambda: str(tmpdir))
|
||||||
lambda: '/some-non-existing-dir')
|
assert not spell.installed_file('en-US')
|
||||||
assert spell.get_installed_languages() == []
|
|
||||||
|
|
||||||
|
|
||||||
def test_get_installed_languages_non_empty(tmpdir, mocker):
|
def test_installed_file_dictionary_installed(tmpdir, monkeypatch):
|
||||||
mocker.patch('qutebrowser.browser.webengine.spell.get_dictionary_dir',
|
monkeypatch.setattr(spell, 'dictionary_dir', lambda: str(tmpdir))
|
||||||
lambda: str(tmpdir))
|
for lang_file in ['en-US-7-1.bdic', 'pl-PL-3-0.bdic']:
|
||||||
for lang in LANGUAGE_LIST:
|
(tmpdir / lang_file).ensure()
|
||||||
open(join(str(tmpdir), lang.file), 'w', encoding='UTF-8').close()
|
assert spell.installed_file('en-US') == 'en-US-7-1'
|
||||||
for actual, expected in zip(spell.get_installed_languages(),
|
assert spell.installed_file('pl-PL') == 'pl-PL-3-0'
|
||||||
LANGUAGE_LIST):
|
|
||||||
assert (actual.code, actual.name, actual.file) ==\
|
|
||||||
(expected.code, expected.name, expected.file)
|
|
||||||
|
|
||||||
|
|
||||||
def test_get_available_languages():
|
|
||||||
language_list = spell.get_available_languages()
|
|
||||||
assert len(language_list) == 42
|
|
||||||
first_lang = language_list[0]
|
|
||||||
assert (first_lang.code, first_lang.name, first_lang.file) ==\
|
|
||||||
(AFRIKAANS.code, AFRIKAANS.name, AFRIKAANS.file)
|
|
||||||
|
|
||||||
|
|
||||||
def test_filter_languages():
|
|
||||||
filtered_languages = spell.filter_languages(LANGUAGE_LIST, ['af-ZA'])
|
|
||||||
assert filtered_languages == [AFRIKAANS]
|
|
||||||
filtered_languages = spell.filter_languages(LANGUAGE_LIST,
|
|
||||||
['pl-PL', 'en-US'])
|
|
||||||
assert filtered_languages == [ENGLISH, POLISH]
|
|
||||||
with pytest.raises(ValueError):
|
|
||||||
spell.filter_languages(LANGUAGE_LIST, ['pl-PL', 'en-GB'])
|
|
||||||
filtered_languages = spell.filter_languages(LANGUAGE_LIST,
|
|
||||||
['pl-PL-3-0.bdic'],
|
|
||||||
by=lambda lang: lang.file)
|
|
||||||
assert filtered_languages == [POLISH]
|
|
||||||
|
|
||||||
|
|
||||||
def test_install(tmpdir, mocker):
|
|
||||||
mocker.patch('qutebrowser.browser.webengine.spell.get_dictionary_dir',
|
|
||||||
lambda: str(tmpdir))
|
|
||||||
mocker.patch('qutebrowser.browser.webengine.spell.download_dictionary',
|
|
||||||
lambda url, dest: open(dest, 'w', encoding='UTF-8').close())
|
|
||||||
spell.install(LANGUAGE_LIST)
|
|
||||||
installed_files = [basename(str(file)) for file in tmpdir.listdir()]
|
|
||||||
expected_files = [lang.file for lang in LANGUAGE_LIST]
|
|
||||||
assert sorted(installed_files) == sorted(expected_files)
|
|
||||||
|
|
||||||
|
|
||||||
# TODO: move somewhere to be checked before a release
|
|
||||||
#def test_available_langs():
|
|
||||||
# for lang in spell.get_available_languages():
|
|
||||||
# lang_url = urljoin(spell.repository_url, lang.file)
|
|
||||||
# response = head(lang_url)
|
|
||||||
# assert response.status_code == 302
|
|
||||||
|
71
tests/unit/scripts/test_install_dict.py
Normal file
71
tests/unit/scripts/test_install_dict.py
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||||
|
|
||||||
|
# Copyright 2017 Michal Siedlaczek <michal.siedlaczek@gmail.com>
|
||||||
|
|
||||||
|
# This file is part of qutebrowser.
|
||||||
|
#
|
||||||
|
# qutebrowser is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# qutebrowser is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|
||||||
|
import py.path # pylint: disable=no-name-in-module
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from qutebrowser.browser.webengine import spell
|
||||||
|
from scripts import install_dict
|
||||||
|
from qutebrowser.config import configdata
|
||||||
|
|
||||||
|
AFRIKAANS = install_dict.Language(
|
||||||
|
'af-ZA',
|
||||||
|
'Afrikaans (South Africa)',
|
||||||
|
'af-ZA-3-0')
|
||||||
|
ENGLISH = install_dict.Language(
|
||||||
|
'en-US',
|
||||||
|
'English (United States)',
|
||||||
|
'en-US-7-1')
|
||||||
|
POLISH = install_dict.Language(
|
||||||
|
'pl-PL',
|
||||||
|
'Polish (Poland)',
|
||||||
|
'pl-PL-3-0')
|
||||||
|
|
||||||
|
LANGUAGE_LIST = [AFRIKAANS, ENGLISH, POLISH]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(autouse=True)
|
||||||
|
def configdata_init():
|
||||||
|
"""Initialize configdata if needed."""
|
||||||
|
if configdata.DATA is None:
|
||||||
|
configdata.init()
|
||||||
|
|
||||||
|
|
||||||
|
def test_filter_languages():
|
||||||
|
filtered_langs = install_dict.filter_languages(LANGUAGE_LIST, ['af-ZA'])
|
||||||
|
assert filtered_langs == [AFRIKAANS]
|
||||||
|
|
||||||
|
filtered_langs = install_dict.filter_languages(
|
||||||
|
LANGUAGE_LIST, ['pl-PL', 'en-US'])
|
||||||
|
assert filtered_langs == [ENGLISH, POLISH]
|
||||||
|
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
install_dict.filter_languages(LANGUAGE_LIST, ['pl-PL', 'en-GB'])
|
||||||
|
|
||||||
|
|
||||||
|
def test_install(tmpdir, monkeypatch):
|
||||||
|
monkeypatch.setattr(spell, 'dictionary_dir', lambda: str(tmpdir))
|
||||||
|
monkeypatch.setattr(
|
||||||
|
install_dict, 'download_dictionary',
|
||||||
|
lambda _url, dest: py.path.local(dest).ensure()) # pylint: disable=no-member
|
||||||
|
install_dict.install(LANGUAGE_LIST)
|
||||||
|
installed_files = [f.basename for f in tmpdir.listdir()]
|
||||||
|
expected_files = [lang.file_path for lang in LANGUAGE_LIST]
|
||||||
|
assert sorted(installed_files) == sorted(expected_files)
|
Loading…
Reference in New Issue
Block a user