Format code with black. Add makefile to run fmt/tests

This commit is contained in:
Griatch 2019-09-28 18:18:11 +02:00
parent d00bce9288
commit c2c7fa311a
299 changed files with 19037 additions and 11611 deletions

View file

@ -11,10 +11,11 @@ class TagAdmin(admin.ModelAdmin):
"""
A django Admin wrapper for Tags.
"""
search_fields = ('db_key', 'db_category', 'db_tagtype')
list_display = ('db_key', 'db_category', 'db_tagtype', 'db_data')
fields = ('db_key', 'db_category', 'db_tagtype', 'db_data')
list_filter = ('db_tagtype',)
search_fields = ("db_key", "db_category", "db_tagtype")
list_display = ("db_key", "db_category", "db_tagtype", "db_data")
fields = ("db_key", "db_category", "db_tagtype", "db_data")
list_filter = ("db_tagtype",)
class TagForm(forms.ModelForm):
@ -26,18 +27,25 @@ class TagForm(forms.ModelForm):
Object's handler, which will handle the creation, change, or deletion of a tag for us, as well
as updating the handler's cache so that all changes are instantly updated in-game.
"""
tag_key = forms.CharField(label='Tag Name',
required=True,
help_text="This is the main key identifier")
tag_category = forms.CharField(label="Category",
help_text="Used for grouping tags. Unset (default) gives a category of None",
required=False)
tag_type = forms.CharField(label="Type",
help_text="Internal use. Either unset, \"alias\" or \"permission\"",
required=False)
tag_data = forms.CharField(label="Data",
help_text="Usually unused. Intended for eventual info about the tag itself",
required=False)
tag_key = forms.CharField(
label="Tag Name", required=True, help_text="This is the main key identifier"
)
tag_category = forms.CharField(
label="Category",
help_text="Used for grouping tags. Unset (default) gives a category of None",
required=False,
)
tag_type = forms.CharField(
label="Type",
help_text='Internal use. Either unset, "alias" or "permission"',
required=False,
)
tag_data = forms.CharField(
label="Data",
help_text="Usually unused. Intended for eventual info about the tag itself",
required=False,
)
class Meta:
fields = ("tag_key", "tag_category", "tag_data", "tag_type")
@ -54,15 +62,15 @@ class TagForm(forms.ModelForm):
tagcategory = None
tagtype = None
tagdata = None
if hasattr(self.instance, 'tag'):
if hasattr(self.instance, "tag"):
tagkey = self.instance.tag.db_key
tagcategory = self.instance.tag.db_category
tagtype = self.instance.tag.db_tagtype
tagdata = self.instance.tag.db_data
self.fields['tag_key'].initial = tagkey
self.fields['tag_category'].initial = tagcategory
self.fields['tag_type'].initial = tagtype
self.fields['tag_data'].initial = tagdata
self.fields["tag_key"].initial = tagkey
self.fields["tag_category"].initial = tagcategory
self.fields["tag_type"].initial = tagtype
self.fields["tag_data"].initial = tagdata
self.instance.tag_key = tagkey
self.instance.tag_category = tagcategory
self.instance.tag_type = tagtype
@ -78,10 +86,10 @@ class TagForm(forms.ModelForm):
# we are spoofing a tag for the Handler that will be called
# instance = super().save(commit=False)
instance = self.instance
instance.tag_key = self.cleaned_data['tag_key']
instance.tag_category = self.cleaned_data['tag_category'] or None
instance.tag_type = self.cleaned_data['tag_type'] or None
instance.tag_data = self.cleaned_data['tag_data'] or None
instance.tag_key = self.cleaned_data["tag_key"]
instance.tag_category = self.cleaned_data["tag_category"] or None
instance.tag_type = self.cleaned_data["tag_type"] or None
instance.tag_data = self.cleaned_data["tag_data"] or None
return instance
@ -110,6 +118,7 @@ class TagFormSet(forms.BaseInlineFormSet):
else:
handler_name = "tags"
return getattr(related, handler_name)
instances = super().save(commit=False)
# self.deleted_objects is a list created when super of save is called, we'll remove those
for obj in self.deleted_objects:
@ -128,6 +137,7 @@ class TagInline(admin.TabularInline):
of the field on that through model which points to the model being used: 'objectdb',
'msg', 'accountdb', etc.
"""
# Set this to the through model of your desired M2M when subclassing.
model = None
form = TagForm
@ -148,6 +158,7 @@ class TagInline(admin.TabularInline):
class ProxyFormset(formset):
pass
ProxyFormset.related_field = self.related_field
return ProxyFormset
@ -161,20 +172,26 @@ class AttributeForm(forms.ModelForm):
the creation, change, or deletion of an Attribute for us, as well as updating the handler's cache so that all
changes are instantly updated in-game.
"""
attr_key = forms.CharField(label='Attribute Name', required=False, initial="Enter Attribute Name Here")
attr_category = forms.CharField(label="Category",
help_text="type of attribute, for sorting",
required=False,
max_length=128)
attr_key = forms.CharField(
label="Attribute Name", required=False, initial="Enter Attribute Name Here"
)
attr_category = forms.CharField(
label="Category", help_text="type of attribute, for sorting", required=False, max_length=128
)
attr_value = PickledFormField(label="Value", help_text="Value to pickle/save", required=False)
attr_type = forms.CharField(label="Type",
help_text="Internal use. Either unset (normal Attribute) or \"nick\"",
required=False,
max_length=16)
attr_lockstring = forms.CharField(label="Locks",
required=False,
help_text="Lock string on the form locktype:lockdef;lockfunc:lockdef;...",
widget=forms.Textarea(attrs={"rows": 1, "cols": 8}))
attr_type = forms.CharField(
label="Type",
help_text='Internal use. Either unset (normal Attribute) or "nick"',
required=False,
max_length=16,
)
attr_lockstring = forms.CharField(
label="Locks",
required=False,
help_text="Lock string on the form locktype:lockdef;lockfunc:lockdef;...",
widget=forms.Textarea(attrs={"rows": 1, "cols": 8}),
)
class Meta:
fields = ("attr_key", "attr_value", "attr_category", "attr_lockstring", "attr_type")
@ -193,24 +210,24 @@ class AttributeForm(forms.ModelForm):
attr_value = None
attr_type = None
attr_lockstring = None
if hasattr(self.instance, 'attribute'):
if hasattr(self.instance, "attribute"):
attr_key = self.instance.attribute.db_key
attr_category = self.instance.attribute.db_category
attr_value = self.instance.attribute.db_value
attr_type = self.instance.attribute.db_attrtype
attr_lockstring = self.instance.attribute.db_lock_storage
self.fields['attr_key'].initial = attr_key
self.fields['attr_category'].initial = attr_category
self.fields['attr_type'].initial = attr_type
self.fields['attr_value'].initial = attr_value
self.fields['attr_lockstring'].initial = attr_lockstring
self.fields["attr_key"].initial = attr_key
self.fields["attr_category"].initial = attr_category
self.fields["attr_type"].initial = attr_type
self.fields["attr_value"].initial = attr_value
self.fields["attr_lockstring"].initial = attr_lockstring
self.instance.attr_key = attr_key
self.instance.attr_category = attr_category
self.instance.attr_value = attr_value
# prevent from being transformed to str
if isinstance(attr_value, (set, _SaverSet)):
self.fields['attr_value'].disabled = True
self.fields["attr_value"].disabled = True
self.instance.deserialized_value = from_pickle(attr_value)
self.instance.attr_type = attr_type
@ -225,13 +242,13 @@ class AttributeForm(forms.ModelForm):
"""
# we are spoofing an Attribute for the Handler that will be called
instance = self.instance
instance.attr_key = self.cleaned_data['attr_key'] or "no_name_entered_for_attribute"
instance.attr_category = self.cleaned_data['attr_category'] or None
instance.attr_value = self.cleaned_data['attr_value']
instance.attr_key = self.cleaned_data["attr_key"] or "no_name_entered_for_attribute"
instance.attr_category = self.cleaned_data["attr_category"] or None
instance.attr_value = self.cleaned_data["attr_value"]
# convert the serialized string value into an object, if necessary, for AttributeHandler
instance.attr_value = from_pickle(instance.attr_value)
instance.attr_type = self.cleaned_data['attr_type'] or None
instance.attr_lockstring = self.cleaned_data['attr_lockstring']
instance.attr_type = self.cleaned_data["attr_type"] or None
instance.attr_lockstring = self.cleaned_data["attr_lockstring"]
return instance
def clean_attr_value(self):
@ -240,7 +257,7 @@ class AttributeForm(forms.ModelForm):
failing on them. Otherwise they will be turned into str.
"""
data = self.cleaned_data['attr_value']
data = self.cleaned_data["attr_value"]
initial = self.instance.attr_value
if isinstance(initial, (set, _SaverSet, datetime)):
return initial
@ -264,6 +281,7 @@ class AttributeFormSet(forms.BaseInlineFormSet):
else:
handler_name = "attributes"
return getattr(related, handler_name)
instances = super().save(commit=False)
for obj in self.deleted_objects:
# self.deleted_objects is a list created when super of save is called, we'll remove those
@ -276,9 +294,13 @@ class AttributeFormSet(forms.BaseInlineFormSet):
value = instance.attr_value
try:
handler.add(instance.attr_key, value,
category=instance.attr_category, strattr=False,
lockstring=instance.attr_lockstring)
handler.add(
instance.attr_key,
value,
category=instance.attr_category,
strattr=False,
lockstring=instance.attr_lockstring,
)
except (TypeError, ValueError):
# catch errors in nick templates and continue
traceback.print_exc()
@ -293,6 +315,7 @@ class AttributeInline(admin.TabularInline):
of the field on that through model which points to the model being used: 'objectdb',
'msg', 'accountdb', etc.
"""
# Set this to the through model of your desired M2M when subclassing.
model = None
form = AttributeForm

View file

