Made typeclass loading a little more forgiving, adding a multitude of try-levels to fall back to in case of errors. Default is now to fallback to first settings-set default, then to the library default and only as a last resort fall back to the model. Every fallback step is logged. This should make the missing-hook error of #698 go away and report missing typeclasses in a better way.
This commit is contained in:
parent
c9ed8b5ec5
commit
d752106906
5 changed files with 71 additions and 6 deletions
|
|
@ -3,6 +3,7 @@ Default Typeclass for Comms.
|
||||||
|
|
||||||
See objects.objects for more information on Typeclassing.
|
See objects.objects for more information on Typeclassing.
|
||||||
"""
|
"""
|
||||||
|
from django.conf import settings
|
||||||
from evennia.typeclasses.models import TypeclassBase
|
from evennia.typeclasses.models import TypeclassBase
|
||||||
from evennia.comms.models import Msg, TempMsg, ChannelDB
|
from evennia.comms.models import Msg, TempMsg, ChannelDB
|
||||||
from evennia.comms.managers import ChannelManager
|
from evennia.comms.managers import ChannelManager
|
||||||
|
|
@ -15,7 +16,10 @@ class DefaultChannel(ChannelDB):
|
||||||
This is the base class for all Comms. Inherit from this to create different
|
This is the base class for all Comms. Inherit from this to create different
|
||||||
types of communication channels.
|
types of communication channels.
|
||||||
"""
|
"""
|
||||||
|
# typeclass setup
|
||||||
__metaclass__ = TypeclassBase
|
__metaclass__ = TypeclassBase
|
||||||
|
__settingclasspath__ = settings.BASE_CHANNEL_TYPECLASS
|
||||||
|
__defaultclasspath__ = "evennia.comms.comms.DefaultChannel"
|
||||||
objects = ChannelManager()
|
objects = ChannelManager()
|
||||||
|
|
||||||
def at_first_save(self):
|
def at_first_save(self):
|
||||||
|
|
|
||||||
|
|
@ -135,6 +135,8 @@ class DefaultObject(ObjectDB):
|
||||||
"""
|
"""
|
||||||
# typeclass setup
|
# typeclass setup
|
||||||
__metaclass__ = TypeclassBase
|
__metaclass__ = TypeclassBase
|
||||||
|
__settingsclasspath__ = settings.BASE_OBJECT_TYPECLASS
|
||||||
|
__defaultclasspath__ = "evennia.objects.objects.DefaultObject"
|
||||||
objects = ObjectManager()
|
objects = ObjectManager()
|
||||||
|
|
||||||
# on-object properties
|
# on-object properties
|
||||||
|
|
|
||||||
|
|
@ -109,6 +109,9 @@ class DefaultPlayer(PlayerDB):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__metaclass__ = TypeclassBase
|
__metaclass__ = TypeclassBase
|
||||||
|
__settingsclasspath__ = settings.BASE_SCRIPT_TYPECLASS
|
||||||
|
__defaultclasspath__ = "evennia.players.players.DefaultPlayer"
|
||||||
|
|
||||||
objects = PlayerManager()
|
objects = PlayerManager()
|
||||||
|
|
||||||
# properties
|
# properties
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ ability to run timers.
|
||||||
from twisted.internet.defer import Deferred, maybeDeferred
|
from twisted.internet.defer import Deferred, maybeDeferred
|
||||||
from twisted.internet.task import LoopingCall
|
from twisted.internet.task import LoopingCall
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
|
from django.conf import settings
|
||||||
from evennia.typeclasses.models import TypeclassBase
|
from evennia.typeclasses.models import TypeclassBase
|
||||||
from evennia.scripts.models import ScriptDB
|
from evennia.scripts.models import ScriptDB
|
||||||
from evennia.scripts.manager import ScriptManager
|
from evennia.scripts.manager import ScriptManager
|
||||||
|
|
@ -140,6 +141,8 @@ class ScriptBase(ScriptDB):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
__metaclass__ = TypeclassBase
|
__metaclass__ = TypeclassBase
|
||||||
|
__settingsclasspath__ = settings.BASE_SCRIPT_TYPECLASS
|
||||||
|
__defaultclasspath__ = "evennia.scripts.scripts.DefaultScript"
|
||||||
objects = ScriptManager()
|
objects = ScriptManager()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -89,8 +89,23 @@ class TypeclassBase(SharedMemoryModelBase):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# storage of stats
|
# storage of stats
|
||||||
attrs["typename"] = name#cls.__name__
|
attrs["typename"] = name
|
||||||
attrs["path"] = "%s.%s" % (attrs["__module__"], name)
|
attrs["path"] = "%s.%s" % (attrs["__module__"], name)
|
||||||
|
#defaultpath = attrs["__defaultclasspath__"]
|
||||||
|
#attrs["__defaultclass__"] = class_from_module(attrs["__defaultclasspath__"])
|
||||||
|
#try:
|
||||||
|
# defaultpath = attrs["__defaultclasspath__"]
|
||||||
|
# attrs["__defaultclass__"] = class_from_module(attrs["__defaultclasspath__"])
|
||||||
|
#except Exception:
|
||||||
|
# log_trace("Typeclass error for %s: Default typeclass '%s' could not load. "
|
||||||
|
# "Falling back to library base." % (name, defaultpath))
|
||||||
|
# try:
|
||||||
|
# # two levels down from TypedObject will always be the default base class.
|
||||||
|
# attrs["__defaultclass__"] = cls.__mro__[cls.__mro__.index(TypedObject)-2]
|
||||||
|
# except Exception:
|
||||||
|
# log_trace("Critical error for %s: Neither typeclass, "
|
||||||
|
# "default fallback nor base class could load." % name)
|
||||||
|
# attrs["__defaultclass__"] = cls
|
||||||
|
|
||||||
# typeclass proxy setup
|
# typeclass proxy setup
|
||||||
if not "Meta" in attrs:
|
if not "Meta" in attrs:
|
||||||
|
|
@ -172,9 +187,33 @@ class TypedObject(SharedMemoryModel):
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
This is the main function of the typeclass system -
|
The `__init__` method of typeclasses is the core operational
|
||||||
to dynamically re-apply a class based on the
|
code of the typeclass system, where it dynamically re-applies
|
||||||
db_typeclass_path rather than use the one in the model.
|
a class based on the db_typeclass_path database field rather
|
||||||
|
than use the one in the model.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
Passed through to parent.
|
||||||
|
|
||||||
|
Kwargs:
|
||||||
|
Passed through to parent.
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
The loading mechanism will attempt the following steps:
|
||||||
|
|
||||||
|
1. Attempt to load typeclass given on command line
|
||||||
|
1. Attempt to load typeclass stored in db_typeclass_path
|
||||||
|
1. Attempt to load `__settingsclasspath__`, which is by the
|
||||||
|
default classes defined to be the respective user-set
|
||||||
|
base typeclass settings, like `BASE_OBJECT_TYPECLASS`.
|
||||||
|
1. Attempt to load `__defaultclasspath__`, which is the
|
||||||
|
base classes in the library, like DefaultObject etc.
|
||||||
|
1. If everything else fails, use the database model.
|
||||||
|
|
||||||
|
Normal operation is to load successfully at either step 1
|
||||||
|
or 2 depending on how the class was called. Tracebacks
|
||||||
|
will be logged for every step the loader must take beyond
|
||||||
|
2.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
typeclass_path = kwargs.pop("typeclass", None)
|
typeclass_path = kwargs.pop("typeclass", None)
|
||||||
|
|
@ -182,15 +221,29 @@ class TypedObject(SharedMemoryModel):
|
||||||
if typeclass_path:
|
if typeclass_path:
|
||||||
try:
|
try:
|
||||||
self.__class__ = class_from_module(typeclass_path)
|
self.__class__ = class_from_module(typeclass_path)
|
||||||
except ImportError:
|
except Exception:
|
||||||
log_trace()
|
log_trace()
|
||||||
|
try:
|
||||||
|
self.__class__ = class_from_module(self.__settingsclasspath__)
|
||||||
|
except Exception:
|
||||||
|
log_trace()
|
||||||
|
try:
|
||||||
|
self.__class__ = class_from_module(self.__defaultclasspath__)
|
||||||
|
except Exception:
|
||||||
|
log_trace()
|
||||||
|
self.__class__ = self._meta.proxy_for_model or self.__class__
|
||||||
finally:
|
finally:
|
||||||
self.db_typclass_path = typeclass_path
|
self.db_typclass_path = typeclass_path
|
||||||
elif self.db_typeclass_path:
|
elif self.db_typeclass_path:
|
||||||
try:
|
try:
|
||||||
self.__class__ = class_from_module(self.db_typeclass_path)
|
self.__class__ = class_from_module(self.db_typeclass_path)
|
||||||
except ImportError:
|
except Exception:
|
||||||
log_trace()
|
log_trace()
|
||||||
|
try:
|
||||||
|
self.__class__ = class_from_module(self.__defaultclasspath__)
|
||||||
|
except Exception:
|
||||||
|
log_trace()
|
||||||
|
self.__dbclass__ = self._meta.proxy_for_model or self.__class__
|
||||||
else:
|
else:
|
||||||
self.db_typeclass_path = "%s.%s" % (self.__module__, self.__class__.__name__)
|
self.db_typeclass_path = "%s.%s" % (self.__module__, self.__class__.__name__)
|
||||||
# important to put this at the end since _meta is based on the set __class__
|
# important to put this at the end since _meta is based on the set __class__
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue