Testing obj conversion in profuncs

This commit is contained in:
Griatch 2018-06-19 21:44:20 +02:00
parent 721cdb5ae0
commit ec52ca1d55
3 changed files with 41 additions and 17 deletions

View file

@ -248,27 +248,21 @@ def eval(*args, **kwargs):
if isinstance(struct, basestring):
# we must shield the string, otherwise it will be merged as a string and future
# literal_evals will pick up e.g. '2' as something that should be converted to a number
# literal_evas will pick up e.g. '2' as something that should be converted to a number
struct = '"{}"'.format(struct)
def _recursive_parse(val):
# an extra round of recursive parsing after literal_eval, to catch any
# escaped $$profuncs. This is commonly useful for object references.
if is_iter(val):
stype = type(val)
if stype == dict:
return {_recursive_parse(key): _recursive_parse(v) for key, v in val.items()}
return stype((_recursive_parse(v) for v in val))
return _PROTLIB.protfunc_parser(val)
# convert any #dbrefs to objects (also in nested structures)
struct = _PROTLIB.value_to_obj_or_any(struct)
return _recursive_parse(struct)
return struct
def _obj_search(return_list=False, *args, **kwargs):
def _obj_search(*args, **kwargs):
"Helper function to search for an object"
query = "".join(args)
session = kwargs.get("session", None)
return_list = kwargs.pop("return_list", False)
if not session:
raise ValueError("$obj called by Evennia without Session. This is not supported.")
@ -277,6 +271,8 @@ def _obj_search(return_list=False, *args, **kwargs):
raise ValueError("$obj requires a logged-in account session.")
targets = search.search_object(query)
print("targets: {}".format(targets))
if return_list:
retlist = []
for target in targets:
@ -287,11 +283,11 @@ def _obj_search(return_list=False, *args, **kwargs):
# single-match
if not targets:
raise ValueError("$obj: Query '{}' gave no matches.".format(query))
if targets.count() > 1:
if len(targets) > 1:
raise ValueError("$obj: Query '{query}' gave {nmatches} matches. Limit your "
"query or use $objlist instead.".format(
query=query, nmatches=targets.count()))
target = target[0]
query=query, nmatches=len(targets)))
target = targets[0]
if not target.access(account, target, 'control'):
raise ValueError("$obj: Obj {target}(#{dbref} cannot be added - "
"Account {account} does not have 'control' access.".format(
@ -305,7 +301,10 @@ def obj(*args, **kwargs):
Returns one Object searched globally by key, alias or #dbref. Error if more than one.
"""
return _obj_search(*args, **kwargs)
obj = _obj_search(return_list=False, *args, **kwargs)
if obj:
return "#{}".format(obj.id)
return "".join(args)
def objlist(*args, **kwargs):
@ -314,4 +313,4 @@ def objlist(*args, **kwargs):
Returns list with one or more Objects searched globally by key, alias or #dbref.
"""
return _obj_search(return_list=True, *args, **kwargs)
return ["#{}".format(obj.id) for obj in _obj_search(return_list=True, *args, **kwargs)]

View file

@ -5,6 +5,7 @@ Handling storage of prototypes, both database-based ones (DBPrototypes) and thos
"""
import re
from ast import literal_eval
from django.conf import settings
from evennia.scripts.scripts import DefaultScript
@ -26,6 +27,9 @@ _PROTOTYPE_TAG_META_CATEGORY = "db_prototype"
_PROT_FUNCS = {}
_RE_DBREF = re.compile(r"(?<!\$obj\()#[0-9]+")
class PermissionError(RuntimeError):
pass
@ -82,8 +86,13 @@ def protfunc_parser(value, available_functions=None, testing=False, **kwargs):
if not isinstance(value, basestring):
return value
available_functions = _PROT_FUNCS if available_functions is None else available_functions
# insert $obj(#dbref) for #dbref
value = _RE_DBREF.sub("$obj(\\1)", value)
result = inlinefuncs.parse_inlinefunc(
value, available_funcs=available_functions, testing=testing, **kwargs)
# at this point we have a string where all procfuncs were parsed
# print("parse_inlinefuncs(\"{}\", available_funcs={}) => {}".format(value, available_functions, result))
result = value_to_obj_or_any(result)
@ -102,10 +111,24 @@ def protfunc_parser(value, available_functions=None, testing=False, **kwargs):
# helper functions
def value_to_obj(value, force=True):
"Always convert value(s) to Object, or None"
stype = type(value)
if is_iter(value):
if stype == dict:
return {value_to_obj_or_any(key): value_to_obj_or_any(val) for key, val in value.iter()}
else:
return stype([value_to_obj_or_any(val) for val in value])
return dbid_to_obj(value, ObjectDB)
def value_to_obj_or_any(value):
"Convert value(s) to Object if possible, otherwise keep original value"
stype = type(value)
if is_iter(value):
if stype == dict:
return {value_to_obj_or_any(key): value_to_obj_or_any(val) for key, val in value.items()}
else:
return stype([value_to_obj_or_any(val) for val in value])
obj = dbid_to_obj(value, ObjectDB)
return obj if obj is not None else value

View file

@ -226,6 +226,8 @@ class TestProtFuncs(EvenniaTest):
self.assertEqual(protlib.protfunc_parser(
"$eval({'test': '1', 2:3, 3: $toint(3.5)})"), {'test': '1', 2: 3, 3: 3})
self.assertEqual(protlib.protfunc_parser("$obj(#1)", session=self.session), '#1')
class TestPrototypeStorage(EvenniaTest):