@ -60,35 +60,51 @@ class Attribute(SharedMemoryModel):
#
# These database fields are all set using their corresponding properties,
# named same as the field, but withtout the db_* prefix.
db_key = models.CharField('key', max_length=255, db_index=True)
db_key = models.CharField("key", max_length=255, db_index=True)
db_value = PickledObjectField(
'value', null=True,
"value",
null=True,
help_text="The data returned when the attribute is accessed. Must be "
"written as a Python literal if editing through the admin "
"interface. Attribute values which are not Python literals "
"cannot be edited through the admin interface.")
"written as a Python literal if editing through the admin "
"interface. Attribute values which are not Python literals "
"cannot be edited through the admin interface.",
)
db_strvalue = models.TextField(
'strvalue', null=True, blank=True,
help_text="String-specific storage for quick look-up")
"strvalue", null=True, blank=True, help_text="String-specific storage for quick look-up"
)
db_category = models.CharField(
'category', max_length=128, db_index=True, blank=True, null=True,
help_text="Optional categorization of attribute.")
"category",
max_length=128,
db_index=True,
blank=True,
null=True,
help_text="Optional categorization of attribute.",
)
# Lock storage
db_lock_storage = models.TextField(
'locks', blank=True,
help_text="Lockstrings for this object are stored here.")
"locks", blank=True, help_text="Lockstrings for this object are stored here."
)
db_model = models.CharField(
'model', max_length=32, db_index=True, blank=True, null=True,
"model",
max_length=32,
db_index=True,
blank=True,
null=True,
help_text="Which model of object this attribute is attached to (A "
"natural key like 'objects.objectdb'). You should not change "
"this value unless you know what you are doing.")
"natural key like 'objects.objectdb'). You should not change "
"this value unless you know what you are doing.",
)
# subclass of Attribute (None or nick)
db_attrtype = models.CharField(
'attrtype', max_length=16, db_index=True, blank=True, null=True,
help_text="Subclass of Attribute (None or nick)")
"attrtype",
max_length=16,
db_index=True,
blank=True,
null=True,
help_text="Subclass of Attribute (None or nick)",
)
# time stamp
db_date_created = models.DateTimeField(
'date_created', editable=False, auto_now_add=True)
db_date_created = models.DateTimeField("date_created", editable=False, auto_now_add=True)
# Database manager
# objects = managers.AttributeManager()
@ -155,6 +171,7 @@ class Attribute(SharedMemoryModel):
def __value_del(self):
"""Deleter. Allows for del attr.value. This removes the entire attribute."""
self.delete()
value = property(__value_get, __value_set, __value_del)
#
@ -169,7 +186,7 @@ class Attribute(SharedMemoryModel):
def __repr__(self):
return "%s(%s)" % (self.db_key, self.id)
def access(self, accessing_obj, access_type='read', default=False, **kwargs):
def access(self, accessing_obj, access_type="read", default=False, **kwargs):
"""
Determines if another object has permission to access.
@ -195,10 +212,12 @@ class Attribute(SharedMemoryModel):
# Handlers making use of the Attribute model
#
class AttributeHandler(object):
"""
Handler for adding Attributes to the object.
"""
_m2m_fieldname = "db_attributes"
_attrcreate = "attrcreate"
_attredit = "attredit"
@ -218,17 +237,26 @@ class AttributeHandler(object):
def _fullcache(self):
"""Cache all attributes of this object"""
query = {"%s__id" % self._model: self._objid,
"attribute__db_model__iexact": self._model,
"attribute__db_attrtype": self._attrtype}
query = {
"%s__id" % self._model: self._objid,
"attribute__db_model__iexact": self._model,
"attribute__db_attrtype": self._attrtype,
}
attrs = [
conn.attribute for conn in getattr(
self.obj,
self._m2m_fieldname).through.objects.filter(
**query)]
self._cache = dict(("%s-%s" % (to_str(attr.db_key).lower(),
attr.db_category.lower() if attr.db_category else None),
attr) for attr in attrs)
conn.attribute
for conn in getattr(self.obj, self._m2m_fieldname).through.objects.filter(**query)
]
self._cache = dict(
(
"%s-%s"
% (
to_str(attr.db_key).lower(),
attr.db_category.lower() if attr.db_category else None,
),
attr,
)
for attr in attrs
)
self._cache_complete = True
def _getcache(self, key=None, category=None):
@ -276,11 +304,13 @@ class AttributeHandler(object):
else:
return [] # no such attribute: return an empty list
else:
query = {"%s__id" % self._model: self._objid,
"attribute__db_model__iexact": self._model,
"attribute__db_attrtype": self._attrtype,
"attribute__db_key__iexact": key.lower(),
"attribute__db_category__iexact": category.lower() if category else None}
query = {
"%s__id" % self._model: self._objid,
"attribute__db_model__iexact": self._model,
"attribute__db_attrtype": self._attrtype,
"attribute__db_key__iexact": key.lower(),
"attribute__db_category__iexact": category.lower() if category else None,
}
if not self.obj.pk:
return []
conn = getattr(self.obj, self._m2m_fieldname).through.objects.filter(**query)
@ -303,12 +333,18 @@ class AttributeHandler(object):
return [attr for key, attr in self._cache.items() if key.endswith(catkey) and attr]
else:
# we have to query to make this category up-date in the cache
query = {"%s__id" % self._model: self._objid,
"attribute__db_model__iexact": self._model,
"attribute__db_attrtype": self._attrtype,
"attribute__db_category__iexact": category.lower() if category else None}
attrs = [conn.attribute for conn
in getattr(self.obj, self._m2m_fieldname).through.objects.filter(**query)]
query = {
"%s__id" % self._model: self._objid,
"attribute__db_model__iexact": self._model,
"attribute__db_attrtype": self._attrtype,
"attribute__db_category__iexact": category.lower() if category else None,
}
attrs = [
conn.attribute
for conn in getattr(self.obj, self._m2m_fieldname).through.objects.filter(
**query
)
]
for attr in attrs:
if attr.pk:
cachekey = "%s-%s" % (attr.db_key, category)
@ -350,8 +386,11 @@ class AttributeHandler(object):
cachekey = "%s-%s" % (key, category)
self._cache.pop(cachekey, None)
else:
self._cache = {key: attrobj for key, attrobj in
list(self._cache.items()) if not key.endswith(catkey)}
self._cache = {
key: attrobj
for key, attrobj in list(self._cache.items())
if not key.endswith(catkey)
}
# mark that the category cache is no longer up-to-date
self._catcache.pop(catkey, None)
self._cache_complete = False
@ -388,9 +427,18 @@ class AttributeHandler(object):
ret.extend(bool(attr) for attr in self._getcache(keystr, category))
return ret[0] if len(ret) == 1 else ret
def get(self, key=None, default=None, category=None, return_obj=False,
strattr=False, raise_exception=False, accessing_obj=None,
default_access=True, return_list=False):
def get(
self,
key=None,
default=None,
category=None,
return_obj=False,
strattr=False,
raise_exception=False,
accessing_obj=None,
default_access=True,
return_list=False,
):
"""
Get the Attribute.
@ -444,9 +492,11 @@ class AttributeHandler(object):
if accessing_obj:
# check 'attrread' locks
ret = [attr for attr in ret if attr.access(accessing_obj,
self._attrread,
default=default_access)]
ret = [
attr
for attr in ret
if attr.access(accessing_obj, self._attrread, default=default_access)
]
if strattr:
ret = ret if return_obj else [attr.strvalue for attr in ret if attr]
else:
@ -456,8 +506,16 @@ class AttributeHandler(object):
return ret if ret else [default] if default is not None else []
return ret[0] if ret and len(ret) == 1 else ret or default
def add(self, key, value, category=None, lockstring="",
strattr=False, accessing_obj=None, default_access=True):
def add(
self,
key,
value,
category=None,
lockstring="",
strattr=False,
accessing_obj=None,
default_access=True,
):
"""
Add attribute to object, with optional `lockstring`.
@ -479,8 +537,9 @@ class AttributeHandler(object):
`attrcreate` is defined on the Attribute in question.
"""
if accessing_obj and not self.obj.access(accessing_obj, self._attrcreate,
default=default_access):
if accessing_obj and not self.obj.access(
accessing_obj, self._attrcreate, default=default_access
):
# check create access
return
@ -503,12 +562,14 @@ class AttributeHandler(object):
attr_obj.value = value
else:
# create a new Attribute (no OOB handlers can be notified)
kwargs = {"db_key": keystr,
"db_category": category,
"db_model": self._model,
"db_attrtype": self._attrtype,
"db_value": None if strattr else to_pickle(value),
"db_strvalue": value if strattr else None}
kwargs = {
"db_key": keystr,
"db_category": category,
"db_model": self._model,
"db_attrtype": self._attrtype,
"db_value": None if strattr else to_pickle(value),
"db_strvalue": value if strattr else None,
}
new_attr = Attribute(**kwargs)
new_attr.save()
getattr(self.obj, self._m2m_fieldname).add(new_attr)
@ -547,7 +608,7 @@ class AttributeHandler(object):
"""
new_attrobjs = []
strattr = kwargs.get('strattr', False)
strattr = kwargs.get("strattr", False)
for tup in args:
if not is_iter(tup) or len(tup) < 2:
raise RuntimeError("batch_add requires iterables as arguments (got %r)." % tup)
@ -563,7 +624,7 @@ class AttributeHandler(object):
attr_obj = attr_objs[0]
# update an existing attribute object
attr_obj.db_category = category
attr_obj.db_lock_storage = lockstring or ''
attr_obj.db_lock_storage = lockstring or ""
attr_obj.save(update_fields=["db_category", "db_lock_storage"])
if strattr:
# store as a simple string (will not notify OOB handlers)
@ -574,13 +635,15 @@ class AttributeHandler(object):
attr_obj.value = new_value
else:
# create a new Attribute (no OOB handlers can be notified)
kwargs = {"db_key": keystr,
"db_category": category,
"db_model": self._model,
"db_attrtype": self._attrtype,
"db_value": None if strattr else to_pickle(new_value),
"db_strvalue": new_value if strattr else None,
"db_lock_storage": lockstring or ''}
kwargs = {
"db_key": keystr,
"db_category": category,
"db_model": self._model,
"db_attrtype": self._attrtype,
"db_value": None if strattr else to_pickle(new_value),
"db_strvalue": new_value if strattr else None,
"db_lock_storage": lockstring or "",
}
new_attr = Attribute(**kwargs)
new_attr.save()
new_attrobjs.append(new_attr)
@ -589,8 +652,14 @@ class AttributeHandler(object):
# Add new objects to m2m field all at once
getattr(self.obj, self._m2m_fieldname).add(*new_attrobjs)
def remove(self, key=None, raise_exception=False, category=None,
accessing_obj=None, default_access=True):
def remove(
self,
key=None,
raise_exception=False,
category=None,
accessing_obj=None,
default_access=True,
):
"""
Remove attribute or a list of attributes from object.
@ -620,8 +689,9 @@ class AttributeHandler(object):
"""
if key is None:
self.clear(category=category, accessing_obj=accessing_obj,
default_access=default_access)
self.clear(
category=category, accessing_obj=accessing_obj, default_access=default_access
)
return
category = category.strip().lower() if category is not None else None
@ -632,10 +702,9 @@ class AttributeHandler(object):
attr_objs = self._getcache(keystr, category)
for attr_obj in attr_objs:
if not (
accessing_obj and not attr_obj.access(
accessing_obj,
self._attredit,
default=default_access)):
accessing_obj
and not attr_obj.access(accessing_obj, self._attredit, default=default_access)
):
try:
attr_obj.delete()
except AssertionError:
@ -672,9 +741,11 @@ class AttributeHandler(object):
attrs = self._cache.values()
if accessing_obj:
[attr.delete() for attr in attrs
if attr and
attr.access(accessing_obj, self._attredit, default=default_access)]
[
attr.delete()
for attr in attrs
if attr and attr.access(accessing_obj, self._attredit, default=default_access)
]
else:
[attr.delete() for attr in attrs if attr and attr.pk]
self._cache = {}
@ -700,11 +771,13 @@ class AttributeHandler(object):
"""
if not self._cache_complete:
self._fullcache()
attrs = sorted([attr for attr in self._cache.values() if attr],
key=lambda o: o.id)
attrs = sorted([attr for attr in self._cache.values() if attr], key=lambda o: o.id)
if accessing_obj:
return [attr for attr in attrs
if attr.access(accessing_obj, self._attredit, default=default_access)]
return [
attr
for attr in attrs
if attr.access(accessing_obj, self._attredit, default=default_access)
]
else:
return attrs
@ -815,6 +888,7 @@ class NickHandler(AttributeHandler):
They also always use the `strvalue` fields for their data.
"""
_attrtype = "nick"
def __init__(self, *args, **kwargs):
@ -858,8 +932,11 @@ class NickHandler(AttributeHandler):
else:
retval = super().get(key=key, category=category, **kwargs)
if retval:
return retval[3] if isinstance(retval, tuple) else \
[tup[3] for tup in make_iter(retval)]
return (
retval[3]
if isinstance(retval, tuple)
else [tup[3] for tup in make_iter(retval)]
)
return None
def add(self, key, replacement, category="inputline", **kwargs):
@ -879,8 +956,7 @@ class NickHandler(AttributeHandler):
nick_regex, nick_template = initialize_nick_templates(key + " $1", replacement + " $1")
else:
nick_regex, nick_template = initialize_nick_templates(key, replacement)
super().add(key, (nick_regex, nick_template, key, replacement),
category=category, **kwargs)
super().add(key, (nick_regex, nick_template, key, replacement), category=category, **kwargs)
def remove(self, key, category="inputline", **kwargs):
"""
@ -917,12 +993,24 @@ class NickHandler(AttributeHandler):
"""
nicks = {}
for category in make_iter(categories):
nicks.update({nick.key: nick for nick in make_iter(
self.get(category=category, return_obj=True)) if nick and nick.key})
nicks.update(
{
nick.key: nick
for nick in make_iter(self.get(category=category, return_obj=True))
if nick and nick.key
}
)
if include_account and self.obj.has_account:
for category in make_iter(categories):
nicks.update({nick.key: nick for nick in make_iter(self.obj.account.nicks.get(
category=category, return_obj=True)) if nick and nick.key})
nicks.update(
{
nick.key: nick
for nick in make_iter(
self.obj.account.nicks.get(category=category, return_obj=True)
)
if nick and nick.key
}
)
for key, nick in nicks.items():
nick_regex, template, _, _ = nick.value
regex = self._regex_cache.get(nick_regex)

View file

@ -11,23 +11,27 @@ from evennia.utils.utils import make_iter, variable_from_module
from evennia.typeclasses.attributes import Attribute
from evennia.typeclasses.tags import Tag
__all__ = ("TypedObjectManager", )
__all__ = ("TypedObjectManager",)
_GA = object.__getattribute__
_Tag = None
# Managers
class TypedObjectManager(idmapper.manager.SharedMemoryManager):
"""
Common ObjectManager for all dbobjects.
"""
# common methods for all typed managers. These are used
# in other methods. Returns querysets.
# Attribute manager methods
def get_attribute(self, key=None, category=None, value=None, strvalue=None, obj=None, attrtype=None):
def get_attribute(
self, key=None, category=None, value=None, strvalue=None, obj=None, attrtype=None
):
"""
Return Attribute objects by key, by category, by value, by
strvalue, by object (it is stored on) or with a combination of
@ -69,8 +73,10 @@ class TypedObjectManager(idmapper.manager.SharedMemoryManager):
# no reason to make strvalue/value mutually exclusive at this level
query.append(("attribute__db_value", value))
return Attribute.objects.filter(
pk__in=self.model.db_attributes.through.objects.filter(
**dict(query)).values_list("attribute_id", flat=True))
pk__in=self.model.db_attributes.through.objects.filter(**dict(query)).values_list(
"attribute_id", flat=True
)
)
def get_nick(self, key=None, category=None, value=None, strvalue=None, obj=None):
"""
@ -91,7 +97,9 @@ class TypedObjectManager(idmapper.manager.SharedMemoryManager):
nicks (list): The matching Nicks.
"""
return self.get_attribute(key=key, category=category, value=value, strvalue=strvalue, obj=obj)
return self.get_attribute(
key=key, category=category, value=value, strvalue=strvalue, obj=obj
)
def get_by_attribute(self, key=None, category=None, value=None, strvalue=None, attrtype=None):
"""
@ -149,7 +157,6 @@ class TypedObjectManager(idmapper.manager.SharedMemoryManager):
# Tag manager methods
def get_tag(self, key=None, category=None, obj=None, tagtype=None, global_search=False):
"""
Return Tag objects by key, by category, by object (it is
@ -194,8 +201,10 @@ class TypedObjectManager(idmapper.manager.SharedMemoryManager):
if category:
query.append(("tag__db_category", category))
return Tag.objects.filter(
pk__in=self.model.db_tags.through.objects.filter(
**dict(query)).values_list("tag_id", flat=True))
pk__in=self.model.db_tags.through.objects.filter(**dict(query)).values_list(
"tag_id", flat=True
)
)
def get_permission(self, key=None, category=None, obj=None):
"""
@ -259,8 +268,11 @@ class TypedObjectManager(idmapper.manager.SharedMemoryManager):
n_categories = len(categories)
dbmodel = self.model.__dbclass__.__name__.lower()
query = self.filter(db_tags__db_tagtype__iexact=tagtype,
db_tags__db_model__iexact=dbmodel).distinct().order_by('id')
query = (
self.filter(db_tags__db_tagtype__iexact=tagtype, db_tags__db_model__iexact=dbmodel)
.distinct()
.order_by("id")
)
if n_keys > 0:
# keys and/or categories given
@ -270,11 +282,14 @@ class TypedObjectManager(idmapper.manager.SharedMemoryManager):
cat = categories[0]
categories = [cat for _ in range(n_keys)]
elif 1 < n_categories < n_keys:
raise IndexError("get_by_tag needs a single category or a list of categories "
"the same length as the list of tags.")
raise IndexError(
"get_by_tag needs a single category or a list of categories "
"the same length as the list of tags."
)
for ikey, key in enumerate(keys):
query = query.filter(db_tags__db_key__iexact=key,
db_tags__db_category__iexact=categories[ikey])
query = query.filter(
db_tags__db_key__iexact=key, db_tags__db_category__iexact=categories[ikey]
)
else:
# only one or more categories given
for category in categories:
@ -336,8 +351,7 @@ class TypedObjectManager(idmapper.manager.SharedMemoryManager):
# try to get old tag
dbmodel = self.model.__dbclass__.__name__.lower()
tag = self.get_tag(key=key, category=category, tagtype=tagtype,
global_search=True)
tag = self.get_tag(key=key, category=category, tagtype=tagtype, global_search=True)
if tag and data is not None:
# get tag from list returned by get_tag
tag = tag[0]
@ -354,7 +368,8 @@ class TypedObjectManager(idmapper.manager.SharedMemoryManager):
db_category=category.strip().lower() if category and key is not None else None,
db_data=data,
db_model=dbmodel,
db_tagtype=tagtype.strip().lower() if tagtype is not None else None)
db_tagtype=tagtype.strip().lower() if tagtype is not None else None,
)
tag.save()
return make_iter(tag)[0]
@ -378,7 +393,7 @@ class TypedObjectManager(idmapper.manager.SharedMemoryManager):
if reqhash and not (isinstance(dbref, str) and dbref.startswith("#")):
return None
if isinstance(dbref, str):
dbref = dbref.lstrip('#')
dbref = dbref.lstrip("#")
try:
if int(dbref) < 0:
return None
@ -449,10 +464,9 @@ class TypedObjectManager(idmapper.manager.SharedMemoryManager):
"""
dbtotals = {}
typeclass_paths = set(self.values_list('db_typeclass_path', flat=True))
typeclass_paths = set(self.values_list("db_typeclass_path", flat=True))
for typeclass_path in typeclass_paths:
dbtotals[typeclass_path] = \
self.filter(db_typeclass_path=typeclass_path).count()
dbtotals[typeclass_path] = self.filter(db_typeclass_path=typeclass_path).count()
return dbtotals
def typeclass_search(self, typeclass, include_children=False, include_parents=False):
@ -539,30 +553,30 @@ class TypeclassManager(TypedObjectManager):
for ipart, part in enumerate(querysplit):
key, rest = part, ""
if ":" in part:
key, rest = part.split(':', 1)
key, rest = part.split(":", 1)
# tags are on the form tag or tag:category
if key.startswith('tag=='):
if key.startswith("tag=="):
plustags.append((key[5:], rest))
continue
elif key.startswith('tag!='):
elif key.startswith("tag!="):
negtags.append((key[5:], rest))
continue
# attrs are on the form attr:value or attr:value:category
elif rest:
value, category = rest, ""
if ":" in rest:
value, category = rest.split(':', 1)
if key.startswith('attr=='):
value, category = rest.split(":", 1)
if key.startswith("attr=="):
plusattrs.append((key[7:], value, category))
continue
elif key.startswith('attr!='):
elif key.startswith("attr!="):
negattrs.append((key[7:], value, category))
continue
# if we get here, we are entering a key search criterion which
# we assume is one word.
queries.append(part)
# build query from components
query = ' '.join(queries)
query = " ".join(queries)
# TODO
def get(self, *args, **kwargs):
@ -663,7 +677,11 @@ class TypeclassManager(TypedObjectManager):
Returns:
Annotated queryset.
"""
return super(TypeclassManager, self).filter(db_typeclass_path=self.model.path).annotate(*args, **kwargs)
return (
super(TypeclassManager, self)
.filter(db_typeclass_path=self.model.path)
.annotate(*args, **kwargs)
)
def values(self, *args, **kwargs):
"""
@ -675,7 +693,11 @@ class TypeclassManager(TypedObjectManager):
Returns:
Queryset of values dictionaries, just filtered by typeclass first.
"""
return super(TypeclassManager, self).filter(db_typeclass_path=self.model.path).values(*args, **kwargs)
return (
super(TypeclassManager, self)
.filter(db_typeclass_path=self.model.path)
.values(*args, **kwargs)
)
def values_list(self, *args, **kwargs):
"""
@ -687,7 +709,11 @@ class TypeclassManager(TypedObjectManager):
Returns:
Queryset of value_list tuples, just filtered by typeclass first.
"""
return super(TypeclassManager, self).filter(db_typeclass_path=self.model.path).values_list(*args, **kwargs)
return (
super(TypeclassManager, self)
.filter(db_typeclass_path=self.model.path)
.values_list(*args, **kwargs)
)
def _get_subclasses(self, cls):
"""
@ -717,8 +743,9 @@ class TypeclassManager(TypedObjectManager):
on the model base used.
"""
paths = [self.model.path] + ["%s.%s" % (cls.__module__, cls.__name__)
for cls in self._get_subclasses(self.model)]
paths = [self.model.path] + [
"%s.%s" % (cls.__module__, cls.__name__) for cls in self._get_subclasses(self.model)
]
kwargs.update({"db_typeclass_path__in": paths})
return super().get(**kwargs)
@ -738,8 +765,9 @@ class TypeclassManager(TypedObjectManager):
"""
# query, including all subclasses
paths = [self.model.path] + ["%s.%s" % (cls.__module__, cls.__name__)
for cls in self._get_subclasses(self.model)]
paths = [self.model.path] + [
"%s.%s" % (cls.__module__, cls.__name__) for cls in self._get_subclasses(self.model)
]
kwargs.update({"db_typeclass_path__in": paths})
return super().filter(*args, **kwargs)
@ -752,6 +780,7 @@ class TypeclassManager(TypedObjectManager):
objects (list): The objects found.
"""
paths = [self.model.path] + ["%s.%s" % (cls.__module__, cls.__name__)
for cls in self._get_subclasses(self.model)]
paths = [self.model.path] + [
"%s.%s" % (cls.__module__, cls.__name__) for cls in self._get_subclasses(self.model)
]
return super().all().filter(db_typeclass_path__in=paths)

View file

@ -8,54 +8,156 @@ import evennia.utils.picklefield
class Migration(migrations.Migration):
dependencies = [
]
dependencies = []
operations = [
migrations.CreateModel(
name='Attribute',
name="Attribute",
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('db_key', models.CharField(max_length=255, verbose_name='key', db_index=True)),
('db_value', evennia.utils.picklefield.PickledObjectField(help_text='The data returned when the attribute is accessed. Must be written as a Python literal if editing through the admin interface. Attribute values which are not Python literals cannot be edited through the admin interface.', null=True, verbose_name='value')),
('db_strvalue', models.TextField(help_text='String-specific storage for quick look-up', null=True, verbose_name='strvalue', blank=True)),
('db_category', models.CharField(max_length=128, blank=True, help_text='Optional categorization of attribute.', null=True, verbose_name='category', db_index=True)),
('db_lock_storage', models.TextField(help_text='Lockstrings for this object are stored here.', verbose_name='locks', blank=True)),
('db_model', models.CharField(max_length=32, blank=True, help_text='Which model of object this attribute is attached to (A natural key like objects.dbobject). You should not change this value unless you know what you are doing.', null=True, verbose_name='model', db_index=True)),
('db_attrtype', models.CharField(max_length=16, blank=True, help_text='Subclass of Attribute (None or nick)', null=True, verbose_name='attrtype', db_index=True)),
('db_date_created', models.DateTimeField(auto_now_add=True, verbose_name='date_created')),
(
"id",
models.AutoField(
verbose_name="ID", serialize=False, auto_created=True, primary_key=True
),
),
("db_key", models.CharField(max_length=255, verbose_name="key", db_index=True)),
(
"db_value",
evennia.utils.picklefield.PickledObjectField(
help_text="The data returned when the attribute is accessed. Must be written as a Python literal if editing through the admin interface. Attribute values which are not Python literals cannot be edited through the admin interface.",
null=True,
verbose_name="value",
),
),
(
"db_strvalue",
models.TextField(
help_text="String-specific storage for quick look-up",
null=True,
verbose_name="strvalue",
blank=True,
),
),
(
"db_category",
models.CharField(
max_length=128,
blank=True,
help_text="Optional categorization of attribute.",
null=True,
verbose_name="category",
db_index=True,
),
),
(
"db_lock_storage",
models.TextField(
help_text="Lockstrings for this object are stored here.",
verbose_name="locks",
blank=True,
),
),
(
"db_model",
models.CharField(
max_length=32,
blank=True,
help_text="Which model of object this attribute is attached to (A natural key like objects.dbobject). You should not change this value unless you know what you are doing.",
null=True,
verbose_name="model",
db_index=True,
),
),
(
"db_attrtype",
models.CharField(
max_length=16,
blank=True,
help_text="Subclass of Attribute (None or nick)",
null=True,
verbose_name="attrtype",
db_index=True,
),
),
(
"db_date_created",
models.DateTimeField(auto_now_add=True, verbose_name="date_created"),
),
],
options={
'verbose_name': 'Evennia Attribute',
},
options={"verbose_name": "Evennia Attribute"},
bases=(models.Model,),
),
migrations.CreateModel(
name='Tag',
name="Tag",
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('db_key', models.CharField(help_text='tag identifier', max_length=255, null=True, verbose_name='key', db_index=True)),
('db_category', models.CharField(help_text='tag category', max_length=64, null=True, verbose_name='category', db_index=True)),
('db_data', models.TextField(help_text='optional data field with extra information. This is not searched for.', null=True, verbose_name='data', blank=True)),
('db_model', models.CharField(help_text='database model to Tag', max_length=32, null=True, verbose_name='model', db_index=True)),
('db_tagtype', models.CharField(help_text='overall type of Tag', max_length=16, null=True, verbose_name='tagtype', db_index=True)),
(
"id",
models.AutoField(
verbose_name="ID", serialize=False, auto_created=True, primary_key=True
),
),
(
"db_key",
models.CharField(
help_text="tag identifier",
max_length=255,
null=True,
verbose_name="key",
db_index=True,
),
),
(
"db_category",
models.CharField(
help_text="tag category",
max_length=64,
null=True,
verbose_name="category",
db_index=True,
),
),
(
"db_data",
models.TextField(
help_text="optional data field with extra information. This is not searched for.",
null=True,
verbose_name="data",
blank=True,
),
),
(
"db_model",
models.CharField(
help_text="database model to Tag",
max_length=32,
null=True,
verbose_name="model",
db_index=True,
),
),
(
"db_tagtype",
models.CharField(
help_text="overall type of Tag",
max_length=16,
null=True,
verbose_name="tagtype",
db_index=True,
),
),
],
options={
'verbose_name': 'Tag',
},
options={"verbose_name": "Tag"},
bases=(models.Model,),
),
migrations.AlterUniqueTogether(
name='tag',
unique_together=set([('db_key', 'db_category', 'db_tagtype')]),
name="tag", unique_together=set([("db_key", "db_category", "db_tagtype")])
),
migrations.AlterIndexTogether(
name='tag',
index_together=set([('db_key', 'db_category', 'db_tagtype')]),
name="tag", index_together=set([("db_key", "db_category", "db_tagtype")])
),
]
# if we are using Oracle, we need to remove the AlterIndexTogether operation
# since Oracle seems to create its own index already at AlterUniqueTogether, meaning
# there is a conflict (see issue #732).
if settings.DATABASES['default']['ENGINE'] == "django.db.backends.oracle":
if settings.DATABASES["default"]["ENGINE"] == "django.db.backends.oracle":
del operations[3]

View file

@ -7,14 +7,21 @@ from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('typeclasses', '0001_initial'),
('auth', '0007_alter_validators_add_error_messages')
("typeclasses", "0001_initial"),
("auth", "0007_alter_validators_add_error_messages"),
]
operations = [
migrations.AlterField(
model_name='attribute',
name='db_model',
field=models.CharField(max_length=32, blank=True, help_text="Which model of object this attribute is attached to (A natural key like 'objects.dbobject'). You should not change this value unless you know what you are doing.", null=True, verbose_name='model', db_index=True),
),
model_name="attribute",
name="db_model",
field=models.CharField(
max_length=32,
blank=True,
help_text="Which model of object this attribute is attached to (A natural key like 'objects.dbobject'). You should not change this value unless you know what you are doing.",
null=True,
verbose_name="model",
db_index=True,
),
)
]

View file

@ -8,107 +8,64 @@ import evennia.accounts.manager
class Migration(migrations.Migration):
dependencies = [
('objects', '0005_auto_20150403_2339'),
('scripts', '0007_auto_20150403_2339'),
('accounts', '0004_auto_20150403_2339'),
('typeclasses', '0002_auto_20150109_0913'),
("objects", "0005_auto_20150403_2339"),
("scripts", "0007_auto_20150403_2339"),
("accounts", "0004_auto_20150403_2339"),
("typeclasses", "0002_auto_20150109_0913"),
]
operations = [
migrations.CreateModel(
name='DefaultObject',
fields=[
],
options={
'proxy': True,
},
bases=('objects.objectdb',),
name="DefaultObject", fields=[], options={"proxy": True}, bases=("objects.objectdb",)
),
migrations.CreateModel(
name='DefaultAccount',
fields=[
],
options={
'proxy': True,
},
bases=('accounts.accountdb',),
managers=[
('objects', evennia.accounts.manager.AccountManager()),
],
name="DefaultAccount",
fields=[],
options={"proxy": True},
bases=("accounts.accountdb",),
managers=[("objects", evennia.accounts.manager.AccountManager())],
),
migrations.CreateModel(
name='ScriptBase',
fields=[
],
options={
'proxy': True,
},
bases=('scripts.scriptdb',),
name="ScriptBase", fields=[], options={"proxy": True}, bases=("scripts.scriptdb",)
),
migrations.CreateModel(
name='DefaultCharacter',
fields=[
],
options={
'proxy': True,
},
bases=('typeclasses.defaultobject',),
name="DefaultCharacter",
fields=[],
options={"proxy": True},
bases=("typeclasses.defaultobject",),
),
migrations.CreateModel(
name='DefaultExit',
fields=[
],
options={
'proxy': True,
},
bases=('typeclasses.defaultobject',),
name="DefaultExit",
fields=[],
options={"proxy": True},
bases=("typeclasses.defaultobject",),
),
migrations.CreateModel(
name='DefaultGuest',
fields=[
],
options={
'proxy': True,
},
bases=('typeclasses.defaultaccount',),
managers=[
('objects', evennia.accounts.manager.AccountManager()),
],
name="DefaultGuest",
fields=[],
options={"proxy": True},
bases=("typeclasses.defaultaccount",),
managers=[("objects", evennia.accounts.manager.AccountManager())],
),
migrations.CreateModel(
name='DefaultRoom',
fields=[
],
options={
'proxy': True,
},
bases=('typeclasses.defaultobject',),
name="DefaultRoom",
fields=[],
options={"proxy": True},
bases=("typeclasses.defaultobject",),
),
migrations.CreateModel(
name='DefaultScript',
fields=[
],
options={
'proxy': True,
},
bases=('typeclasses.scriptbase',),
name="DefaultScript",
fields=[],
options={"proxy": True},
bases=("typeclasses.scriptbase",),
),
migrations.CreateModel(
name='DoNothing',
fields=[
],
options={
'proxy': True,
},
bases=('typeclasses.defaultscript',),
name="DoNothing",
fields=[],
options={"proxy": True},
bases=("typeclasses.defaultscript",),
),
migrations.CreateModel(
name='Store',
fields=[
],
options={
'proxy': True,
},
bases=('typeclasses.defaultscript',),
name="Store", fields=[], options={"proxy": True}, bases=("typeclasses.defaultscript",)
),
]

View file

@ -7,13 +7,23 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('typeclasses', '0003_defaultcharacter_defaultexit_defaultguest_defaultobject_defaultplayer_defaultroom_defaultscript_dono'),
(
"typeclasses",
"0003_defaultcharacter_defaultexit_defaultguest_defaultobject_defaultplayer_defaultroom_defaultscript_dono",
)
]
operations = [
migrations.AlterField(
model_name='attribute',
name='db_model',
field=models.CharField(max_length=32, blank=True, help_text="Which model of object this attribute is attached to (A natural key like 'objects.objectdb'). You should not change this value unless you know what you are doing.", null=True, verbose_name='model', db_index=True),
),
model_name="attribute",
name="db_model",
field=models.CharField(
max_length=32,
blank=True,
help_text="Which model of object this attribute is attached to (A natural key like 'objects.objectdb'). You should not change this value unless you know what you are doing.",
null=True,
verbose_name="model",
db_index=True,
),
)
]

View file

@ -22,11 +22,9 @@ def update_nicks(apps, schema_editor):
class Migration(migrations.Migration):
dependencies = [
('typeclasses', '0004_auto_20151101_1759'),
('comms', '0010_auto_20161206_1912'),
('help', '0001_initial')
("typeclasses", "0004_auto_20151101_1759"),
("comms", "0010_auto_20161206_1912"),
("help", "0001_initial"),
]
operations = [
migrations.RunPython(update_nicks)
]
operations = [migrations.RunPython(update_nicks)]

View file

@ -7,41 +7,37 @@ from django.db import migrations
def update_tags_with_dbmodel(apps, schema_editor):
ObjectDB = apps.get_model('objects', 'ObjectDB')
ObjectDB = apps.get_model("objects", "ObjectDB")
for obj in ObjectDB.objects.all():
obj.db_attributes.all().update(db_model="objectdb")
obj.db_tags.all().update(db_model="objectdb")
AccountDB = apps.get_model('accounts', 'AccountDB')
AccountDB = apps.get_model("accounts", "AccountDB")
for obj in AccountDB.objects.all():
obj.db_attributes.all().update(db_model="accountdb")
obj.db_tags.all().update(db_model="accountdb")
ScriptDB = apps.get_model('scripts', 'ScriptDB')
ScriptDB = apps.get_model("scripts", "ScriptDB")
for obj in ScriptDB.objects.all():
obj.db_attributes.all().update(db_model="scriptdb")
obj.db_tags.all().update(db_model="scriptdb")
ChannelDB = apps.get_model('comms', 'ChannelDB')
ChannelDB = apps.get_model("comms", "ChannelDB")
for obj in ChannelDB.objects.all():
obj.db_attributes.all().update(db_model="channeldb")
obj.db_tags.all().update(db_model="channeldb")
HelpEntry = apps.get_model('help', 'HelpEntry')
HelpEntry = apps.get_model("help", "HelpEntry")
for obj in HelpEntry.objects.all():
obj.db_tags.all().update(db_model="helpentry")
Msg = apps.get_model('comms', 'Msg')
Msg = apps.get_model("comms", "Msg")
for obj in Msg.objects.all():
obj.db_tags.all().update(db_model="msg")
class Migration(migrations.Migration):
dependencies = [
('typeclasses', '0005_auto_20160625_1812'),
]
dependencies = [("typeclasses", "0005_auto_20160625_1812")]
operations = [
migrations.RunPython(update_tags_with_dbmodel)
]
operations = [migrations.RunPython(update_tags_with_dbmodel)]

View file

@ -7,79 +7,103 @@ from django.db import migrations
def update_tags_with_dbmodel(apps, schema_editor):
Tag = apps.get_model('typeclasses', 'Tag')
Tag = apps.get_model("typeclasses", "Tag")
ObjectDB = apps.get_model('objects', 'ObjectDB')
ObjectDB = apps.get_model("objects", "ObjectDB")
for obj in ObjectDB.objects.all().exclude(db_tags__db_model="objectdb"):
for tag in obj.db_tags.all().exclude(db_model="objectdb"):
obj.db_tags.remove(tag)
newtag = Tag(db_key=tag.db_key, db_category=tag.db_category,
db_data=tag.db_data, db_tagtype=tag.db_tagtype, db_model="objectdb")
newtag = Tag(
db_key=tag.db_key,
db_category=tag.db_category,
db_data=tag.db_data,
db_tagtype=tag.db_tagtype,
db_model="objectdb",
)
newtag.save()
obj.db_tags.add(newtag)
AccountDB = apps.get_model('accounts', 'AccountDB')
AccountDB = apps.get_model("accounts", "AccountDB")
for obj in AccountDB.objects.all().exclude(db_tags__db_model="accountdb"):
for tag in obj.db_tags.all().exclude(db_model="accountdb"):
obj.db_tags.remove(tag)
newtag = Tag(db_key=tag.db_key, db_category=tag.db_category,
db_data=tag.db_data, db_tagtype=tag.db_tagtype, db_model="accountdb")
newtag = Tag(
db_key=tag.db_key,
db_category=tag.db_category,
db_data=tag.db_data,
db_tagtype=tag.db_tagtype,
db_model="accountdb",
)
newtag.save()
obj.db_tags.add(newtag)
ScriptDB = apps.get_model('scripts', 'ScriptDB')
ScriptDB = apps.get_model("scripts", "ScriptDB")
for obj in ScriptDB.objects.all().exclude(db_tags__db_model="scriptdb"):
for tag in obj.db_tags.all().exclude(db_model="scriptdb"):
obj.db_tags.remove(tag)
newtag = Tag(db_key=tag.db_key, db_category=tag.db_category,
db_data=tag.db_data, db_tagtype=tag.db_tagtype, db_model="scriptdb")
newtag = Tag(
db_key=tag.db_key,
db_category=tag.db_category,
db_data=tag.db_data,
db_tagtype=tag.db_tagtype,
db_model="scriptdb",
)
newtag.save()
obj.db_tags.add(newtag)
ChannelDB = apps.get_model('comms', 'ChannelDB')
ChannelDB = apps.get_model("comms", "ChannelDB")
for obj in ChannelDB.objects.all().exclude(db_tags__db_model="channeldb"):
for tag in obj.db_tags.all().exclude(db_model="channeldb"):
obj.db_tags.remove(tag)
newtag = Tag(db_key=tag.db_key, db_category=tag.db_category,
db_data=tag.db_data, db_tagtype=tag.db_tagtype, db_model="channeldb")
newtag = Tag(
db_key=tag.db_key,
db_category=tag.db_category,
db_data=tag.db_data,
db_tagtype=tag.db_tagtype,
db_model="channeldb",
)
newtag.save()
obj.db_tags.add(newtag)
HelpEntry = apps.get_model('help', 'HelpEntry')
HelpEntry = apps.get_model("help", "HelpEntry")
for obj in HelpEntry.objects.all().exclude(db_tags__db_model="helpentry"):
for tag in obj.db_tags.all().exclude(db_model="helpentry"):
obj.db_tags.remove(tag)
newtag = Tag(db_key=tag.db_key, db_category=tag.db_category,
db_data=tag.db_data, db_tagtype=tag.db_tagtype, db_model="helpentry")
newtag = Tag(
db_key=tag.db_key,
db_category=tag.db_category,
db_data=tag.db_data,
db_tagtype=tag.db_tagtype,
db_model="helpentry",
)
newtag.save()
obj.db_tags.add(newtag)
Msg = apps.get_model('comms', 'Msg')
Msg = apps.get_model("comms", "Msg")
for obj in Msg.objects.all().exclude(db_tags__db_model="msg"):
for tag in obj.db_tags.all().exclude(db_model="msg"):
obj.db_tags.remove(tag)
newtag = Tag(db_key=tag.db_key, db_category=tag.db_category,
db_data=tag.db_data, db_tagtype=tag.db_tagtype, db_model="msg")
newtag = Tag(
db_key=tag.db_key,
db_category=tag.db_category,
db_data=tag.db_data,
db_tagtype=tag.db_tagtype,
db_model="msg",
)
newtag.save()
obj.db_tags.add(newtag)
class Migration(migrations.Migration):
dependencies = [
('typeclasses', '0006_auto_add_dbmodel_value_for_tags_attributes'),
]
dependencies = [("typeclasses", "0006_auto_add_dbmodel_value_for_tags_attributes")]
operations = [
migrations.AlterUniqueTogether(
name='tag',
unique_together=set([('db_key', 'db_category', 'db_tagtype', 'db_model')]),
name="tag", unique_together=set([("db_key", "db_category", "db_tagtype", "db_model")])
),
migrations.AlterIndexTogether(
name='tag',
index_together=set([('db_key', 'db_category', 'db_tagtype', 'db_model')]),
name="tag", index_together=set([("db_key", "db_category", "db_tagtype", "db_model")])
),
migrations.RunPython(update_tags_with_dbmodel)
migrations.RunPython(update_tags_with_dbmodel),
]

View file

@ -9,9 +9,15 @@ from django.db import migrations
def update_perms_and_locks(apps, schema_editor):
# update all permissions
Tag = apps.get_model('typeclasses', 'Tag')
perm_map = {"guests": "guest", "players": "player", "playerhelpers": "helper",
"builders": "builder", "wizards": "admin", "immortals": "developer"}
Tag = apps.get_model("typeclasses", "Tag")
perm_map = {
"guests": "guest",
"players": "player",
"playerhelpers": "helper",
"builders": "builder",
"wizards": "admin",
"immortals": "developer",
}
for perm in Tag.objects.filter(db_tagtype="permission"):
if perm.db_key in perm_map:
@ -19,10 +25,15 @@ def update_perms_and_locks(apps, schema_editor):
perm.save(update_fields=("db_key",))
# update all locks on all entities
apps_models = [("objects", "ObjectDB"), ("accounts", "AccountDB"), ("scripts", "ScriptDB"),
("comms", "ChannelDB")]
p_reg = re.compile(r"(?<=perm\()(\w+)(?=\))|(?<=perm_above\()(\w+)(?=\))",
re.IGNORECASE + re.UNICODE)
apps_models = [
("objects", "ObjectDB"),
("accounts", "AccountDB"),
("scripts", "ScriptDB"),
("comms", "ChannelDB"),
]
p_reg = re.compile(
r"(?<=perm\()(\w+)(?=\))|(?<=perm_above\()(\w+)(?=\))", re.IGNORECASE + re.UNICODE
)
def _sub(match):
perm = match.group(1)
@ -35,16 +46,11 @@ def update_perms_and_locks(apps, schema_editor):
repl_lock = p_reg.sub(_sub, orig_lock)
if repl_lock != orig_lock:
obj.db_lock_storage = repl_lock
obj.save(update_fields=('db_lock_storage',))
obj.save(update_fields=("db_lock_storage",))
class Migration(migrations.Migration):
dependencies = [
('typeclasses', '0007_tag_migrations_may_be_slow'),
]
dependencies = [("typeclasses", "0007_tag_migrations_may_be_slow")]
operations = [
migrations.RunPython(update_perms_and_locks)
]
operations = [migrations.RunPython(update_perms_and_locks)]

View file

@ -22,6 +22,7 @@ def _case_sensitive_replace(string, old, new):
`old` has been replaced with `new`, retaining case.
"""
def repl(match):
current = match.group()
# treat multi-word sentences word-by-word
@ -41,12 +42,12 @@ def _case_sensitive_replace(string, old, new):
all_upper = False
# special cases - keep remaing case)
if new_word.lower() in CASE_WORD_EXCEPTIONS:
result.append(new_word[ind + 1:])
result.append(new_word[ind + 1 :])
# append any remaining characters from new
elif all_upper:
result.append(new_word[ind + 1:].upper())
result.append(new_word[ind + 1 :].upper())
else:
result.append(new_word[ind + 1:].lower())
result.append(new_word[ind + 1 :].lower())
out.append("".join(result))
# if we have more new words than old ones, just add them verbatim
out.extend([new_word for ind, new_word in enumerate(new_words) if ind >= len(old_words)])
@ -61,45 +62,41 @@ def _case_sensitive_replace(string, old, new):
def update_typeclasses(apps, schema_editor):
ObjectDB = apps.get_model('objects', 'ObjectDB')
AccountDB = apps.get_model('accounts', 'AccountDB')
ScriptDB = apps.get_model('scripts', 'ScriptDB')
ChannelDB = apps.get_model('comms', 'ChannelDB')
Attributes = apps.get_model('typeclasses', 'Attribute')
Tags = apps.get_model('typeclasses', 'Tag')
ObjectDB = apps.get_model("objects", "ObjectDB")
AccountDB = apps.get_model("accounts", "AccountDB")
ScriptDB = apps.get_model("scripts", "ScriptDB")
ChannelDB = apps.get_model("comms", "ChannelDB")
Attributes = apps.get_model("typeclasses", "Attribute")
Tags = apps.get_model("typeclasses", "Tag")
for obj in ObjectDB.objects.all():
obj.db_typeclass_path = _case_sensitive_replace(obj.db_typeclass_path, 'player', 'account')
obj.db_cmdset_storage = _case_sensitive_replace(obj.db_cmdset_storage, 'player', 'account')
obj.db_lock_storage = _case_sensitive_replace(obj.db_lock_storage, 'player', 'account')
obj.save(update_fields=['db_typeclass_path', 'db_cmdset_storage', 'db_lock_storage'])
obj.db_typeclass_path = _case_sensitive_replace(obj.db_typeclass_path, "player", "account")
obj.db_cmdset_storage = _case_sensitive_replace(obj.db_cmdset_storage, "player", "account")
obj.db_lock_storage = _case_sensitive_replace(obj.db_lock_storage, "player", "account")
obj.save(update_fields=["db_typeclass_path", "db_cmdset_storage", "db_lock_storage"])
for obj in AccountDB.objects.all():
obj.db_typeclass_path = _case_sensitive_replace(obj.db_typeclass_path, 'player', 'account')
obj.db_cmdset_storage = _case_sensitive_replace(obj.db_cmdset_storage, 'player', 'account')
obj.db_lock_storage = _case_sensitive_replace(obj.db_lock_storage, 'player', 'account')
obj.save(update_fields=['db_typeclass_path', 'db_cmdset_storage', 'db_lock_storage'])
obj.db_typeclass_path = _case_sensitive_replace(obj.db_typeclass_path, "player", "account")
obj.db_cmdset_storage = _case_sensitive_replace(obj.db_cmdset_storage, "player", "account")
obj.db_lock_storage = _case_sensitive_replace(obj.db_lock_storage, "player", "account")
obj.save(update_fields=["db_typeclass_path", "db_cmdset_storage", "db_lock_storage"])
for obj in ScriptDB.objects.all():
obj.db_typeclass_path = _case_sensitive_replace(obj.db_typeclass_path, 'player', 'account')
obj.db_lock_storage = _case_sensitive_replace(obj.db_lock_storage, 'player', 'account')
obj.save(update_fields=['db_typeclass_path', 'db_lock_storage'])
obj.db_typeclass_path = _case_sensitive_replace(obj.db_typeclass_path, "player", "account")
obj.db_lock_storage = _case_sensitive_replace(obj.db_lock_storage, "player", "account")
obj.save(update_fields=["db_typeclass_path", "db_lock_storage"])
for obj in ChannelDB.objects.all():
obj.db_typeclass_path = _case_sensitive_replace(obj.db_typeclass_path, 'player', 'account')
obj.db_lock_storage = _case_sensitive_replace(obj.db_lock_storage, 'player', 'account')
obj.save(update_fields=['db_typeclass_path', 'db_lock_storage'])
for obj in Attributes.objects.filter(db_model='playerdb'):
obj.db_model = 'accountdb'
obj.save(update_fields=['db_model'])
for obj in Tags.objects.filter(db_model='playerdb'):
obj.db_model = 'accountdb'
obj.save(update_fields=['db_model'])
obj.db_typeclass_path = _case_sensitive_replace(obj.db_typeclass_path, "player", "account")
obj.db_lock_storage = _case_sensitive_replace(obj.db_lock_storage, "player", "account")
obj.save(update_fields=["db_typeclass_path", "db_lock_storage"])
for obj in Attributes.objects.filter(db_model="playerdb"):
obj.db_model = "accountdb"
obj.save(update_fields=["db_model"])
for obj in Tags.objects.filter(db_model="playerdb"):
obj.db_model = "accountdb"
obj.save(update_fields=["db_model"])
class Migration(migrations.Migration):
dependencies = [
('typeclasses', '0008_lock_and_perm_rename'),
]
dependencies = [("typeclasses", "0008_lock_and_perm_rename")]
operations = [
migrations.RunPython(update_typeclasses),
]
operations = [migrations.RunPython(update_typeclasses)]

