Cleanup of options methods, callables

This commit is contained in:
Griatch 2019-04-14 17:01:32 +02:00
parent 6ddc98a947
commit f2d9391827
3 changed files with 90 additions and 58 deletions

View file

@ -35,32 +35,34 @@ class Container(object):
""" """
self.loaded_data = None self.loaded_data = None
def _load_data(self): def load_data(self):
""" """
Delayed import to avoid eventual circular imports from inside Delayed import to avoid eventual circular imports from inside
the storage modules. the storage modules.
""" """
if self.loaded_data is None: if self.loaded_data is None:
self.loaded_data = {}
for module in self.storage_modules: for module in self.storage_modules:
self.loaded_data.update(callables_from_module(module)) self.loaded_data.update(callables_from_module(module))
def __getattr__(self, key): def __getattr__(self, key):
self._load_data() return self.get(key)
return self.loaded_data.get(key)
def get(self, key): def get(self, key, default=None):
""" """
Retrive data by key (in case of not knowing it beforehand). Retrive data by key (in case of not knowing it beforehand).
Args: Args:
key (str): The name of the script. key (str): The name of the script.
default (any, optional): Value to return if key is not found.
Returns: Returns:
any (any): The data loaded on this container. any (any): The data loaded on this container.
""" """
return self.__getattr__(key) self.load_data()
return self.loaded_data.get(key, default)
def all(self): def all(self):
""" """
@ -70,7 +72,7 @@ class Container(object):
scripts (list): All global script objects stored on the container. scripts (list): All global script objects stored on the container.
""" """
self._load_data() self.load_data()
return list(self.loaded_data.values()) return list(self.loaded_data.values())
@ -121,12 +123,7 @@ class GlobalScriptContainer(Container):
self.script_storage = {} self.script_storage = {}
self.typeclass_storage = None self.typeclass_storage = None
def __getattr__(self, key): def load_data(self):
if key not in self.loaded_data:
return None
return self.script_storage.get(key) or self._load_script(key)
def _load_data(self):
""" """
This delayed import avoids trying to load Scripts before they are This delayed import avoids trying to load Scripts before they are
initialized. initialized.
@ -144,7 +141,7 @@ class GlobalScriptContainer(Container):
def _load_script(self, key): def _load_script(self, key):
self._load_data() self.load_data()
typeclass = self.typeclass_storage[key] typeclass = self.typeclass_storage[key]
found = typeclass.objects.filter(db_key=key).first() found = typeclass.objects.filter(db_key=key).first()
@ -175,6 +172,23 @@ class GlobalScriptContainer(Container):
self.script_storage[key] = found self.script_storage[key] = found
return found return found
def get(self, key, default=None):
"""
Retrive data by key (in case of not knowing it beforehand).
Args:
key (str): The name of the script.
default (any, optional): Value to return if key is not found
at all on this container (i.e it cannot be loaded at all).
Returns:
any (any): The data loaded on this container.
"""
if key not in self.loaded_data:
return default
return self.script_storage.get(key) or self._load_script(key)
def all(self): def all(self):
""" """
Get all scripts. Get all scripts.

View file

@ -3,6 +3,7 @@ from evennia import logger as _log
from evennia.utils.ansi import ANSIString as _ANSI from evennia.utils.ansi import ANSIString as _ANSI
from evennia.utils.validatorfuncs import _TZ_DICT from evennia.utils.validatorfuncs import _TZ_DICT
from evennia.utils.containers import VALIDATOR_FUNCS from evennia.utils.containers import VALIDATOR_FUNCS
from evennia.utils.utils import crop
class BaseOption(object): class BaseOption(object):
@ -22,7 +23,11 @@ class BaseOption(object):
validator_key = '' validator_key = ''
def __str__(self): def __str__(self):
return self.key return "<Option {key}: {value}>".format(
key=self.key, value=crop(str(self.value), width=10))
def __repr__(self):
return str(self)
def __init__(self, handler, key, description, default, save_data=None): def __init__(self, handler, key, description, default, save_data=None):
""" """
@ -163,6 +168,10 @@ class BaseOption(object):
""" """
Renders the Option's value as something pretty to look at. Renders the Option's value as something pretty to look at.
Kwargs:
any (any): These are options passed by the caller to potentially
customize display dynamically.
Returns: Returns:
str: How the stored value should be projected to users (e.g. a raw str: How the stored value should be projected to users (e.g. a raw
timedelta is pretty ugly). timedelta is pretty ugly).
@ -171,6 +180,7 @@ class BaseOption(object):
return self.value return self.value
# Option classes
class Text(BaseOption): class Text(BaseOption):

View file

