Added the ability to give multiple typeclass search-paths to config file. This way you can add a path to your custom directory and don't have to write so much when creating typeclassed objects using e.g. @create.

This commit is contained in:
Griatch 2011-05-13 22:26:08 +00:00
parent b9c1921a0b
commit d2400a8a6b
11 changed files with 112 additions and 173 deletions

View file

@ -386,19 +386,8 @@ class CmdCreate(ObjManipCommand):
aliases = objdef['aliases']
typeclass = objdef['option']
# analyze typeclass. If it starts at the evennia basedir,
# (i.e. starts with game or src) we let it be, otherwise we
# add a base path as defined in settings
if typeclass and not (typeclass.startswith('src.') or
typeclass.startswith('game.') or
typeclass.startswith('contrib')):
typeclass = "%s.%s" % (settings.BASE_TYPECLASS_PATH,
typeclass)
# create object (if not a valid typeclass, the default
# object typeclass will automatically be used)
lockstring = "control:id(%s);examine:perm(Builders);delete:id(%s) or perm(Wizards);get:all()" % (caller.id, caller.id)
obj = create.create_object(typeclass, name, caller,
home=caller, aliases=aliases, locks=lockstring)
@ -420,7 +409,6 @@ class CmdCreate(ObjManipCommand):
caller.msg(string)
#TODO: make @debug more clever with arbitrary hooks?
class CmdDebug(MuxCommand):
"""
Debug game entities
@ -438,11 +426,7 @@ class CmdDebug(MuxCommand):
@debug/obj examples.red_button.RedButton
This command helps when debugging the codes of objects and scripts.
It creates the given object and runs tests on its hooks. You can
supply both full paths (starting from the evennia base directory),
otherwise the system will start from the defined root directory
for scripts and objects respectively (defined in settings file).
It creates the given object and runs tests on its hooks.
"""
key = "@debug"
@ -459,27 +443,11 @@ class CmdDebug(MuxCommand):
path = self.args
if 'obj' in self.switches or 'object' in self.switches:
# analyze path. If it starts at the evennia basedir,
# (i.e. starts with game or src) we let it be, otherwise we
# add a base path as defined in settings
if path and not (path.startswith('src.') or
path.startswith('game.')):
path = "%s.%s" % (settings.BASE_TYPECLASS_PATH,
path)
# create and debug the object
self.caller.msg(debug.debug_object(path, self.caller))
self.caller.msg(debug.debug_object_scripts(path, self.caller))
elif 'script' in self.switches:
# analyze path. If it starts at the evennia basedir,
# (i.e. starts with game or src) we let it be, otherwise we
# add a base path as defined in settings
if path and not (path.startswith('src.') or
path.startswith('game.')):
path = "%s.%s" % (settings.BASE_SCRIPT_PATH,
path)
self.caller.msg(debug.debug_syntax_script(path))
@ -629,16 +597,7 @@ class CmdDig(ObjManipCommand):
if not typeclass:
typeclass = settings.BASE_ROOM_TYPECLASS
# analyze typeclass path. If it starts at the evennia basedir,
# (i.e. starts with game or src) we let it be, otherwise we
# add a base path as defined in settings
if typeclass and not (typeclass.startswith('src.') or
typeclass.startswith('game.')):
typeclass = "%s.%s" % (settings.BASE_TYPECLASS_PATH,
typeclass)
# create room
lockstring = "control:id(%s) or perm(Immortal); delete:id(%s) or perm(Wizard); edit:id(%s) or perm(Wizard)"
lockstring = lockstring % (caller.dbref, caller.dbref, caller.dbref)
@ -669,13 +628,7 @@ class CmdDig(ObjManipCommand):
typeclass = to_exit["option"]
if not typeclass:
typeclass = settings.BASE_EXIT_TYPECLASS
# analyze typeclass. If it starts at the evennia basedir,
# (i.e. starts with game or src) we let it be, otherwise we
# add a base path as defined in settings
if typeclass and not (typeclass.startswith('src.') or
typeclass.startswith('game.')):
typeclass = "%s.%s" % (settings.BASE_TYPECLASS_PATH,
typeclass)
new_to_exit = create.create_object(typeclass, to_exit["name"], location,
aliases=to_exit["aliases"],
locks=lockstring, destination=new_room)
@ -701,13 +654,6 @@ class CmdDig(ObjManipCommand):
typeclass = back_exit["option"]
if not typeclass:
typeclass = settings.BASE_EXIT_TYPECLASS
# analyze typeclass. If it starts at the evennia basedir,
# (i.e. starts with game or src) we let it be, otherwise we
# add a base path as defined in settings
if typeclass and not (typeclass.startswith('src.') or
typeclass.startswith('game.')):
typeclass = "%s.%s" % (settings.BASE_TYPECLASS_PATH,
typeclass)
new_back_exit = create.create_object(typeclass, back_exit["name"],
new_room, aliases=back_exit["aliases"],
locks=lockstring, destination=location)
@ -1068,14 +1014,6 @@ class CmdOpen(ObjManipCommand):
exit_aliases = self.lhs_objs[0]['aliases']
exit_typeclass = self.lhs_objs[0]['option']
# analyze typeclass. If it starts at the evennia basedir,
# (i.e. starts with game or src) we let it be, otherwise we
# add a base path as defined in settings
if exit_typeclass and not (exit_typeclass.startswith('src.') or
exit_typeclass.startswith('game.')):
exit_typeclass = "%s.%s" % (settings.BASE_TYPECLASS_PATH,
exit_typeclass)
dest_name = self.rhs_objs[0]['name']
# first, check so the destination exists.
@ -1097,13 +1035,6 @@ class CmdOpen(ObjManipCommand):
back_exit_aliases = self.rhs_objs[1]['name']
back_exit_typeclass = self.rhs_objs[1]['option']
# analyze typeclass. If it starts at the evennia basedir,
# (i.e. starts with game or src) we let it be, otherwise we
# add a base path as defined in settings
if back_exit_typeclass and not (back_exit_typeclass.startswith('src.') or
back_exit_typeclass.startswith('game.')):
back_exit_typeclass = "%s.%s" % (settings.BASE_TYPECLASS_PATH,
back_exit_typeclass)
# Create the back-exit
self.create_exit(back_exit_name, destination, location,
back_exit_aliases, back_exit_typeclass)
@ -1250,14 +1181,6 @@ class CmdTypeclass(MuxCommand):
# we have an =, a typeclass was supplied.
typeclass = self.rhs
# analyze typeclass. If it starts at the evennia basedir,
# (i.e. starts with game or src) we let it be, otherwise we
# add a base path as defined in settings
if typeclass and not (typeclass.startswith('src.') or
typeclass.startswith('game.')):
typeclass = "%s.%s" % (settings.BASE_TYPECLASS_PATH,
typeclass)
if not obj.access(caller, 'edit'):
caller.msg("You are not allowed to do that.")
return
@ -1827,34 +1750,38 @@ class CmdScript(MuxCommand):
caller.msg(string)
return
inp = self.rhs
if not inp.startswith('src.') and not inp.startswith('game.'):
# append the default path.
inp = "%s.%s" % (settings.BASE_SCRIPT_PATH, inp)
obj = caller.search(self.lhs)
if not obj:
return
string = ""
if "stop" in self.switches:
# we are stopping an already existing script
ok = obj.scripts.stop(inp)
if not ok:
string = "Script %s could not be stopped. Does it exist?" % inp
else:
string = "Script stopped and removed from object."
if "start" in self.switches:
# we are starting an already existing script
ok = obj.scripts.start(inp)
if not ok:
string = "Script %s could not be (re)started." % inp
else:
string = "Script started successfully."
if not self.switches:
# adding a new script, and starting it
ok = obj.scripts.add(inp, autostart=True)
ok = obj.scripts.add(self.rhs, autostart=True)
if not ok:
string = "Script %s could not be added." % inp
string += "\nScript %s could not be added." % self.rhs
else:
string = "Script successfully added and started."
caller.msg(string)
else:
paths = [self.rhs] + ["%s.%s" % (prefix, self.rhs)
for prefix in settings.SCRIPT_TYPECLASS_PATHS]
if "stop" in self.switches:
# we are stopping an already existing script
for path in paths:
ok = obj.scripts.stop(path)
if not ok:
string += "\nScript %s could not be stopped. Does it exist?" % path
else:
string = "Script stopped and removed from object."
break
if "start" in self.switches:
# we are starting an already existing script
for path in paths:
ok = obj.scripts.start(path)
if not ok:
string += "\nScript %s could not be (re)started." % path
else:
string = "Script started successfully."
break
caller.msg(string.strip())