View file

@ -6,6 +6,7 @@ from django.db import migrations, connection
_ENGINE = None
def _table_exists(db_cursor, tablename):
"Returns bool if table exists or not"
return tablename in connection.introspection.table_names()
@ -15,6 +16,7 @@ def _drop_table(db_cursor, table_name):
global _ENGINE
if not _ENGINE:
from django.conf import settings
try:
_ENGINE = settings.DATABASES["default"]["ENGINE"]
except KeyError:
@ -47,10 +49,6 @@ def drop_tables(apps, schema_migrator):
class Migration(migrations.Migration):
dependencies = [
('typeclasses', '0009_rename_player_cmdsets_typeclasses'),
]
dependencies = [("typeclasses", "0009_rename_player_cmdsets_typeclasses")]
operations = [
migrations.RunPython(drop_tables)
]
operations = [migrations.RunPython(drop_tables)]

View file

@ -7,104 +7,145 @@ import evennia.utils.picklefield
class Migration(migrations.Migration):
dependencies = [
('typeclasses', '0010_delete_old_player_tables'),
]
dependencies = [("typeclasses", "0010_delete_old_player_tables")]
operations = [
migrations.DeleteModel(
name='DefaultAccount',
),
migrations.DeleteModel(
name='DefaultCharacter',
),
migrations.DeleteModel(
name='DefaultExit',
),
migrations.DeleteModel(
name='DefaultGuest',
),
migrations.DeleteModel(
name='DefaultObject',
),
migrations.DeleteModel(
name='DefaultRoom',
),
migrations.DeleteModel(
name='DefaultScript',
),
migrations.DeleteModel(
name='DoNothing',
),
migrations.DeleteModel(
name='ScriptBase',
),
migrations.DeleteModel(
name='Store',
migrations.DeleteModel(name="DefaultAccount"),
migrations.DeleteModel(name="DefaultCharacter"),
migrations.DeleteModel(name="DefaultExit"),
migrations.DeleteModel(name="DefaultGuest"),
migrations.DeleteModel(name="DefaultObject"),
migrations.DeleteModel(name="DefaultRoom"),
migrations.DeleteModel(name="DefaultScript"),
migrations.DeleteModel(name="DoNothing"),
migrations.DeleteModel(name="ScriptBase"),
migrations.DeleteModel(name="Store"),
migrations.AlterField(
model_name="attribute",
name="db_attrtype",
field=models.CharField(
blank=True,
db_index=True,
help_text="Subclass of Attribute (None or nick)",
max_length=16,
null=True,
verbose_name="attrtype",
),
),
migrations.AlterField(
model_name='attribute',
name='db_attrtype',
field=models.CharField(blank=True, db_index=True, help_text='Subclass of Attribute (None or nick)', max_length=16, null=True, verbose_name='attrtype'),
model_name="attribute",
name="db_category",
field=models.CharField(
blank=True,
db_index=True,
help_text="Optional categorization of attribute.",
max_length=128,
null=True,
verbose_name="category",
),
),
migrations.AlterField(
model_name='attribute',
name='db_category',
field=models.CharField(blank=True, db_index=True, help_text='Optional categorization of attribute.', max_length=128, null=True, verbose_name='category'),
model_name="attribute",
name="db_date_created",
field=models.DateTimeField(auto_now_add=True, verbose_name="date_created"),
),
migrations.AlterField(
model_name='attribute',
name='db_date_created',
field=models.DateTimeField(auto_now_add=True, verbose_name='date_created'),
model_name="attribute",
name="db_key",
field=models.CharField(db_index=True, max_length=255, verbose_name="key"),
),
migrations.AlterField(
model_name='attribute',
name='db_key',
field=models.CharField(db_index=True, max_length=255, verbose_name='key'),
model_name="attribute",
name="db_lock_storage",
field=models.TextField(
blank=True,
help_text="Lockstrings for this object are stored here.",
verbose_name="locks",
),
),
migrations.AlterField(
model_name='attribute',
name='db_lock_storage',
field=models.TextField(blank=True, help_text='Lockstrings for this object are stored here.', verbose_name='locks'),
model_name="attribute",
name="db_model",
field=models.CharField(
blank=True,
db_index=True,
help_text="Which model of object this attribute is attached to (A natural key like 'objects.objectdb'). You should not change this value unless you know what you are doing.",
max_length=32,
null=True,
verbose_name="model",
),
),
migrations.AlterField(
model_name='attribute',
name='db_model',
field=models.CharField(blank=True, db_index=True, help_text="Which model of object this attribute is attached to (A natural key like 'objects.objectdb'). You should not change this value unless you know what you are doing.", max_length=32, null=True, verbose_name='model'),
model_name="attribute",
name="db_strvalue",
field=models.TextField(
blank=True,
help_text="String-specific storage for quick look-up",
null=True,
verbose_name="strvalue",
),
),
migrations.AlterField(
model_name='attribute',
name='db_strvalue',
field=models.TextField(blank=True, help_text='String-specific storage for quick look-up', null=True, verbose_name='strvalue'),
model_name="attribute",
name="db_value",
field=evennia.utils.picklefield.PickledObjectField(
help_text="The data returned when the attribute is accessed. Must be written as a Python literal if editing through the admin interface. Attribute values which are not Python literals cannot be edited through the admin interface.",
null=True,
verbose_name="value",
),
),
migrations.AlterField(
model_name='attribute',
name='db_value',
field=evennia.utils.picklefield.PickledObjectField(help_text='The data returned when the attribute is accessed. Must be written as a Python literal if editing through the admin interface. Attribute values which are not Python literals cannot be edited through the admin interface.', null=True, verbose_name='value'),
model_name="tag",
name="db_category",
field=models.CharField(
db_index=True,
help_text="tag category",
max_length=64,
null=True,
verbose_name="category",
),
),
migrations.AlterField(
model_name='tag',
name='db_category',
field=models.CharField(db_index=True, help_text='tag category', max_length=64, null=True, verbose_name='category'),
model_name="tag",
name="db_data",
field=models.TextField(
blank=True,
help_text="optional data field with extra information. This is not searched for.",
null=True,
verbose_name="data",
),
),
migrations.AlterField(
model_name='tag',
name='db_data',
field=models.TextField(blank=True, help_text='optional data field with extra information. This is not searched for.', null=True, verbose_name='data'),
model_name="tag",
name="db_key",
field=models.CharField(
db_index=True,
help_text="tag identifier",
max_length=255,
null=True,
verbose_name="key",
),
),
migrations.AlterField(
model_name='tag',
name='db_key',
field=models.CharField(db_index=True, help_text='tag identifier', max_length=255, null=True, verbose_name='key'),
model_name="tag",
name="db_model",
field=models.CharField(
db_index=True,
help_text="database model to Tag",
max_length=32,
null=True,
verbose_name="model",
),
),
migrations.AlterField(
model_name='tag',
name='db_model',
field=models.CharField(db_index=True, help_text='database model to Tag', max_length=32, null=True, verbose_name='model'),
),
migrations.AlterField(
model_name='tag',
name='db_tagtype',
field=models.CharField(db_index=True, help_text='overall type of Tag', max_length=16, null=True, verbose_name='tagtype'),
model_name="tag",
name="db_tagtype",
field=models.CharField(
db_index=True,
help_text="overall type of Tag",
max_length=16,
null=True,
verbose_name="tagtype",
),
),
]

View file

@ -9,7 +9,7 @@ from evennia.utils.utils import to_bytes
def forwards(apps, schema_editor):
Attribute = apps.get_model('typeclasses', 'Attribute')
Attribute = apps.get_model("typeclasses", "Attribute")
for attr in Attribute.objects.all():
# we need to re-assign the Attribute it's own value to make sure pickle switches from v2 to v4,
# otherwise we will not be able to search db by-value.
@ -19,10 +19,6 @@ def forwards(apps, schema_editor):
class Migration(migrations.Migration):
dependencies = [
('typeclasses', '0011_auto_20190128_1820'),
]
dependencies = [("typeclasses", "0011_auto_20190128_1820")]
operations = [
migrations.RunPython(forwards, migrations.RunPython.noop),
]
operations = [migrations.RunPython(forwards, migrations.RunPython.noop)]

View file

@ -44,12 +44,10 @@ from evennia.server.signals import SIGNAL_TYPED_OBJECT_POST_RENAME
from evennia.typeclasses import managers
from evennia.locks.lockhandler import LockHandler
from evennia.utils.utils import (
is_iter, inherits_from, lazy_property,
class_from_module)
from evennia.utils.utils import is_iter, inherits_from, lazy_property, class_from_module
from evennia.utils.logger import log_trace
__all__ = ("TypedObject", )
__all__ = ("TypedObject",)
TICKER_HANDLER = None
@ -61,6 +59,7 @@ _SA = object.__setattr__
# signal receivers. Connected in __new__
def call_at_first_save(sender, instance, created, **kwargs):
"""
Receives a signal just after the object is saved.
@ -107,9 +106,11 @@ class TypeclassBase(SharedMemoryModelBase):
# typeclass proxy setup
if "Meta" not in attrs:
class Meta(object):
proxy = True
app_label = attrs.get("__applabel__", "typeclasses")
attrs["Meta"] = Meta
attrs["Meta"].proxy = True
@ -124,27 +125,29 @@ class TypeclassBase(SharedMemoryModelBase):
class DbHolder(object):
"Holder for allowing property access of attributes"
def __init__(self, obj, name, manager_name='attributes'):
def __init__(self, obj, name, manager_name="attributes"):
_SA(self, name, _GA(obj, manager_name))
_SA(self, 'name', name)
_SA(self, "name", name)
def __getattribute__(self, attrname):
if attrname == 'all':
if attrname == "all":
# we allow to overload our default .all
attr = _GA(self, _GA(self, 'name')).get("all")
attr = _GA(self, _GA(self, "name")).get("all")
return attr if attr else _GA(self, "all")
return _GA(self, _GA(self, 'name')).get(attrname)
return _GA(self, _GA(self, "name")).get(attrname)
def __setattr__(self, attrname, value):
_GA(self, _GA(self, 'name')).add(attrname, value)
_GA(self, _GA(self, "name")).add(attrname, value)
def __delattr__(self, attrname):
_GA(self, _GA(self, 'name')).remove(attrname)
_GA(self, _GA(self, "name")).remove(attrname)
def get_all(self):
return _GA(self, _GA(self, 'name')).all()
return _GA(self, _GA(self, "name")).all()
all = property(get_all)
#
# Main TypedObject abstraction
#
@ -180,21 +183,32 @@ class TypedObject(SharedMemoryModel):
# Main identifier of the object, for searching. Is accessed with self.key
# or self.name
db_key = models.CharField('key', max_length=255, db_index=True)
db_key = models.CharField("key", max_length=255, db_index=True)
# This is the python path to the type class this object is tied to. The
# typeclass is what defines what kind of Object this is)
db_typeclass_path = models.CharField('typeclass', max_length=255, null=True,
help_text="this defines what 'type' of entity this is. This variable holds a Python path to a module with a valid Evennia Typeclass.")
db_typeclass_path = models.CharField(
"typeclass",
max_length=255,
null=True,
help_text="this defines what 'type' of entity this is. This variable holds a Python path to a module with a valid Evennia Typeclass.",
)
# Creation date. This is not changed once the object is created.
db_date_created = models.DateTimeField('creation date', editable=False, auto_now_add=True)
db_date_created = models.DateTimeField("creation date", editable=False, auto_now_add=True)
# Lock storage
db_lock_storage = models.TextField('locks', blank=True,
help_text="locks limit access to an entity. A lock is defined as a 'lock string' on the form 'type:lockfunctions', defining what functionality is locked and how to determine access. Not defining a lock means no access is granted.")
db_lock_storage = models.TextField(
"locks",
blank=True,
help_text="locks limit access to an entity. A lock is defined as a 'lock string' on the form 'type:lockfunctions', defining what functionality is locked and how to determine access. Not defining a lock means no access is granted.",
)
# many2many relationships
db_attributes = models.ManyToManyField(Attribute,
help_text='attributes on this object. An attribute can hold any pickle-able python object (see docs for special cases).')
db_tags = models.ManyToManyField(Tag,
help_text='tags on this object. Tags are simple string markers to identify, group and alias objects.')
db_attributes = models.ManyToManyField(
Attribute,
help_text="attributes on this object. An attribute can hold any pickle-able python object (see docs for special cases).",
)
db_tags = models.ManyToManyField(
Tag,
help_text="tags on this object. Tags are simple string markers to identify, group and alias objects.",
)
# Database manager
objects = managers.TypedObjectManager()
@ -207,7 +221,9 @@ class TypedObject(SharedMemoryModel):
def set_class_from_typeclass(self, typeclass_path=None):
if typeclass_path:
try:
self.__class__ = class_from_module(typeclass_path, defaultpaths=settings.TYPECLASS_PATHS)
self.__class__ = class_from_module(
typeclass_path, defaultpaths=settings.TYPECLASS_PATHS
)
except Exception:
log_trace()
try:
@ -241,7 +257,10 @@ class TypedObject(SharedMemoryModel):
self.__class__ = class_from_module("evennia.objects.objects.DefaultObject")
self.__dbclass__ = class_from_module("evennia.objects.models.ObjectDB")
self.db_typeclass_path = "evennia.objects.objects.DefaultObject"
log_trace("Critical: Class %s of %s is not a valid typeclass!\nTemporarily falling back to %s." % (err_class, self, self.__class__))
log_trace(
"Critical: Class %s of %s is not a valid typeclass!\nTemporarily falling back to %s."
% (err_class, self, self.__class__)
)
def __init__(self, *args, **kwargs):
"""
@ -307,9 +326,10 @@ class TypedObject(SharedMemoryModel):
"""
Django setup info.
"""
abstract = True
verbose_name = "Evennia Database Object"
ordering = ['-db_date_created', 'id', 'db_typeclass_path', 'db_key']
ordering = ["-db_date_created", "id", "db_typeclass_path", "db_key"]
# wrapper
# Wrapper properties to easily set database fields. These are
@ -329,6 +349,7 @@ class TypedObject(SharedMemoryModel):
def __name_del(self):
raise Exception("Cannot delete name")
name = property(__name_get, __name_set, __name_del)
# key property (overrides's the idmapper's db_key for the at_rename hook)
@ -366,7 +387,7 @@ class TypedObject(SharedMemoryModel):
def __repr__(self):
return "%s" % self.db_key
#@property
# @property
def __dbid_get(self):
"""
Caches and returns the unique id of the object.
@ -379,9 +400,10 @@ class TypedObject(SharedMemoryModel):
def __dbid_del(self):
raise Exception("dbid cannot be deleted!")
dbid = property(__dbid_get, __dbid_set, __dbid_del)
#@property
# @property
def __dbref_get(self):
"""
Returns the object's dbref on the form #NN.
@ -393,6 +415,7 @@ class TypedObject(SharedMemoryModel):
def __dbref_del(self):
raise Exception("dbref cannot be deleted!")
dbref = property(__dbref_get, __dbref_set, __dbref_del)
def at_idmapper_flush(self):
@ -455,7 +478,9 @@ class TypedObject(SharedMemoryModel):
"""
if isinstance(typeclass, str):
typeclass = [typeclass] + ["%s.%s" % (prefix, typeclass) for prefix in settings.TYPECLASS_PATHS]
typeclass = [typeclass] + [
"%s.%s" % (prefix, typeclass) for prefix in settings.TYPECLASS_PATHS
]
else:
typeclass = [typeclass.path]
@ -465,10 +490,18 @@ class TypedObject(SharedMemoryModel):
return selfpath in typeclass
else:
# check parent chain
return any(hasattr(cls, "path") and cls.path in typeclass for cls in self.__class__.mro())
return any(
hasattr(cls, "path") and cls.path in typeclass for cls in self.__class__.mro()
)
def swap_typeclass(self, new_typeclass, clean_attributes=False,
run_start_hooks="all", no_default=True, clean_cmdsets=False):
def swap_typeclass(
self,
new_typeclass,
clean_attributes=False,
run_start_hooks="all",
no_default=True,
clean_cmdsets=False,
):
"""
This performs an in-situ swap of the typeclass. This means
that in-game, this object will suddenly be something else.
@ -513,9 +546,11 @@ class TypedObject(SharedMemoryModel):
if inherits_from(self, "evennia.scripts.models.ScriptDB"):
if self.interval > 0:
raise RuntimeError("Cannot use swap_typeclass on time-dependent "
"Script '%s'.\nStop and start a new Script of the "
"right type instead." % self.key)
raise RuntimeError(
"Cannot use swap_typeclass on time-dependent "
"Script '%s'.\nStop and start a new Script of the "
"right type instead." % self.key
)
self.typeclass_path = new_typeclass.path
self.__class__ = new_typeclass
@ -536,7 +571,7 @@ class TypedObject(SharedMemoryModel):
self.cmdset.clear()
self.cmdset.remove_default()
if run_start_hooks == 'all':
if run_start_hooks == "all":
# fake this call to mimic the first save
self.at_first_save()
elif run_start_hooks:
@ -547,7 +582,9 @@ class TypedObject(SharedMemoryModel):
# Lock / permission methods
#
def access(self, accessing_obj, access_type='read', default=False, no_superuser_bypass=False, **kwargs):
def access(
self, accessing_obj, access_type="read", default=False, no_superuser_bypass=False, **kwargs
):
"""
Determines if another object has permission to access this one.
@ -565,8 +602,12 @@ class TypedObject(SharedMemoryModel):
use it to feed to its hook methods.
"""
return self.locks.check(accessing_obj, access_type=access_type, default=default,
no_superuser_bypass=no_superuser_bypass)
return self.locks.check(
accessing_obj,
access_type=access_type,
default=default,
no_superuser_bypass=no_superuser_bypass,
)
def check_permstring(self, permstring):
"""
@ -581,7 +622,11 @@ class TypedObject(SharedMemoryModel):
"""
if hasattr(self, "account"):
if self.account and self.account.is_superuser and not self.account.attributes.get("_quell"):
if (
self.account
and self.account.is_superuser
and not self.account.attributes.get("_quell")
):
return True
else:
if self.is_superuser and not self.attributes.get("_quell"):
@ -597,8 +642,11 @@ class TypedObject(SharedMemoryModel):
if perm in _PERMISSION_HIERARCHY:
# check if we have a higher hierarchy position
ppos = _PERMISSION_HIERARCHY.index(perm)
return any(True for hpos, hperm in enumerate(_PERMISSION_HIERARCHY)
if hperm in perms and hpos > ppos)
return any(
True
for hpos, hperm in enumerate(_PERMISSION_HIERARCHY)
if hperm in perms and hpos > ppos
)
# we ignore pluralization (english only)
if perm.endswith("s"):
return self.check_permstring(perm[:-1])
@ -634,7 +682,7 @@ class TypedObject(SharedMemoryModel):
# Attribute storage
#
#@property db
# @property db
def __db_get(self):
"""
Attribute handler wrapper. Allows for the syntax
@ -650,27 +698,28 @@ class TypedObject(SharedMemoryModel):
try:
return self._db_holder
except AttributeError:
self._db_holder = DbHolder(self, 'attributes')
self._db_holder = DbHolder(self, "attributes")
return self._db_holder
#@db.setter
# @db.setter
def __db_set(self, value):
"Stop accidentally replacing the db object"
string = "Cannot assign directly to db object! "
string += "Use db.attr=value instead."
raise Exception(string)
#@db.deleter
# @db.deleter
def __db_del(self):
"Stop accidental deletion."
raise Exception("Cannot delete the db object!")
db = property(__db_get, __db_set, __db_del)
#
# Non-persistent (ndb) storage
#
#@property ndb
# @property ndb
def __ndb_get(self):
"""
A non-attr_obj store (ndb: NonDataBase). Everything stored
@ -681,20 +730,21 @@ class TypedObject(SharedMemoryModel):
try:
return self._ndb_holder
except AttributeError:
self._ndb_holder = DbHolder(self, "nattrhandler", manager_name='nattributes')
self._ndb_holder = DbHolder(self, "nattrhandler", manager_name="nattributes")
return self._ndb_holder
#@db.setter
# @db.setter
def __ndb_set(self, value):
"Stop accidentally replacing the ndb object"
string = "Cannot assign directly to ndb object! "
string += "Use ndb.attr=value instead."
raise Exception(string)
#@db.deleter
# @db.deleter
def __ndb_del(self):
"Stop accidental deletion."
raise Exception("Cannot delete the ndb object!")
ndb = property(__ndb_get, __ndb_set, __ndb_del)
def get_display_name(self, looker, **kwargs):
@ -719,7 +769,7 @@ class TypedObject(SharedMemoryModel):
builders.
"""
if self.access(looker, access_type='controls'):
if self.access(looker, access_type="controls"):
return "{}(#{})".format(self.name, self.id)
return self.name
@ -773,8 +823,9 @@ class TypedObject(SharedMemoryModel):
"""
content_type = ContentType.objects.get_for_model(self.__class__)
return reverse("admin:%s_%s_change" % (content_type.app_label,
content_type.model), args=(self.id,))
return reverse(
"admin:%s_%s_change" % (content_type.app_label, content_type.model), args=(self.id,)
)
@classmethod
def web_get_create_url(cls):
@ -803,9 +854,9 @@ class TypedObject(SharedMemoryModel):
"""
try:
return reverse('%s-create' % slugify(cls._meta.verbose_name))
return reverse("%s-create" % slugify(cls._meta.verbose_name))
except:
return '#'
return "#"
def web_get_detail_url(self):
"""
@ -834,10 +885,12 @@ class TypedObject(SharedMemoryModel):
"""
try:
return reverse('%s-detail' % slugify(self._meta.verbose_name),
kwargs={'pk': self.pk, 'slug': slugify(self.name)})
return reverse(
"%s-detail" % slugify(self._meta.verbose_name),
kwargs={"pk": self.pk, "slug": slugify(self.name)},
)
except:
return '#'
return "#"
def web_get_puppet_url(self):
"""
@ -866,10 +919,12 @@ class TypedObject(SharedMemoryModel):
"""
try:
return reverse('%s-puppet' % slugify(self._meta.verbose_name),
kwargs={'pk': self.pk, 'slug': slugify(self.name)})
return reverse(
"%s-puppet" % slugify(self._meta.verbose_name),
kwargs={"pk": self.pk, "slug": slugify(self.name)},
)
except:
return '#'
return "#"
def web_get_update_url(self):
"""
@ -898,10 +953,12 @@ class TypedObject(SharedMemoryModel):
"""
try:
return reverse('%s-update' % slugify(self._meta.verbose_name),
kwargs={'pk': self.pk, 'slug': slugify(self.name)})
return reverse(
"%s-update" % slugify(self._meta.verbose_name),
kwargs={"pk": self.pk, "slug": slugify(self.name)},
)
except:
return '#'
return "#"
def web_get_delete_url(self):
"""
@ -929,10 +986,12 @@ class TypedObject(SharedMemoryModel):
"""
try:
return reverse('%s-delete' % slugify(self._meta.verbose_name),
kwargs={'pk': self.pk, 'slug': slugify(self.name)})
return reverse(
"%s-delete" % slugify(self._meta.verbose_name),
kwargs={"pk": self.pk, "slug": slugify(self.name)},
)
except:
return '#'
return "#"
# Used by Django Sites/Admin
get_absolute_url = web_get_detail_url

View file

@ -18,11 +18,11 @@ from evennia.utils.utils import to_str, make_iter
_TYPECLASS_AGGRESSIVE_CACHE = settings.TYPECLASS_AGGRESSIVE_CACHE
#------------------------------------------------------------
# ------------------------------------------------------------
#
# Tags
#
#------------------------------------------------------------
# ------------------------------------------------------------
class Tag(models.Model):
@ -48,40 +48,55 @@ class Tag(models.Model):
default search functions of Evennia to allow quick searches by alias.
"""
db_key = models.CharField('key', max_length=255, null=True,
help_text="tag identifier", db_index=True)
db_category = models.CharField('category', max_length=64, null=True,
help_text="tag category", db_index=True)
db_data = models.TextField('data', null=True, blank=True,
help_text="optional data field with extra information. This is not searched for.")
db_key = models.CharField(
"key", max_length=255, null=True, help_text="tag identifier", db_index=True
)
db_category = models.CharField(
"category", max_length=64, null=True, help_text="tag category", db_index=True
)
db_data = models.TextField(
"data",
null=True,
blank=True,
help_text="optional data field with extra information. This is not searched for.",
)
# this is "objectdb" etc. Required behind the scenes
db_model = models.CharField('model', max_length=32, null=True, help_text="database model to Tag", db_index=True)
db_model = models.CharField(
"model", max_length=32, null=True, help_text="database model to Tag", db_index=True
)
# this is None, alias or permission
db_tagtype = models.CharField('tagtype', max_length=16, null=True, help_text="overall type of Tag", db_index=True)
db_tagtype = models.CharField(
"tagtype", max_length=16, null=True, help_text="overall type of Tag", db_index=True
)
class Meta(object):
"Define Django meta options"
verbose_name = "Tag"
unique_together = (('db_key', 'db_category', 'db_tagtype', 'db_model'),)
index_together = (('db_key', 'db_category', 'db_tagtype', 'db_model'),)
unique_together = (("db_key", "db_category", "db_tagtype", "db_model"),)
index_together = (("db_key", "db_category", "db_tagtype", "db_model"),)
def __lt__(self, other):
return str(self) < str(other)
def __str__(self):
return str("<Tag: %s%s>" % (self.db_key, "(category:%s)" % self.db_category if self.db_category else ""))
return str(
"<Tag: %s%s>"
% (self.db_key, "(category:%s)" % self.db_category if self.db_category else "")
)
#
# Handlers making use of the Tags model
#
class TagHandler(object):
"""
Generic tag-handler. Accessed via TypedObject.tags.
"""
_m2m_fieldname = "db_tags"
_tagtype = None
@ -106,13 +121,26 @@ class TagHandler(object):
def _fullcache(self):
"Cache all tags of this object"
query = {"%s__id" % self._model: self._objid,
"tag__db_model": self._model,
"tag__db_tagtype": self._tagtype}
tags = [conn.tag for conn in getattr(self.obj, self._m2m_fieldname).through.objects.filter(**query)]
self._cache = dict(("%s-%s" % (to_str(tag.db_key).lower(),
tag.db_category.lower() if tag.db_category else None),
tag) for tag in tags)
query = {
"%s__id" % self._model: self._objid,
"tag__db_model": self._model,
"tag__db_tagtype": self._tagtype,
}
tags = [
conn.tag
for conn in getattr(self.obj, self._m2m_fieldname).through.objects.filter(**query)
]
self._cache = dict(
(
"%s-%s"
% (
to_str(tag.db_key).lower(),
tag.db_category.lower() if tag.db_category else None,
),
tag,
)
for tag in tags
)
self._cache_complete = True
def _getcache(self, key=None, category=None):
@ -150,11 +178,13 @@ class TagHandler(object):
if tag:
return [tag] # return cached entity
else:
query = {"%s__id" % self._model: self._objid,
"tag__db_model": self._model,
"tag__db_tagtype": self._tagtype,
"tag__db_key__iexact": key.lower(),
"tag__db_category__iexact": category.lower() if category else None}
query = {
"%s__id" % self._model: self._objid,
"tag__db_model": self._model,
"tag__db_tagtype": self._tagtype,
"tag__db_key__iexact": key.lower(),
"tag__db_category__iexact": category.lower() if category else None,
}
conn = getattr(self.obj, self._m2m_fieldname).through.objects.filter(**query)
if conn:
tag = conn[0].tag
@ -169,12 +199,18 @@ class TagHandler(object):
return [tag for key, tag in self._cache.items() if key.endswith(catkey)]
else:
# we have to query to make this category up-date in the cache
query = {"%s__id" % self._model: self._objid,
"tag__db_model": self._model,
"tag__db_tagtype": self._tagtype,
"tag__db_category__iexact": category.lower() if category else None}
tags = [conn.tag for conn in getattr(self.obj,
self._m2m_fieldname).through.objects.filter(**query)]
query = {
"%s__id" % self._model: self._objid,
"tag__db_model": self._model,
"tag__db_tagtype": self._tagtype,
"tag__db_category__iexact": category.lower() if category else None,
}
tags = [
conn.tag
for conn in getattr(self.obj, self._m2m_fieldname).through.objects.filter(
**query
)
]
for tag in tags:
cachekey = "%s-%s" % (tag.db_key, category)
self._cache[cachekey] = tag
@ -262,8 +298,9 @@ class TagHandler(object):
# this will only create tag if no matches existed beforehand (it
# will overload data on an existing tag since that is not
# considered part of making the tag unique)
tagobj = self.obj.__class__.objects.create_tag(key=tagstr, category=category, data=data,
tagtype=self._tagtype)
tagobj = self.obj.__class__.objects.create_tag(
key=tagstr, category=category, data=data, tagtype=self._tagtype
)
getattr(self.obj, self._m2m_fieldname).add(tagobj)
self._setcache(tagstr, category, tagobj)
@ -293,8 +330,12 @@ class TagHandler(object):
ret = []
for keystr in make_iter(key):
# note - the _getcache call removes case sensitivity for us
ret.extend([tag if return_tagobj else to_str(tag.db_key)
for tag in self._getcache(keystr, category)])
ret.extend(
[
tag if return_tagobj else to_str(tag.db_key)
for tag in self._getcache(keystr, category)
]
)
if return_list:
return ret if ret else [default] if default is not None else []
return ret[0] if len(ret) == 1 else (ret if ret else default)
@ -328,9 +369,8 @@ class TagHandler(object):
# that when no objects reference the tag anymore (but how to check)?
# For now, tags are never deleted, only their connection to objects.
tagobj = getattr(self.obj, self._m2m_fieldname).filter(
db_key=tagstr, db_category=category,
db_model=self._model,
db_tagtype=self._tagtype)
db_key=tagstr, db_category=category, db_model=self._model, db_tagtype=self._tagtype
)
if tagobj:
getattr(self.obj, self._m2m_fieldname).remove(tagobj[0])
self._delcache(key, category)
@ -347,9 +387,11 @@ class TagHandler(object):
"""
if not self._cache_complete:
self._fullcache()
query = {"%s__id" % self._model: self._objid,
"tag__db_model": self._model,
"tag__db_tagtype": self._tagtype}
query = {
"%s__id" % self._model: self._objid,
"tag__db_model": self._model,
"tag__db_tagtype": self._tagtype,
}
if category:
query["tag__db_category"] = category.strip().lower()
getattr(self.obj, self._m2m_fieldname).through.objects.filter(**query).delete()
@ -376,7 +418,7 @@ class TagHandler(object):
self._fullcache()
tags = sorted(self._cache.values())
if return_key_and_category:
# return tuple (key, category)
# return tuple (key, category)
return [(to_str(tag.db_key), tag.db_category) for tag in tags]
elif return_objs:
return tags
@ -422,6 +464,7 @@ class AliasHandler(TagHandler):
A handler for the Alias Tag type.
"""
_tagtype = "alias"
@ -430,4 +473,5 @@ class PermissionHandler(TagHandler):
A handler for the Permission Tag type.
"""
_tagtype = "permission"

View file

@ -12,8 +12,8 @@ from evennia.utils.test_resources import EvenniaTest
class TestAttributes(EvenniaTest):
def test_attrhandler(self):
key = 'testattr'
value = 'test attr value '
key = "testattr"
value = "test attr value "
self.obj1.attributes.add(key, value)
self.assertEqual(self.obj1.attributes.get(key), value)
self.obj1.db.testattr = value
@ -22,13 +22,13 @@ class TestAttributes(EvenniaTest):
def test_weird_text_save(self):
"test 'weird' text type (different in py2 vs py3)"
from django.utils.safestring import SafeText
key = 'test attr 2'
value = SafeText('test attr value 2')
key = "test attr 2"
value = SafeText("test attr value 2")
self.obj1.attributes.add(key, value)
self.assertEqual(self.obj1.attributes.get(key), value)
class TestTypedObjectManager(EvenniaTest):
def _manager(self, methodname, *args, **kwargs):
return list(getattr(self.obj1.__class__.objects, methodname)(*args, **kwargs))
@ -53,7 +53,7 @@ class TestTypedObjectManager(EvenniaTest):
def test_get_by_tag_and_category(self):
self.obj1.tags.add("tag5", "category1")
self.obj1.tags.add("tag6", )
self.obj1.tags.add("tag6")
self.obj1.tags.add("tag7", "category1")
self.obj1.tags.add("tag6", "category3")
self.obj1.tags.add("tag7", "category4")
@ -65,14 +65,19 @@ class TestTypedObjectManager(EvenniaTest):
self.assertEqual(self._manager("get_by_tag", "tag5", "category1"), [self.obj1, self.obj2])
self.assertEqual(self._manager("get_by_tag", "tag6", "category1"), [])
self.assertEqual(self._manager("get_by_tag", "tag6", "category3"), [self.obj1, self.obj2])
self.assertEqual(self._manager("get_by_tag", ["tag5", "tag6"],
["category1", "category3"]), [self.obj1, self.obj2])
self.assertEqual(self._manager("get_by_tag", ["tag5", "tag7"],
"category1"), [self.obj1, self.obj2])
self.assertEqual(
self._manager("get_by_tag", ["tag5", "tag6"], ["category1", "category3"]),
[self.obj1, self.obj2],
)
self.assertEqual(
self._manager("get_by_tag", ["tag5", "tag7"], "category1"), [self.obj1, self.obj2]
)
self.assertEqual(self._manager("get_by_tag", category="category1"), [self.obj1, self.obj2])
self.assertEqual(self._manager("get_by_tag", category="category2"), [self.obj2])
self.assertEqual(self._manager("get_by_tag", category=["category1", "category3"]),
[self.obj1, self.obj2])
self.assertEqual(self._manager("get_by_tag", category=["category1", "category2"]),
[self.obj2])
self.assertEqual(
self._manager("get_by_tag", category=["category1", "category3"]), [self.obj1, self.obj2]
)
self.assertEqual(
self._manager("get_by_tag", category=["category1", "category2"]), [self.obj2]
)
self.assertEqual(self._manager("get_by_tag", category=["category5", "category4"]), [])