Fix unit tests

This commit is contained in:
Griatch 2018-03-18 12:53:38 +01:00
parent 6b383c863b
commit b75cd81eda
3 changed files with 62 additions and 50 deletions

View file

@ -14,8 +14,8 @@ from evennia.utils.utils import inherits_from, class_from_module, get_all_typecl
from evennia.utils.eveditor import EvEditor
from evennia.utils.evmore import EvMore
from evennia.utils.spawner import (spawn, search_prototype, list_prototypes,
store_prototype, build_metaproto, validate_prototype,
delete_prototype, PermissionError)
save_db_prototype, build_metaproto, validate_prototype,
delete_db_prototype, PermissionError)
from evennia.utils.ansi import raw
COMMAND_DEFAULT_CLASS = class_from_module(settings.COMMAND_DEFAULT_CLASS)
@ -1739,6 +1739,7 @@ class CmdTypeclass(COMMAND_DEFAULT_CLASS):
key = "@typeclass"
aliases = ["@type", "@parent", "@swap", "@update"]
switch_options = ("show", "examine", "update", "reset", "force", "list")
locks = "cmd:perm(typeclass) or perm(Builder)"
help_category = "Building"
@ -1749,7 +1750,6 @@ class CmdTypeclass(COMMAND_DEFAULT_CLASS):
if 'list' in self.switches:
tclasses = get_all_typeclasses()
print(list(tclasses.keys()))
contribs = [key for key in sorted(tclasses)
if key.startswith("evennia.contrib")] or ["<None loaded>"]
core = [key for key in sorted(tclasses)
@ -1764,7 +1764,7 @@ class CmdTypeclass(COMMAND_DEFAULT_CLASS):
" {game}").format(core="\n ".join(core),
contrib="\n ".join(contribs),
game="\n ".join(game))
caller.msg(string)
EvMore(caller, string, exit_on_lastpage=True)
return
if not self.args:
@ -2841,7 +2841,7 @@ class CmdSpawn(COMMAND_DEFAULT_CLASS):
"""
key = "@spawn"
switch_options = ("noloc", )
switch_options = ("noloc", "search", "list", "show", "save", "delete", "menu")
locks = "cmd:perm(spawn) or perm(Builder)"
help_category = "Building"
@ -2912,7 +2912,7 @@ class CmdSpawn(COMMAND_DEFAULT_CLASS):
tags = [tag.strip() for tag in tags.split(",")] if tags else None
EvMore(caller, unicode(list_prototypes(caller, key=key, tags=tags)),
exit_on_lastpage=True)
return
return
if 'show' in self.switches or 'examine' in self.switches:
# the argument is a key in this case (may be a partial key)
@ -2943,7 +2943,7 @@ class CmdSpawn(COMMAND_DEFAULT_CLASS):
caller.msg("|rDeletion cancelled.|n")
return
try:
success = delete_prototype(caller, self.args)
success = delete_db_prototype(caller, self.args)
except PermissionError as err:
caller.msg("|rError deleting:|R {}|n".format(err))
caller.msg("Deletion {}.".format(
@ -2961,10 +2961,12 @@ class CmdSpawn(COMMAND_DEFAULT_CLASS):
# handle lhs
parts = self.lhs.split(";", 3)
key, desc, tags, lockstring = "", "", [], ""
key, desc, tags, lockstring = (
"", "User-created prototype", ["user-created"],
"edit:id({}) or perm(Admin); use:all()".format(caller.id))
nparts = len(parts)
if nparts == 1:
key = parts.strip()
key = parts[0].strip()
elif nparts == 2:
key, desc = (part.strip() for part in parts)
elif nparts == 3:
@ -3000,7 +3002,7 @@ class CmdSpawn(COMMAND_DEFAULT_CLASS):
# all seems ok. Try to save.
try:
store_prototype(caller, key, prototype, desc=desc, tags=tags, locks=lockstring)
save_db_prototype(caller, key, prototype, desc=desc, tags=tags, locks=lockstring)
except PermissionError as err:
caller.msg("|rError saving:|R {}|n".format(err))
return
@ -3038,6 +3040,7 @@ class CmdSpawn(COMMAND_DEFAULT_CLASS):
metaproto = metaprotos[0]
if not caller.locks.check_lockstring(caller, metaproto.locks, access_type='use'):
caller.msg("You don't have access to use this prototype.")
print("spawning2 {}:{} - {}".format(self.cmdstring, self.args, prototype))
return
prototype = metaproto.prototype

View file

@ -27,6 +27,7 @@ from evennia.utils import ansi, utils
from evennia.server.sessionhandler import SESSIONS
from evennia import search_object
from evennia import DefaultObject, DefaultCharacter
from evennia.utils import spawner
# set up signal here since we are not starting the server
@ -390,8 +391,10 @@ class TestBuilding(CommandTest):
self.assertEqual(goblin.location, spawnLoc)
goblin.delete()
spawner.save_db_prototype(self.char1, "ball", {'key': 'Ball', 'prototype': 'GOBLIN'})
# Tests "@spawn <prototype_name>"
self.call(building.CmdSpawn(), "'BALL'", "Spawned Ball")
self.call(building.CmdSpawn(), "ball", "Spawned Ball")
ball = getObject(self, "Ball")
self.assertEqual(ball.location, self.char1.location)
self.assertIsInstance(ball, DefaultObject)
@ -416,6 +419,9 @@ class TestBuilding(CommandTest):
# test calling spawn with an invalid prototype.
self.call(building.CmdSpawn(), "'NO_EXIST'", "No prototype named 'NO_EXIST'")
# Test listing commands
self.call(building.CmdSpawn(), "/list", "| Key ")
class TestComms(CommandTest):

View file

@ -109,17 +109,17 @@ from django.conf import settings
from random import randint
import evennia
from evennia.objects.models import ObjectDB
from evennia.utils.utils import make_iter, all_from_module, dbid_to_obj
from evennia.utils.utils import make_iter, all_from_module, dbid_to_obj, is_iter
from collections import namedtuple, defaultdict
from collections import namedtuple
from evennia.scripts.scripts import DefaultScript
from evennia.utils.create import create_script
from evennia.utils.evtable import EvTable
_CREATE_OBJECT_KWARGS = ("key", "location", "home", "destination")
_READONLY_PROTOTYPES = {}
_READONLY_PROTOTYPE_MODULES = {}
_MODULE_PROTOTYPES = {}
_MODULE_PROTOTYPE_MODULES = {}
class PermissionError(RuntimeError):
@ -133,7 +133,7 @@ for mod in settings.PROTOTYPE_MODULES:
# internally we store as (key, desc, locks, tags, prototype_dict)
prots = [(key, prot) for key, prot in all_from_module(mod).items()
if prot and isinstance(prot, dict)]
_READONLY_PROTOTYPES.update(
_MODULE_PROTOTYPES.update(
{key.lower(): MetaProto(
key.lower(),
prot['prototype_desc'] if 'prototype_desc' in prot else mod,
@ -142,12 +142,12 @@ for mod in settings.PROTOTYPE_MODULES:
prot['prototype_tags']) if 'prototype_tags' in prot else ["base-prototype"]),
prot)
for key, prot in prots})
_READONLY_PROTOTYPE_MODULES.update({tup[0]: mod for tup in prots})
_MODULE_PROTOTYPE_MODULES.update({tup[0]: mod for tup in prots})
# Prototype storage mechanisms
class PersistentPrototype(DefaultScript):
class DbPrototype(DefaultScript):
"""
This stores a single prototype
"""
@ -161,10 +161,10 @@ def build_metaproto(key, desc, locks, tags, prototype):
Create a metaproto from combinant parts.
"""
return MetaProto(key, desc, make_iter(locks), tags, dict(prototype))
return MetaProto(key, desc, ";".join(locks) if is_iter(locks) else locks, tags, dict(prototype))
def store_prototype(caller, key, prototype, desc="", tags=None, locks="", delete=False):
def save_db_prototype(caller, key, prototype, desc="", tags=None, locks="", delete=False):
"""
Store a prototype persistently.
@ -176,7 +176,7 @@ def store_prototype(caller, key, prototype, desc="", tags=None, locks="", delete
prototype (dict): Prototype dict.
desc (str, optional): Description of prototype, to use in listing.
tags (list, optional): Tag-strings to apply to prototype. These are always
applied with the 'persistent_prototype' category.
applied with the 'db_prototype' category.
locks (str, optional): Locks to apply to this prototype. Used locks
are 'use' and 'edit'
delete (bool, optional): Delete an existing prototype identified by 'key'.
@ -192,14 +192,14 @@ def store_prototype(caller, key, prototype, desc="", tags=None, locks="", delete
key_orig = key
key = key.lower()
locks = locks if locks else "use:all();edit:id({}) or perm(Admin)".format(caller.id)
tags = [(tag, "persistent_prototype") for tag in make_iter(tags)]
tags = [(tag, "db_prototype") for tag in make_iter(tags)]
if key in _READONLY_PROTOTYPES:
mod = _READONLY_PROTOTYPE_MODULES.get(key, "N/A")
if key in _MODULE_PROTOTYPES:
mod = _MODULE_PROTOTYPE_MODULES.get(key, "N/A")
raise PermissionError("{} is a read-only prototype "
"(defined as code in {}).".format(key_orig, mod))
stored_prototype = PersistentPrototype.objects.filter(db_key=key)
stored_prototype = DbPrototype.objects.filter(db_key=key)
if stored_prototype:
# edit existing prototype
@ -227,12 +227,12 @@ def store_prototype(caller, key, prototype, desc="", tags=None, locks="", delete
else:
# create a new prototype
stored_prototype = create_script(
PersistentPrototype, key=key, desc=desc, persistent=True,
DbPrototype, key=key, desc=desc, persistent=True,
locks=locks, tags=tags, attributes=[("prototype", prototype)])
return stored_prototype
def delete_prototype(caller, key):
def delete_db_prototype(caller, key):
"""
Delete a stored prototype
@ -245,21 +245,21 @@ def delete_prototype(caller, key):
PermissionError: If 'edit' lock was not passed.
"""
return store_prototype(caller, key, None, delete=True)
return save_db_prototype(caller, key, None, delete=True)
def search_persistent_prototype(key=None, tags=None, return_metaprotos=False):
def search_db_prototype(key=None, tags=None, return_metaprotos=False):
"""
Find persistent (database-stored) prototypes based on key and/or tags.
Kwargs:
key (str): An exact or partial key to query for.
tags (str or list): Tag key or keys to query for. These
will always be applied with the 'persistent_protototype'
will always be applied with the 'db_protototype'
tag category.
return_metaproto (bool): Return results as metaprotos.
Return:
matches (queryset or list): All found PersistentPrototypes. If `return_metaprotos`
matches (queryset or list): All found DbPrototypes. If `return_metaprotos`
is set, return a list of MetaProtos.
Note:
@ -269,22 +269,22 @@ def search_persistent_prototype(key=None, tags=None, return_metaprotos=False):
if tags:
# exact match on tag(s)
tags = make_iter(tags)
tag_categories = ["persistent_prototype" for _ in tags]
matches = PersistentPrototype.objects.get_by_tag(tags, tag_categories)
tag_categories = ["db_prototype" for _ in tags]
matches = DbPrototype.objects.get_by_tag(tags, tag_categories)
else:
matches = PersistentPrototype.objects.all()
matches = DbPrototype.objects.all()
if key:
# exact or partial match on key
matches = matches.filter(db_key=key) or matches.filter(db_key__icontains=key)
if return_metaprotos:
return [build_metaproto(match.key, match.desc, match.locks.all(),
match.tags.get(category="persistent_prototype", return_list=True),
match.tags.get(category="db_prototype", return_list=True),
match.attributes.get("prototype"))
for match in matches]
return matches
def search_readonly_prototype(key=None, tags=None):
def search_module_prototype(key=None, tags=None):
"""
Find read-only prototypes, defined in modules.
@ -301,10 +301,10 @@ def search_readonly_prototype(key=None, tags=None):
if tags:
# use tags to limit selection
tagset = set(tags)
matches = {key: metaproto for key, metaproto in _READONLY_PROTOTYPES.items()
matches = {key: metaproto for key, metaproto in _MODULE_PROTOTYPES.items()
if tagset.intersection(metaproto.tags)}
else:
matches = _READONLY_PROTOTYPES
matches = _MODULE_PROTOTYPES
if key:
if key in matches:
@ -324,7 +324,7 @@ def search_prototype(key=None, tags=None, return_meta=True):
Kwargs:
key (str): An exact or partial key to query for.
tags (str or list): Tag key or keys to query for. These
will always be applied with the 'persistent_protototype'
will always be applied with the 'db_protototype'
tag category.
return_meta (bool): If False, only return prototype dicts, if True
return MetaProto namedtuples including prototype meta info
@ -340,15 +340,15 @@ def search_prototype(key=None, tags=None, return_meta=True):
be found.
"""
readonly_prototypes = search_readonly_prototype(key, tags)
persistent_prototypes = search_persistent_prototype(key, tags, return_metaprotos=True)
module_prototypes = search_module_prototype(key, tags)
db_prototypes = search_db_prototype(key, tags, return_metaprotos=True)
matches = persistent_prototypes + readonly_prototypes
matches = db_prototypes + module_prototypes
if len(matches) > 1 and key:
key = key.lower()
# avoid duplicates if an exact match exist between the two types
filter_matches = [mta for mta in matches if mta.key == key]
if len(filter_matches) < len(matches):
if filter_matches and len(filter_matches) < len(matches):
matches = filter_matches
if not return_meta:
@ -369,8 +369,7 @@ def get_protparents():
return {metaproto.key: metaproto.prototype for metaproto in metaprotos}
def list_prototypes(caller, key=None, tags=None, show_non_use=False,
show_non_edit=True, sort_tree=True):
def list_prototypes(caller, key=None, tags=None, show_non_use=False, show_non_edit=True):
"""
Collate a list of found prototypes based on search criteria and access.
@ -380,22 +379,27 @@ def list_prototypes(caller, key=None, tags=None, show_non_use=False,
tags (str or list, optional): Tag key or keys to query for.
show_non_use (bool, optional): Show also prototypes the caller may not use.
show_non_edit (bool, optional): Show also prototypes the caller may not edit.
sort_tree (bool, optional): Order prototypes by inheritance tree.
Returns:
table (EvTable or None): An EvTable representation of the prototypes. None
if no prototypes were found.
"""
# this allows us to pass lists of empty strings
tags = [tag for tag in make_iter(tags) if tag]
# get metaprotos for readonly and db-based prototypes
metaprotos = search_readonly_prototype(key, tags)
metaprotos += search_persistent_prototype(key, tags, return_metaprotos=True)
metaprotos = search_module_prototype(key, tags)
metaprotos += search_db_prototype(key, tags, return_metaprotos=True)
# get use-permissions of readonly attributes (edit is always False)
prototypes = [
(metaproto.key,
metaproto.desc,
("{}/N".format('Y'
if caller.locks.check_lockstring(caller, metaproto.locks, access_type='use') else 'N')),
if caller.locks.check_lockstring(
caller,
metaproto.locks,
access_type='use') else 'N')),
",".join(metaproto.tags))
for metaproto in sorted(metaprotos, key=lambda o: o.key)]
@ -642,7 +646,6 @@ def spawn(*prototypes, **kwargs):
return _batch_create_object(*objsparams)
# Testing
if __name__ == "__main__":