Validate length/bounds for config values

This commit is contained in:
Florian Bruhin 2014-04-21 21:04:19 +02:00
parent a6789095b3
commit b10c934e15
4 changed files with 193 additions and 108 deletions

View File

@ -107,188 +107,190 @@ SECTION_DESC = {
DATA = OrderedDict([
('general', sect.KeyValue(
('show_completion',
SettingValue(types.Bool, "true"),
SettingValue(types.Bool(), "true"),
"Whether to show the autocompletion window or not."),
('completion_height',
SettingValue(types.PercOrInt, "50%"),
SettingValue(types.PercOrInt(minperc=0, maxperc=100, minint=1),
"50%"),
"The height of the completion, in px or as percentage of the "
"window."),
('ignorecase',
SettingValue(types.Bool, "true"),
SettingValue(types.Bool(), "true"),
"Whether to do case-insensitive searching."),
('wrapsearch',
SettingValue(types.Bool, "true"),
SettingValue(types.Bool(), "true"),
"Whether to wrap search to the top when arriving at the end."),
('startpage',
SettingValue(types.List, "http://www.duckduckgo.com"),
SettingValue(types.List(), "http://www.duckduckgo.com"),
"The default page(s) to open at the start, separated with commas."),
('auto_search',
SettingValue(types.AutoSearch, "naive"),
SettingValue(types.AutoSearch(), "naive"),
"Whether to start a search when something else than an URL is "
"entered."),
('zoomlevels',
SettingValue(types.PercList, "25%,33%,50%,67%,75%,90%,100%,110%,125%,"
"150%,175%,200%,250%,300%,400%,500%"),
SettingValue(types.PercList(minval=0),
"25%,33%,50%,67%,75%,90%,100%,110%,125%,150%,175%,200%,"
"250%,300%,400%,500%"),
"The available zoom levels, separated by commas."),
('defaultzoom',
SettingValue(types.ZoomPerc, "100%"),
SettingValue(types.ZoomPerc(), "100%"),
"The default zoom level."),
('autosave',
SettingValue(types.Bool, "true"),
SettingValue(types.Bool(), "true"),
"Whether to save the config automatically on quit."),
('cmd_histlen',
SettingValue(types.Int, "100"),
SettingValue(types.Int(minval=-1), "100"),
"How many commands to save in the history. 0: no history / -1: "
"unlimited"),
('background_tabs',
SettingValue(types.Bool, "false"),
SettingValue(types.Bool(), "false"),
"Whether to open new tabs (middleclick/ctrl+click) in background"),
)),
('tabbar', sect.KeyValue(
('movable',
SettingValue(types.Bool, "true"),
SettingValue(types.Bool(), "true"),
"Whether tabs should be movable."),
('closebuttons',
SettingValue(types.Bool, "false"),
SettingValue(types.Bool(), "false"),
"Whether tabs should have close-buttons."),
('scrollbuttons',
SettingValue(types.Bool, "true"),
SettingValue(types.Bool(), "true"),
"Whether there should be scroll buttons if there are too many tabs."),
('position',
SettingValue(types.Position, "north"),
SettingValue(types.Position(), "north"),
"The position of the tab bar."),
('select_on_remove',
SettingValue(types.SelectOnRemove, "previous"),
SettingValue(types.SelectOnRemove(), "previous"),
"Which tab to select when the focused tab is removed."),
('last_close',
SettingValue(types.LastClose, "ignore"),
SettingValue(types.LastClose(), "ignore"),
"Behaviour when the last tab is closed."),
)),
('webkit', sect.KeyValue(
('auto_load_images',
SettingValue(types.Bool, "true"),
SettingValue(types.Bool(), "true"),
"Specifies whether images are automatically loaded in web pages."),
('dns_prefetch_enabled',
SettingValue(types.Bool, "false"),
SettingValue(types.Bool(), "false"),
"Specifies whether QtWebkit will try to pre-fetch DNS entries to "
"speed up browsing."),
('javascript_enabled',
SettingValue(types.Bool, "true"),
SettingValue(types.Bool(), "true"),
"Enables or disables the running of JavaScript programs."),
#('java_enabled',
# SettingValue(types.Bool, "true"),
# SettingValue(types.Bool(), "true"),
# "Enables or disables Java applets. Currently Java applets are "
# "not supported"),
('plugins_enabled',
SettingValue(types.Bool, "false"),
SettingValue(types.Bool(), "false"),
"Enables or disables plugins in Web pages"),
('private_browsing_enabled',
SettingValue(types.Bool, "false"),
SettingValue(types.Bool(), "false"),
"Private browsing prevents WebKit from recording visited pages in "
"the history and storing web page icons."),
('javascript_can_open_windows',
SettingValue(types.Bool, "false"),
SettingValue(types.Bool(), "false"),
"Specifies whether JavaScript programs can open new windows."),
('javascript_can_close_windows',
SettingValue(types.Bool, "false"),
SettingValue(types.Bool(), "false"),
"Specifies whether JavaScript programs can close windows."),
('javascript_can_access_clipboard',
SettingValue(types.Bool, "false"),
SettingValue(types.Bool(), "false"),
"Specifies whether JavaScript programs can read or write to the "
"clipboard."),
('developer_extras_enabled',
SettingValue(types.Bool, "false"),
SettingValue(types.Bool(), "false"),
"Enables extra tools for Web developers (e.g. webinspector)"),
('spatial_navigation_enabled',
SettingValue(types.Bool, "false"),
SettingValue(types.Bool(), "false"),
"Enables or disables the Spatial Navigation feature, which consists "
"in the ability to navigate between focusable elements in a Web "
"page, such as hyperlinks and form controls, by using Left, Right, "
"Up and Down arrow keys."),
('links_included_in_focus_chain',
SettingValue(types.Bool, "true"),
SettingValue(types.Bool(), "true"),
"Specifies whether hyperlinks should be included in the keyboard "
"focus chain."),
('zoom_text_only',
SettingValue(types.Bool, "false"),
SettingValue(types.Bool(), "false"),
"Specifies whether the zoom factor on a frame applies only to the "
"text or to all content."),
('print_element_backgrounds',
SettingValue(types.Bool, "true"),
SettingValue(types.Bool(), "true"),
"Specifies whether the background color and images are also drawn "
"when the page is printed. "),
('offline_storage_database_enabled',
SettingValue(types.Bool, "false"),
SettingValue(types.Bool(), "false"),
"Specifies whether support for the HTML 5 offline storage feature is "
"enabled or not. "),
('offline_web_application_storage_enabled',
SettingValue(types.Bool, "false"),
SettingValue(types.Bool(), "false"),
"Specifies whether support for the HTML 5 web application cache "
"feature is enabled or not. "),
('local_storage_enabled',
SettingValue(types.Bool, "false"),
SettingValue(types.Bool(), "false"),
"Specifies whether support for the HTML 5 local storage feature is "
"enabled or not."),
('local_content_can_access_remote_urls',
SettingValue(types.Bool, "false"),
SettingValue(types.Bool(), "false"),
"Specifies whether locally loaded documents are allowed to access "
"remote urls."),
('local_content_can_access_file_urls',
SettingValue(types.Bool, "true"),
SettingValue(types.Bool(), "true"),
"Specifies whether locally loaded documents are allowed to access "
"other local urls."),
('xss_auditing_enabled',
SettingValue(types.Bool, "false"),
SettingValue(types.Bool(), "false"),
"Specifies whether load requests should be monitored for cross-site "
"scripting attempts. Suspicious scripts will be blocked and reported "
"in the inspector's JavaScript console. Enabling this feature might "
"have an impact on performance."),
#('accelerated_compositing_enabled',
# SettingValue(types.Bool, "true"),
# SettingValue(types.Bool(), "true"),
# "This feature, when used in conjunction with QGraphicsWebView, "
# "accelerates animations of web content. CSS animations of the "
# "transform and opacity properties will be rendered by composing the "
# "cached content of the animated elements. "),
#('tiled_backing_store_enabled',
# SettingValue(types.Bool, "false"),
# SettingValue(types.Bool(), "false"),
# "This setting enables the tiled backing store feature for a "
# "QGraphicsWebView. With the tiled backing store enabled, the web "
# "page contents in and around the current visible area is "
@ -298,30 +300,30 @@ DATA = OrderedDict([
# "Enabling the feature increases memory consuption."),
('frame_flattening_enabled',
SettingValue(types.Bool, "false"),
SettingValue(types.Bool(), "false"),
"With this setting each subframe is expanded to its contents. This "
"will flatten all the frames to become one scrollable "
"page."),
('site_specific_quirks_enabled',
SettingValue(types.Bool, "true"),
SettingValue(types.Bool(), "true"),
"This setting enables WebKit's workaround for broken sites."),
)),
('hints', sect.KeyValue(
('border',
SettingValue(types.String, "1px solid #E3BE23"),
SettingValue(types.String(), "1px solid #E3BE23"),
"CSS border value for hints."),
('opacity',
SettingValue(types.Float, "0.7"),
SettingValue(types.Float(minval=0.0, maxval=1.0), "0.7"),
"Opacity for hints."),
('chars',
SettingValue(types.String, "asdfghjkl"),
('chars',
SettingValue(types.String(minlen=2), "asdfghjkl"),
"Chars used for hint strings."),
)),
('searchengines', sect.ValueList(
types.SearchEngineName, types.SearchEngineUrl,
types.SearchEngineName(), types.SearchEngineUrl(),
('DEFAULT', '${duckduckgo}'),
('duckduckgo', 'https://duckduckgo.com/?q={}'),
('ddg', '${duckduckgo}'),
@ -333,7 +335,7 @@ DATA = OrderedDict([
)),
('keybind', sect.ValueList(
types.KeyBindingName, types.KeyBinding,
types.KeyBindingName(), types.KeyBinding(),
('o', 'open'),
('go', 'opencur'),
('O', 'tabopen'),
@ -381,140 +383,140 @@ DATA = OrderedDict([
)),
('aliases', sect.ValueList(
types.Command, types.Command,
types.Command(), types.Command(),
)),
('colors', sect.KeyValue(
('completion.fg',
SettingValue(types.Color, "#333333"),
SettingValue(types.Color(), "#333333"),
"Text color of the completion widget."),
('completion.item.bg',
SettingValue(types.Color, "white"),
SettingValue(types.Color(), "white"),
"Background color of completion widget items."),
('completion.category.bg',
SettingValue(types.Color, "qlineargradient(x1:0, y1:0, x2:0, y2:1, "
SettingValue(types.Color(), "qlineargradient(x1:0, y1:0, x2:0, y2:1, "
"stop:0 #e4e4e4, stop:1 #dbdbdb)"),
"Background color of the completion widget category headers."),
('completion.category.border.top',
SettingValue(types.Color, "#808080"),
SettingValue(types.Color(), "#808080"),
"Top border color of the completion widget category headers."),
('completion.category.border.bottom',
SettingValue(types.Color, "#bbbbbb"),
SettingValue(types.Color(), "#bbbbbb"),
"Bottom border color of the completion widget category headers."),
('completion.item.selected.fg',
SettingValue(types.Color, "#333333"),
SettingValue(types.Color(), "#333333"),
"Foreground color of the selected completion item."),
('completion.item.selected.bg',
SettingValue(types.Color, "#ffec8b"),
SettingValue(types.Color(), "#ffec8b"),
"Background color of the selected completion item."),
('completion.item.selected.border.top',
SettingValue(types.Color, "#f2f2c0"),
SettingValue(types.Color(), "#f2f2c0"),
"Top border color of the completion widget category headers."),
('completion.item.selected.border.bottom',
SettingValue(types.Color, "#ffec8b"),
SettingValue(types.Color(), "#ffec8b"),
"Bottom border color of the selected completion item."),
('completion.match.fg',
SettingValue(types.Color, "red"),
SettingValue(types.Color(), "red"),
"Foreground color of the matched text in the completion."),
('statusbar.bg',
SettingValue(types.Color, "black"),
SettingValue(types.Color(), "black"),
"Foreground color of the statusbar."),
('statusbar.fg',
SettingValue(types.Color, "white"),
SettingValue(types.Color(), "white"),
"Foreground color of the statusbar."),
('statusbar.bg.error',
SettingValue(types.Color, "red"),
SettingValue(types.Color(), "red"),
"Background color of the statusbar if there was an error."),
('statusbar.fg.error',
SettingValue(types.Color, "${statusbar.fg}"),
SettingValue(types.Color(), "${statusbar.fg}"),
"Foreground color of the statusbar if there was an error."),
('statusbar.progress.bg',
SettingValue(types.Color, "white"),
SettingValue(types.Color(), "white"),
"Background color of the progress bar."),
('statusbar.url.fg',
SettingValue(types.Color, "${statusbar.fg}"),
SettingValue(types.Color(), "${statusbar.fg}"),
"Default foreground color of the URL in the statusbar."),
('statusbar.url.fg.success',
SettingValue(types.Color, "lime"),
SettingValue(types.Color(), "lime"),
"Foreground color of the URL in the statusbar on successful "
"load."),
('statusbar.url.fg.error',
SettingValue(types.Color, "orange"),
SettingValue(types.Color(), "orange"),
"Foreground color of the URL in the statusbar on error."),
('statusbar.url.fg.warn',
SettingValue(types.Color, "yellow"),
SettingValue(types.Color(), "yellow"),
"Foreground color of the URL in the statusbar when there's a "
"warning."),
('statusbar.url.fg.hover',
SettingValue(types.Color, "aqua"),
SettingValue(types.Color(), "aqua"),
"Foreground color of the URL in the statusbar for hovered "
"links."),
('tab.fg',
SettingValue(types.Color, "white"),
SettingValue(types.Color(), "white"),
"Foreground color of the tabbar."),
('tab.bg',
SettingValue(types.Color, "grey"),
SettingValue(types.Color(), "grey"),
"Background color of the tabbar."),
('tab.bg.selected',
SettingValue(types.Color, "black"),
SettingValue(types.Color(), "black"),
"Background color of the tabbar for the selected tab."),
('tab.seperator',
SettingValue(types.Color, "white"),
SettingValue(types.Color(), "white"),
"Color for the tab seperator."),
('hints.fg',
SettingValue(types.CssColor, "black"),
SettingValue(types.CssColor(), "black"),
"Font color for hints."),
('hints.fg.match',
SettingValue(types.CssColor, "green"),
SettingValue(types.CssColor(), "green"),
"Font color for the matched part of hints."),
('hints.bg',
SettingValue(types.CssColor, "-webkit-gradient(linear, left top, "
"left bottom, color-stop(0%,#FFF785), "
"color-stop(100%,#FFC542))"),
SettingValue(types.CssColor(), "-webkit-gradient(linear, left top, "
"left bottom, color-stop(0%,#FFF785), "
"color-stop(100%,#FFC542))"),
"Background color for hints."),
)),
('fonts', sect.KeyValue(
('completion',
SettingValue(types.Font, "8pt Monospace"),
SettingValue(types.Font(), "8pt Monospace"),
"Font used in the completion widget."),
('tabbar',
SettingValue(types.Font, "8pt Monospace"),
SettingValue(types.Font(), "8pt Monospace"),
"Font used in the tabbar."),
('statusbar',
SettingValue(types.Font, "8pt Monospace"),
SettingValue(types.Font(), "8pt Monospace"),
"Font used in the statusbar."),
('hints',
SettingValue(types.Font, "bold 12px Monospace"),
SettingValue(types.Font(), "bold 12px Monospace"),
"Font used for the hints."),
)),
])

View File

@ -113,16 +113,29 @@ class BaseType:
class String(BaseType):
"""Base class for a string setting (case-insensitive)."""
"""Base class for a string setting (case-insensitive).
Attributes:
minlen: Minimum length (inclusive).
maxlen: Maximum length (inclusive).
"""
typestr = 'string'
def __init__(self, minlen=None, maxlen=None):
self.minlen = minlen
self.maxlen = maxlen
def transform(self, value):
return value.lower()
def validate(self, value):
# Nothing to do
return
if self.minlen is not None and len(value) < self.minlen:
raise ValidationError(value, "must be at least {} chars "
"long!".format(self.minlen))
if self.maxlen is not None and len(value) > self.maxlen:
raise ValidationError(value, "must be at most {} long!".format(
self.maxlen))
class Bool(BaseType):
@ -150,34 +163,64 @@ class Bool(BaseType):
class Int(BaseType):
"""Base class for an integer setting."""
"""Base class for an integer setting.
Attributes:
minval: Minimum value (inclusive).
maxval: Maximum value (inclusive).
"""
typestr = 'int'
def __init__(self, minval=None, maxval=None):
self.minval = minval
self.maxval = maxval
def transform(self, value):
return int(value)
def validate(self, value):
try:
int(value)
intval = int(value)
except ValueError:
raise ValidationError(value, "must be an integer!")
if self.minval is not None and intval < self.minval:
raise ValidationError(value, "must be {} or bigger!".format(
self.minval))
if self.maxval is not None and intval > self.maxval:
raise ValidationError(value, "must be {} or smaller!".format(
self.maxval))
class Float(BaseType):
"""Base class for an float setting."""
"""Base class for an float setting.
Attributes:
minval: Minimum value (inclusive).
maxval: Maximum value (inclusive).
"""
typestr = 'float'
def __init__(self, minval=None, maxval=None):
self.minval = minval
self.maxval = maxval
def transform(self, value):
return float(value)
def validate(self, value):
try:
float(value)
floatval = float(value)
except ValueError:
raise ValidationError(value, "must be a float!")
if self.minval is not None and floatval < self.minval:
raise ValidationError(value, "must be {} or bigger!".format(
self.minval))
if self.maxval is not None and floatval > self.maxval:
raise ValidationError(value, "must be {} or smaller!".format(
self.maxval))
class List(BaseType):
@ -212,7 +255,16 @@ class IntList(List):
class Perc(BaseType):
"""Percentage which may be >100 but needs to be positive."""
"""Percentage.
Attributes:
minval: Minimum value (inclusive).
maxval: Maximum value (inclusive).
"""
def __init__(self, minval=None, maxval=None):
self.minval = minval
self.maxval = maxval
def transform(self, value):
return int(value.rstrip('%'))
@ -224,26 +276,39 @@ class Perc(BaseType):
intval = int(value.rstrip('%'))
except ValueError:
raise ValidationError(value, "invalid percentage!")
else:
if not intval >= 0:
raise ValidationError(value, "percentage needs to be >= 0!")
if self.minval is not None and intval < self.minval:
raise ValidationError(value, "must be {}% or more!".format(
self.minval))
if self.maxval is not None and intval > self.maxval:
raise ValidationError(value, "must be {}% or less!".format(
self.maxval))
class PercList(List):
"""Base class for a list of percentages."""
"""Base class for a list of percentages.
Attributes:
minval: Minimum value (inclusive).
maxval: Maximum value (inclusive).
"""
typestr = 'perc-list'
def __init__(self, minval=None, maxval=None):
self.minval = minval
self.maxval = maxval
def transform(self, value):
vals = super().transform(value)
return [int(val.rstrip('%')) for val in vals]
def validate(self, value):
vals = super().transform(value)
perctype = Perc(minval=self.minval, maxval=self.maxval)
try:
for val in vals:
Perc.validate(self, val)
perctype.validate(val)
except ValidationError:
raise ValidationError(value, "must be a list of percentages!")
@ -259,7 +324,20 @@ class ZoomPerc(Perc):
class PercOrInt(BaseType):
"""Percentage or integer."""
"""Percentage or integer.
Attributes:
minperc: Minimum value for percentage (inclusive).
maxperc: Maximum value for percentage (inclusive).
minint: Minimum value for integer (inclusive).
maxint: Maximum value for integer (inclusive).
"""
def __init__(self, minperc=None, maxperc=None, minint=None, maxint=None):
self.minperc = minperc
self.maxperc = maxperc
self.minint = minint
self.maxint = maxint
def validate(self, value):
if value.endswith('%'):
@ -267,18 +345,23 @@ class PercOrInt(BaseType):
intval = int(value.rstrip('%'))
except ValueError:
raise ValidationError(value, "invalid percentage!")
else:
if not 0 <= intval <= 100:
raise ValidationError(value, "percentage needs to be >= 0 "
"and <= 100!")
if self.minperc is not None and intval < self.minperc:
raise ValidationError(value, "must be {}% or more!".format(
self.minperc))
if self.maxperc is not None and intval > self.maxperc:
raise ValidationError(value, "must be {}% or less!".format(
self.maxperc))
else:
try:
intval = int(value)
except ValueError:
raise ValidationError(value, "must be integer or percentage!")
else:
if intval < 0:
raise ValidationError(value, "must be >= 0")
if self.minint is not None and intval < self.minint:
raise ValidationError(value, "must be {} or bigger!".format(
self.minint))
if self.maxint is not None and intval > self.maxint:
raise ValidationError(value, "must be {} or smaller!".format(
self.maxint))
class Command(BaseType):

View File

@ -149,8 +149,8 @@ class ValueList(Section):
"""Wrap types over default values. Take care when overriding this.
Args:
keytype: The type to be used for keys.
valtype: The type to be used for values.
keytype: The type instance to be used for keys.
valtype: The type instance to be used for values.
*defaults: A (key, value) list of default values.
"""
super().__init__()
@ -166,7 +166,7 @@ class ValueList(Section):
self.layers['default'])
def setv(self, layer, key, value, interpolated):
self.keytype().validate(key)
self.keytype.validate(key)
if key in self.layers[layer]:
self.layers[layer][key].setv(layer, value, interpolated)
else:

View File

@ -27,7 +27,7 @@ class SettingValue:
Intended to be subclassed by config value "types".
Attributes:
typ: A BaseType subclass.
typ: A BaseType subclass instance.
value: (readonly property) The currently valid, most important value.
_values: An OrderedDict with the values on different layers, with the
most significant layer first.
@ -40,7 +40,7 @@ class SettingValue:
typ: The BaseType to use.
default: Raw value to set.
"""
self.typ = typ()
self.typ = typ
self._values = OrderedDict.fromkeys(['temp', 'conf', 'default'])
self._values['default'] = default