Add more work on OLC field structures.

This commit is contained in:
Griatch 2017-05-06 22:31:44 +02:00
parent e8a1daa526
commit 69d7362203

View file

@ -6,6 +6,9 @@ know what data to read and how to display it.
"""
from collections import deque
from evennia.utils.utils import to_str, to_unicode
from evennia.utils.olc import olc_utils
# from django.conf import settings
_OLC_VALIDATION_ERROR = """
@ -18,6 +21,22 @@ The reported error was
_LEN_HISTORY = 10 # settings.OLC_HISTORY_LENGTH
class InvalidActionError(RuntimeError):
"""
Raised when trying to perform a field action the field
does not support.
"""
pass
class ValidationError(RuntimeError):
"""
Raised when failing to validate new data being entered
into the field (from any source)
"""
pass
class OLCField(object):
"""
This is the parent for all OLC fields. This docstring acts
@ -31,10 +50,10 @@ class OLCField(object):
# used for displaying extra info in the OLC
label = "Empty field"
# initial value of field if not given
initial = None
default = None
# actions available on this field. Available actions
# are replace, edit, append, remove, clear, help
actions = ['replace', 'edit', 'remove', 'clear', 'help']
actions = ['replace', 'edit', 'clear', 'help']
def __init__(self, olcsession):
self.olcsession = olcsession
@ -43,7 +62,74 @@ class OLCField(object):
self._has_changed = False
def __repr__(self):
return self.display()
return to_str(self.display())
def __unicode__(self):
return to_unicode(self.display())
# perform actions
# TODO - include editor in check!
def do_replace(self, newval):
"""
Replace field value.
Args:
newval (any): New value to replace existing one.
Raises:
InvalidActionError: If replacing is not allowed.
"""
if 'replace' in self.actions:
self.value = newval
else:
raise InvalidActionError('Replace {value}->{newval}'.format(value=self.value, newval))
def can_edit(self):
"""
Check if we may edit.
Returns:
can_edit (bool): If we can edit or not.
"""
if 'edit' in self.actions:
return self.value
return False
def do_clear(self):
"""
Clear field back to default.
Returns:
default (any): The field'd default value, now set.
Raises:
InvalidActionError: If clearing is not allowed.
"""
if 'clear' in self.actions:
# don't validate this
object.__setattr__(self, 'value', self.default)
return self.value
else:
raise InvalidActionError('Clear')
def get_help(self):
"""
Get the help text for the field.
Returns:
help (str): Field help text.
Raises:
InvalidActionError: If help is not given for this field,
either becuase it's disallowed or unset.
"""
if 'help' not in self.actions or not self.__doc__:
raise InvalidActioNError('Help')
return self.__doc__
# storing data to the field in a history-aware way
@property
@ -60,8 +146,7 @@ class OLCField(object):
value = self.validate(value)
except Exception as err:
errtext = _OLC_VALIDATION_ERROR.format(fieldname=self.key, value=original_value, error=err)
self.olcsession.caller.msg(errtext)
return
raise ValidationError(errtxt)
if (self._value_history and isinstance(value, (basestring, bool, int, float)) and
self._value_history[0] == value):
# don't change/update history if re-adding the same thing
@ -104,7 +189,9 @@ class OLCField(object):
def from_entity(self, entity, **kwargs):
"""
Populate this field from an entity.
Populate this field by retrieving data from an entity.
All fields on a page will have this called, so must
be able to handle also incompatible entities.
Args:
entity (any): An object to use for
@ -124,7 +211,7 @@ class OLCField(object):
def validate(self, value, **kwargs):
"""
Validate/preprocess data to store in this field.
Validate/preprocess incoming data to store in this field.
Args:
value (any): An input value to
@ -187,7 +274,7 @@ class OLCLocationField(OLCField):
label = "The object's current location"
def validate(self, value):
return self.olcsession.search_by_string(value)
return olc_utils.search_by_string(self.olcsession, value)
def from_entity(self, entity, **kwargs):
self.value = entity.db_location
@ -208,7 +295,7 @@ class OLCHomeField(OLCField):
label = "The object's home location"
def validate(self, value):
return self.olcsession.search_by_string(value)
return olc_utils.search_by_string(self.olcsession, value)
def from_entity(self, entity, **kwargs):
self.value = entity.db_home
@ -216,6 +303,7 @@ class OLCHomeField(OLCField):
def to_prototype(self, prototype):
prototype['home'] = self.value
class OLCDestinationField(OLCField):
"""
An object's destination is usually not set unless the object
@ -229,7 +317,7 @@ class OLCDestinationField(OLCField):
label = "The object's (usually exit's) destination"
def validate(self, value):
return self.olcsession.search_by_string(value)
return olc_utils.search_by_string(self.olcsession, value)
def from_entity(self, entity, **kwargs):
self.value = entity.db_destination
@ -238,6 +326,7 @@ class OLCDestinationField(OLCField):
prototype['destination'] = self.value
# batch-setting aliases
class OLCAliasField(OLCField):
"""
Specify as a comma-separated list. Use quotes around the
@ -255,7 +344,7 @@ class OLCAliasField(OLCField):
actions = OLCField.actions + ['append']
def validate(self, value):
return split_by_comma(value)
return olc_utils.split_by_comma(value)
def from_entity(self, entity, **kwargs):
self.value = list(entity.db_aliases.all())
@ -264,6 +353,7 @@ class OLCAliasField(OLCField):
prototype['aliases'] = self.value
# batch-setting tags
class OLCTagField(OLCField):
"""
Specify as a comma-separated list of tagname or tagname:category.
@ -276,12 +366,12 @@ class OLCTagField(OLCField):
"""
key = 'Aliases'
required = False
label = "The object's (usually exit's) destination"
label = "Alternative ways to refer to this object."
actions = OLCField.actions + ['append']
def validate(self, value):
return [tagstr.split(':', 1) if ':' in tagstr else (tagstr, None)
for tagstr in split_by_comma(value)]
return [tuple(tagstr.split(':', 1)) if ':' in tagstr else (tagstr, None)
for tagstr in olc_utils.split_by_comma(value)]
def from_entity(self, entity, **kwargs):
self.value = entity.tags.all(return_key_and_category=True)
@ -289,3 +379,26 @@ class OLCTagField(OLCField):
def to_prototype(self, prototype):
prototype['tags'] = self.value
# batch-setting attributes
class OLCAttributeField(OLCField):
"""
Specify as a comma-separated list of attrname=value or attrname:category=value.
Attributes are arbitrary pieces of data attached to an object. They can
contain references to other objects as well as simple Python structures such
as lists and dicts.
"""
key = 'Attributes'
required = False
label = "Additional data attached to this object."
actions = OLCField.actions + ['append']
def validate(self, value):
return [tuple(lhs.split(':', 1) + [rhs]) if ':' in lhs else (lhs, None) + (rhs, )
for lhs, rhs in (attrstr.split('=', 1) if ':' in attrstr else ((attrstr, None),))
for attrstr in olc_utils.split_by_comma(value)]
def from_entity(self, entity, **kwargs):
self.value = entity.attributes.all