Skip to content

Commit

Permalink
Improved .options validation and docstrings
Browse files Browse the repository at this point in the history
  • Loading branch information
philippjfr committed Feb 5, 2018
1 parent 59bf4dc commit c65ce1c
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 19 deletions.
47 changes: 41 additions & 6 deletions holoviews/core/dimension.py
Expand Up @@ -1088,9 +1088,20 @@ def __call__(self, options=None, **kwargs):

def opts(self, options=None, backend=None, **kwargs):
"""
Apply the supplied options to a clone of the object which is
then returned. Note that if no options are supplied at all,
all ids are reset.
Applies options on an object or nested group of objects in a
by options group returning a new object with the options
applied. If the options are to be set directly on the object a
simple format may be used, e.g.:
obj.opts(style={'cmap': 'viridis'}, plot={'show_title': False})
If the object is nested the options must be qualified using
a type[.group][.label] specification, e.g.:
obj.opts({'Image': {'plot': {'show_title': False},
'style': {'cmap': 'viridis}}})
If no opts are supplied all options on the object will be reset.
"""
backend = backend or Store.current_backend
if isinstance(options, basestring):
Expand All @@ -1102,14 +1113,15 @@ def opts(self, options=None, backend=None, **kwargs):
'{clsname} {options}'.format(clsname=self.__class__.__name__,
options=options))

groups = set(Store.options(backend=backend).groups.keys())
backend_options = Store.options(backend=backend)
groups = set(backend_options.groups.keys())
if kwargs and set(kwargs) <= groups:
if not all(isinstance(v, dict) for v in kwargs.values()):
raise Exception("The %s options must be specified using dictionary groups" %
','.join(repr(k) for k in kwargs.keys()))

# Check whether the user is specifying targets (such as 'Image.Foo')
entries = Store.options(backend=backend).children
entries = backend_options.children
targets = [k.split('.')[0] in entries for grp in kwargs.values() for k in grp]
if any(targets) and not all(targets):
raise Exception("Cannot mix target specification keys such as 'Image' with non-target keywords.")
Expand All @@ -1136,7 +1148,30 @@ def opts(self, options=None, backend=None, **kwargs):


def options(self, options=None, backend=None, **kwargs):
if options and kwargs:
"""
Applies options on an object or nested group of objects in a
flat format returning a new object with the options
applied. If the options are to be set directly on the object a
simple format may be used, e.g.:
obj.options(cmap='viridis', show_title=False)
If the object is nested the options must be qualified using
a type[.group][.label] specification, e.g.:
obj.options('Image', cmap='viridis', show_title=False)
or using:
obj.options({'Image': dict(cmap='viridis', show_title=False)})
If no options are supplied all options on the object will be reset.
"""
backend = backend or Store.current_backend
backend_options = Store.options(backend=backend)
if isinstance(options, basestring):
options = {options: kwargs}
elif options and kwargs:
raise ValueError("Options must be defined in one of two formats."
"Either supply keywords defining the options for "
"the current object, e.g. obj.options(cmap='viridis'), "
Expand Down
37 changes: 31 additions & 6 deletions holoviews/core/spaces.py
Expand Up @@ -859,9 +859,20 @@ def _execute_callback(self, *args):

def opts(self, options=None, backend=None, **kwargs):
"""
Apply the supplied options to a clone of the DynamicMap which is
then returned. Note that if no options are supplied at all,
all ids are reset.
Applies options on an object or nested group of objects in a
by options group returning a new object with the options
applied. If the options are to be set directly on the object a
simple format may be used, e.g.:
obj.opts(style={'cmap': 'viridis'}, plot={'show_title': False})
If the object is nested the options must be qualified using
a type[.group][.label] specification, e.g.:
obj.opts({'Image': {'plot': {'show_title': False},
'style': {'cmap': 'viridis}}})
If no opts are supplied all options on the object will be reset.
"""
from ..util import Dynamic
dmap = Dynamic(self, operation=lambda obj, **dynkwargs: obj.opts(options, backend, **kwargs),
Expand All @@ -873,9 +884,23 @@ def opts(self, options=None, backend=None, **kwargs):

def options(self, options=None, backend=None, **kwargs):
"""
Apply the supplied options to a clone of the DynamicMap which is
then returned. Note that if no options are supplied at all,
all ids are reset.
Applies options on an object or nested group of objects in a
flat format returning a new object with the options
applied. If the options are to be set directly on the object a
simple format may be used, e.g.:
obj.options(cmap='viridis', show_title=False)
If the object is nested the options must be qualified using
a type[.group][.label] specification, e.g.:
obj.options('Image', cmap='viridis', show_title=False)
or using:
obj.options({'Image': dict(cmap='viridis', show_title=False)})
If no options are supplied all options on the object will be reset.
"""
from ..util import Dynamic
dmap = Dynamic(self, operation=lambda obj, **dynkwargs: obj.options(options, backend, **kwargs),
Expand Down
22 changes: 15 additions & 7 deletions holoviews/util/__init__.py
Expand Up @@ -3,7 +3,7 @@
import param

from ..core import DynamicMap, HoloMap, Dimensioned, ViewableElement, StoreOptions, Store
from ..core.options import options_policy
from ..core.options import options_policy, Keywords
from ..core.operation import Operation
from ..core.util import Aliases, basestring # noqa (API import)
from ..core.operation import OperationCallable
Expand Down Expand Up @@ -115,20 +115,28 @@ def expand_options(cls, options, backend=None):
backend_options = Store.options(backend=backend)
groups = set(backend_options.groups.keys())
expanded = {}
for objtype, options in options.items():
for objspec, options in options.items():
objtype = objspec.split('.')[0]
if objtype not in backend_options:
raise ValueError('%s type not found, could not apply options.' % objtype)
raise ValueError('%s type not found, could not apply options.'
% objtype)
obj_options = backend_options[objtype]
expanded[objtype] = {g: {} for g in obj_options.groups}
expanded[objspec] = {g: {} for g in obj_options.groups}
for opt, value in options.items():
found = False
valid_options = []
for g, group_opts in obj_options.groups.items():
if opt in group_opts.allowed_keywords:
expanded[objtype][g][opt] = value
expanded[objspec][g][opt] = value
found = True
valid_options += group_opts.allowed_keywords
if not found:
raise ValueError('%s option is not valid for %s types '
'on %s backend.' % (opt, objtype, backend))
kws = Keywords(values=valid_options, target=objspec)
matches = kws.fuzzy_match(opt)
raise ValueError('Unexpected option %r for %s types '
'when using the %r backend. Similar '
'options are: %s.' %
(opt, objtype, backend, matches))
return expanded


Expand Down

0 comments on commit c65ce1c

Please sign in to comment.