diff --git a/evennia/typeclasses/admin.py b/evennia/typeclasses/admin.py index 4571b30214..d59d5783df 100644 --- a/evennia/typeclasses/admin.py +++ b/evennia/typeclasses/admin.py @@ -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') diff --git a/evennia/typeclasses/attributes.py b/evennia/typeclasses/attributes.py index f88e9fd2f2..9bec73f74a 100644 --- a/evennia/typeclasses/attributes.py +++ b/evennia/typeclasses/attributes.py @@ -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_` """ _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("_")] diff --git a/evennia/typeclasses/managers.py b/evennia/typeclasses/managers.py index 366f63aa16..b533cb6a0d 100644 --- a/evennia/typeclasses/managers.py +++ b/evennia/typeclasses/managers.py @@ -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)] diff --git a/evennia/typeclasses/models.py b/evennia/typeclasses/models.py index 7856d6faab..49a74226a5 100644 --- a/evennia/typeclasses/models.py +++ b/evennia/typeclasses/models.py @@ -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: diff --git a/evennia/typeclasses/tags.py b/evennia/typeclasses/tags.py index 330b9e342c..bcee866c4e 100644 --- a/evennia/typeclasses/tags.py +++ b/evennia/typeclasses/tags.py @@ -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"