@ -4,13 +4,12 @@ from evennia.utils.containers import OPTION_CLASSES
class OptionHandler(object): class OptionHandler(object):
""" """
This is a generic Option handler meant for Typed Objects - anything that implements AttributeHandler. This is a generic Option handler meant for Typed Objects - anything that
implements AttributeHandler. Retrieve options eithers as properties on
this handler or by using the .get method.
It uses a dictionary to store-and-cache frequently used settings such as colors for borders or an This is used for Account.options but it could be used by Scripts or Objects
account's timezone. just as easily. All it needs to be provided is an options_dict.
This is used for Account.options but it could be used by Scripts or Objects just as easily. All
it needs to be provided is an options_dict.
""" """
def __init__(self, obj, options_dict=None, save_category=None): def __init__(self, obj, options_dict=None, save_category=None):
@ -18,60 +17,70 @@ class OptionHandler(object):
Initialize an OptionHandler. Initialize an OptionHandler.
Args: Args:
obj (TypedObject): The Typed Object this sits on. Obj MUST implement the Evennia AttributeHandler obj (TypedObject): The Typed Object this sits on. Obj MUST
or this will barf. implement the Evennia AttributeHandler or this will barf.
options_dict (dict): A dictionary of option keys, where the values are options. The format of those options_dict (dict): A dictionary of option keys, where the values
tuples is: ('key', "Description to show", 'option_type', <default value>) are options. The format of those tuples is: ('key', "Description to
save_category (str): The Options data will be stored to this Attribute category on obj. show", 'option_type', <default value>)
save_category (str): The Options data will be stored to this
Attribute category on obj.
""" """
if not options_dict: if not options_dict:
options_dict = dict() options_dict = {}
self.options_dict = options_dict self.options_dict = options_dict
self.save_category = save_category self.save_category = save_category
self.obj = obj self.obj = obj
# This dictionary stores the in-memory Options by their key. Values are the Option objects. # This dictionary stores the in-memory Options by their key. Values are the Option objects.
self.options = dict() self.options = {}
# We use lazy-loading of each Option when it's called for, but it's good to have the save data # We use lazy-loading of each Option when it's called for, but it's
# on hand. # good to have the save data on hand.
self.save_data = {s.key: s.value for s in obj.attributes.get(category=save_category, self.save_data = {s.key: s.value for s in obj.attributes.get(
return_list=True, return_obj=True) if s} category=save_category, return_list=True, return_obj=True) if s}
def __getitem__(self, item): def __getattr__(self, key):
""" return self.get(key).value
Shortcut to self.get(item) used as a different syntax. This entire object is
essentially a dictionary of option_key -> value.
Args: def get(self, key, return_obj=False):
item (str): The Key of the item to get.
Returns:
The Option's value.
"""
return self.get(item).value
def get(self, item, return_obj=False):
""" """
Retrieves an Option stored in the handler. Will load it if it doesn't exist. Retrieves an Option stored in the handler. Will load it if it doesn't exist.
Args: Args:
item (str): The key to retrieve. key (str): The option key to retrieve.
return_obj (bool): If True, returns the actual option object instead of its value. return_obj (bool, optional): If True, returns the actual option
object instead of its value.
Returns: Returns:
An option value (varies) or the Option itself. option_value (any or Option): An option value the Option itself.
Raises:
KeyError: If option is not defined.
""" """
if item not in self.options_dict: if key not in self.options_dict:
raise KeyError("Option not found!") raise KeyError("Option not found!")
if item in self.options: if key in self.options:
op_found = self.options[item] op_found = self.options[key]
else: else:
op_found = self._load_option(item) op_found = self._load_option(key)
if return_obj: if return_obj:
return op_found return op_found
return op_found.value return op_found.value
def all(self, return_objs=False):
"""
Get all options defined on this handler.
Args:
return_objs (bool, optional): Return the actual Option objects rather
than their values.
Returns:
all_options (dict): All options on this handler, either `{key: value}`
or `{key: <Option>}` if `return_objs` is `True`.
"""
return [self.get(key, return_obj=return_objs) for key in self.options_dict]
def _load_option(self, key): def _load_option(self, key):
""" """
Loads option on-demand if it has not been loaded yet. Loads option on-demand if it has not been loaded yet.
@ -82,10 +91,10 @@ class OptionHandler(object):
Returns: Returns:
""" """
option_def = self.options_dict[key] desc, clsname, default_val = self.options_dict[key]
save_data = self.save_data.get(key, None) save_data = self.save_data.get(key, None)
self.obj.msg(save_data) self.obj.msg(save_data)
loaded_option = OPTION_CONTAINER[option_def[1]](self, key, option_def[0], option_def[2], save_data) loaded_option = OPTION_CLASSES.get(clsname)(self, key, desc, default_val, save_data)
self.options[key] = loaded_option self.options[key] = loaded_option
return loaded_option return loaded_option
@ -96,6 +105,8 @@ class OptionHandler(object):
Args: Args:
option (str): The key of an option that can be changed. Allows partial matching. option (str): The key of an option that can be changed. Allows partial matching.
value (str): The value that should be checked, coerced, and stored. value (str): The value that should be checked, coerced, and stored.
kwargs (any, optional): These are passed into the Option's validation function,
save function and display function and allows to customize either.
Returns: Returns:
New value New value
@ -110,7 +121,4 @@ class OptionHandler(object):
found = found[0] found = found[0]
op = self.get(found, return_obj=True) op = self.get(found, return_obj=True)
op.set(value, **kwargs) op.set(value, **kwargs)
return op.display() return op.display(**kwargs)