More work on unittests, still issues
This commit is contained in:
parent
706ed47ccc
commit
a721889fc1
3 changed files with 56 additions and 69 deletions
|
|
@ -2795,17 +2795,17 @@ class CmdSpawn(COMMAND_DEFAULT_CLASS):
|
||||||
spawn objects from prototype
|
spawn objects from prototype
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
@spawn[/noloc] <prototype_name>
|
@spawn[/noloc] <prototype_key>
|
||||||
@spawn[/noloc] <prototype_dict>
|
@spawn[/noloc] <prototype_dict>
|
||||||
|
|
||||||
@spawn/search [key][;tag[,tag]]
|
@spawn/search [prototype_keykey][;tag[,tag]]
|
||||||
@spawn/list [tag, tag]
|
@spawn/list [tag, tag, ...]
|
||||||
@spawn/show [<key>]
|
@spawn/show [<prototype_key>]
|
||||||
@spawn/update <key>
|
@spawn/update <prototype_key>
|
||||||
|
|
||||||
@spawn/save <key>[;desc[;tag,tag[,...][;lockstring]]] = <prototype_dict>
|
@spawn/save <prototype_dict>
|
||||||
@spawn/menu [<key>]
|
@spawn/edit [<prototype_key>]
|
||||||
@olc - equivalent to @spawn/menu
|
@olc - equivalent to @spawn/edit
|
||||||
|
|
||||||
Switches:
|
Switches:
|
||||||
noloc - allow location to be None if not specified explicitly. Otherwise,
|
noloc - allow location to be None if not specified explicitly. Otherwise,
|
||||||
|
|
@ -2819,7 +2819,7 @@ class CmdSpawn(COMMAND_DEFAULT_CLASS):
|
||||||
them with latest version of given prototype. If given with /save,
|
them with latest version of given prototype. If given with /save,
|
||||||
will auto-update all objects with the old version of the prototype
|
will auto-update all objects with the old version of the prototype
|
||||||
without asking first.
|
without asking first.
|
||||||
menu, olc - create/manipulate prototype in a menu interface.
|
edit, olc - create/manipulate prototype in a menu interface.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
@spawn GOBLIN
|
@spawn GOBLIN
|
||||||
|
|
@ -2827,10 +2827,11 @@ class CmdSpawn(COMMAND_DEFAULT_CLASS):
|
||||||
@spawn/save {"key": "grunt", prototype: "goblin"};;mobs;edit:all()
|
@spawn/save {"key": "grunt", prototype: "goblin"};;mobs;edit:all()
|
||||||
|
|
||||||
Dictionary keys:
|
Dictionary keys:
|
||||||
|wprototype |n - name of parent prototype to use. Can be a list for
|
|wprototype_parent |n - name of parent prototype to use. Required if typeclass is
|
||||||
multiple inheritance (inherits left to right)
|
not set. Can be a path or a list for multiple inheritance (inherits
|
||||||
|
left to right). If set one of the parents must have a typeclass.
|
||||||
|
|wtypeclass |n - string. Required if prototype_parent is not set.
|
||||||
|wkey |n - string, the main object identifier
|
|wkey |n - string, the main object identifier
|
||||||
|wtypeclass |n - string, if not set, will use settings.BASE_OBJECT_TYPECLASS
|
|
||||||
|wlocation |n - this should be a valid object or #dbref
|
|wlocation |n - this should be a valid object or #dbref
|
||||||
|whome |n - valid object or #dbref
|
|whome |n - valid object or #dbref
|
||||||
|wdestination|n - only valid for exits (object or dbref)
|
|wdestination|n - only valid for exits (object or dbref)
|
||||||
|
|
@ -2875,7 +2876,8 @@ class CmdSpawn(COMMAND_DEFAULT_CLASS):
|
||||||
string = ("{}\n|RCritical Python syntax error in argument. Only primitive "
|
string = ("{}\n|RCritical Python syntax error in argument. Only primitive "
|
||||||
"Python structures are allowed. \nYou also need to use correct "
|
"Python structures are allowed. \nYou also need to use correct "
|
||||||
"Python syntax. Remember especially to put quotes around all "
|
"Python syntax. Remember especially to put quotes around all "
|
||||||
"strings inside lists and dicts.|n".format(err))
|
"strings inside lists and dicts.|n For more advanced uses, embed "
|
||||||
|
"inline functions in the strings.".format(err))
|
||||||
else:
|
else:
|
||||||
string = "Expected {}, got {}.".format(expect, type(prototype))
|
string = "Expected {}, got {}.".format(expect, type(prototype))
|
||||||
self.caller.msg(string)
|
self.caller.msg(string)
|
||||||
|
|
@ -2896,9 +2898,9 @@ class CmdSpawn(COMMAND_DEFAULT_CLASS):
|
||||||
def _search_show_prototype(query, prototypes=None):
|
def _search_show_prototype(query, prototypes=None):
|
||||||
# prototype detail
|
# prototype detail
|
||||||
if not prototypes:
|
if not prototypes:
|
||||||
prototypes = spawner.search_prototype(key=query)
|
prototypes = protlib.search_prototype(key=query)
|
||||||
if prototypes:
|
if prototypes:
|
||||||
return "\n".join(spawner.prototype_to_str(prot) for prot in prototypes)
|
return "\n".join(protlib.prototype_to_str(prot) for prot in prototypes)
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
@ -2947,64 +2949,36 @@ class CmdSpawn(COMMAND_DEFAULT_CLASS):
|
||||||
|
|
||||||
if 'list' in self.switches:
|
if 'list' in self.switches:
|
||||||
# for list, all optional arguments are tags
|
# for list, all optional arguments are tags
|
||||||
|
# import pudb; pudb.set_trace()
|
||||||
|
|
||||||
EvMore(caller, unicode(protlib.list_prototypes(caller,
|
EvMore(caller, unicode(protlib.list_prototypes(caller,
|
||||||
tags=self.lhslist)), exit_on_lastpage=True)
|
tags=self.lhslist)), exit_on_lastpage=True)
|
||||||
return
|
return
|
||||||
|
|
||||||
if 'save' in self.switches:
|
if 'save' in self.switches:
|
||||||
# store a prototype to the database store
|
# store a prototype to the database store
|
||||||
if not self.args or not self.rhs:
|
if not self.args:
|
||||||
caller.msg(
|
caller.msg(
|
||||||
"Usage: @spawn/save <key>[;desc[;tag,tag[,...][;lockstring]]] = <prototype_dict>")
|
"Usage: @spawn/save <key>[;desc[;tag,tag[,...][;lockstring]]] = <prototype_dict>")
|
||||||
return
|
return
|
||||||
|
|
||||||
# handle lhs
|
|
||||||
parts = self.lhs.split(";", 3)
|
|
||||||
nparts = len(parts)
|
|
||||||
if nparts == 1:
|
|
||||||
key = parts[0].strip()
|
|
||||||
elif nparts == 2:
|
|
||||||
key, desc = (part.strip() for part in parts)
|
|
||||||
elif nparts == 3:
|
|
||||||
key, desc, tags = (part.strip() for part in parts)
|
|
||||||
tags = [tag.strip().lower() for tag in tags.split(",") if tag]
|
|
||||||
else:
|
|
||||||
# lockstrings can itself contain ;
|
|
||||||
key, desc, tags, lockstring = (part.strip() for part in parts)
|
|
||||||
tags = [tag.strip().lower() for tag in tags.split(",") if tag]
|
|
||||||
if not key:
|
|
||||||
caller.msg("The prototype must have a key.")
|
|
||||||
return
|
|
||||||
if not desc:
|
|
||||||
desc = "User-created prototype"
|
|
||||||
if not tags:
|
|
||||||
tags = ["user"]
|
|
||||||
if not lockstring:
|
|
||||||
lockstring = "edit:id({}) or perm(Admin); use:all()".format(caller.id)
|
|
||||||
|
|
||||||
is_valid, err = caller.locks.validate(lockstring)
|
|
||||||
if not is_valid:
|
|
||||||
caller.msg("|rLock error|n: {}".format(err))
|
|
||||||
return
|
|
||||||
|
|
||||||
# handle rhs:
|
# handle rhs:
|
||||||
prototype = _parse_prototype(self.rhs)
|
prototype = _parse_prototype(self.lhs.strip())
|
||||||
if not prototype:
|
if not prototype:
|
||||||
return
|
return
|
||||||
|
|
||||||
# inject the prototype_* keys into the prototype to save
|
|
||||||
prototype['prototype_key'] = prototype.get('prototype_key', key)
|
|
||||||
prototype['prototype_desc'] = prototype.get('prototype_desc', desc)
|
|
||||||
prototype['prototype_tags'] = prototype.get('prototype_tags', tags)
|
|
||||||
prototype['prototype_locks'] = prototype.get('prototype_locks', lockstring)
|
|
||||||
|
|
||||||
# present prototype to save
|
# present prototype to save
|
||||||
new_matchstring = _search_show_prototype("", prototypes=[prototype])
|
new_matchstring = _search_show_prototype("", prototypes=[prototype])
|
||||||
string = "|yCreating new prototype:|n\n{}".format(new_matchstring)
|
string = "|yCreating new prototype:|n\n{}".format(new_matchstring)
|
||||||
question = "\nDo you want to continue saving? [Y]/N"
|
question = "\nDo you want to continue saving? [Y]/N"
|
||||||
|
|
||||||
|
prototype_key = prototype.get("prototype_key")
|
||||||
|
if not prototype_key:
|
||||||
|
caller.msg("\n|yTo save a prototype it must have the 'prototype_key' set.")
|
||||||
|
return
|
||||||
|
|
||||||
# check for existing prototype,
|
# check for existing prototype,
|
||||||
old_matchstring = _search_show_prototype(key)
|
old_matchstring = _search_show_prototype(prototype_key)
|
||||||
|
|
||||||
if old_matchstring:
|
if old_matchstring:
|
||||||
string += "\n|yExisting saved prototype found:|n\n{}".format(old_matchstring)
|
string += "\n|yExisting saved prototype found:|n\n{}".format(old_matchstring)
|
||||||
|
|
@ -3017,14 +2991,10 @@ class CmdSpawn(COMMAND_DEFAULT_CLASS):
|
||||||
|
|
||||||
# all seems ok. Try to save.
|
# all seems ok. Try to save.
|
||||||
try:
|
try:
|
||||||
prot = spawner.save_db_prototype(
|
prot = protlib.save_prototype(**prototype)
|
||||||
caller, key, prototype, desc=desc, tags=tags, locks=lockstring)
|
|
||||||
if not prot:
|
if not prot:
|
||||||
caller.msg("|rError saving:|R {}.|n".format(key))
|
caller.msg("|rError saving:|R {}.|n".format(key))
|
||||||
return
|
return
|
||||||
prot.locks.append("edit", "perm(Admin)")
|
|
||||||
if not prot.locks.get("use"):
|
|
||||||
prot.locks.add("use:all()")
|
|
||||||
except PermissionError as err:
|
except PermissionError as err:
|
||||||
caller.msg("|rError saving:|R {}|n".format(err))
|
caller.msg("|rError saving:|R {}|n".format(err))
|
||||||
return
|
return
|
||||||
|
|
|
||||||
|
|
@ -360,6 +360,7 @@ class TestBuilding(CommandTest):
|
||||||
# check that it exists in the process.
|
# check that it exists in the process.
|
||||||
query = search_object(objKeyStr)
|
query = search_object(objKeyStr)
|
||||||
commandTest.assertIsNotNone(query)
|
commandTest.assertIsNotNone(query)
|
||||||
|
commandTest.assertTrue(bool(query))
|
||||||
obj = query[0]
|
obj = query[0]
|
||||||
commandTest.assertIsNotNone(obj)
|
commandTest.assertIsNotNone(obj)
|
||||||
return obj
|
return obj
|
||||||
|
|
@ -368,18 +369,20 @@ class TestBuilding(CommandTest):
|
||||||
self.call(building.CmdSpawn(), " ", "Usage: @spawn")
|
self.call(building.CmdSpawn(), " ", "Usage: @spawn")
|
||||||
|
|
||||||
# Tests "@spawn <prototype_dictionary>" without specifying location.
|
# Tests "@spawn <prototype_dictionary>" without specifying location.
|
||||||
|
with mock.patch('evennia.commands.default.func', return_value=iter(['y'])) as mock_iter:
|
||||||
self.call(building.CmdSpawn(),
|
self.call(building.CmdSpawn(),
|
||||||
"{'prototype_key': 'testprot', 'key':'goblin', "
|
"/save {'prototype_key': 'testprot', 'key':'Test Char', "
|
||||||
"'typeclass':'evennia.DefaultCharacter'}", "Spawned goblin")
|
"'typeclass':'evennia.objects.objects.DefaultCharacter'}", "")
|
||||||
goblin = getObject(self, "goblin")
|
mock_iter.assert_called()
|
||||||
|
|
||||||
# Tests that the spawned object's type is a DefaultCharacter.
|
self.call(building.CmdSpawn(), "/list", "foo")
|
||||||
self.assertIsInstance(goblin, DefaultCharacter)
|
|
||||||
|
|
||||||
|
self.call(building.CmdSpawn(), 'testprot', "Spawned Test Char")
|
||||||
# Tests that the spawned object's location is the same as the caharacter's location, since
|
# Tests that the spawned object's location is the same as the caharacter's location, since
|
||||||
# we did not specify it.
|
# we did not specify it.
|
||||||
self.assertEqual(goblin.location, self.char1.location)
|
testchar = getObject(self, "Test Char")
|
||||||
goblin.delete()
|
self.assertEqual(testchar.location, self.char1.location)
|
||||||
|
testchar.delete()
|
||||||
|
|
||||||
# Test "@spawn <prototype_dictionary>" with a location other than the character's.
|
# Test "@spawn <prototype_dictionary>" with a location other than the character's.
|
||||||
spawnLoc = self.room2
|
spawnLoc = self.room2
|
||||||
|
|
@ -389,10 +392,13 @@ class TestBuilding(CommandTest):
|
||||||
spawnLoc = self.room1
|
spawnLoc = self.room1
|
||||||
|
|
||||||
self.call(building.CmdSpawn(),
|
self.call(building.CmdSpawn(),
|
||||||
"{'prototype_key':'GOBLIN', 'key':'goblin', 'location':'%s'}"
|
"{'prototype_key':'GOBLIN', 'typeclass':'evennia.objects.objects.DefaultCharacter', "
|
||||||
% spawnLoc.dbref, "Spawned goblin")
|
"'key':'goblin', 'location':'%s'}" % spawnLoc.dbref, "Spawned goblin")
|
||||||
goblin = getObject(self, "goblin")
|
goblin = getObject(self, "goblin")
|
||||||
|
# Tests that the spawned object's type is a DefaultCharacter.
|
||||||
|
self.assertIsInstance(goblin, DefaultCharacter)
|
||||||
self.assertEqual(goblin.location, spawnLoc)
|
self.assertEqual(goblin.location, spawnLoc)
|
||||||
|
|
||||||
goblin.delete()
|
goblin.delete()
|
||||||
|
|
||||||
protlib.create_prototype(**{'key': 'Ball', 'prototype': 'GOBLIN', 'prototype_key': 'testball'})
|
protlib.create_prototype(**{'key': 'Ball', 'prototype': 'GOBLIN', 'prototype_key': 'testball'})
|
||||||
|
|
|
||||||
|
|
@ -506,7 +506,7 @@ def list_prototypes(caller, key=None, tags=None, show_non_use=False, show_non_ed
|
||||||
",".join(ptags)))
|
",".join(ptags)))
|
||||||
|
|
||||||
if not display_tuples:
|
if not display_tuples:
|
||||||
return None
|
return ""
|
||||||
|
|
||||||
table = []
|
table = []
|
||||||
width = 78
|
width = 78
|
||||||
|
|
@ -607,3 +607,14 @@ def validate_prototype(prototype, protkey=None, protparents=None,
|
||||||
raise RuntimeError("Error: " + "\nError: ".join(_flags['errors']))
|
raise RuntimeError("Error: " + "\nError: ".join(_flags['errors']))
|
||||||
if _flags['warnings']:
|
if _flags['warnings']:
|
||||||
raise RuntimeWarning("Warning: " + "\nWarning: ".join(_flags['warnings']))
|
raise RuntimeWarning("Warning: " + "\nWarning: ".join(_flags['warnings']))
|
||||||
|
|
||||||
|
# make sure prototype_locks are set to defaults
|
||||||
|
prototype_locks = [lstring.split(":", 1)
|
||||||
|
for lstring in prototype.get("prototype_locks", "").split(';')]
|
||||||
|
locktypes = [tup[0].strip() for tup in prototype_locks]
|
||||||
|
if "spawn" not in locktypes:
|
||||||
|
prototype_locks.append(("spawn", "all()"))
|
||||||
|
if "edit" not in locktypes:
|
||||||
|
prototype_locks.append(("edit", "all()"))
|
||||||
|
prototype_locks = ";".join(":".join(tup) for tup in prototype_locks)
|
||||||
|
prototype['prototype_locks'] = prototype_locks
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue