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

70
README
View file

@ -5,6 +5,7 @@ Evennia README http://evennia.com
- < 2010 (earlier revisions) - < 2010 (earlier revisions)
- May 2010 - merged ABOUT and README. Added Current status /Griatch - May 2010 - merged ABOUT and README. Added Current status /Griatch
- Aug 2010 - evennia devel merged into trunk /Griatch - Aug 2010 - evennia devel merged into trunk /Griatch
- May 2011 - all commands implemented, web client, contribs /Griatch
Contents: Contents:
--------- ---------
@ -23,21 +24,17 @@ Evennia Alpha SVN version
About Evennia About Evennia
------------- -------------
Evennia is a proof-of-concept MU* server that aims to provide a functional
bare-bones base for developers. While there are quite a few codebases that do the same
(and very well in many cases), we are taking a unique spin on the problem.
Some of our flagship features include (or will one day include):
* Coded fully in Python using Django and Twisted Evennia is a MUD/MUX/MU* server that aims to provide a functional
* Extensive web integration. bare-bones base for developers. Some of our main features are:
* The ability to build/administer through a web browser.
* Shared accounts between the website and the game. * Coded and extended using normal Python modules.
* Optional web-based character creation. * Extensive web integration due to our use of Django.
* Runs its own Twisted webserver. Comes with game website and ajax web-browser mud client.
* Extensive current and potential connectivity and protocol-support through Twisted.
* Extremely easy-to-manipulate SQL database back-end via Django * Extremely easy-to-manipulate SQL database back-end via Django
(djangoproject.com) (djangoproject.com)
* Simple and easily extensible design. * Powerful an extremely extendable bare-bones base system
* Very granular permissions. Individual and group based.
* Powerful an extremely extendable base system
The essential points here are the web integration and the SQL backing via The essential points here are the web integration and the SQL backing via
Django. The Django framework has database abstraction abilities that give us Django. The Django framework has database abstraction abilities that give us
@ -60,6 +57,14 @@ See the INSTALL file for help on setting up and running Evennia.
Current Status Current Status
-------------- --------------
May 2011:
The new version of Evennia, originally hitting trunk in Aug2010, is
maturing. All commands from the pre-Aug version, including IRC/IMC2
support works again. An ajax web-client was added earlier in the year,
including moving Evennia to be its own webserver (no more need for
Apache or django-testserver). Contrib-folder added.
Aug 2010: Aug 2010:
Evennia-griatch-branch is ready for merging with trunk. This marks Evennia-griatch-branch is ready for merging with trunk. This marks
a rather big change in the inner workings of the server, but should a rather big change in the inner workings of the server, but should
@ -77,17 +82,16 @@ to Events, Commands and Permissions.
Contact, Support and Development Contact, Support and Development
----------------------- -----------------------
We are early in development, but we try to give support best we can This is still alpha software, but we try to give support best we can
if you feel daring enough to play with the codebase. Make a post to if you have questions. Make a post to the mailing list or chat us up
the mailing list or chat us up on IRC if you have questions. We also on IRC. We also have a bug tracker if you want to report
have a bug tracker if you want to report bugs. Finally, if bugs. Finally, if you are willing to help with the code work, we much
you are willing to help with the code work, we much appreciate all help! appreciate all help! Visit either of the following resources:
Visit either of the following resources:
* Evennia Webpage * Evennia Webpage
http://evennia.com http://evennia.com
* Evennia wiki (documentation) * Evennia manual (wiki)
http://code.google.com/p/evennia/wiki/Index http://code.google.com/p/evennia/wiki/Index
* Evennia Code Page (See INSTALL text for installation) * Evennia Code Page (See INSTALL text for installation)
@ -107,8 +111,10 @@ evennia
| |___(engine-related dirs) | |___(engine-related dirs)
| |
|_______game (start the server) |_______game (start the server)
|___gamesrc | |___gamesrc
|___(game-related dirs) | |___(game-related dirs)
|
|_______contrib
The two main directories you will spend most of your time in The two main directories you will spend most of your time in
are src/ and game/ (probably mostly game/). are src/ and game/ (probably mostly game/).
@ -129,6 +135,11 @@ to make your dream game. game/ contains the main server settings
and the actual evennia executable to start things. game/gamesrc/ and the actual evennia executable to start things. game/gamesrc/
holds all the templates for creating objects in your virtual world. holds all the templates for creating objects in your virtual world.
contrib/ contains optional code snippets. These are potentially useful
but deemed to be too game-specific to be part of the server itself.
Modules in contrib are not used unless you yourself decide to import
and use them.
With this little first orientation, you should head into the online With this little first orientation, you should head into the online
Evennia wiki documentation to get going with the codebase. Evennia wiki documentation to get going with the codebase.
@ -140,18 +151,15 @@ for capable admins to craft their own respective games. It is not the
intention to provide a full-fledged, ready-to-run base, rather Evennia intention to provide a full-fledged, ready-to-run base, rather Evennia
is offering the means to make such games. is offering the means to make such games.
2) Development of games on Evennia must be easy for anyone with some degree 2) Development of games on Evennia must be easy for anyone with some
of Python experience. Building needs to be easy, and per-room, per-object, degree of Python experience. Building needs to be easy, and per-room,
and environmental customizations need to be simple to do. per-object, and environmental customizations need to be simple to
do. This is handled by use of normal Python classes transparently
abstracting and wrapping the SQL backend. The user should not need to
use SQL or even know Django to any greater extent.
3) The server must utilize SQL as a storage back-end to allow for web->game 3) The server must utilize SQL as a storage back-end to allow for web->game
integration. See the details on Django later on in the document for more integration through Django.
details.
4) Any and all game-specific configuration must reside in SQL, not
external configuration files. The only exception is the settings.py file
containing the SQL information.
The Components The Components
-------------- --------------

View file

@ -14,7 +14,6 @@ or you won't see any messages!
import random import random
from game.gamesrc.scripts.basescript import Script from game.gamesrc.scripts.basescript import Script
class BodyFunctions(Script): class BodyFunctions(Script):
""" """
This class defines the script itself This class defines the script itself
@ -24,7 +23,7 @@ class BodyFunctions(Script):
self.key = "bodyfunction" self.key = "bodyfunction"
self.desc = "Adds various timed events to a character." self.desc = "Adds various timed events to a character."
self.interval = 20 # seconds self.interval = 20 # seconds
self.start_delay # wait self.interval until first call self.start_delay = True # wait self.interval until first call
self.persistent = False self.persistent = False
def at_repeat(self): def at_repeat(self):

View file

@ -40,7 +40,7 @@ if not os.path.exists('settings.py'):
# this file. Try to *only* copy over things you really need to customize # this file. Try to *only* copy over things you really need to customize
# and do *not* make any changes to src/settings_default.py directly. # and do *not* make any changes to src/settings_default.py directly.
# This way you'll always have a sane default to fall back on # This way you'll always have a sane default to fall back on
# (also, the master file may change with server updates). # (also, the master config file may change with server updates).
# #
from src.settings_default import * from src.settings_default import *
@ -62,7 +62,7 @@ from src.settings_default import *
################################################### ###################################################
################################################### ###################################################
# Default Object typeclasses # Typeclasses
################################################### ###################################################
################################################### ###################################################
@ -90,7 +90,7 @@ from src.settings_default import *
################################################### ###################################################
################################################### ###################################################
# Evennia components (django apps) # Evennia components
################################################### ###################################################
""" """

View file

@ -386,19 +386,8 @@ class CmdCreate(ObjManipCommand):
aliases = objdef['aliases'] aliases = objdef['aliases']
typeclass = objdef['option'] 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 # create object (if not a valid typeclass, the default
# object typeclass will automatically be used) # 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) 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, obj = create.create_object(typeclass, name, caller,
home=caller, aliases=aliases, locks=lockstring) home=caller, aliases=aliases, locks=lockstring)
@ -420,7 +409,6 @@ class CmdCreate(ObjManipCommand):
caller.msg(string) caller.msg(string)
#TODO: make @debug more clever with arbitrary hooks?
class CmdDebug(MuxCommand): class CmdDebug(MuxCommand):
""" """
Debug game entities Debug game entities
@ -438,11 +426,7 @@ class CmdDebug(MuxCommand):
@debug/obj examples.red_button.RedButton @debug/obj examples.red_button.RedButton
This command helps when debugging the codes of objects and scripts. This command helps when debugging the codes of objects and scripts.
It creates the given object and runs tests on its hooks. You can It creates the given object and runs tests on its hooks.
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).
""" """
key = "@debug" key = "@debug"
@ -459,27 +443,11 @@ class CmdDebug(MuxCommand):
path = self.args path = self.args
if 'obj' in self.switches or 'object' in self.switches: 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 # create and debug the object
self.caller.msg(debug.debug_object(path, self.caller)) self.caller.msg(debug.debug_object(path, self.caller))
self.caller.msg(debug.debug_object_scripts(path, self.caller)) self.caller.msg(debug.debug_object_scripts(path, self.caller))
elif 'script' in self.switches: 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)) self.caller.msg(debug.debug_syntax_script(path))
@ -629,16 +597,7 @@ class CmdDig(ObjManipCommand):
if not typeclass: if not typeclass:
typeclass = settings.BASE_ROOM_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 # create room
lockstring = "control:id(%s) or perm(Immortal); delete:id(%s) or perm(Wizard); edit:id(%s) or perm(Wizard)" 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) lockstring = lockstring % (caller.dbref, caller.dbref, caller.dbref)
@ -669,13 +628,7 @@ class CmdDig(ObjManipCommand):
typeclass = to_exit["option"] typeclass = to_exit["option"]
if not typeclass: if not typeclass:
typeclass = settings.BASE_EXIT_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, new_to_exit = create.create_object(typeclass, to_exit["name"], location,
aliases=to_exit["aliases"], aliases=to_exit["aliases"],
locks=lockstring, destination=new_room) locks=lockstring, destination=new_room)
@ -701,13 +654,6 @@ class CmdDig(ObjManipCommand):
typeclass = back_exit["option"] typeclass = back_exit["option"]
if not typeclass: if not typeclass:
typeclass = settings.BASE_EXIT_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_back_exit = create.create_object(typeclass, back_exit["name"],
new_room, aliases=back_exit["aliases"], new_room, aliases=back_exit["aliases"],
locks=lockstring, destination=location) locks=lockstring, destination=location)
@ -1068,14 +1014,6 @@ class CmdOpen(ObjManipCommand):
exit_aliases = self.lhs_objs[0]['aliases'] exit_aliases = self.lhs_objs[0]['aliases']
exit_typeclass = self.lhs_objs[0]['option'] 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'] dest_name = self.rhs_objs[0]['name']
# first, check so the destination exists. # first, check so the destination exists.
@ -1097,13 +1035,6 @@ class CmdOpen(ObjManipCommand):
back_exit_aliases = self.rhs_objs[1]['name'] back_exit_aliases = self.rhs_objs[1]['name']
back_exit_typeclass = self.rhs_objs[1]['option'] 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 # Create the back-exit
self.create_exit(back_exit_name, destination, location, self.create_exit(back_exit_name, destination, location,
back_exit_aliases, back_exit_typeclass) back_exit_aliases, back_exit_typeclass)
@ -1250,14 +1181,6 @@ class CmdTypeclass(MuxCommand):
# we have an =, a typeclass was supplied. # we have an =, a typeclass was supplied.
typeclass = self.rhs 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'): if not obj.access(caller, 'edit'):
caller.msg("You are not allowed to do that.") caller.msg("You are not allowed to do that.")
return return
@ -1827,34 +1750,38 @@ class CmdScript(MuxCommand):
caller.msg(string) caller.msg(string)
return 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) obj = caller.search(self.lhs)
if not obj: if not obj:
return return
string = "" 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: if not self.switches:
# adding a new script, and starting it # 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: if not ok:
string = "Script %s could not be added." % inp string += "\nScript %s could not be added." % self.rhs
else: else:
string = "Script successfully added and started." 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: Usage:
serversetting(IRC_ENABLED) 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. A given True/False or integers will be converted properly.
""" """

View file

@ -418,9 +418,10 @@ class ObjectDB(TypedObject):
# ObjectDB class access methods/properties # 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_path = "src.objects.models"
attribute_model_name = "ObjAttribute" attribute_model_name = "ObjAttribute"
typeclass_paths = settings.OBJECT_TYPECLASS_PATHS
# this is used by all typedobjects as a fallback # this is used by all typedobjects as a fallback
try: try:

View file

