# -*- coding: utf-8 -*-
"""This module contains DemoOptions- the `options` delegate for Demo, and Option- a class that holds information about a registered option."""
# For py2.7 compatibility
from __future__ import print_function
import functools
import inspect
from .exceptions import (DemoException, DemoRetry, KeyNotFoundError,
OptionNotFoundError, CallbackNotFoundError,
CallbackLockError, CallbackResponseError, catch_exc)
[docs]class Option(object):
"""Holds information about a registered option.
Attributes:
name (str): The name of the option.
desc (str): The description of the option that should be printed in :meth:`~cli_demo.demo.Demo.print_options`.
callback (function): The function that :meth:`~cli_demo.options.Option.call` should wrap.
newline (bool): Whether an empty line should be printed before :attr:`~cli_demo.options.Option.callback` is called in :meth:`~cli_demo.options.Option.call`.
retry (bool): Whether an input function should be called again once :attr:`~cli_demo.options.Option.callback` has returned.
lock (bool): Whether the `key` of a triggering input function should be received by :attr:`~cli_demo.options.Option.callback`.
args (tuple): The default arguments that should be used to call :attr:`~cli_demo.options.Option.callback` in :meth:`~cli_demo.options.Option.call`.
kwargs (dict): The default keyword arguments that should be used to call :attr:`~cli_demo.options.Option.callback` in :meth:`~cli_demo.options.Option.call`.
"""
__slots__ = ["name", "desc", "callback", "newline",
"retry", "lock", "args", "kwargs"]
def __init__(self, **kwargs):
for attr in ["name", "desc", "callback", "newline",
"retry", "lock", "args", "kwargs"]:
value = kwargs.get(attr, None)
setattr(self, attr, value)
[docs] def call(self, demo, *args, **kwargs):
"""Call the registered :attr:`~cli_demo.options.Option.callback`.
Args:
demo: The :class:`~cli_demo.demo.Demo` instance that should be passed into :attr:`~cli_demo.options.Option.callback`.
*args: The arguments that should be passed into :attr:`~cli_demo.options.Option.callback`.
**kwargs: The keyword arguments that should be passed into :attr:`~cli_demo.options.Option.callback`.
Note:
* :attr:`~cli_demo.options.Option.args` is used if `args` is empty.
* :attr:`~cli_demo.options.Option.kwargs` is used if `kwargs` is empty.
* An empty line is printed before :attr:`~cli_demo.options.Option.callback` is called if :attr:`~cli_demo.options.Option.newline` is ``True``.
* :meth:`~cli_demo.demo.Demo.retry` will be called if :attr:`~cli_demo.options.Option.retry` is ``True`` and :attr:`~cli_demo.options.Option.callback` successfully returned.
"""
if not args:
args = self.args
if not kwargs:
kwargs = self.kwargs
if self.newline:
print()
did_return = False
try:
result = self.callback(demo, *args, **kwargs)
did_return = True
return result
finally:
if did_return and self.retry:
demo.retry()
[docs] def copy(self):
"""Initialize a new copy of :class:`~cli_demo.options.Option`.
Returns:
An instance of :class:`~cli_demo.options.Option` with a deep copy of all attributes belonging to ``self``.
"""
new_option = Option(
name=str(self.name),
desc=str(self.desc),
callback=self.callback,
newline=bool(self.newline),
retry=bool(self.retry),
lock=bool(self.lock),
args=tuple(self.args),
kwargs=dict(self.kwargs))
return new_option
[docs]class DemoOptions(object):
"""Designates options for input functions and forwards their registered callbacks dynamically.
Attributes:
demo: The parent :class:`~cli_demo.demo.Demo` instance.
registry (dict): The options and their :class:`~cli_demo.options.Option` instances that have been registered.
cache (dict): A cache of input function key ids and their options and keyword options that have been captured.
"""
def __init__(self):
self.demo = None
self.registry = {}
self.cache = {}
[docs] def __call__(self, *opts, **kw_opts):
"""Designate a set of options to an input function.
If a user input falls within the designated options, invoke the :attr:`~cli_demo.options.Option.callback` of the corresponding :class:`~cli_demo.options.Option` instance through its :meth:`~cli_demo.options.Option.call` method.
Args:
retry (str, optional): The text to print before the input function is called again when the user response is invalid. Defaults to ``"Please try again"``.
key (str, optional): The key of the input function.
args (tuple, optional): The arguments that should be passed into the :attr:`~cli_demo.options.Option.callback` of the :class:`~cli_demo.options.Option` instance registered under `key`. Defaults to ``()``.
kwargs (dict, optional): The keyword arguments that should be passed into :attr:`~cli_demo.options.Option.callback` of the :class:`~cli_demo.options.Option` instance registered under `key`. Defaults to ``{}``.
*opts: The user responses that should be accepted.
**kw_opts: The user responses that should be redirected.
Note:
If `key` is provided:
* `key` will be used to store a record of `opts` and `kw_opts` in :attr:`~cli_demo.options.DemoOptions.cache`.
* To reference the options stored in :attr:`~cli_demo.options.DemoOptions.cache` when calling :meth:`~cli_demo.demo.Demo.print_options`, you can pass in `key` as the `key` argument.
* If a user input does not fall within the designated options, the response will be forwarded to the :attr:`~cli_demo.options.Option.callback` of the :class:`~cli_demo.options.Option` instance registered under `key` through its :meth:`~cli_demo.options.Option.call` method.
If `key` is not provided:
* The **input function** itself will be used to store a record of `opts` and `kw_opts` in :attr:`~cli_demo.options.DemoOptions.cache`.
* To reference the options stored in :attr:`~cli_demo.options.DemoOptions.cache` when calling :meth:`~cli_demo.demo.Demo.print_options`, you need to pass in the input function itself as the `key` argument.
* If a user input does not fall within the designated options, :meth:`~cli_demo.demo.Demo.retry` will be called and `retry` will be printed.
Returns:
``options_decorator()``: A decorator which takes a function (expected to be an input function) and returns a wrapped function.
The following exceptions will only be raised when the wrapped function is called.
Raises:
:class:`~cli_demo.exceptions.OptionNotFoundError`: If an option does not exist in :attr:`~cli_demo.options.DemoOptions.registry`, or if its value is not an instance of :class:`~cli_demo.options.Option`.
:class:`~cli_demo.exceptions.CallbackNotFoundError`: If the :attr:`~cli_demo.options.Option.callback` of an :class:`~cli_demo.options.Option` instance has not been set.
:class:`~cli_demo.exceptions.CallbackLockError`: If the :attr:`~cli_demo.options.Option.lock` attribute of an :class:`~cli_demo.options.Option` instance is ``True`` but its :attr:`~cli_demo.options.Option.callback` does not accept a `key` argument.
:class:`~cli_demo.exceptions.CallbackResponseError`: If `key` is provided but the :attr:`~cli_demo.options.Option.callback` of the :class:`~cli_demo.options.Option` instance registered under `key` does not accept a `response` argument.
"""
retry = kw_opts.pop("retry", "Please try again.")
key = kw_opts.pop("key", None)
args = kw_opts.pop("args", ())
kwargs = kw_opts.pop("kwargs", {})
def options_decorator(input_func):
self.set_options(key or input_func, *opts, **kw_opts)
@functools.wraps(input_func)
@catch_exc(DemoRetry)
def inner(demo):
response = input_func(demo)
opts, kw_opts = demo.options.get_options(key or input_func)
if response in opts or response in kw_opts:
option = kw_opts.get(response) or response
if option not in demo.options:
raise OptionNotFoundError(response)
elif demo.options.is_lock(option):
try:
return demo.options.call(option, key=key)
except TypeError as exc:
raise CallbackLockError(response)
else:
return demo.options.call(option)
elif key:
try:
return demo.options.call(key, response=response,
*args, **kwargs)
except TypeError as exc:
raise CallbackResponseError(response)
else:
demo.retry(retry)
return inner
return options_decorator
[docs] @staticmethod
def get_id(key):
"""Create a unique id for `key`.
Args:
key: A key for a set of options and keyword options.
Returns:
int: The id of `key`.
"""
return id(key)
[docs] def has_options(self, key):
"""Check if there are any options set with `key`.
Args:
key: A key for a set of options and keyword options.
Returns:
``True`` if the id of `key` exists in :attr:`~cli_demo.options.DemoOptions.cache`, ``False`` otherwise.
"""
return self.get_id(key) in self.cache
[docs] def get_options(self, key):
"""Get the options that were set with `key`.
Args:
key: A key for a set of options and keyword options.
Returns:
list[list, dict]: The options and keyword options set under `key`.
Raises:
:class:`~cli_demo.exceptions.KeyNotFoundError`: If the id of `key` does not exist in :attr:`~cli_demo.options.DemoOptions.cache`.
"""
try:
return self.cache[self.get_id(key)]
except KeyError:
raise KeyNotFoundError(key)
[docs] def set_options(self, key, *opts, **kw_opts):
"""Change the options that were set with `key`.
If `opts` or `kw_opts` are provided, override the options or keyword options that were recorded previously.
Args:
key: A key for a set of options and keyword options.
*opts: Argument options for `key`.
**kw_opts: Keyword options for `key`.
"""
key_id = self.get_id(key)
if key_id not in self.cache:
self.cache[key_id] = [[], {}]
if opts:
self.cache[key_id][0] = list(opts)
if kw_opts:
self.cache[key_id][1] = dict(kw_opts)
[docs] def insert(self, key, kw, opt, **kw_opts):
"""Insert an option into the options that were set with `key`.
Insert `opt` into the argument options at index `kw` if it is an int or a digit. Otherwise, update the keyword options with `kw` and `opt`.
Args:
key: A key for a set of options and keyword options.
kw: An index for argument options or a keyword option.
opt (str): The option to insert.
**kw_opts: More `kw` and `opt` arguments.
Raises:
:class:`~cli_demo.exceptions.KeyNotFoundError`: If the id of `key` does not exist in :attr:`~cli_demo.options.DemoOptions.cache`.
"""
options = self.get_options(key)
for kw, opt in dict(kw_opts, **{kw:opt}).items():
if isinstance(kw, str) and not kw.isdigit():
options[1][kw] = opt
else:
options[0].insert(int(kw), opt)
[docs] def register(self, option, desc="", **kwargs):
"""Register an option.
Create an :class:`~cli_demo.options.Option` instance based on the arguments and keyword arguments provided and then store in :attr:`~cli_demo.options.DemoOptions.registry`.
Returns:
``register_decorator()``: A decorator which takes a function, sets the :attr:`~cli_demo.options.Option.callback` of the :class:`~cli_demo.options.Option` instance using :meth:`~cli_demo.options.DemoOptions.set_callback`, and returns the original function.
Args:
option (str): The name of the option.
desc (str, optional): The description of the option that should be printed in :meth:`~cli_demo.demo.Demo.print_options`. If not provided, it will be set to the name of the function passed into :meth:`~cli_demo.options.DemoOptions.set_callback`.
newline (bool, optional): Whether an empty line should be printed before :attr:`~cli_demo.options.Option.callback` is called. Defaults to ``False``.
retry (bool, optional): Whether an input function should be called again once :attr:`~cli_demo.options.Option.callback` has returned. Defaults to ``False``.
lock (bool, optional): Whether the `key` of a triggering input function should be received by :attr:`~cli_demo.options.Option.callback`. Defaults to ``False``.
args (tuple, optional): The default arguments that should be used to call :attr:`~cli_demo.options.Option.callback`. Defaults to ``()``.
kwargs (dict, optional): The default keyword arguments that should be used to call :attr:`~cli_demo.options.Option.callback`. Defaults to ``{}``.
Note:
* `option` can be an expected user response or an input function key.
* If `option` is an input function key:
* The function passed into ``register_decorator()`` must accept a `response` argument- the user's response to that input function.
* Any response to that input function which does not fall within its designated options will be forwarded to the function through the :meth:`~cli_demo.options.Option.call` method of the :class:`~cli_demo.options.Option` instance for further processing.
* If `lock` is ``True``, the function passed into ``register_decorator()`` must accept a `key` argument- the key of the input function that triggered it.
"""
self.registry[option] = Option(name=option, desc=desc,
newline=kwargs.get("newline", False),
retry=kwargs.get("retry", False),
lock=kwargs.get("lock", False),
args=kwargs.get("args", ()),
kwargs=kwargs.get("kwargs", {}))
def register_decorator(func):
self.set_callback(option, func)
return func
return register_decorator
[docs] def __contains__(self, option):
"""Check if an :class:`~cli_demo.options.Option` instance is registered.
Args:
option (str): The :attr:`~cli_demo.options.Option.name` used to register the :class:`~cli_demo.options.Option` instance.
Returns:
``True`` if `option` exists in :attr:`~cli_demo.options.DemoOptions.registry` and its value is an instance of :class:`~cli_demo.options.Option`, ``False`` otherwise.
"""
return (option in self.registry
and isinstance(self.registry[option], Option))
[docs] def __getitem__(self, option):
"""Get the registered :class:`~cli_demo.options.Option` instance.
Args:
option (str): The :attr:`~cli_demo.options.Option.name` used to register the :class:`~cli_demo.options.Option` instance.
Returns:
The :class:`~cli_demo.options.Option` instance registered under `option`.
Raises:
:class:`~cli_demo.exceptions.OptionNotFoundError`: If `option` does not exist in :attr:`~cli_demo.options.DemoOptions.registry`, or if its value is not an instance of :class:`~cli_demo.options.Option`.
"""
if option not in self:
raise OptionNotFoundError(option)
else:
return self.registry[option]
[docs] def call(self, option, *args, **kwargs):
"""Invoke the :attr:`~cli_demo.options.Option.callback` of the :class:`~cli_demo.options.Option` instance through its :meth:`~cli_demo.options.Option.call` method.
Args:
option (str): The :attr:`~cli_demo.options.Option.name` used to register the :class:`~cli_demo.options.Option` instance.
*args: The arguments to use when calling :attr:`~cli_demo.options.Option.callback`.
**kwargs: The keyword arguments to use when calling :attr:`~cli_demo.options.Option.callback`.
Returns:
The return value of :attr:`~cli_demo.options.Option.callback`.
Raises:
:class:`~cli_demo.exceptions.DemoException`: If :attr:`~cli_demo.options.DemoOptions.demo` is not set.
:class:`~cli_demo.exceptions.OptionNotFoundError`: If `option` does not exist in :attr:`~cli_demo.options.DemoOptions.registry`, or if its value is not an instance of :class:`~cli_demo.options.Option`.
:class:`~cli_demo.exceptions.CallbackNotFoundError`: If the :attr:`~cli_demo.options.Option.callback` of the :class:`~cli_demo.options.Option` instance has not been set.
"""
if not self.demo:
raise DemoException("Demo not set yet.")
else:
callback = self.get_callback(option)
return callback(self.demo, *args, **kwargs)
[docs] def get_callback(self, option):
"""Get the :meth:`~cli_demo.options.Option.call` method of the :class:`~cli_demo.options.Option` instance.
Args:
option (str): The :attr:`~cli_demo.options.Option.name` used to register the :class:`~cli_demo.options.Option` instance.
Returns:
The :meth:`~cli_demo.options.Option.call` method of the :class:`~cli_demo.options.Option` instance.
Raises:
:class:`~cli_demo.exceptions.OptionNotFoundError`: If `option` does not exist in :attr:`~cli_demo.options.DemoOptions.registry`, or if its value is not an instance of :class:`~cli_demo.options.Option`.
:class:`~cli_demo.exceptions.CallbackNotFoundError`: If the :attr:`~cli_demo.options.Option.callback` of the :class:`~cli_demo.options.Option` instance has not been set.
"""
opt = self[option]
if opt.callback is None:
raise CallbackNotFoundError(option)
else:
return opt.call
[docs] def set_callback(self, option, callback):
"""Set the :attr:`~cli_demo.options.Option.callback` of the :class:`~cli_demo.options.Option` instance.
If the :attr:`~cli_demo.options.Option.desc` of the :class:`~cli_demo.options.Option` instance is blank, use the name of `callback` to set it.
Args:
option (str): The :attr:`~cli_demo.options.Option.name` used to register the :class:`~cli_demo.options.Option` instance.
callback: The function that the :meth:`~cli_demo.options.Option.call` method of the :class:`~cli_demo.options.Option` instance should wrap.
Raises:
:class:`~cli_demo.exceptions.OptionNotFoundError`: If `option` does not exist in :attr:`~cli_demo.options.DemoOptions.registry`, or if its value is not an instance of :class:`~cli_demo.options.Option`.
"""
self[option].callback = callback
if not self.get_desc(option):
self.set_desc(option, "{}.".format(
callback.__name__.replace("_", " ").capitalize()))
[docs] def is_lock(self, option):
"""Check if the `key` of a triggering input function will be received by the :attr:`~cli_demo.options.Option.callback` of the :class:`~cli_demo.options.Option` instance.
Args:
option (str): The :attr:`~cli_demo.options.Option.name` used to register the :class:`~cli_demo.options.Option` instance.
Returns:
``True`` if the :attr:`~cli_demo.options.Option.lock` attribute of the :class:`~cli_demo.options.Option` instance is ``True``, ``False`` otherwise.
Raises:
:class:`~cli_demo.exceptions.OptionNotFoundError`: If `option` does not exist in :attr:`~cli_demo.options.DemoOptions.registry`, or if its value is not an instance of :class:`~cli_demo.options.Option`.
"""
return self[option].lock is True
[docs] def set_lock(self, option, lock):
"""Set whether the `key` of a triggering input function should be received by the :attr:`~cli_demo.options.Option.callback` of the :class:`~cli_demo.options.Option` instance.
Args:
option (str): The :attr:`~cli_demo.options.Option.name` used to register the :class:`~cli_demo.options.Option` instance.
lock (bool): Whether the `key` of a triggering input function should be received by :attr:`~cli_demo.options.Option.callback`.
Raises:
:class:`~cli_demo.exceptions.OptionNotFoundError`: If `option` does not exist in :attr:`~cli_demo.options.DemoOptions.registry`, or if its value is not an instance of :class:`~cli_demo.options.Option`.
"""
self[option].lock = bool(lock)
[docs] def will_retry(self, option):
"""Check if an input function will be called again once the :attr:`~cli_demo.options.Option.callback` of the :class:`~cli_demo.options.Option` instance has returned.
Args:
option (str): The :attr:`~cli_demo.options.Option.name` used to register the :class:`~cli_demo.options.Option` instance.
Returns:
``True`` if the :attr:`~cli_demo.options.Option.retry` attribute of the :class:`~cli_demo.options.Option` instance is ``True``, ``False`` otherwise.
Raises:
:class:`~cli_demo.exceptions.OptionNotFoundError`: If `option` does not exist in :attr:`~cli_demo.options.DemoOptions.registry`, or if its value is not an instance of :class:`~cli_demo.options.Option`.
"""
return self[option].retry is True
[docs] def set_retry(self, option, retry):
"""Set whether an input function should be called again once the :attr:`~cli_demo.options.Option.callback` of the :class:`~cli_demo.options.Option` instance has returned.
Args:
option (str): The :attr:`~cli_demo.options.Option.name` used to register the :class:`~cli_demo.options.Option` instance.
retry (bool): Whether an input function should be called again once :attr:`~cli_demo.options.Option.callback` has returned.
Raises:
:class:`~cli_demo.exceptions.OptionNotFoundError`: If `option` does not exist in :attr:`~cli_demo.options.DemoOptions.registry`, or if its value is not an instance of :class:`~cli_demo.options.Option`.
"""
self[option].retry = bool(retry)
[docs] def has_newline(self, option):
"""Check if an empty line will be printed before the :attr:`~cli_demo.options.Option.callback` of the :class:`~cli_demo.options.Option` instance is called.
Args:
option (str): The :attr:`~cli_demo.options.Option.name` used to register the :class:`~cli_demo.options.Option` instance.
Returns:
``True`` if the :attr:`~cli_demo.options.Option.newline` attribute of the :class:`~cli_demo.options.Option` instance is ``True``, ``False`` otherwise.
Raises:
:class:`~cli_demo.exceptions.OptionNotFoundError`: If `option` does not exist in :attr:`~cli_demo.options.DemoOptions.registry`, or if its value is not an instance of :class:`~cli_demo.options.Option`.
"""
return self[option].newline is True
[docs] def set_newline(self, option, newline):
"""Set whether an empty line should be printed before the :attr:`~cli_demo.options.Option.callback` of the :class:`~cli_demo.options.Option` instance is called.
Args:
option (str): The :attr:`~cli_demo.options.Option.name` used to register the :class:`~cli_demo.options.Option` instance.
newline (bool): Whether an empty line should be printed before :attr:`~cli_demo.options.Option.callback` is called.
Raises:
:class:`~cli_demo.exceptions.OptionNotFoundError`: If `option` does not exist in :attr:`~cli_demo.options.DemoOptions.registry`, or if its value is not an instance of :class:`~cli_demo.options.Option`.
"""
self[option].newline = bool(newline)
[docs] def get_desc(self, option):
"""Get the description of the :class:`~cli_demo.options.Option` instance.
Args:
option (str): The :attr:`~cli_demo.options.Option.name` used to register the :class:`~cli_demo.options.Option` instance.
Returns:
str: The :attr:`~cli_demo.options.Option.desc` attribute of the :class:`~cli_demo.options.Option` instance.
Raises:
:class:`~cli_demo.exceptions.OptionNotFoundError`: If `option` does not exist in :attr:`~cli_demo.options.DemoOptions.registry`, or if its value is not an instance of :class:`~cli_demo.options.Option`.
"""
return self[option].desc
[docs] def set_desc(self, option, desc):
"""Set the description of the :class:`~cli_demo.options.Option` instance.
Args:
option (str): The :attr:`~cli_demo.options.Option.name` used to register the :class:`~cli_demo.options.Option` instance.
desc (str): The description that should be printed in :meth:`~cli_demo.demo.Demo.print_options`.
Raises:
:class:`~cli_demo.exceptions.OptionNotFoundError`: If `option` does not exist in :attr:`~cli_demo.options.DemoOptions.registry`, or if its value is not an instance of :class:`~cli_demo.options.Option`.
"""
self[option].desc = str(desc)
[docs] def get_args(self, option):
"""Get the default arguments that will be used to call the :attr:`~cli_demo.options.Option.callback` of the :class:`~cli_demo.options.Option` instance.
Args:
option (str): The :attr:`~cli_demo.options.Option.name` used to register the :class:`~cli_demo.options.Option` instance.
Returns:
tuple: The :attr:`~cli_demo.options.Option.args` attribute of the :class:`~cli_demo.options.Option` instance.
Raises:
:class:`~cli_demo.exceptions.OptionNotFoundError`: If `option` does not exist in :attr:`~cli_demo.options.DemoOptions.registry`, or if its value is not an instance of :class:`~cli_demo.options.Option`.
"""
return self[option].args
[docs] def set_args(self, option, *args):
"""Set the default arguments that should be used to call the :attr:`~cli_demo.options.Option.callback` of the :class:`~cli_demo.options.Option` instance.
Args:
option (str): The :attr:`~cli_demo.options.Option.name` used to register the :class:`~cli_demo.options.Option` instance.
*args: The default arguments that should be used to call :attr:`~cli_demo.options.Option.callback` in :meth:`~cli_demo.options.Option.call`.
Raises:
:class:`~cli_demo.exceptions.OptionNotFoundError`: If `option` does not exist in :attr:`~cli_demo.options.DemoOptions.registry`, or if its value is not an instance of :class:`~cli_demo.options.Option`.
"""
self[option].args = tuple(args)
[docs] def get_kwargs(self, option):
"""Get the default keyword arguments that will be used to call the :attr:`~cli_demo.options.Option.callback` of the :class:`~cli_demo.options.Option` instance.
Args:
option (str): The :attr:`~cli_demo.options.Option.name` used to register the :class:`~cli_demo.options.Option` instance.
Returns:
dict: The :attr:`~cli_demo.options.Option.kwargs` attribute of the :class:`~cli_demo.options.Option` instance.
Raises:
:class:`~cli_demo.exceptions.OptionNotFoundError`: If `option` does not exist in :attr:`~cli_demo.options.DemoOptions.registry`, or if its value is not an instance of :class:`~cli_demo.options.Option`.
"""
return self[option].kwargs
[docs] def set_kwargs(self, option, **kwargs):
"""Set the default keyword arguments that should be used to call the :attr:`~cli_demo.options.Option.callback` of the :class:`~cli_demo.options.Option` instance.
Args:
option (str): The :attr:`~cli_demo.options.Option.name` used to register the :class:`~cli_demo.options.Option` instance.
**kwargs: The default keyword arguments that should be used to call :attr:`~cli_demo.options.Option.callback` in :meth:`~cli_demo.options.Option.call`.
Raises:
:class:`~cli_demo.exceptions.OptionNotFoundError`: If `option` does not exist in :attr:`~cli_demo.options.DemoOptions.registry`, or if its value is not an instance of :class:`~cli_demo.options.Option`.
"""
self[option].kwargs = dict(kwargs)
[docs] def copy(self):
"""Initialize a new copy of :class:`~cli_demo.options.DemoOptions`.
Returns:
An instance of :class:`~cli_demo.options.DemoOptions` with a deep copy of the :attr:`~cli_demo.options.DemoOptions.cache` and :attr:`~cli_demo.options.DemoOptions.registry` belonging to ``self``.
"""
new_options = DemoOptions()
for key_id, [opts, kw_opts] in self.cache.items():
new_options.cache[key_id] = [list(opts), dict(kw_opts)]
for name, option in self.registry.items():
new_options.registry[name] = option.copy()
return new_options