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)[source]

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)[source]

Bases: object

Tag Property.

taghandler_name = 'tags'
__init__(category=None, data=None)[source]

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")
class evennia.typeclasses.tags.TagCategoryProperty(*default_tags)[source]

Bases: object

Tag Category Property.

taghandler_name = 'tags'
__init__(*default_tags)[source]

Assign a property for a Tag Category, with any number of Tag keys. This is often more useful than the TagProperty since it’s common to want to check which tags of a particular category the object is a member of.

Parameters

*args (str or callable) – Tag keys to assign to this property, using the category given by the name of the property. Note that, if these tags are always set on the object, if they are removed by some other means, they will be re-added when this property is accessed. Furthermore, changing this list after the object was created, will not remove any old tags (there is no way for the property to know if the new list is new or not). If a callable, it will be called without arguments to return the tag key. It is not possible to set tag data this way (use the Taghandler directly for that). Tag keys are not case sensitive.

Raises

ValueError – If the input is not a valid tag key or tuple.

Notes

It is not possible to set Tags with a None category using a TagCategoryProperty - use obj.tags.add() instead.

Example:

class RogueCharacter(DefaultCharacter):
    guild = TagCategoryProperty("thieves_guild", "merchant_guild")
class evennia.typeclasses.tags.TagHandler(obj)[source]

Bases: object

Generic tag-handler. Accessed via TypedObject.tags.

__init__(obj)[source]

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()[source]

Reset the cache from the outside.

add(key=None, category=None, data=None)[source]

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)[source]

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)[source]

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)[source]

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)[source]

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)[source]

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)[source]

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).

batch_remove(*args)[source]

Batch-remove 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) (the data field is ignored, only keystr/category matters). It’s possible to mix input types.

class evennia.typeclasses.tags.AliasProperty(category=None, data=None)[source]

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)[source]

Bases: evennia.typeclasses.tags.TagHandler

A handler for the Alias Tag type.

class evennia.typeclasses.tags.PermissionProperty(category=None, data=None)[source]

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)[source]

Bases: evennia.typeclasses.tags.TagHandler

A handler for the Permission Tag type.

check(*permissions, require_all=False)[source]

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).