View file

@ -420,7 +420,7 @@ def serversetting(accessing_obj, accessed_obj, *args, **kwargs):
Usage:
serversetting(IRC_ENABLED)
serversetting(BASE_SCRIPT_PATH, game.gamesrc.scripts)
serversetting(BASE_SCRIPT_PATH, [game.gamesrc.scripts])
A given True/False or integers will be converted properly.
"""

View file

@ -418,9 +418,10 @@ class ObjectDB(TypedObject):
# ObjectDB class access methods/properties
#
# this is required to properly handle attributes
# this is required to properly handle attributes and typeclass loading.
attribute_model_path = "src.objects.models"
attribute_model_name = "ObjAttribute"
typeclass_paths = settings.OBJECT_TYPECLASS_PATHS
# this is used by all typedobjects as a fallback
try:

View file

@ -261,9 +261,10 @@ class PlayerDB(TypedObject):
except Exception:
default_typeclass_path = "src.players.player.Player"
# this is required to properly handle attributes
# this is required to properly handle attributes and typeclass loading
attribute_model_path = "src.players.models"
attribute_model_name = "PlayerAttribute"
typeclass_paths = settings.PLAYER_TYPECLASS_PATHS
# name property (wraps self.user.username)
#@property

View file

@ -243,9 +243,10 @@ class ScriptDB(TypedObject):
#
#
# this is required to properly handle typeclass-dependent attributes
# this is required to properly handle attrubutes and typeclass loading
attribute_model_path = "src.scripts.models"
attribute_model_name = "ScriptAttribute"
typeclass_paths = settings.SCRIPT_TYPECLASS_PATHS
# this is used by all typedobjects as a fallback
try:

View file

@ -161,20 +161,19 @@ CMDSET_DEFAULT = "game.gamesrc.commands.basecmdset.DefaultCmdSet"
CMDSET_OOC = "game.gamesrc.commands.basecmdset.OOCCmdSet"
###################################################
# Default Object typeclasses
# Typeclasses
###################################################
# Note that all typeclasses must originally
# inherit from src.objects.objects.Object somewhere in
# their path.
# Base paths for typeclassed object classes. These paths must be
# defined relative evennia's root directory. They will be searched in
# order to find relative typeclass paths.
OBJECT_TYPECLASS_PATHS = ["game.gamesrc.objects", "game.gamesrc.objects.examples"]
SCRIPT_TYPECLASS_PATHS = ["game.gamesrc.scripts", "game.gamesrc.scripts.examples"]
PLAYER_TYPECLASS_PATHS = ["game.gamesrc.objects"]
# This sets the default base dir to search when importing
# things, so one doesn't have to write the entire
# path in-game.
BASE_TYPECLASS_PATH = "game.gamesrc.objects"
# Typeclass for player objects (linked to a character) (fallback)
BASE_PLAYER_TYPECLASS = "game.gamesrc.objects.baseobjects.Player"
# Typeclass and base for all following objects (fallback)
# Typeclass and base for all objects (fallback)
BASE_OBJECT_TYPECLASS = "game.gamesrc.objects.baseobjects.Object"
# Typeclass for character objects linked to a player (fallback)
BASE_CHARACTER_TYPECLASS = "game.gamesrc.objects.baseobjects.Character"
@ -183,14 +182,6 @@ BASE_ROOM_TYPECLASS = "game.gamesrc.objects.baseobjects.Room"
# Typeclass for Exit objects (fallback)
BASE_EXIT_TYPECLASS = "game.gamesrc.objects.baseobjects.Exit"
###################################################
# Scripts
###################################################
# Python path to a directory to start searching
# for scripts.
BASE_SCRIPT_PATH = "game.gamesrc.scripts"
###################################################
# Batch processors
###################################################

View file

@ -561,6 +561,7 @@ class TypedObject(SharedMemoryModel):
# attribute model (ObjAttribute, PlayerAttribute etc).
attribute_model_path = "src.typeclasses.models"
attribute_model_name = "Attribute"
typeclass_paths = settings.OBJECT_TYPECLASS_PATHS
def __eq__(self, other):
return other and hasattr(other, 'id') and self.id == other.id
@ -647,20 +648,31 @@ class TypedObject(SharedMemoryModel):
defpath = object.__getattribute__(self, 'default_typeclass_path')
typeclass = object.__getattribute__(self, '_path_import')(defpath)
#typeclass = self._path_import(defpath)
else:
typeclass = TYPECLASS_CACHE.get(path, None)
if typeclass:
# we've imported this before. We're done.
return typeclass
# not in cache. Import anew.
typeclass = object.__getattribute__(self, "_path_import")(path)
if not callable(typeclass):
# given path failed to import, fallback to default.
errstring = " %s" % typeclass # this is an error message
if hasattr(typeclass, '__file__'):
errstring += "\nThis seems to be just the path to a module. You need"
else:
# handle loading/importing of typeclasses, searching all paths.
# (self.typeclss_paths is a shortcut to settings.TYPECLASS_*_PATH
# where '*' is either OBJECT, SCRIPT or PLAYER depending on the typed
# object).
typeclass_paths = [path] + ["%s.%s" % (prefix, path) for prefix in self.typeclass_paths]
for tpath in typeclass_paths:
# try to find any matches to the typeclass path, in all possible permutations..
typeclass = TYPECLASS_CACHE.get(tpath, None)
if typeclass:
# we've imported this before. We're done.
return typeclass
# not in cache. Try to import anew.
typeclass = object.__getattribute__(self, "_path_import")(tpath)
if callable(typeclass):
# don't return yet, we must cache this further down.
break
elif hasattr(typeclass, '__file__'):
errstring += "\n%s seems to be just the path to a module. You need" % tpath
errstring += " to specify the actual typeclass name inside the module too."
errstring += "\n Typeclass '%s' failed to load." % path
else:
errstring += "\n%s" % typeclass # this will hold an error message.
if not callable(typeclass):
# Still not a valid import. Fallback to default.
defpath = object.__getattribute__(self, "default_typeclass_path")
errstring += " Using Default class '%s'." % defpath
self.db_typeclass_path = defpath
@ -669,7 +681,7 @@ class TypedObject(SharedMemoryModel):
typeclass = object.__getattribute__(self, "_path_import")(defpath)
errmsg(errstring)
if not callable(typeclass):
# if typeclass still doesn't exist, we're in trouble.
# if typeclass still doesn't exist at this point, we're in trouble.
# fall back to hardcoded core class.
errstring = " %s\n%s" % (typeclass, errstring)
errstring += " Default class '%s' failed to load." % defpath

View file

@ -45,7 +45,6 @@ class MetaTypeClass(type):
def __str__(cls):
return "%s" % cls.__name__
class TypeClass(object):
"""
This class implements a 'typeclass' object. This is connected