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): class TagAdmin(admin.ModelAdmin):
"""
A django Admin wrapper for Tags.
"""
fields = ('db_key', 'db_category', 'db_data') fields = ('db_key', 'db_category', 'db_data')
class TagInline(admin.TabularInline): class TagInline(admin.TabularInline):
"""
A handler for inline Tags.
"""
# Set this to the through model of your desired M2M when subclassing. # Set this to the through model of your desired M2M when subclassing.
model = None model = None
raw_id_fields = ('tag',) raw_id_fields = ('tag',)
@ -17,7 +25,8 @@ class TagInline(admin.TabularInline):
class AttributeInline(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. # Set this to the through model of your desired M2M when subclassing.
model = None model = None
@ -50,7 +59,8 @@ class AttributeInline(admin.TabularInline):
class AttributeAdmin(ModelAdmin): class AttributeAdmin(ModelAdmin):
""" """
Defines how to display the attributes Defines how to display the attributes.
""" """
search_fields = ('db_key', 'db_strvalue', 'db_value') search_fields = ('db_key', 'db_strvalue', 'db_value')
list_display = ('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. attributes on the fly as we like.
The Attribute class defines the following properties: The Attribute class defines the following properties:
key - primary identifier. - key (str): Primary identifier.
lock_storage - perm strings. - lock_storage (str): Perm strings.
obj - which object the attribute is defined on. - model (str): A string defining the model this is connected to. This
date_created - when the attribute was created. is a natural_key, like "objects.objectdb"
value - the data stored in the attribute, in pickled form - date_created (datetime): When the attribute was created.
using wrappers to be able to store/retrieve models. - value (any): The data stored in the attribute, in pickled form
strvalue - string-only data. This data is not pickled and is using wrappers to be able to store/retrieve models.
thus faster to search for in the database. - strvalue (str): String-only data. This data is not pickled and
category - optional character string for grouping the Attribute. 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( 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 " 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.") "this value unless you know what you are doing.")
# subclass of Attribute (None or nick) # subclass of Attribute (None or nick)
db_attrtype = models.CharField( db_attrtype = models.CharField(
@ -166,18 +168,20 @@ class Attribute(SharedMemoryModel):
Determines if another object has permission to access. Determines if another object has permission to access.
Args: Args:
accessing_obj (object): object trying to access this one. accessing_obj (object): Entity trying to access this one.
access_type (optional): type of access sought. access_type (str, optional): Type of access sought, see
default (optional): what to return if no lock of access_type was found the lock documentation.
default (bool, optional): What result to return if no lock
Kwargs: of access_type was found. The default, `False`, means a lockdown
**kwargs: passed to `at_access` hook along with `result`. policy, only allowing explicit access.
kwargs (any, optional): Not used; here to make the API consistent with
other access calls.
Returns: Returns:
result: result (bool): If the lock was passed or not.
""" """
result = self.locks.check(accessing_obj, access_type=access_type, default=default) result = self.locks.check(accessing_obj, access_type=access_type, default=default)
#self.at_access(result, **kwargs)
return result return result
@ -196,7 +200,7 @@ class AttributeHandler(object):
_attrtype = None _attrtype = None
def __init__(self, obj): def __init__(self, obj):
"Initialize handler" "Initialize handler."
self.obj = obj self.obj = obj
self._objid = obj.id self._objid = obj.id
self._model = to_str(obj.__dbclass__.__name__.lower()) 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 Checks if the given Attribute (or list of Attributes) exists on
the object. 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: if self._cache is None or not _TYPECLASS_AGGRESSIVE_CACHE:
self._recache() self._recache()
@ -228,21 +241,38 @@ class AttributeHandler(object):
def get(self, key=None, category=None, default=None, return_obj=False, def get(self, key=None, category=None, default=None, return_obj=False,
strattr=False, raise_exception=False, accessing_obj=None, 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. Get the Attribute.
`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.
If `return_obj=True`, return the matching Attribute object Args:
instead. Returns `default` if no matches (or [ ] if `key` was a list key (str or list, optional): the attribute identifier or
with no matches). If `raise_exception=True`, failure to find a multiple attributes to get. if a list of keys, the
match will raise `AttributeError` instead. 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): class RetDefault(object):
@ -288,12 +318,21 @@ class AttributeHandler(object):
""" """
Add attribute to object, with optional `lockstring`. Add attribute to object, with optional `lockstring`.
If `strattr` is set, the `db_strvalue` field will be used (no pickling). Args:
Use the `get()` method with the `strattr` keyword to get it back. 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, if accessing_obj and not self.obj.access(accessing_obj,
self._attrcreate, default=default_access): self._attrcreate, default=default_access):
@ -334,11 +373,27 @@ class AttributeHandler(object):
strattr=False, accessing_obj=None, default_access=True): strattr=False, accessing_obj=None, default_access=True):
""" """
Batch-version of `add()`. This is more efficient than 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 Args:
representing a key-value pair. 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, if accessing_obj and not self.obj.access(accessing_obj,
self._attrcreate, default=default_access): self._attrcreate, default=default_access):
@ -390,8 +445,24 @@ class AttributeHandler(object):
""" """
Remove attribute or a list of attributes from object. Remove attribute or a list of attributes from object.
If `accessing_obj` is given, will check against the `attredit` lock. Args:
If not given, this check is skipped. 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: if self._cache is None or not _TYPECLASS_AGGRESSIVE_CACHE:
self._recache() self._recache()
@ -409,9 +480,17 @@ class AttributeHandler(object):
def clear(self, category=None, accessing_obj=None, default_access=True): def clear(self, category=None, accessing_obj=None, default_access=True):
""" """
Remove all Attributes on this object. If `accessing_obj` is Remove all Attributes on this object.
given, check the `attredit` lock on each Attribute before
continuing. If not given, skip check. 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: if self._cache is None or not _TYPECLASS_AGGRESSIVE_CACHE:
self._recache() self._recache()
@ -426,9 +505,18 @@ class AttributeHandler(object):
""" """
Return all Attribute objects on this object. Return all Attribute objects on this object.
If `accessing_obj` is given, check the `attrread` lock on Args:
each attribute before returning them. If not given, this accessing_obj (object, optional): Check the `attrread`
check is skipped. 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: if self._cache is None or not _TYPECLASS_AGGRESSIVE_CACHE:
self._recache() self._recache()
@ -442,31 +530,92 @@ class AttributeHandler(object):
class NickHandler(AttributeHandler): class NickHandler(AttributeHandler):
""" """
Handles the addition and removal of Nicks Handles the addition and removal of Nicks. Nicks are special
(uses Attributes' `strvalue` and `category` fields) 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" _attrtype = "nick"
def has(self, key, category="inputline"): 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) return super(NickHandler, self).has(key, category=category)
def get(self, key=None, category="inputline", **kwargs): 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) return super(NickHandler, self).get(key=key, category=category, strattr=True, **kwargs)
def add(self, key, replacement, category="inputline", **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) super(NickHandler, self).add(key, replacement, category=category, strattr=True, **kwargs)
def remove(self, key, category="inputline", **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) super(NickHandler, self).remove(key, category=category, **kwargs)
def nickreplace(self, raw_string, categories=("inputline", "channel"), include_player=True): 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 raw_string
obj_nicks, player_nicks = [], [] obj_nicks, player_nicks = [], []
for category in make_iter(categories): for category in make_iter(categories):
@ -491,35 +640,83 @@ class NAttributeHandler(object):
for the `AttributeHandler`. for the `AttributeHandler`.
""" """
def __init__(self, obj): def __init__(self, obj):
"initialized on the object" """
Initialized on the object
"""
self._store = {} self._store = {}
self.obj = weakref.proxy(obj) self.obj = weakref.proxy(obj)
def has(self, key): 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 return key in self._store
def get(self, key): 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) return self._store.get(key, None)
def add(self, key, value): 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._store[key] = value
self.obj.set_recache_protection() self.obj.set_recache_protection()
def remove(self, key): 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: if key in self._store:
del self._store[key] del self._store[key]
self.obj.set_recache_protection(self._store) self.obj.set_recache_protection(self._store)
def clear(self): def clear(self):
"Remove all nattributes from handler" """
Remove all NAttributes from handler.
"""
self._store = {} self._store = {}
def all(self, return_tuples=False): 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: if return_tuples:
return [(key, value) for (key, value) in self._store.items() if not key.startswith("_")] 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("_")] 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 This implements the common managers that are used by the
abstract models in dbobjects.py (and which are thus shared by abstract models in dbobjects.py (and which are thus shared by
all Attributes and TypedObjects). all Attributes and TypedObjects).
""" """
from functools import update_wrapper from functools import update_wrapper
from django.db.models import Q from django.db.models import Q
@ -18,8 +19,8 @@ _Tag = None
def returns_typeclass_list(method): def returns_typeclass_list(method):
""" """
Decorator: Always returns a list, even Decorator: Always returns a list, even if it is empty.
if it is empty.
""" """
def func(self, *args, **kwargs): def func(self, *args, **kwargs):
self.__doc__ = method.__doc__ self.__doc__ = method.__doc__
@ -34,7 +35,8 @@ def returns_typeclass_list(method):
def returns_typeclass(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): def func(self, *args, **kwargs):
self.__doc__ = method.__doc__ self.__doc__ = method.__doc__
@ -47,6 +49,7 @@ def returns_typeclass(method):
class TypedObjectManager(idmapper.manager.SharedMemoryManager): class TypedObjectManager(idmapper.manager.SharedMemoryManager):
""" """
Common ObjectManager for all dbobjects. Common ObjectManager for all dbobjects.
""" """
# common methods for all typed managers. These are used # common methods for all typed managers. These are used
# in other methods. Returns querysets. # in other methods. Returns querysets.
@ -61,16 +64,24 @@ class TypedObjectManager(idmapper.manager.SharedMemoryManager):
Attrs: Attrs:
key (str, optional): The attribute's key to search for key (str, optional): The attribute's key to search for
category (str, optional): The category of the attribute(s) to search for. category (str, optional): The category of the attribute(s)
value (str, optional): The attribute value to search for. Note that this to search for.
is not a very efficient operation since it will query for a pickled value (str, optional): The attribute value to search for.
entity. Mutually exclusive to `strvalue`. Note that this is not a very efficient operation since it
strvalue (str, optional): The str-value to search for. Most Attributes will query for a pickled entity. Mutually exclusive to
will not have strvalue set. This is mutually exclusive to the `value` `strvalue`.
keyword and will take precedence if given. strvalue (str, optional): The str-value to search for.
obj (Object, optional): On which object the Attribute to search for is. Most Attributes will not have strvalue set. This is
attrype (str, optional): An attribute-type to search for. By default this mutually exclusive to the `value` keyword and will take
is either `None` (normal Attributes) or `"nick"`. 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)] 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))] 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): 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) return self.get_attribute(key=key, category=category, value=value, strvalue=strvalue, obj=obj)
@returns_typeclass_list @returns_typeclass_list
def get_by_attribute(self, key=None, category=None, value=None, strvalue=None, attrtype=None): 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, Return objects having attributes with the given key, category,
strvalue or combination of those criteria. 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)] query = [("db_attributes__db_attrtype", attrtype)]
if key: if key:
@ -109,7 +158,19 @@ class TypedObjectManager(idmapper.manager.SharedMemoryManager):
return self.filter(**dict(query)) return self.filter(**dict(query))
def get_by_nick(self, key=None, nick=None, category="inputline"): 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") return self.get_by_attribute(key=key, category=category, strvalue=nick, attrtype="nick")
# Tag manager methods # Tag manager methods
@ -119,9 +180,20 @@ class TypedObjectManager(idmapper.manager.SharedMemoryManager):
Return Tag objects by key, by category, by object (it is Return Tag objects by key, by category, by object (it is
stored on) or with a combination of those criteria. stored on) or with a combination of those criteria.
tagtype - one of None (normal tags), "alias" or "permission" Attrs:
global_search - include all possible tags, not just tags on key (str, optional): The Tag's key to search for
this object 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 global _Tag
if not _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))] 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): 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") return self.get_tag(key=key, category=category, obj=obj, tagtype="permission")
def get_alias(self, key=None, category=None, obj=None): 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") return self.get_tag(key=key, category=category, obj=obj, tagtype="alias")
@returns_typeclass_list @returns_typeclass_list
@ -165,6 +261,8 @@ class TypedObjectManager(idmapper.manager.SharedMemoryManager):
tagtype (str or None, optional): 'type' of Tag, by default tagtype (str or None, optional): 'type' of Tag, by default
this is either `None` (a normal Tag), `alias` or this is either `None` (a normal Tag), `alias` or
`permission`. `permission`.
Returns:
objects (list): Objects with matching tag.
""" """
query = [("db_tags__db_tagtype", tagtype)] query = [("db_tags__db_tagtype", tagtype)]
if key: if key:
@ -174,19 +272,55 @@ class TypedObjectManager(idmapper.manager.SharedMemoryManager):
return self.filter(**dict(query)) return self.filter(**dict(query))
def get_by_permission(self, key=None, category=None): 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") return self.get_by_tag(key=key, category=category, tagtype="permission")
def get_by_alias(self, key=None, category=None): 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") return self.get_by_tag(key=key, category=category, tagtype="alias")
def create_tag(self, key=None, category=None, data=None, tagtype=None): def create_tag(self, key=None, category=None, data=None, tagtype=None):
""" """
Create a new Tag of the base type associated with this typedobject. Create a new Tag of the base type associated with this
This makes sure to create case-insensitive tags. If the exact same object. This makes sure to create case-insensitive tags.
tag configuration (key+category+tagtype) exists on the model, a If the exact same tag configuration (key+category+tagtype)
new tag will not be created, but an old one returned. A data exists on the model, a new tag will not be created, but an old
keyword is not part of the uniqueness of the tag and setting one one returned.
on an existing tag will overwrite the old data field.
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 data = str(data) if data is not None else None
# try to get old tag # try to get old tag
@ -213,11 +347,20 @@ class TypedObjectManager(idmapper.manager.SharedMemoryManager):
def dbref(self, dbref, reqhash=True): def dbref(self, dbref, reqhash=True):
""" """
Valid forms of dbref (database reference number) Determing if input is a valid dbref.
are either a string '#N' or an integer N.
Output is the integer part. Args:
reqhash - require input to be on form "#N" to be dbref (str or int): A possible dbref.
identified as a 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("#")): if reqhash and not (isinstance(dbref, basestring) and dbref.startswith("#")):
return None return None
@ -233,7 +376,14 @@ class TypedObjectManager(idmapper.manager.SharedMemoryManager):
@returns_typeclass @returns_typeclass
def get_id(self, dbref): 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) dbref = self.dbref(dbref, reqhash=False)
try: try:
@ -244,15 +394,30 @@ class TypedObjectManager(idmapper.manager.SharedMemoryManager):
def dbref_search(self, dbref): 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) return self.get_id(dbref)
@returns_typeclass_list @returns_typeclass_list
def get_dbref_range(self, min_dbref=None, max_dbref=None): def get_dbref_range(self, min_dbref=None, max_dbref=None):
""" """
Return all objects inside and including the Get objects within a certain range of dbrefs.
given boundaries.
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() retval = super(TypedObjectManager, self).all()
if min_dbref is not None: if min_dbref is not None:
@ -263,9 +428,14 @@ class TypedObjectManager(idmapper.manager.SharedMemoryManager):
def object_totals(self): def object_totals(self):
""" """
Returns a dictionary with all the typeclasses active in-game Get info about database statistics.
as well as the number of such objects defined (i.e. the number
of database object having that typeclass set on themselves). 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 = {} dbtotals = {}
typeclass_paths = set(self.values_list('db_typeclass_path', flat=True)) 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 certain typeclass. If location is set, limit search to objects
in that location. in that location.
typeclass - a typeclass class or a python path to a typeclass Args:
include_children - return objects with given typeclass and all typeclass (str or class): A typeclass class or a python path to a typeclass.
children inheriting from this typeclass. include_children (bool, optional): Return objects with
include_parents - return objects with given typeclass and all given typeclass *and* all children inheriting from this
parents to this typeclass typeclass. Mutuall exclusive to `include_parents`.
The include_children/parents keywords are mutually exclusive. 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): if callable(typeclass):
@ -319,11 +495,29 @@ class TypedObjectManager(idmapper.manager.SharedMemoryManager):
class TypeclassManager(TypedObjectManager): 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): def get(self, **kwargs):
""" """
Overload the standard get. This will limit itself to only Overload the standard get. This will limit itself to only
return the current typeclass. return the current typeclass.
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}) kwargs.update({"db_typeclass_path":self.model.path})
return super(TypedObjectManager, self).get(**kwargs) return super(TypedObjectManager, self).get(**kwargs)
@ -332,19 +526,33 @@ class TypeclassManager(TypedObjectManager):
""" """
Overload of the standard filter function. This filter will Overload of the standard filter function. This filter will
limit itself to only the current typeclass. 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}) kwargs.update({"db_typeclass_path":self.model.path})
return super(TypedObjectManager, self).filter(**kwargs) return super(TypedObjectManager, self).filter(**kwargs)
def all(self, **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) return super(TypedObjectManager, self).all(**kwargs).filter(db_typeclass_path=self.model.path)
def _get_subclasses(self, cls): def _get_subclasses(self, cls):
""" """
Recursively get all subclasses to a class Recursively get all subclasses to a class.
""" """
all_subclasses = cls.__subclasses__() all_subclasses = cls.__subclasses__()
for subclass in all_subclasses: for subclass in all_subclasses:
@ -353,8 +561,19 @@ class TypeclassManager(TypedObjectManager):
def get_family(self, **kwargs): def get_family(self, **kwargs):
""" """
Variation of get that not only returns the current Variation of get that not only returns the current typeclass
typeclass but also all subclasses of that 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__) paths = [self.model.path] + ["%s.%s" % (cls.__module__, cls.__name__)
for cls in self._get_subclasses(self.model)] for cls in self._get_subclasses(self.model)]
@ -365,6 +584,13 @@ class TypeclassManager(TypedObjectManager):
""" """
Variation of filter that allows results both from typeclass Variation of filter that allows results both from typeclass
and from subclasses of 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 # query, including all subclasses
paths = [self.model.path] + ["%s.%s" % (cls.__module__, cls.__name__) 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 Return all matches, allowing matches from all subclasses of
the typeclass. 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__) paths = [self.model.path] + ["%s.%s" % (cls.__module__, cls.__name__)
for cls in self._get_subclasses(self.model)] 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 loaded) typeclass - can be a class object or the python path
to such an object to match against. to such an object to match against.
typeclass - a class or the full python path to the class Args:
exact - returns true only typeclass (str or class): A class or the full python path
if the object's type is exactly this typeclass, ignoring to the class to check.
parents. 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): if isinstance(typeclass, basestring):
typeclass = [typeclass] + ["%s.%s" % (prefix, typeclass) for prefix in settings.TYPECLASS_PATHS] 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 to create a new object and just swap the player over to
that one instead. that one instead.
Arguments: Args:
new_typeclass (path/classobj) - type to switch to new_typeclass (str or classobj): Type to switch to.
clean_attributes (bool/list) - will delete all attributes clean_attributes (bool or list, optional): Will delete all
stored on this object (but not any attributes stored on this object (but not any of the
of the database fields such as name or database fields such as name or location). You can't get
location). You can't get attributes back, attributes back, but this is often the safest bet to make
but this is often the safest bet to make sure nothing in the new typeclass clashes with the old
sure nothing in the new typeclass clashes one. If you supply a list, only those named attributes
with the old one. If you supply a list, will be cleared.
only those named attributes will be cleared. run_start_hooks (bool, optional): Trigger the start hooks
run_start_hooks - trigger the start hooks of the object, as if of the object, as if it was created for the first time.
it was created for the first time. no_default (bool, optiona): If set, the swapper will not
no_default - if this is active, the swapper will not allow for allow for swapping to a default typeclass in case the
swapping to a default typeclass in case the given given one fails for some reason. Instead the old one will
one fails for some reason. Instead the old one be preserved.
will be preserved.
Returns: 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: Args:
accessing_obj (str): Object trying to access this one. accessing_obj (str): Object trying to access this one.
access_type (str, optional): Type of access sought. access_type (str, optional): Type of access sought.
default (bool, optional): What to return if no lock of access_type was found default (bool, optional): What to return if no lock of
no_superuser_bypass (bool, optional): Turn off the superuser lock bypass (be careful with this one). access_type was found
no_superuser_bypass (bool, optional): Turn off the
superuser lock bypass (be careful with this one).
Kwargs: Kwargs:
kwargs (any): Ignored, but is there to make the api consistent with the kwargs (any): Ignored, but is there to make the api
object-typeclass method access, which use it to feed to its hook methods. 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, return self.locks.check(accessing_obj, access_type=access_type, default=default,
@ -483,8 +492,15 @@ class TypedObject(SharedMemoryModel):
def check_permstring(self, permstring): def check_permstring(self, permstring):
""" """
This explicitly checks if we hold particular permission without This explicitly checks if we hold particular permission
involving any locks. 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 hasattr(self, "player"):
if self.player and self.player.is_superuser: if self.player and self.player.is_superuser:
@ -512,11 +528,16 @@ class TypedObject(SharedMemoryModel):
# #
def _deleted(self, *args, **kwargs): def _deleted(self, *args, **kwargs):
"Scrambling method for already deleted objects" """
Scrambling method for already deleted objects
"""
raise ObjectDoesNotExist("This object was already deleted!") raise ObjectDoesNotExist("This object was already deleted!")
def delete(self): def delete(self):
"Cleaning up handlers on the typeclass level" """
Cleaning up handlers on the typeclass level
"""
global TICKER_HANDLER global TICKER_HANDLER
if not TICKER_HANDLER: if not TICKER_HANDLER:
from evennia.scripts.tickerhandler import 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. Displays the name of the object in a viewer-aware manner.
Args: 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: Returns:
A string containing the name of the object, including the DBREF if this user is privileged to control name (str): A string containing the name of the object,
said object. including the DBREF if this user is privileged to control
said object.
Notes: Notes:
This function could be extended to change how object names 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 appear to users in character, but be wary. This function
aliases when searching, and is expected to produce something useful for builders. 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'): if self.access(looker, access_type='controls'):
@ -633,18 +658,22 @@ class TypedObject(SharedMemoryModel):
def get_extra_info(self, looker, **kwargs): def get_extra_info(self, looker, **kwargs):
""" """
Used when an object is in a list of ambiguous objects as an additional Used when an object is in a list of ambiguous objects as an
information tag. additional information tag.
For instance, if you had potions which could have varying levels of liquid For instance, if you had potions which could have varying
left in them, you might want to display how many drinks are left in each when levels of liquid left in them, you might want to display how
selecting which to drop, but not in your normal inventory listing. many drinks are left in each when selecting which to drop, but
not in your normal inventory listing.
Args: 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: 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: if self.location == looker:

View file

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