@ -261,9 +261,10 @@ class PlayerDB(TypedObject):
except Exception: except Exception:
default_typeclass_path = "src.players.player.Player" 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_path = "src.players.models"
attribute_model_name = "PlayerAttribute" attribute_model_name = "PlayerAttribute"
typeclass_paths = settings.PLAYER_TYPECLASS_PATHS
# name property (wraps self.user.username) # name property (wraps self.user.username)
#@property #@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_path = "src.scripts.models"
attribute_model_name = "ScriptAttribute" attribute_model_name = "ScriptAttribute"
typeclass_paths = settings.SCRIPT_TYPECLASS_PATHS
# this is used by all typedobjects as a fallback # this is used by all typedobjects as a fallback
try: try:

View file

@ -161,20 +161,19 @@ CMDSET_DEFAULT = "game.gamesrc.commands.basecmdset.DefaultCmdSet"
CMDSET_OOC = "game.gamesrc.commands.basecmdset.OOCCmdSet" CMDSET_OOC = "game.gamesrc.commands.basecmdset.OOCCmdSet"
################################################### ###################################################
# Default Object typeclasses # Typeclasses
################################################### ###################################################
# Note that all typeclasses must originally # Base paths for typeclassed object classes. These paths must be
# inherit from src.objects.objects.Object somewhere in # defined relative evennia's root directory. They will be searched in
# their path. # 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) # Typeclass for player objects (linked to a character) (fallback)
BASE_PLAYER_TYPECLASS = "game.gamesrc.objects.baseobjects.Player" 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" BASE_OBJECT_TYPECLASS = "game.gamesrc.objects.baseobjects.Object"
# Typeclass for character objects linked to a player (fallback) # Typeclass for character objects linked to a player (fallback)
BASE_CHARACTER_TYPECLASS = "game.gamesrc.objects.baseobjects.Character" 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) # Typeclass for Exit objects (fallback)
BASE_EXIT_TYPECLASS = "game.gamesrc.objects.baseobjects.Exit" 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 # Batch processors
################################################### ###################################################

View file

@ -561,6 +561,7 @@ class TypedObject(SharedMemoryModel):
# attribute model (ObjAttribute, PlayerAttribute etc). # attribute model (ObjAttribute, PlayerAttribute etc).
attribute_model_path = "src.typeclasses.models" attribute_model_path = "src.typeclasses.models"
attribute_model_name = "Attribute" attribute_model_name = "Attribute"
typeclass_paths = settings.OBJECT_TYPECLASS_PATHS
def __eq__(self, other): def __eq__(self, other):
return other and hasattr(other, 'id') and self.id == other.id 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') defpath = object.__getattribute__(self, 'default_typeclass_path')
typeclass = object.__getattribute__(self, '_path_import')(defpath) typeclass = object.__getattribute__(self, '_path_import')(defpath)
#typeclass = self._path_import(defpath) #typeclass = self._path_import(defpath)
else: else:
typeclass = TYPECLASS_CACHE.get(path, None) # handle loading/importing of typeclasses, searching all paths.
if typeclass: # (self.typeclss_paths is a shortcut to settings.TYPECLASS_*_PATH
# we've imported this before. We're done. # where '*' is either OBJECT, SCRIPT or PLAYER depending on the typed
return typeclass # object).
# not in cache. Import anew. typeclass_paths = [path] + ["%s.%s" % (prefix, path) for prefix in self.typeclass_paths]
typeclass = object.__getattribute__(self, "_path_import")(path) for tpath in typeclass_paths:
if not callable(typeclass): # try to find any matches to the typeclass path, in all possible permutations..
# given path failed to import, fallback to default. typeclass = TYPECLASS_CACHE.get(tpath, None)
errstring = " %s" % typeclass # this is an error message if typeclass:
if hasattr(typeclass, '__file__'): # we've imported this before. We're done.
errstring += "\nThis seems to be just the path to a module. You need" 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 += " 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") defpath = object.__getattribute__(self, "default_typeclass_path")
errstring += " Using Default class '%s'." % defpath errstring += " Using Default class '%s'." % defpath
self.db_typeclass_path = defpath self.db_typeclass_path = defpath
@ -669,7 +681,7 @@ class TypedObject(SharedMemoryModel):
typeclass = object.__getattribute__(self, "_path_import")(defpath) typeclass = object.__getattribute__(self, "_path_import")(defpath)
errmsg(errstring) errmsg(errstring)
if not callable(typeclass): 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. # fall back to hardcoded core class.
errstring = " %s\n%s" % (typeclass, errstring) errstring = " %s\n%s" % (typeclass, errstring)
errstring += " Default class '%s' failed to load." % defpath errstring += " Default class '%s' failed to load." % defpath

View file

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