Updated the typeclasses/ directory modules to use Google style docstrings, as per #709.

This commit is contained in:
Griatch 2015-07-12 13:52:21 +02:00
parent b9043a9e95
commit 8e554ef8f6
5 changed files with 726 additions and 185 deletions

View file

@ -5,10 +5,18 @@ from evennia.typeclasses.models import Attribute, Tag
class TagAdmin(admin.ModelAdmin):
"""
A django Admin wrapper for Tags.
"""
fields = ('db_key', 'db_category', 'db_data')
class TagInline(admin.TabularInline):
"""
A handler for inline Tags.
"""
# Set this to the through model of your desired M2M when subclassing.
model = None
raw_id_fields = ('tag',)
@ -17,7 +25,8 @@ class TagInline(admin.TabularInline):
class AttributeInline(admin.TabularInline):
"""
Inline creation of player attributes
Inline creation of player attributes.j
"""
# Set this to the through model of your desired M2M when subclassing.
model = None
@ -50,7 +59,8 @@ class AttributeInline(admin.TabularInline):
class AttributeAdmin(ModelAdmin):
"""
Defines how to display the attributes
Defines how to display the attributes.
"""
search_fields = ('db_key', 'db_strvalue', 'db_value')
list_display = ('db_key', 'db_strvalue', 'db_value')

View file

