# evennia.typeclasses.tags

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.

class `evennia.typeclasses.tags.``Tag`(*args, **kwargs)

  Bases: `django.db.models.base.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 tags 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 regular 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`

    A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

  `db_category`

    A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

  `db_data`

    A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

  `db_model`

    A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

  `db_tagtype`

    A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

  exception `DoesNotExist`

    Bases: `django.core.exceptions.ObjectDoesNotExist`

  exception `MultipleObjectsReturned`

    Bases: `django.core.exceptions.MultipleObjectsReturned`

  `accountdb_set`

    Accessor to the related objects manager on the forward and reverse sides of a many-to-many relation.

    In the example:

        class Pizza(Model):
            toppings = ManyToManyField(Topping, related_name='pizzas')

    **Pizza.toppings** and **Topping.pizzas** are **ManyToManyDescriptor** instances.

    Most of the implementation is delegated to a dynamically defined manager class built by **create_forward_many_to_many_manager()** defined below.

  `channeldb_set`

    Accessor to the related objects manager on the forward and reverse sides of a many-to-many relation.

    In the example:

        class Pizza(Model):
            toppings = ManyToManyField(Topping, related_name='pizzas')

    **Pizza.toppings** and **Topping.pizzas** are **ManyToManyDescriptor** instances.

    Most of the implementation is delegated to a dynamically defined manager class built by **create_forward_many_to_many_manager()** defined below.

  `helpentry_set`

    Accessor to the related objects manager on the forward and reverse sides of a many-to-many relation.

    In the example:

        class Pizza(Model):
            toppings = ManyToManyField(Topping, related_name='pizzas')

    **Pizza.toppings** and **Topping.pizzas** are **ManyToManyDescriptor** instances.

    Most of the implementation is delegated to a dynamically defined manager class built by **create_forward_many_to_many_manager()** defined below.

  `id`

    A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

  `msg_set`

    Accessor to the related objects manager on the forward and reverse sides of a many-to-many relation.

    In the example:

        class Pizza(Model):
            toppings = ManyToManyField(Topping, related_name='pizzas')

    **Pizza.toppings** and **Topping.pizzas** are **ManyToManyDescriptor** instances.

    Most of the implementation is delegated to a dynamically defined manager class built by **create_forward_many_to_many_manager()** defined below.

  `objectdb_set`

    Accessor to the related objects manager on the forward and reverse sides of a many-to-many relation.

    In the example:

        class Pizza(Model):
            toppings = ManyToManyField(Topping, related_name='pizzas')

    **Pizza.toppings** and **Topping.pizzas** are **ManyToManyDescriptor** instances.

    Most of the implementation is delegated to a dynamically defined manager class built by **create_forward_many_to_many_manager()** defined below.

  `objects` = <django.db.models.manager.Manager object>
  `scriptdb_set`

    Accessor to the related objects manager on the forward and reverse sides of a many-to-many relation.

    In the example:

        class Pizza(Model):
            toppings = ManyToManyField(Topping, related_name='pizzas')

    **Pizza.toppings** and **Topping.pizzas** are **ManyToManyDescriptor** instances.

    Most of the implementation is delegated to a dynamically defined manager class built by **create_forward_many_to_many_manager()** defined below.

class `evennia.typeclasses.tags.``TagProperty`(category=None, data=None)

  Bases: `object`

  Tag property descriptor. Allows for setting tags on an object as Django-like ‘fields’ on the class level. Since Tags are almost always used for querying, Tags are always created/assigned along with the object. Make sure the property/tagname does not collide with an existing method/property on the class. If it does, you must use tags.add() instead.

  Note that while you _can_ check e.g. obj.tagname,this will give an AttributeError if the Tag is not set. Most often you want to use **obj.tags.get(“tagname”) to check if a tag is set on an object.

  Example:

      class Character(DefaultCharacter):
          mytag = TagProperty()  # category=None
          mytag2 = TagProperty(category="tagcategory")

  `taghandler_name` = 'tags'
  `__init__`(category=None, data=None)

    Initialize self. See help(type(self)) for accurate signature.

