Source code for stalker.core.models.entity

#-*- coding: utf-8 -*-



import datetime
import re
from stalker.ext.validatedList import ValidatedList



########################################################################
class EntityMeta(type):
    """the metaclass for the very basic entity, just adds the name of the class
    as the entity_type class attribute
    """
    
    
    
    #----------------------------------------------------------------------
    def __init__(cls, classname, bases, dict_):
        setattr(cls, "entity_type", unicode(classname))
        return type.__init__(cls, classname, bases, dict_)






########################################################################
[docs]class SimpleEntity(object): """The base class of all the others This class has the basic information about an entity which are the name, the description, tags and the audit information like created_by, updated_by, date_created and date_updated about this entity. Two SimpleEntities considered equal if they have the same name, the other attributes doesn't matter. :param string name: A string or unicode value that holds the name of this entity. It can not be empty, the first letter should be an alphabetic ([a-zA-z]) (not alphanumeric [a-zA-Z0-9]) letter and it should not contain any white space at the beggining and at the end of the string, giving an object the object will be converted to string and then the resulting string will be conditioned. :param str description: A string or unicode attribute that holds the description of this entity object, it could be an empty string, and it could not again have white spaces at the beggining and at the end of the string, again any given objects will be converted to strings :param created_by: The :class:`~stalker.core.models.user.User` who has created this object :type created_by: :class:`~stalker.core.models.user.User` :param updated_by: The :class:`~stalker.core.models.user.User` who has updated this object lastly. The created_by and updated_by attributes point the same object if this object is just created. :param date_created: The date that this object is created. :type date_created: :class:`datetime.datetime` :param date_updated: The date that this object is updated lastly. For newly created entities this is equal to date_created and thedate_updated cannot point a date which is before date_created. :type date_updated: :class:`datetime.datetime` :param str code: The code name of this object. It accepts string or unicode values and any other kind of objects will be converted to string. Can be omitted and it will be set to the uppercase version of the nice_name attribute. If both the name and code arguments are given the code attribute will be set to code, but in any update to name attribute the code also will be updated to the uppercase form of the nice_name attribute. The default value is the upper case form of the nice_name """ __metaclass__ = EntityMeta #----------------------------------------------------------------------
[docs] def __init__(self, name=None, description="", created_by=None, updated_by=None, date_created=datetime.datetime.now(), date_updated=datetime.datetime.now(), code=None, **kwargs ): # code attribute # just set it to None for now self._code = "" # name and nice_name self._nice_name = "" self._name = "" self.name = name # code # if the given code argument is not None # use it to set the code if code is not None and code is not "": self._code = self._validate_code(code) self._description = self._validate_description(description) self._created_by = self._validate_created_by(created_by) self._updated_by = self._validate_updated_by(updated_by) self._date_created = self._validate_date_created(date_created) self._date_updated = self._validate_date_updated(date_updated) #----------------------------------------------------------------------
def __repr__(self): """the representation of the SimpleEntity """ return "<%s (%s, %s)>" % (self.entity_type, self.name, self.code) #---------------------------------------------------------------------- def _validate_description(self, description_in): """validates the given description_in value """ if description_in is None: description_in = "" return str(description_in) #---------------------------------------------------------------------- def _validate_name(self, name_in): """validates the given name_in value """ # it is None if name_in is None: raise ValueError("the name couldn't be set to None") name_in = self._condition_name(str(name_in)) # it is empty if name_in == "": raise ValueError("the name couldn't be an empty string") return name_in def _condition_code(self, code_in): """formats the given code_in value """ # just set it to the uppercase of what nice_name gives return self._condition_nice_name(code_in).upper() #---------------------------------------------------------------------- def _condition_name(self, name_in): """conditions the name_in value """ # remove unnecesary characters from the string name_in = re.sub("([^a-zA-Z0-9\s_\-]+)", r"", name_in).strip() # remove all the characters which are not alpabetic name_in = re.sub("(^[^a-zA-Z]+)", r"", name_in) return name_in #---------------------------------------------------------------------- def _condition_nice_name(self, nice_name_in): """conditions the given nice name """ ## remove unnecesary characters from the beginning #nice_name_in = re.sub("(^[^A-Za-z]+)", r"", nice_name_in) # remove unnecesary characters from the string nice_name_in = self._validate_name(nice_name_in) # replace camel case letters nice_name_in = re.sub(r"(.+?[a-z]+)([A-Z])", r"\1_\2", nice_name_in) # replace white spaces with under score nice_name_in = re.sub("([\s\-])+", r"_", nice_name_in) # remove multiple underscores nice_name_in = re.sub(r"([_]+)", r"_", nice_name_in) # turn it to lower case nice_name_in = nice_name_in.lower() return nice_name_in #----------------------------------------------------------------------
[docs] def description(): def fget(self): return self._description def fset(self, description_in): self._description = self._validate_description(description_in) doc = """Description of this object.""" return locals()
description = property(**description()) #----------------------------------------------------------------------
[docs] def name(): def fget(self): return self._name def fset(self, name_in): self._name = self._validate_name(name_in) # also set the nice_name self._nice_name = self._condition_nice_name(self._name) # set the code self.code = self._name doc = """name of this object""" return locals()
name = property(**name()) #----------------------------------------------------------------------
[docs] def nice_name(): def fget(self): return self._nice_name doc = """The ``nice name`` of this object. It has the same value with the name (contextually) but with a different format like, all the white spaces replaced by underscores ("\_"), all the CamelCase form will be expanded by underscore (\_) characters and it is always lower case. There is also the ``code`` attribute which is simply the upper case form of ``nice_name`` if it is not defined differently (i.e set to another value).""" return locals()
nice_name = property(**nice_name()) #---------------------------------------------------------------------- def _validate_code(self, code_in): """validates the given code value """ # check if the code_in is None or empty string if code_in is None or code_in=="": # restore the value from nice_name and let it be reformatted code_in = self.nice_name return self._condition_code(str(code_in)) #---------------------------------------------------------------------- def _validate_created_by(self, created_by_in): """validates the given created_by_in attribute """ #------------------------------------------------------------------- # Python documentation says one of the nice ways to over come circular # imports is late imports and it is perfectly ok to use it like that # # just try to import the module as late as possible # # ref: # http://docs.python.org/faq/programming.html# # what-are-the-best-practices-for-using-import-in-a-module #------------------------------------------------------------------- from stalker.core.models import user ## raise ValueError when: ## it is None #if created_by_in is None: #raise ValueError("the created_by attribute can not be set to None") if created_by_in is not None: if not isinstance(created_by_in, user.User): raise ValueError("the created_by attribute should be an " "instance of stalker.core.models.user.User") return created_by_in #---------------------------------------------------------------------- def _validate_updated_by(self, updated_by_in): """validates the given updated_by_in attribute """ from stalker.core.models import user if updated_by_in is None: # set it to what created_by attribute has updated_by_in = self._created_by if updated_by_in is not None: if not isinstance(updated_by_in, user.User): raise ValueError("the updated_by attribute should be an " "instance of stalker.core.models.user.User") return updated_by_in #---------------------------------------------------------------------- def _validate_date_created(self, date_created_in): """validates the given date_creaetd_in """ # raise ValueError when: # it is None if date_created_in is None: raise ValueError("the date_created could not be None") if not isinstance(date_created_in, datetime.datetime): raise ValueError("the date_created should be an instance of " "datetime.datetime") return date_created_in #---------------------------------------------------------------------- def _validate_date_updated(self, date_updated_in): """validates the given date_updated_in """ # raise ValueError when: # it is None if date_updated_in is None: raise ValueError("the date_updated could not be None") # it is not an instance of datetime.datetime if not isinstance(date_updated_in, datetime.datetime): raise ValueError("the date_updated should be an instance of " "datetime.datetime") # lower than date_created if date_updated_in < self.date_created: raise ValueError("the date_updated could not be set to a date " "before date_created, try setting the " "date_created before") return date_updated_in #----------------------------------------------------------------------
[docs] def code(): def fget(self): return self._code def fset(self, code_in): self._code = self._validate_code(code_in) doc = """The code name of this object. It accepts string or unicode values and any other kind of objects will be converted to string. In any update to the name attribute the code also will be updated to the uppercase form of the nice_name attribute. If the not initialized or given as None, it will be set to the uppercase version of the nice_name attribute. Setting the code attribute to None will reset it to the default value. The default value is the upper case form of the nice_name. """ return locals()
code = property(**code()) #----------------------------------------------------------------------
[docs] def created_by(): def fget(self): return self._created_by def fset(self, created_by_in): self._created_by = self._validate_created_by(created_by_in) doc = """The :class:`~stalker.core.models.user.User` who has created this object.""" return locals()
created_by = property(**created_by()) #----------------------------------------------------------------------
[docs] def updated_by(): def fget(self): return self._updated_by def fset(self, updated_by_in): self._updated_by = self._validate_updated_by(updated_by_in) doc = """The :class:`~stalker.core.models.user.User` who has updated this object.""" return locals()
updated_by = property(**updated_by()) #----------------------------------------------------------------------
[docs] def date_created(): def fget(self): return self._date_created def fset(self, date_created_in): self._date_created = self._validate_date_created(date_created_in) doc = """A :class:`datetime.datetime` instance showing the creation date and time of this object.""" return locals()
date_created = property(**date_created()) #----------------------------------------------------------------------
[docs] def date_updated(): def fget(self): return self._date_updated def fset(self, date_updated_in): self._date_updated = self._validate_date_updated(date_updated_in) doc = """A :class:`datetime.datetime` instance showing the update date and time of this object.""" return locals()
date_updated = property(**date_updated()) #---------------------------------------------------------------------- def __eq__(self, other): """the equality operator """ return isinstance(other, SimpleEntity) and \ self.name == other.name #and \ #self.description == other.description #---------------------------------------------------------------------- def __ne__(self, other): """the inequality operator """ return not self.__eq__(other) ########################################################################
[docs]class Entity(SimpleEntity): """Another base data class that adds tags and notes to the attributes list. This is the entity class which is derived from the SimpleEntity and adds only tags to the list of parameters. Two Entities considered equal if they have the same name. It doesn't matter if they have different tags or notes. :param tags: a list of tag objects related to this entity. tags could be an empty list, or when omitted it will be set to an empty list :param notes: a list of note objects. notes can be an empty list, or when omitted it will be set to an empty list """ #----------------------------------------------------------------------
[docs] def __init__(self, tags=[], notes=[], **kwargs ): super(Entity, self).__init__(**kwargs) self._tags = self._validate_tags(tags) self._notes = self._validate_notes(notes) #----------------------------------------------------------------------
def _validate_notes(self, notes_in): """validates the given notes value """ if not isinstance(notes_in, list): raise ValueError("notes should be an instance of list") from stalker.core.models import note for element in notes_in: if not isinstance(element, note.Note): raise ValueError("every element in notes should be an " "instance of stalker.core.models.note.Note " "class") return ValidatedList(notes_in) #---------------------------------------------------------------------- def _validate_tags(self, tags_in): """validates the given tags_in value """ # it is not an instance of list if not isinstance(tags_in, list): raise ValueError("the tags attribute should be set to a list") return ValidatedList(tags_in) #----------------------------------------------------------------------
[docs] def notes(): def fget(self): return self._notes def fset(self, notes_in): self._notes = self._validate_notes(notes_in) doc = """all the notes about this entity, it should be a list of Notes objects or an empty list, None is not accepted """ return locals()
notes = property(**notes()) #----------------------------------------------------------------------
[docs] def tags(): def fget(self): return self._tags def fset(self, tags_in): self._tags = self._validate_tags(tags_in) doc = """a list of Tag objects which shows the related tags to the entity""" return locals()
tags = property(**tags()) #---------------------------------------------------------------------- def __eq__(self, other): """the equality operator """ return super(Entity, self).__eq__(other) and \ isinstance(other, Entity) ########################################################################
[docs]class TypeEntity(Entity): """The entry point for types. It is created to group the `Type` objects, so any other classes accepting a ``TypeEntity`` object can have one of the derived classes, this is done in that way mainly to ease the of creation of only one :class:`~stalker.core.models.types.TypeTemplate` class and let the others to use this one TypeTemplate class. It doesn't add any new parameters to it's super. """ #----------------------------------------------------------------------
[docs] def __init__(self, **kwargs): super(TypeEntity, self).__init__(**kwargs) ##---------------------------------------------------------------------- #def __repr__(self): #"""the representation #""" #return "<TypeEntity (%s, %s)>" % (self.name, self.code) #----------------------------------------------------------------------
def __eq__(self, other): """the equality operator """ return super(TypeEntity, self).__eq__(other) and \ isinstance(other, TypeEntity) #---------------------------------------------------------------------- def __ne__(self, other): """the inequality operator """ return not self.__eq__(other)