@ -39,15 +39,17 @@ class Attribute(SharedMemoryModel):
attributes on the fly as we like.
The Attribute class defines the following properties:
key - primary identifier.
lock_storage - perm strings.
obj - which object the attribute is defined on.
date_created - when the attribute was created.
value - the data stored in the attribute, in pickled form
using wrappers to be able to store/retrieve models.
strvalue - string-only data. This data is not pickled and is
thus faster to search for in the database.
category - optional character string for grouping the Attribute.
- key (str): Primary identifier.
- lock_storage (str): Perm strings.
- model (str): A string defining the model this is connected to. This
is a natural_key, like "objects.objectdb"
- date_created (datetime): When the attribute was created.
- value (any): The data stored in the attribute, in pickled form
using wrappers to be able to store/retrieve models.
- strvalue (str): String-only data. This data is not pickled and
is thus faster to search for in the database.
- category (str): Optional character string for grouping the
Attribute.
"""
@ -76,7 +78,7 @@ class Attribute(SharedMemoryModel):
db_model = models.CharField(
'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.dbobject'). You should not change "
"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(
@ -166,18 +168,20 @@ class Attribute(SharedMemoryModel):
Determines if another object has permission to access.
Args:
accessing_obj (object): object trying to access this one.
access_type (optional): type of access sought.
default (optional): what to return if no lock of access_type was found
Kwargs:
**kwargs: passed to `at_access` hook along with `result`.
accessing_obj (object): Entity trying to access this one.
access_type (str, optional): Type of access sought, see
the lock documentation.
default (bool, optional): What result to return if no lock
of access_type was found. The default, `False`, means a lockdown
policy, only allowing explicit access.
kwargs (any, optional): Not used; here to make the API consistent with
other access calls.
Returns:
result:
result (bool): If the lock was passed or not.
"""
result = self.locks.check(accessing_obj, access_type=access_type, default=default)
#self.at_access(result, **kwargs)
return result
@ -196,7 +200,7 @@ class AttributeHandler(object):
_attrtype = None
def __init__(self, obj):
"Initialize handler"
"Initialize handler."
self.obj = obj
self._objid = obj.id
self._model = to_str(obj.__dbclass__.__name__.lower())
@ -216,7 +220,16 @@ class AttributeHandler(object):
Checks if the given Attribute (or list of Attributes) exists on
the object.
If an iterable is given, returns list of booleans.
Args:
key (str or iterable): The Attribute key or keys to check for.
category (str): Limit the check to Attributes with this
category (note, that `None` is the default category).
Returns:
has_attribute (bool or list): If the Attribute exists on
this object or not. If `key` was given as an iterable then
the return is a list of booleans.
"""
if self._cache is None or not _TYPECLASS_AGGRESSIVE_CACHE:
self._recache()
@ -228,21 +241,38 @@ class AttributeHandler(object):
def get(self, key=None, category=None, default=None, return_obj=False,
strattr=False, raise_exception=False, accessing_obj=None,
default_access=True, not_found_none=False):
default_access=True):
"""
Returns the value of the given Attribute or list of Attributes.
`strattr` will cause the string-only value field instead of the normal
pickled field data. Use to get back values from Attributes added with
the `strattr` keyword.
Get the Attribute.
If `return_obj=True`, return the matching Attribute object
instead. Returns `default` if no matches (or [ ] if `key` was a list
with no matches). If `raise_exception=True`, failure to find a
match will raise `AttributeError` instead.
Args:
key (str or list, optional): the attribute identifier or
multiple attributes to get. if a list of keys, the
method will return a list.
category (str, optional): the category within which to
retrieve attribute(s).
default (any, optional): The value to return if an
Attribute was not defined.
return_obj (bool, optional): If set, the return is not the value of the
Attribute but the Attribute object itself.
strattr (bool, optional): Return the `strvalue` field of
the Attribute rather than the usual `value`, this is a
string-only value for quick database searches.
raise_exception (bool, optional): When an Attribute is not
found, the return from this is usually `default`. If this
is set, an exception is raised instead.
accessing_obj (object, optional): If set, an `attrread`
permission lock will be checked before returning each
looked-after Attribute.
Returns:
result (any, Attribute or list): A list of varying type depending
on the arguments given.
Raises:
AttributeError: If `raise_exception` is set and no matching Attribute
was found matching `key`.
If `accessing_obj` is given, its `attrread` permission lock will be
checked before displaying each looked-after Attribute. If no
`accessing_obj` is given, no check will be done.
"""
class RetDefault(object):
@ -288,12 +318,21 @@ class AttributeHandler(object):
"""
Add attribute to object, with optional `lockstring`.
If `strattr` is set, the `db_strvalue` field will be used (no pickling).
Use the `get()` method with the `strattr` keyword to get it back.
Args:
key (str): An Attribute name to add.
value (any or str): The value of the Attribute. If
`strattr` keyword is set, this *must* be a string.
category (str, optional): The category for the Attribute.
The default `None` is the normal category used.
lockstring (str, optional): A lock string limiting access
to the attribute.
accessing_obj (object, optional): An entity to check for
the `attrcreate` access-type. If not passing, this method
will be exited.
default_access (bool, optional): What access to grant if
`accessing_obj` is given but no lock of the type
`attrcreate` is defined on the Attribute in question.
If `accessing_obj` is given, `self.obj`'s `attrcreate` lock access
will be checked against it. If no `accessing_obj` is given, no check
will be done.
"""
if accessing_obj and not self.obj.access(accessing_obj,
self._attrcreate, default=default_access):
@ -334,11 +373,27 @@ class AttributeHandler(object):
strattr=False, accessing_obj=None, default_access=True):
"""
Batch-version of `add()`. This is more efficient than
repeat-calling add.
repeat-calling add when having many Attributes to add.
`key` and `value` must be sequences of the same length, each
representing a key-value pair.
Args:
key (list): A list of Attribute names to add.
value (list): A list of values. It must match the `key`
list. If `strattr` keyword is set, all entries *must* be
strings.
category (str, optional): The category for the Attribute.
The default `None` is the normal category used.
lockstring (str, optional): A lock string limiting access
to the attribute.
accessing_obj (object, optional): An entity to check for
the `attrcreate` access-type. If not passing, this method
will be exited.
default_access (bool, optional): What access to grant if
`accessing_obj` is given but no lock of the type
`attrcreate` is defined on the Attribute in question.
Raises:
RuntimeError: If `key` and `value` lists are not of the
same lengths.
"""
if accessing_obj and not self.obj.access(accessing_obj,
self._attrcreate, default=default_access):
@ -390,8 +445,24 @@ class AttributeHandler(object):
"""
Remove attribute or a list of attributes from object.
If `accessing_obj` is given, will check against the `attredit` lock.
If not given, this check is skipped.
Args:
key (str): An Attribute key to remove.
raise_exception (bool, optional): If set, not finding the
Attribute to delete will raise an exception instead of
just quietly failing.
category (str, optional): The category within which to
remove the Attribute.
accessing_obj (object, optional): An object to check
against the `attredit` lock. If not given, the check will
be skipped.
default_access (bool, optional): The fallback access to
grant if `accessing_obj` is given but there is no
`attredit` lock set on the Attribute in question.
Raises:
AttributeError: If `raise_exception` is set and no matching Attribute
was found matching `key`.
"""
if self._cache is None or not _TYPECLASS_AGGRESSIVE_CACHE:
self._recache()
@ -409,9 +480,17 @@ class AttributeHandler(object):
def clear(self, category=None, accessing_obj=None, default_access=True):
"""
Remove all Attributes on this object. If `accessing_obj` is
given, check the `attredit` lock on each Attribute before
continuing. If not given, skip check.
Remove all Attributes on this object.
Args:
category (str, optional): If given, clear only Attributes
of this category.
accessing_obj (object, optional): If given, check the
`attredit` lock on each Attribute before continuing.
default_access (bool, optional): Use this permission as
fallback if `access_obj` is given but there is no lock of
type `attredit` on the Attribute in question.
"""
if self._cache is None or not _TYPECLASS_AGGRESSIVE_CACHE:
self._recache()
@ -426,9 +505,18 @@ class AttributeHandler(object):
"""
Return all Attribute objects on this object.
If `accessing_obj` is given, check the `attrread` lock on
each attribute before returning them. If not given, this
check is skipped.
Args:
accessing_obj (object, optional): Check the `attrread`
lock on each attribute before returning them. If not
given, this check is skipped.
default_access (bool, optional): Use this permission as a
fallback if `accessing_obj` is given but one or more
Attributes has no lock of type `attrread` defined on them.
Returns:
Attributes (list): All the Attribute objects (note: Not
their values!) in the handler.
"""
if self._cache is None or not _TYPECLASS_AGGRESSIVE_CACHE:
self._recache()
@ -442,31 +530,92 @@ class AttributeHandler(object):
class NickHandler(AttributeHandler):
"""
Handles the addition and removal of Nicks
(uses Attributes' `strvalue` and `category` fields)
Handles the addition and removal of Nicks. Nicks are special
versions of Attributes with an `_attrtype` hardcoded to `nick`.
They also always use the `strvalue` fields for their data.
Nicks are stored as Attributes
with categories `nick_<nicktype>`
"""
_attrtype = "nick"
def has(self, key, category="inputline"):
"""
Args:
key (str or iterable): The Nick key or keys to check for.
category (str): Limit the check to Nicks with this
category (note, that `None` is the default category).
Returns:
has_nick (bool or list): If the Nick exists on this object
or not. If `key` was given as an iterable then the return
is a list of booleans.
"""
return super(NickHandler, self).has(key, category=category)
def get(self, key=None, category="inputline", **kwargs):
"Get the replacement value matching the given key and category"
"""
Get the replacement value matching the given key and category
Args:
key (str or list, optional): the attribute identifier or
multiple attributes to get. if a list of keys, the
method will return a list.
category (str, optional): the category within which to
retrieve the nick. The "inputline" means replacing data
sent by the user.
kwargs (any, optional): These are passed on to `AttributeHandler.get`.
"""
return super(NickHandler, self).get(key=key, category=category, strattr=True, **kwargs)
def add(self, key, replacement, category="inputline", **kwargs):
"Add a new nick"
"""
Add a new nick.
Args:
key (str): A key for the nick to match for.
replacement (str): The string to replace `key` with (the "nickname").
category (str, optional): the category within which to
retrieve the nick. The "inputline" means replacing data
sent by the user.
kwargs (any, optional): These are passed on to `AttributeHandler.get`.
"""
super(NickHandler, self).add(key, replacement, category=category, strattr=True, **kwargs)
def remove(self, key, category="inputline", **kwargs):
"Remove Nick with matching category"
"""
Remove Nick with matching category.
Args:
key (str): A key for the nick to match for.
category (str, optional): the category within which to
removethe nick. The "inputline" means replacing data
sent by the user.
kwargs (any, optional): These are passed on to `AttributeHandler.get`.
"""
super(NickHandler, self).remove(key, category=category, **kwargs)
def nickreplace(self, raw_string, categories=("inputline", "channel"), include_player=True):
"Replace entries in raw_string with nick replacement"
"""
Apply nick replacement of entries in raw_string with nick replacement.
Args:
raw_string (str): The string in which to perform nick
replacement.
categories (tuple, optional): Replacement categories in
which to perform the replacement, such as "inputline",
"channel" etc.
include_player (bool, optional): Also include replacement
with nicks stored on the Player level.
kwargs (any, optional): Not used.
Returns:
string (str): A string with matching keys replaced with
their nick equivalents.
"""
raw_string
obj_nicks, player_nicks = [], []
for category in make_iter(categories):
@ -491,35 +640,83 @@ class NAttributeHandler(object):
for the `AttributeHandler`.
"""
def __init__(self, obj):
"initialized on the object"
"""
Initialized on the object
"""
self._store = {}
self.obj = weakref.proxy(obj)
def has(self, key):
"Check if object has this attribute or not"
"""
Check if object has this attribute or not.
Args:
key (str): The Nattribute key to check.
Returns:
has_nattribute (bool): If Nattribute is set or not.
"""
return key in self._store
def get(self, key):
"Returns named key value"
"""
Get the named key value.
Args:
key (str): The Nattribute key to get.
Returns:
the value of the Nattribute.
"""
return self._store.get(key, None)
def add(self, key, value):
"Add new key and value"
"""
Add new key and value.
Args:
key (str): The name of Nattribute to add.
value (any): The value to store.
"""
self._store[key] = value
self.obj.set_recache_protection()
def remove(self, key):
"Remove key from storage"
"""
Remove Nattribute from storage.
Args:
key (str): The name of the Nattribute to remove.
"""
if key in self._store:
del self._store[key]
self.obj.set_recache_protection(self._store)
def clear(self):
"Remove all nattributes from handler"
"""
Remove all NAttributes from handler.
"""
self._store = {}
def all(self, return_tuples=False):
"List all keys or (keys, values) stored, except _keys"
"""
List the contents of the handler.
Args:
return_tuples (bool, optional): Defines if the Nattributes
are returns as a list of keys or as a list of `(key, value)`.
Returns:
nattributes (list): A list of keys `[key, key, ...]` or a
list of tuples `[(key, value), ...]` depending on the
setting of `return_tuples`.
"""
if return_tuples:
return [(key, value) for (key, value) in self._store.items() if not key.startswith("_")]
return [key for key in self._store if not key.startswith("_")]

View file

@ -2,6 +2,7 @@
This implements the common managers that are used by the
abstract models in dbobjects.py (and which are thus shared by
all Attributes and TypedObjects).
"""
from functools import update_wrapper
from django.db.models import Q
@ -18,8 +19,8 @@ _Tag = None
def returns_typeclass_list(method):
"""
Decorator: Always returns a list, even
if it is empty.
Decorator: Always returns a list, even if it is empty.
"""
def func(self, *args, **kwargs):
self.__doc__ = method.__doc__
@ -34,7 +35,8 @@ def returns_typeclass_list(method):
def returns_typeclass(method):
"""
Decorator: Returns a single match or None
Decorator: Returns a single typeclass match or None.
"""
def func(self, *args, **kwargs):
self.__doc__ = method.__doc__
@ -47,6 +49,7 @@ def returns_typeclass(method):
class TypedObjectManager(idmapper.manager.SharedMemoryManager):
"""
Common ObjectManager for all dbobjects.
"""
# common methods for all typed managers. These are used
# in other methods. Returns querysets.
@ -61,16 +64,24 @@ class TypedObjectManager(idmapper.manager.SharedMemoryManager):
Attrs:
key (str, optional): The attribute's key to search for
category (str, optional): The category of the attribute(s) to search for.
value (str, optional): The attribute value to search for. Note that this
is not a very efficient operation since it will query for a pickled
entity. Mutually exclusive to `strvalue`.
strvalue (str, optional): The str-value to search for. Most Attributes
will not have strvalue set. This is mutually exclusive to the `value`
keyword and will take precedence if given.
obj (Object, optional): On which object the Attribute to search for is.
attrype (str, optional): An attribute-type to search for. By default this
is either `None` (normal Attributes) or `"nick"`.
category (str, optional): The category of the attribute(s)
to search for.
value (str, optional): The attribute value to search for.
Note that this is not a very efficient operation since it
will query for a pickled entity. Mutually exclusive to
`strvalue`.
strvalue (str, optional): The str-value to search for.
Most Attributes will not have strvalue set. This is
mutually exclusive to the `value` keyword and will take
precedence if given.
obj (Object, optional): On which object the Attribute to
search for is.
attrype (str, optional): An attribute-type to search for.
By default this is either `None` (normal Attributes) or
`"nick"`.
Returns:
attributes (list): The matching Attributes.
"""
query = [("attribute__db_attrtype", attrtype)]
@ -88,13 +99,51 @@ class TypedObjectManager(idmapper.manager.SharedMemoryManager):
return [th.attribute for th in self.model.db_attributes.through.objects.filter(**dict(query))]
def get_nick(self, key=None, category=None, value=None, strvalue=None, obj=None):
"""
Get a nick, in parallel to `get_attribute`.
Attrs:
key (str, optional): The nicks's key to search for
category (str, optional): The category of the nicks(s) to search for.
value (str, optional): The attribute value to search for. Note that this
is not a very efficient operation since it will query for a pickled
entity. Mutually exclusive to `strvalue`.
strvalue (str, optional): The str-value to search for. Most Attributes
will not have strvalue set. This is mutually exclusive to the `value`
keyword and will take precedence if given.
obj (Object, optional): On which object the Attribute to search for is.
Returns:
nicks (list): The matching Nicks.
"""
return self.get_attribute(key=key, category=category, value=value, strvalue=strvalue, obj=obj)
@returns_typeclass_list
def get_by_attribute(self, key=None, category=None, value=None, strvalue=None, attrtype=None):
"""
Return objects having attributes with the given key, category, value,
strvalue or combination of those criteria.
Return objects having attributes with the given key, category,
value, strvalue or combination of those criteria.
Args:
key (str, optional): The attribute's key to search for
category (str, optional): The category of the attribute
to search for.
value (str, optional): The attribute value to search for.
Note that this is not a very efficient operation since it
will query for a pickled entity. Mutually exclusive to
`strvalue`.
strvalue (str, optional): The str-value to search for.
Most Attributes will not have strvalue set. This is
mutually exclusive to the `value` keyword and will take
precedence if given.
attrype (str, optional): An attribute-type to search for.
By default this is either `None` (normal Attributes) or
`"nick"`.
Returns:
obj (list): Objects having the matching Attributes.
"""
query = [("db_attributes__db_attrtype", attrtype)]
if key:
@ -109,7 +158,19 @@ class TypedObjectManager(idmapper.manager.SharedMemoryManager):
return self.filter(**dict(query))
def get_by_nick(self, key=None, nick=None, category="inputline"):
"Get object based on its key or nick."
"""
Get object based on its key or nick.
Args:
key (str, optional): The attribute's key to search for
nick (str, optional): The nickname to search for
category (str, optional): The category of the nick
to search for.
Returns:
obj (list): Objects having the matching Nicks.
"""
return self.get_by_attribute(key=key, category=category, strvalue=nick, attrtype="nick")
# Tag manager methods
@ -119,9 +180,20 @@ class TypedObjectManager(idmapper.manager.SharedMemoryManager):
Return Tag objects by key, by category, by object (it is
stored on) or with a combination of those criteria.
tagtype - one of None (normal tags), "alias" or "permission"
global_search - include all possible tags, not just tags on
this object
Attrs:
key (str, optional): The Tag's key to search for
category (str, optional): The Tag of the attribute(s)
to search for.
obj (Object, optional): On which object the Tag to
search for is.
tagtype (str, optional): One of None (normal tags),
"alias" or "permission"
global_search (bool, optional): Include all possible tags,
not just tags on this object
Returns:
tag (list): The matching Tags.
"""
global _Tag
if not _Tag:
@ -148,9 +220,33 @@ class TypedObjectManager(idmapper.manager.SharedMemoryManager):
return [th.tag for th in self.model.db_tags.through.objects.filter(**dict(query))]
def get_permission(self, key=None, category=None, obj=None):
"""
Get a permission from the database.
Args:
key (str, optional): The permission's identifier.
category (str, optional): The permission's category.
obj (object, optional): The object on which this Tag is set.
Returns:
permission (list): Permission objects.
"""
return self.get_tag(key=key, category=category, obj=obj, tagtype="permission")
def get_alias(self, key=None, category=None, obj=None):
"""
Get an alias from the database.
Args:
key (str, optional): The permission's identifier.
category (str, optional): The permission's category.
obj (object, optional): The object on which this Tag is set.
Returns:
alias (list): Alias objects.
"""
return self.get_tag(key=key, category=category, obj=obj, tagtype="alias")
@returns_typeclass_list
@ -165,6 +261,8 @@ class TypedObjectManager(idmapper.manager.SharedMemoryManager):
tagtype (str or None, optional): 'type' of Tag, by default
this is either `None` (a normal Tag), `alias` or
`permission`.
Returns:
objects (list): Objects with matching tag.
"""
query = [("db_tags__db_tagtype", tagtype)]
if key:
@ -174,19 +272,55 @@ class TypedObjectManager(idmapper.manager.SharedMemoryManager):
return self.filter(**dict(query))
def get_by_permission(self, key=None, category=None):
"""
Return objects having permissions with a given key or category or
combination of the two.
Args:
key (str, optional): Permissions key. Not case sensitive.
category (str, optional): Permission category. Not case sensitive.
Returns:
objects (list): Objects with matching permission.
"""
return self.get_by_tag(key=key, category=category, tagtype="permission")
def get_by_alias(self, key=None, category=None):
"""
Return objects having aliases with a given key or category or
combination of the two.
Args:
key (str, optional): Alias key. Not case sensitive.
category (str, optional): Alias category. Not case sensitive.
Returns:
objects (list): Objects with matching alias.
"""
return self.get_by_tag(key=key, category=category, tagtype="alias")
def create_tag(self, key=None, category=None, data=None, tagtype=None):
"""
Create a new Tag of the base type associated with this typedobject.
This makes sure to create case-insensitive tags. If the exact same
tag configuration (key+category+tagtype) exists on the model, a
new tag will not be created, but an old one returned. A data
keyword is not part of the uniqueness of the tag and setting one
on an existing tag will overwrite the old data field.
Create a new Tag of the base type associated with this
object. This makes sure to create case-insensitive tags.
If the exact same tag configuration (key+category+tagtype)
exists on the model, a new tag will not be created, but an old
one returned.
Args:
key (str, optional): Tag key. Not case sensitive.
category (str, optional): Tag category. Not case sensitive.
data (str, optional): Extra information about the tag.
tagtype (str or None, optional): 'type' of Tag, by default
this is either `None` (a normal Tag), `alias` or
`permission`.
Notes:
The `data` field is not part of the uniqueness of the tag:
Setting `data` on an existing tag will overwrite the old
data field. It is intended only as a way to carry
information about the tag (like a help text), not to carry
any information about the tagged objects themselves.
"""
data = str(data) if data is not None else None
# try to get old tag
@ -213,11 +347,20 @@ class TypedObjectManager(idmapper.manager.SharedMemoryManager):
def dbref(self, dbref, reqhash=True):
"""
Valid forms of dbref (database reference number)
are either a string '#N' or an integer N.
Output is the integer part.
reqhash - require input to be on form "#N" to be
identified as a dbref
Determing if input is a valid dbref.
Args:
dbref (str or int): A possible dbref.
reqhash (bool, optional): If the "#" is required for this
to be considered a valid hash.
Returns:
dbref (int or None): The integer part of the dbref.
Notes:
Valid forms of dbref (database reference number) are
either a string '#N' or an integer N.
"""
if reqhash and not (isinstance(dbref, basestring) and dbref.startswith("#")):
return None
@ -233,7 +376,14 @@ class TypedObjectManager(idmapper.manager.SharedMemoryManager):
@returns_typeclass
def get_id(self, dbref):
"""
Find object with given dbref
Find object with given dbref.
Args:
dbref (str or int): The id to search for.
Returns:
object (TypedObject): The matched object.
"""
dbref = self.dbref(dbref, reqhash=False)
try:
@ -244,15 +394,30 @@ class TypedObjectManager(idmapper.manager.SharedMemoryManager):
def dbref_search(self, dbref):
"""
Alias to get_id
Alias to get_id.
Args:
dbref (str or int): The id to search for.
Returns:
object (TypedObject): The matched object.
"""
return self.get_id(dbref)
@returns_typeclass_list
def get_dbref_range(self, min_dbref=None, max_dbref=None):
"""
Return all objects inside and including the
given boundaries.
Get objects within a certain range of dbrefs.
Args:
min_dbref (int): Start of dbref range.
max_dbref (int): End of dbref range (inclusive)
Returns:
objects (list): TypedObjects with dbrefs within
the given dbref ranges.
"""
retval = super(TypedObjectManager, self).all()
if min_dbref is not None:
@ -263,9 +428,14 @@ class TypedObjectManager(idmapper.manager.SharedMemoryManager):
def object_totals(self):
"""
Returns a dictionary with all the typeclasses active in-game
as well as the number of such objects defined (i.e. the number
of database object having that typeclass set on themselves).
Get info about database statistics.
Returns:
census (dict): A dictionary `{typeclass_path: number, ...}` with
all the typeclasses active in-game as well as the number
of such objects defined (i.e. the number of database
object having that typeclass set on themselves).
"""
dbtotals = {}
typeclass_paths = set(self.values_list('db_typeclass_path', flat=True))
@ -281,12 +451,18 @@ class TypedObjectManager(idmapper.manager.SharedMemoryManager):
certain typeclass. If location is set, limit search to objects
in that location.
typeclass - a typeclass class or a python path to a typeclass
include_children - return objects with given typeclass and all
children inheriting from this typeclass.
include_parents - return objects with given typeclass and all
parents to this typeclass
The include_children/parents keywords are mutually exclusive.
Args:
typeclass (str or class): A typeclass class or a python path to a typeclass.
include_children (bool, optional): Return objects with
given typeclass *and* all children inheriting from this
typeclass. Mutuall exclusive to `include_parents`.
include_parents (bool, optional): Return objects with
given typeclass *and* all parents to this typeclass.
Mutually exclusive to `include_children`.
Returns:
objects (list): The objects found with the given typeclasses.
"""
if callable(typeclass):
@ -319,11 +495,29 @@ class TypedObjectManager(idmapper.manager.SharedMemoryManager):
class TypeclassManager(TypedObjectManager):
"""
Manager for the typeclasses. The main purpose of this manager is
to limit database queries to the given typeclass despite all
typeclasses technically being defined in the same core database
model.
"""
def get(self, **kwargs):
"""
Overload the standard get. This will limit itself to only
return the current typeclass.
Kwargs:
kwargs (any): These are passed on as normal arguments
to the default django get method
Returns:
object (object): The object found.
Raises:
ObjectNotFound: The exact name of this exception depends
on the model base used.
"""
kwargs.update({"db_typeclass_path":self.model.path})
return super(TypedObjectManager, self).get(**kwargs)
@ -332,19 +526,33 @@ class TypeclassManager(TypedObjectManager):
"""
Overload of the standard filter function. This filter will
limit itself to only the current typeclass.
Kwargs:
kwargs (any): These are passed on as normal arguments
to the default django filter method.
Returns:
objects (list): The objects found.
"""
kwargs.update({"db_typeclass_path":self.model.path})
return super(TypedObjectManager, self).filter(**kwargs)
def all(self, **kwargs):
"""
Overload method to return all matches, filtering for typeclass
Overload method to return all matches, filtering for typeclass.
Kwargs:
kwargs (any): These are passed on as normal arguments
to the default django all method (usually none are given).
Returns:
objects (list): The objects found.
"""
return super(TypedObjectManager, self).all(**kwargs).filter(db_typeclass_path=self.model.path)
def _get_subclasses(self, cls):
"""
Recursively get all subclasses to a class
Recursively get all subclasses to a class.
"""
all_subclasses = cls.__subclasses__()
for subclass in all_subclasses:
@ -353,8 +561,19 @@ class TypeclassManager(TypedObjectManager):
def get_family(self, **kwargs):
"""
Variation of get that not only returns the current
typeclass but also all subclasses of that typeclass.
Variation of get that not only returns the current typeclass
but also all subclasses of that typeclass.
Kwargs:
kwargs (any): These are passed on as normal arguments
to the default django get method.
Returns:
objects (list): The objects found.
Raises:
ObjectNotFound: The exact name of this exception depends
on the model base used.
"""
paths = [self.model.path] + ["%s.%s" % (cls.__module__, cls.__name__)
for cls in self._get_subclasses(self.model)]
@ -365,6 +584,13 @@ class TypeclassManager(TypedObjectManager):
"""
Variation of filter that allows results both from typeclass
and from subclasses of typeclass
Kwargs:
kwargs (any): These are passed on as normal arguments
to the default django filter method.
Returns:
objects (list): The objects found.
"""
# query, including all subclasses
paths = [self.model.path] + ["%s.%s" % (cls.__module__, cls.__name__)
@ -376,6 +602,13 @@ class TypeclassManager(TypedObjectManager):
"""
Return all matches, allowing matches from all subclasses of
the typeclass.
Kwargs:
kwargs (any): These are passed on as normal arguments
to the default django all method (usually none are given).
Returns:
objects (list): The objects found.
"""
paths = [self.model.path] + ["%s.%s" % (cls.__module__, cls.__name__)
for cls in self._get_subclasses(self.model)]

View file

@ -371,10 +371,16 @@ class TypedObject(SharedMemoryModel):
loaded) typeclass - can be a class object or the python path
to such an object to match against.
typeclass - a class or the full python path to the class
exact - returns true only
if the object's type is exactly this typeclass, ignoring
parents.
Args:
typeclass (str or class): A class or the full python path
to the class to check.
exact (bool, optional): Returns true only if the object's
type is exactly this typeclass, ignoring parents.
Returns:
is_typeclass (bool): If this typeclass matches the given
typeclass.
"""
if isinstance(typeclass, basestring):
typeclass = [typeclass] + ["%s.%s" % (prefix, typeclass) for prefix in settings.TYPECLASS_PATHS]
@ -405,24 +411,24 @@ class TypedObject(SharedMemoryModel):
to create a new object and just swap the player over to
that one instead.
Arguments:
new_typeclass (path/classobj) - type to switch to
clean_attributes (bool/list) - will delete all attributes
stored on this object (but not any
of the database fields such as name or
location). You can't get attributes back,
but this is often the safest bet to make
sure nothing in the new typeclass clashes
with the old one. If you supply a list,
only those named attributes will be cleared.
run_start_hooks - trigger the start hooks of the object, as if
it was created for the first time.
no_default - if this is active, the swapper will not allow for
swapping to a default typeclass in case the given
one fails for some reason. Instead the old one
will be preserved.
Args:
new_typeclass (str or classobj): Type to switch to.
clean_attributes (bool or list, optional): Will delete all
attributes stored on this object (but not any of the
database fields such as name or location). You can't get
attributes back, but this is often the safest bet to make
sure nothing in the new typeclass clashes with the old
one. If you supply a list, only those named attributes
will be cleared.
run_start_hooks (bool, optional): Trigger the start hooks
of the object, as if it was created for the first time.
no_default (bool, optiona): If set, the swapper will not
allow for swapping to a default typeclass in case the
given one fails for some reason. Instead the old one will
be preserved.
Returns:
boolean True/False depending on if the swap worked or not.
result (bool): True/False depending on if the swap worked
or not.
"""
@ -470,12 +476,15 @@ class TypedObject(SharedMemoryModel):
Args:
accessing_obj (str): Object trying to access this one.
access_type (str, optional): Type of access sought.
default (bool, optional): What to return if no lock of access_type was found
no_superuser_bypass (bool, optional): Turn off the superuser lock bypass (be careful with this one).
default (bool, optional): What to return if no lock of
access_type was found
no_superuser_bypass (bool, optional): Turn off the
superuser lock bypass (be careful with this one).
Kwargs:
kwargs (any): Ignored, but is there to make the api consistent with the
object-typeclass method access, which use it to feed to its hook methods.
kwargs (any): Ignored, but is there to make the api
consistent with the object-typeclass method access, which
use it to feed to its hook methods.
"""
return self.locks.check(accessing_obj, access_type=access_type, default=default,
@ -483,8 +492,15 @@ class TypedObject(SharedMemoryModel):
def check_permstring(self, permstring):
"""
This explicitly checks if we hold particular permission without
involving any locks.
This explicitly checks if we hold particular permission
without involving any locks.
Args:
permstring (str): The permission string to check against.
Returns:
result (bool): If the permstring is passed or not.
"""
if hasattr(self, "player"):
if self.player and self.player.is_superuser:
@ -512,11 +528,16 @@ class TypedObject(SharedMemoryModel):
#
def _deleted(self, *args, **kwargs):
"Scrambling method for already deleted objects"
"""
Scrambling method for already deleted objects
"""
raise ObjectDoesNotExist("This object was already deleted!")
def delete(self):
"Cleaning up handlers on the typeclass level"
"""
Cleaning up handlers on the typeclass level
"""
global TICKER_HANDLER
if not TICKER_HANDLER:
from evennia.scripts.tickerhandler import TICKER_HANDLER
@ -615,16 +636,20 @@ class TypedObject(SharedMemoryModel):
Displays the name of the object in a viewer-aware manner.
Args:
looker (TypedObject): The object or player that is looking at/getting inforamtion for this object.
looker (TypedObject): The object or player that is looking
at/getting inforamtion for this object.
Returns:
A string containing the name of the object, including the DBREF if this user is privileged to control
said object.
name (str): A string containing the name of the object,
including the DBREF if this user is privileged to control
said object.
Notes:
This function could be extended to change how object names
appear to users in character, but be wary. This function does not change an object's keys or
aliases when searching, and is expected to produce something useful for builders.
appear to users in character, but be wary. This function
does not change an object's keys or aliases when
searching, and is expected to produce something useful for
builders.
"""
if self.access(looker, access_type='controls'):
@ -633,18 +658,22 @@ class TypedObject(SharedMemoryModel):
def get_extra_info(self, looker, **kwargs):
"""
Used when an object is in a list of ambiguous objects as an additional
information tag.
Used when an object is in a list of ambiguous objects as an
additional information tag.
For instance, if you had potions which could have varying levels of liquid
left in them, you might want to display how many drinks are left in each when
selecting which to drop, but not in your normal inventory listing.
For instance, if you had potions which could have varying
levels of liquid left in them, you might want to display how
many drinks are left in each when selecting which to drop, but
not in your normal inventory listing.
Args:
looker (TypedObject): The object or player that is looking at/getting information for this object.
looker (TypedObject): The object or player that is looking
at/getting information for this object.
Returns:
A string with disambiguating information, conventionally with a leading space.
info (str): A string with disambiguating information,
conventionally with a leading space.
"""
if self.location == looker:

View file

@ -1,11 +1,12 @@
"""
Tags are entities that are attached to objects like Attributes but
which are unique to an individual object - any number of objects
can have the same Tag attached to them.
Tags are entities that are attached to objects in the same way as
Attributes. But contrary to Attributes, which are unique to an
individual object, a single Tag can be attached to any number of
objects at the same time.
Tags are used for tagging, obviously, but the data structure
is also used for storing Aliases and Permissions. This module
contains the respective handlers.
Tags are used for tagging, obviously, but the data structure is also
used for storing Aliases and Permissions. This module contains the
respective handlers.
"""
@ -24,24 +25,26 @@ _TYPECLASS_AGGRESSIVE_CACHE = settings.TYPECLASS_AGGRESSIVE_CACHE
class Tag(models.Model):
"""
Tags are quick markers for objects in-game. An typeobject
can have any number of tags, stored via its db_tags property.
Tagging similar objects will make it easier to quickly locate the
group later (such as when implementing zones). The main advantage
of tagging as opposed to using Attributes is speed; a tag is very
Tags are quick markers for objects in-game. An typeobject can have
any number of tags, stored via its db_tags property. Tagging
similar objects will make it easier to quickly locate the group
later (such as when implementing zones). The main advantage of
tagging as opposed to using Attributes is speed; a tag is very
limited in what data it can hold, and the tag key+category is
indexed for efficient lookup in the database. Tags are shared between
objects - a new tag is only created if the key+category combination
did not previously exist, making them unsuitable for storing
object-related data (for this a full Attribute
should be used).
The 'db_data' field is intended as a documentation
field for the tag itself, such as to document what this tag+category
stands for and display that in a web interface or similar.
indexed for efficient lookup in the database. Tags are shared
between objects - a new tag is only created if the key+category
combination did not previously exist, making them unsuitable for
storing object-related data (for this a full Attribute should be
used).
The 'db_data' field is intended as a documentation field for the
tag itself, such as to document what this tag+category stands for
and display that in a web interface or similar.
The main default use for Tags is to implement Aliases for objects.
this uses the 'aliases' tag category, which is also checked by the
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)
@ -74,15 +77,20 @@ class Tag(models.Model):
class TagHandler(object):
"""
Generic tag-handler. Accessed via TypedObject.tags.
"""
_m2m_fieldname = "db_tags"
_tagtype = None
def __init__(self, obj):
"""
Tags are stored internally in the TypedObject.db_tags m2m field
with an tag.db_model based on the obj the taghandler is stored on
and with a tagtype given by self.handlertype
Tags are stored internally in the TypedObject.db_tags m2m
field with an tag.db_model based on the obj the taghandler is
stored on and with a tagtype given by self.handlertype
Args:
obj (object): The object on which the handler is set.
"""
self.obj = obj
self._objid = obj.id
@ -90,7 +98,10 @@ class TagHandler(object):
self._cache = None
def _recache(self):
"Cache all tags of this object"
"""
Cache all tags of this object.
"""
query = {"%s__id" % self._model : self._objid,
"tag__db_tagtype" : self._tagtype}
tagobjs = [conn.tag for conn in getattr(self.obj, self._m2m_fieldname).through.objects.filter(**query)]
@ -99,7 +110,23 @@ class TagHandler(object):
tagobj) for tagobj in tagobjs)
def add(self, tag=None, category=None, data=None):
"Add a new tag to the handler. Tag is a string or a list of strings."
"""
Add a new tag to the handler.
Args:
tag (str or list): The name of the tag to add. If a list,
add several Tags.
category (str, optional): Category of Tag. `None` is the default category.
data (str, optional): Info text about the tag(s) added.
This can not be used to store object-unique info but only
eventual info about the text itself.
Notes:
If the tag + category combination matches an already
existing Tag object, this will be re-used and no new Tag
will be created.
"""
if not tag:
return
for tagstr in make_iter(tag):
@ -121,9 +148,21 @@ class TagHandler(object):
def get(self, key, category=None, return_tagobj=False):
"""
Get the tag for the given key or list of tags. If
return_data=True, return the matching Tag objects instead.
Returns a single tag if a unique match, otherwise a list
Get the tag for the given key or list of tags.
Args:
key (str or list): The tag or tags to retrieve.
category (str, optional): The Tag category to limit the
request to. Note that `None` is the valid, default
category.
return_tagobj (bool, optional): Return the Tag object itself
instead of a string representation of the Tag.
Returns:
tags (str, TagObject or list): The matches, either string
representations of the tags or the Tag objects themselves
depending on `return_tagobj`.
"""
if self._cache is None or not _TYPECLASS_AGGRESSIVE_CACHE:
self._recache()
@ -135,7 +174,16 @@ class TagHandler(object):
return ret[0] if len(ret) == 1 else ret
def remove(self, key, category=None):
"Remove a tag from the handler based ond key and category."
"""
Remove a tag from the handler based ond key and category.
Args:
key (str or list): The tag or tags to retrieve.
category (str, optional): The Tag category to limit the
request to. Note that `None` is the valid, default
category.
"""
for key in make_iter(key):
if not (key or key.strip()): # we don't allow empty tags
continue
@ -151,8 +199,13 @@ class TagHandler(object):
def clear(self, category=None):
"""
Remove all tags from the handle. Optionally, only remove those within
a certain category.
Remove all tags from the handler.
Args:
category (str, optional): The Tag category to limit the
request to. Note that `None` is the valid, default
category.
"""
if not category:
getattr(self.obj, self._m2m_fieldname).clear()
@ -163,8 +216,19 @@ class TagHandler(object):
def all(self, category=None, return_key_and_category=False):
"""
Get all tags in this handler.
If category is given, return only Tags with this category. If
return_keys_and_categories is set, return a list of tuples [(key, category), ...]
Args:
category (str, optional): The Tag category to limit the
request to. Note that `None` is the valid, default
category.
return_key_and_category (bool, optional): Return a list of
tuples `[(key, category), ...]`.
Returns:
tags (list): A list of tag keys `[tagkey, tagkey, ...]` or
a list of tuples `[(key, category), ...]` if
`return_key_and_category` is set.
"""
if self._cache is None or not _TYPECLASS_AGGRESSIVE_CACHE:
self._recache()
@ -191,9 +255,17 @@ class TagHandler(object):
class AliasHandler(TagHandler):
"""
A handler for the Alias Tag type.
"""
_tagtype = "alias"
class PermissionHandler(TagHandler):
"""
A handler for the Permission Tag type.
"""
_tagtype = "permission"