From ec52ca1d5502b856985b18147a70b5a9bdfe0273 Mon Sep 17 00:00:00 2001 From: Griatch Date: Tue, 19 Jun 2018 21:44:20 +0200 Subject: [PATCH] Testing obj conversion in profuncs --- evennia/prototypes/protfuncs.py | 33 ++++++++++++++++---------------- evennia/prototypes/prototypes.py | 23 ++++++++++++++++++++++ evennia/prototypes/tests.py | 2 ++ 3 files changed, 41 insertions(+), 17 deletions(-) diff --git a/evennia/prototypes/protfuncs.py b/evennia/prototypes/protfuncs.py index 5ecb4b5e7d..4c9d9a4a5f 100644 --- a/evennia/prototypes/protfuncs.py +++ b/evennia/prototypes/protfuncs.py @@ -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)] diff --git a/evennia/prototypes/prototypes.py b/evennia/prototypes/prototypes.py index 86230354b9..81bb4188a2 100644 --- a/evennia/prototypes/prototypes.py +++ b/evennia/prototypes/prototypes.py @@ -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"(? {}".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 diff --git a/evennia/prototypes/tests.py b/evennia/prototypes/tests.py index 36be5f4c6b..c49292bbf5 100644 --- a/evennia/prototypes/tests.py +++ b/evennia/prototypes/tests.py @@ -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):