Made the proxy typeclass system work in principle, using a wrapper of the __new__ method for the class.
This commit is contained in:
parent
8314d8ba5e
commit
32e44dceab
7 changed files with 26 additions and 78 deletions
|
|
@ -4,7 +4,6 @@ Default Typeclass for Comms.
|
||||||
See objects.objects for more information on Typeclassing.
|
See objects.objects for more information on Typeclassing.
|
||||||
"""
|
"""
|
||||||
from src.comms.models import Msg, TempMsg, ChannelDB
|
from src.comms.models import Msg, TempMsg, ChannelDB
|
||||||
from src.typeclasses.models import TypeclassBase
|
|
||||||
from src.utils import logger
|
from src.utils import logger
|
||||||
from src.utils.utils import make_iter
|
from src.utils.utils import make_iter
|
||||||
|
|
||||||
|
|
@ -14,19 +13,7 @@ class Channel(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.
|
||||||
"""
|
"""
|
||||||
|
_is_typeclass = True
|
||||||
def __new__(cls, *args, **kwargs):
|
|
||||||
"""
|
|
||||||
We must define our Typeclasses as proxies. We also store the path
|
|
||||||
directly on the class, this is useful for managers.
|
|
||||||
"""
|
|
||||||
if hasattr(cls, "Meta"):
|
|
||||||
cls.Meta.proxy = True
|
|
||||||
else:
|
|
||||||
class Meta:
|
|
||||||
proxy = True
|
|
||||||
cls.Meta = Meta
|
|
||||||
return super(TypeclassBase, cls).__new__(*args, **kwargs)
|
|
||||||
|
|
||||||
# helper methods, for easy overloading
|
# helper methods, for easy overloading
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@ they control by simply linking to a new object's user property.
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from src.objects.models import ObjectDB
|
from src.objects.models import ObjectDB
|
||||||
from src.typeclasses.models import TypeclassBase
|
|
||||||
from src.commands import cmdset, command
|
from src.commands import cmdset, command
|
||||||
from src.utils.logger import log_depmsg
|
from src.utils.logger import log_depmsg
|
||||||
|
|
||||||
|
|
@ -37,18 +36,7 @@ class Object(ObjectDB):
|
||||||
This is the base class for all in-game objects. Inherit from this
|
This is the base class for all in-game objects. Inherit from this
|
||||||
to create different types of objects in the game.
|
to create different types of objects in the game.
|
||||||
"""
|
"""
|
||||||
def __new__(cls, *args, **kwargs):
|
_is_typeclass = True
|
||||||
"""
|
|
||||||
We must define our Typeclasses as proxies. We also store the path
|
|
||||||
directly on the class, this is useful for managers.
|
|
||||||
"""
|
|
||||||
if hasattr(cls, "Meta"):
|
|
||||||
cls.Meta.proxy = True
|
|
||||||
else:
|
|
||||||
class Meta:
|
|
||||||
proxy = True
|
|
||||||
cls.Meta = Meta
|
|
||||||
return super(Object, cls).__new__(*args, **kwargs)
|
|
||||||
|
|
||||||
# __init__ is only defined here in order to present docstring to API.
|
# __init__ is only defined here in order to present docstring to API.
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|
|
||||||
|
|
@ -22,23 +22,11 @@ _MULTISESSION_MODE = settings.MULTISESSION_MODE
|
||||||
_CMDSET_PLAYER = settings.CMDSET_PLAYER
|
_CMDSET_PLAYER = settings.CMDSET_PLAYER
|
||||||
_CONNECT_CHANNEL = None
|
_CONNECT_CHANNEL = None
|
||||||
|
|
||||||
|
|
||||||
class Player(PlayerDB):
|
class Player(PlayerDB):
|
||||||
"""
|
"""
|
||||||
Base typeclass for all Players.
|
Base typeclass for all Players.
|
||||||
"""
|
"""
|
||||||
def __new__(cls, *args, **kwargs):
|
_is_typeclass = True
|
||||||
"""
|
|
||||||
We must define our Typeclasses as proxies. We also store the path
|
|
||||||
directly on the class, this is useful for managers.
|
|
||||||
"""
|
|
||||||
if hasattr(cls, "Meta"):
|
|
||||||
cls.Meta.proxy = True
|
|
||||||
else:
|
|
||||||
class Meta:
|
|
||||||
proxy = True
|
|
||||||
cls.Meta = Meta
|
|
||||||
return super(Player, cls).__new__(*args, **kwargs)
|
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@ from twisted.internet.defer import Deferred, maybeDeferred
|
||||||
from twisted.internet.task import LoopingCall
|
from twisted.internet.task import LoopingCall
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
from src.typeclasses.models import TypeclassBase
|
|
||||||
from src.scripts.models import ScriptDB
|
from src.scripts.models import ScriptDB
|
||||||
from src.comms import channelhandler
|
from src.comms import channelhandler
|
||||||
from src.utils import logger
|
from src.utils import logger
|
||||||
|
|
@ -113,21 +112,7 @@ class ScriptBase(ScriptDB):
|
||||||
Base class for scripts. Don't inherit from this, inherit
|
Base class for scripts. Don't inherit from this, inherit
|
||||||
from the class 'Script' instead.
|
from the class 'Script' instead.
|
||||||
"""
|
"""
|
||||||
#__metaclass__ = TypeclassBase
|
_is_typeclass = True
|
||||||
# private methods
|
|
||||||
|
|
||||||
def __new__(cls, *args, **kwargs):
|
|
||||||
"""
|
|
||||||
We must define our Typeclasses as proxies. We also store the path
|
|
||||||
directly on the class, this is useful for managers.
|
|
||||||
"""
|
|
||||||
if hasattr(cls, "Meta"):
|
|
||||||
cls.Meta.proxy = True
|
|
||||||
else:
|
|
||||||
class Meta:
|
|
||||||
proxy = True
|
|
||||||
cls.Meta = Meta
|
|
||||||
return super(ScriptBase, cls).__new__(*args, **kwargs)
|
|
||||||
|
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,6 @@ class TypedObjectManager(idmapper.manager.SharedMemoryManager):
|
||||||
Overload the standard get. This will limit itself to only
|
Overload the standard get. This will limit itself to only
|
||||||
return the current typeclass.
|
return the current typeclass.
|
||||||
"""
|
"""
|
||||||
print self.model
|
|
||||||
kwargs.update({"db_typeclass_path":self.model.path})
|
kwargs.update({"db_typeclass_path":self.model.path})
|
||||||
return super(TypedObjectManager, self).get(**kwargs)
|
return super(TypedObjectManager, self).get(**kwargs)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -740,7 +740,7 @@ class PermissionHandler(TagHandler):
|
||||||
#------------------------------------------------------------
|
#------------------------------------------------------------
|
||||||
|
|
||||||
# imported for access by other
|
# imported for access by other
|
||||||
from src.utils.idmapper.base import SharedMemoryModelBase
|
#from src.utils.idmapper.base import SharedMemoryModelBase
|
||||||
|
|
||||||
#class TypeclassBase(SharedMemoryModelBase):
|
#class TypeclassBase(SharedMemoryModelBase):
|
||||||
# """
|
# """
|
||||||
|
|
|
||||||
|
|
@ -30,8 +30,7 @@ from django.db.models.base import subclass_exception
|
||||||
import warnings
|
import warnings
|
||||||
from django.db.models.options import Options
|
from django.db.models.options import Options
|
||||||
from django.utils.deprecation import RemovedInDjango19Warning
|
from django.utils.deprecation import RemovedInDjango19Warning
|
||||||
from django.core.exceptions import (ObjectDoesNotExist,
|
from django.core.exceptions import MultipleObjectsReturned
|
||||||
MultipleObjectsReturned, FieldError)
|
|
||||||
from django.apps.config import MODELS_MODULE_NAME
|
from django.apps.config import MODELS_MODULE_NAME
|
||||||
from django.db.models.fields.related import OneToOneField
|
from django.db.models.fields.related import OneToOneField
|
||||||
#/ django patch imports
|
#/ django patch imports
|
||||||
|
|
@ -95,6 +94,15 @@ class SharedMemoryModelBase(ModelBase):
|
||||||
already has a wrapper of the given name, the automatic creation is skipped. Note: Remember to
|
already has a wrapper of the given name, the automatic creation is skipped. Note: Remember to
|
||||||
document this auto-wrapping in the class header, this could seem very much like magic to the user otherwise.
|
document this auto-wrapping in the class header, this could seem very much like magic to the user otherwise.
|
||||||
"""
|
"""
|
||||||
|
# set up the typeclass handling only if a variable _is_typeclass is set on the class
|
||||||
|
if "_is_typeclass" in attrs:
|
||||||
|
if "Meta" in attrs:
|
||||||
|
attrs["Meta"].proxy = True
|
||||||
|
else:
|
||||||
|
class Meta:
|
||||||
|
proxy = True
|
||||||
|
attrs["Meta"] = Meta
|
||||||
|
|
||||||
def create_wrapper(cls, fieldname, wrappername, editable=True, foreignkey=False):
|
def create_wrapper(cls, fieldname, wrappername, editable=True, foreignkey=False):
|
||||||
"Helper method to create property wrappers with unique names (must be in separate call)"
|
"Helper method to create property wrappers with unique names (must be in separate call)"
|
||||||
def _get(cls, fname):
|
def _get(cls, fname):
|
||||||
|
|
@ -189,9 +197,8 @@ class SharedMemoryModelBase(ModelBase):
|
||||||
#print "wrapping %s -> %s" % (fieldname, wrappername)
|
#print "wrapping %s -> %s" % (fieldname, wrappername)
|
||||||
create_wrapper(cls, fieldname, wrappername, editable=field.editable, foreignkey=foreignkey)
|
create_wrapper(cls, fieldname, wrappername, editable=field.editable, foreignkey=foreignkey)
|
||||||
|
|
||||||
# django patch
|
# patch start
|
||||||
# Evennia mod, based on Django Ticket #11560: https://code.djangoproject.com/ticket/11560
|
|
||||||
# The actual patch is small and further down.
|
|
||||||
super_new = super(ModelBase, cls).__new__
|
super_new = super(ModelBase, cls).__new__
|
||||||
|
|
||||||
# Also ensure initialization is only performed for subclasses of Model
|
# Also ensure initialization is only performed for subclasses of Model
|
||||||
|
|
@ -319,16 +326,14 @@ class SharedMemoryModelBase(ModelBase):
|
||||||
raise TypeError("Abstract base class containing model fields not permitted for proxy model '%s'." % name)
|
raise TypeError("Abstract base class containing model fields not permitted for proxy model '%s'." % name)
|
||||||
else:
|
else:
|
||||||
continue
|
continue
|
||||||
# Evennia mod, based on Django Ticket #11560: https://code.djangoproject.com/ticket/11560
|
if base is not None:
|
||||||
# This allows multiple inheritance for proxy models
|
|
||||||
while parent._meta.proxy:
|
|
||||||
parent = parent._meta.proxy_for_model
|
|
||||||
if base is not None and base is not parent:
|
|
||||||
#if base is not None:
|
|
||||||
raise TypeError("Proxy model '%s' has more than one non-abstract model base class." % name)
|
raise TypeError("Proxy model '%s' has more than one non-abstract model base class." % name)
|
||||||
else:
|
else:
|
||||||
base = parent
|
base = parent
|
||||||
if base is None:
|
#if base is None: # patch
|
||||||
|
while parent._meta.proxy: # patch
|
||||||
|
parent = parent._meta.proxy_for_model # patch
|
||||||
|
if base is not None and base is not parent: # patch
|
||||||
raise TypeError("Proxy model '%s' has no non-abstract model base class." % name)
|
raise TypeError("Proxy model '%s' has no non-abstract model base class." % name)
|
||||||
new_class._meta.setup_proxy(base)
|
new_class._meta.setup_proxy(base)
|
||||||
new_class._meta.concrete_model = base._meta.concrete_model
|
new_class._meta.concrete_model = base._meta.concrete_model
|
||||||
|
|
@ -423,14 +428,10 @@ class SharedMemoryModelBase(ModelBase):
|
||||||
new_class._meta.apps.register_model(new_class._meta.app_label, new_class)
|
new_class._meta.apps.register_model(new_class._meta.app_label, new_class)
|
||||||
return new_class
|
return new_class
|
||||||
|
|
||||||
def __init__(cls, *args, **kwargs):
|
|
||||||
"""
|
# /patch end
|
||||||
This is for the typeclass system.
|
#return super(SharedMemoryModelBase, cls).__new__(cls, name, bases, attrs, *args, **kwargs)
|
||||||
"""
|
|
||||||
super(SharedMemoryModelBase, cls).__init__(*args, **kwargs)
|
|
||||||
cls.typename = cls.__name__
|
|
||||||
cls.path = "%s.%s" % (cls.__module__, cls.__name__)
|
|
||||||
print "shared __init__", cls
|
|
||||||
|
|
||||||
class SharedMemoryModel(Model):
|
class SharedMemoryModel(Model):
|
||||||
# CL: setting abstract correctly to allow subclasses to inherit the default
|
# CL: setting abstract correctly to allow subclasses to inherit the default
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue