summaryrefslogtreecommitdiff
path: root/vobject/behavior.py
diff options
context:
space:
mode:
Diffstat (limited to 'vobject/behavior.py')
-rw-r--r--vobject/behavior.py164
1 files changed, 164 insertions, 0 deletions
diff --git a/vobject/behavior.py b/vobject/behavior.py
new file mode 100644
index 0000000..226c0cc
--- /dev/null
+++ b/vobject/behavior.py
@@ -0,0 +1,164 @@
+"""Behavior (validation, encoding, and transformations) for vobjects."""
+
+import base
+
+#------------------------ Abstract class for behavior --------------------------
+class Behavior(object):
+ """Abstract class to describe vobject options, requirements and encodings.
+
+ Behaviors are used for root components like VCALENDAR, for subcomponents
+ like VEVENT, and for individual lines in components.
+
+ Behavior subclasses are not meant to be instantiated, all methods should
+ be classmethods.
+
+ @cvar name:
+ The uppercase name of the object described by the class, or a generic
+ name if the class defines behavior for many objects.
+ @cvar description:
+ A brief excerpt from the RFC explaining the function of the component or
+ line.
+ @cvar versionString:
+ The string associated with the component, for instance, 2.0 if there's a
+ line like VERSION:2.0, an empty string otherwise.
+ @cvar knownChildren:
+ A dictionary with uppercased component/property names as keys and a
+ tuple (min, max, id) as value, where id is the id used by
+ L{registerBehavior}, min and max are the limits on how many of this child
+ must occur. None is used to denote no max or no id.
+ @cvar quotedPrintable:
+ A boolean describing whether the object should be encoded and decoded
+ using quoted printable line folding and character escaping.
+ @cvar defaultBehavior:
+ Behavior to apply to ContentLine children when no behavior is found.
+ @cvar hasNative:
+ A boolean describing whether the object can be transformed into a more
+ Pythonic object.
+ @cvar isComponent:
+ A boolean, True if the object should be a Component.
+ @cvar sortFirst:
+ The lower-case list of children which should come first when sorting.
+ @cvar allowGroup:
+ Whether or not vCard style group prefixes are allowed.
+ """
+ name=''
+ description=''
+ versionString=''
+ knownChildren = {}
+ quotedPrintable = False
+ defaultBehavior = None
+ hasNative= False
+ isComponent = False
+ allowGroup = False
+ forceUTC = False
+ sortFirst = []
+
+ def __init__(self):
+ err="Behavior subclasses are not meant to be instantiated"
+ raise base.VObjectError(err)
+
+ @classmethod
+ def validate(cls, obj, raiseException=False, complainUnrecognized=False):
+ """Check if the object satisfies this behavior's requirements.
+
+ @param obj:
+ The L{ContentLine<base.ContentLine>} or
+ L{Component<base.Component>} to be validated.
+ @param raiseException:
+ If True, raise a L{base.ValidateError} on validation failure.
+ Otherwise return a boolean.
+ @param complainUnrecognized:
+ If True, fail to validate if an uncrecognized parameter or child is
+ found. Otherwise log the lack of recognition.
+
+ """
+ if not cls.allowGroup and obj.group is not None:
+ err = str(obj) + " has a group, but this object doesn't support groups"
+ raise base.VObjectError(err)
+ if isinstance(obj, base.ContentLine):
+ return cls.lineValidate(obj, raiseException, complainUnrecognized)
+ elif isinstance(obj, base.Component):
+ count = {}
+ for child in obj.getChildren():
+ if not child.validate(raiseException, complainUnrecognized):
+ return False
+ name=child.name.upper()
+ count[name] = count.get(name, 0) + 1
+ for key, val in cls.knownChildren.iteritems():
+ if count.get(key,0) < val[0]:
+ if raiseException:
+ m = "%s components must contain at least %i %s"
+ raise base.ValidateError(m % (cls.name, val[0], key))
+ return False
+ if val[1] and count.get(key,0) > val[1]:
+ if raiseException:
+ m = "%s components cannot contain more than %i %s"
+ raise base.ValidateError(m % (cls.name, val[1], key))
+ return False
+ return True
+ else:
+ err = str(obj) + " is not a Component or Contentline"
+ raise base.VObjectError(err)
+
+ @classmethod
+ def lineValidate(cls, line, raiseException, complainUnrecognized):
+ """Examine a line's parameters and values, return True if valid."""
+ return True
+
+ @classmethod
+ def decode(cls, line):
+ if line.encoded: line.encoded=0
+
+ @classmethod
+ def encode(cls, line):
+ if not line.encoded: line.encoded=1
+
+ @classmethod
+ def transformToNative(cls, obj):
+ """Turn a ContentLine or Component into a Python-native representation.
+
+ If appropriate, turn dates or datetime strings into Python objects.
+ Components containing VTIMEZONEs turn into VtimezoneComponents.
+
+ """
+ return obj
+
+ @classmethod
+ def transformFromNative(cls, obj):
+ """Inverse of transformToNative."""
+ raise base.NativeError("No transformFromNative defined")
+
+ @classmethod
+ def generateImplicitParameters(cls, obj):
+ """Generate any required information that don't yet exist."""
+ pass
+
+ @classmethod
+ def serialize(cls, obj, buf, lineLength, validate=True):
+ """Set implicit parameters, do encoding, return unicode string.
+
+ If validate is True, raise VObjectError if the line doesn't validate
+ after implicit parameters are generated.
+
+ Default is to call base.defaultSerialize.
+
+ """
+
+ cls.generateImplicitParameters(obj)
+ if validate: cls.validate(obj, raiseException=True)
+
+ if obj.isNative:
+ transformed = obj.transformFromNative()
+ undoTransform = True
+ else:
+ transformed = obj
+ undoTransform = False
+
+ out = base.defaultSerialize(transformed, buf, lineLength)
+ if undoTransform: obj.transformToNative()
+ return out
+
+ @classmethod
+ def valueRepr( cls, line ):
+ """return the representation of the given content line value"""
+ return line.value \ No newline at end of file