class `evennia.typeclasses.tags.``TagHandler`(obj)

  Bases: `object`

  Generic tag-handler. Accessed via TypedObject.tags.

  `__init__`(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

    Parameters

      obj (object) – The object on which the handler is set.

  `reset_cache`()

    Reset the cache from the outside.

  `add`(key=None, category=None, data=None)

    Add a new tag to the handler.

    Parameters

      - key (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 tag 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.

  `has`(key=None, category=None, return_list=False)

    Checks if the given Tag (or list of Tags) exists on the object.

    Parameters

      - key (str or iterable) – The Tag key or tags to check for. If None, search by category.

      - category (str, optional) – Limit the check to Tags with this category (note, that None is the default category).

    Returns

      has_tag (bool or list) –

      If the Tag exists on this object or not.

        If tag was given as an iterable then the return is a list of booleans.

    Raises

      ValueError – If neither tag nor category is given.

  `get`(key=None, default=None, category=None, return_tagobj=False, return_list=False, raise_exception=False)

    Get the tag for the given key, category or combination of the two.

    Parameters

      - key (str or list, optional) – The tag or tags to retrieve.

      - default (any, optional) – The value to return in case of no match.

      - category (str, optional) – The Tag category to limit the request to. Note that None is the valid, default category. If no key is given, all tags of this category will be returned.

      - return_tagobj (bool, optional) – Return the Tag object itself instead of a string representation of the Tag.

      - return_list (bool, optional) – Always return a list, regardless of number of matches.

      - raise_exception (bool, optional) – Raise AttributeError if no matches are found.

    Returns

      tags (list) –

      The matches, either string

        representations of the tags or the Tag objects themselves depending on return_tagobj. If ‘default’ is set, this will be a list with the default value as its only element.

    Raises

      AttributeError – If finding no matches and raise_exception is True.

  `remove`(key=None, category=None)

    Remove a tag from the handler based ond key and/or category.

    Parameters

      - key (str or list, optional) – 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

    Notes

    If neither key nor category is specified, this acts as .clear().

  `clear`(category=None)

    Remove all tags from the handler.

    Parameters

      category (str, optional) – The Tag category to limit the request to. Note that None is the valid, default category.

  `all`(return_key_and_category=False, return_objs=False)

    Get all tags in this handler, regardless of category.

    Parameters

      - return_key_and_category (bool, optional) – Return a list of tuples [(key, category), …].

      - return_objs (bool, optional) – Return tag objects.

    Returns

      tags (list) –

      A list of tag keys [tagkey, tagkey, …] or

        a list of tuples [(key, category), …] if return_key_and_category is set.

  `batch_add`(*args)

    Batch-add tags from a list of tuples.

    Parameters

      *args (tuple or str) – Each argument should be a tagstr keys or tuple (keystr, category) or (keystr, category, data). It’s possible to mix input types.

    Notes

    This will generate a mimimal number of self.add calls, based on the number of categories involved (including None) (data is not unique and may be overwritten by the content of a latter tuple with the same category).

class `evennia.typeclasses.tags.``AliasProperty`(category=None, data=None)

  Bases: `evennia.typeclasses.tags.TagProperty`

  Allows for setting aliases like Django fields:

      class Character(DefaultCharacter):
          # note that every character will get the alias bob. Make sure
          # the alias property does not collide with an existing method
          # or property on the class.
          bob = AliasProperty()

  `taghandler_name` = 'aliases'

class `evennia.typeclasses.tags.``AliasHandler`(obj)

  Bases: `evennia.typeclasses.tags.TagHandler`

  A handler for the Alias Tag type.

class `evennia.typeclasses.tags.``PermissionProperty`(category=None, data=None)

  Bases: `evennia.typeclasses.tags.TagProperty`

  Allows for setting permissions like Django fields:

      class Character(DefaultCharacter):
          # note that every character will get this permission! Make
          # sure it doesn't collide with an existing method or property.
          myperm = PermissionProperty()

  `taghandler_name` = 'permissions'

class `evennia.typeclasses.tags.``PermissionHandler`(obj)

  Bases: `evennia.typeclasses.tags.TagHandler`

  A handler for the Permission Tag type.

  `check`(*permissions, require_all=False)

    Straight-up check the provided permission against this handler. The check will pass if

    - any/all given permission exists on the handler (depending on if require_all is set).

    - If handler sits on puppeted object and this is a hierarachical perm, the puppeting Account’s permission will also be included in the check, prioritizing the Account’s perm (this avoids escalation exploits by puppeting a too-high prio character)

    - a permission is also considered to exist on the handler, if it is lower than a permission on the handler and this is a ‘hierarchical’ permission given in settings.PERMISSION_HIERARCHY. Example: If the ‘Developer’ hierarchical perm perm is set on the handler, and we check for the ‘Builder’ perm, the check will pass.

    Parameters

      - *permissions (str) – Any number of permissions to check. By default, the permission is passed if any of these (or higher, if a hierarchical permission defined in settings.PERMISSION_HIERARCHY) exists in the handler. Permissions are not case-sensitive.

      - require_all (bool) – If set, all provided permissions much pass the check for the entire check to pass. By default only one needs to pass.

    Returns

      bool – If the provided permission(s) pass the check on this handler.

    Example

    ::

      can_enter = obj.permissions.check(“Blacksmith”, “Builder”)

    Notes

    This works the same way as the perms lockfunc and could be replicated with a lock check against the lockstring

    > “locktype: perm(perm1) OR perm(perm2) OR …”

    (using AND for the require_all condition).