Module exchangelib.extended_properties
Expand source code
import logging
from decimal import Decimal
from .ewsdatetime import EWSDateTime
from .properties import EWSElement, ExtendedFieldURI
from .util import create_element, add_xml_child, get_xml_attrs, get_xml_attr, set_xml_value, value_to_xml_text, \
xml_text_to_value, is_iterable, TNS
log = logging.getLogger(__name__)
class ExtendedProperty(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/extendedproperty"""
ELEMENT_NAME = 'ExtendedProperty'
# Enum values: https://docs.microsoft.com/en-us/dotnet/api/exchangewebservices.distinguishedpropertysettype
DISTINGUISHED_SETS = {
'Address',
'Appointment',
'CalendarAssistant',
'Common',
'InternetHeaders',
'Meeting',
'PublicStrings',
'Sharing',
'Task',
'UnifiedMessaging',
}
# Enum values: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/extendedfielduri
PROPERTY_TYPES = {
'ApplicationTime',
'Binary',
'BinaryArray',
'Boolean',
'CLSID',
'CLSIDArray',
'Currency',
'CurrencyArray',
'Double',
'DoubleArray',
# 'Error',
'Float',
'FloatArray',
'Integer',
'IntegerArray',
'Long',
'LongArray',
# 'Null',
# 'Object',
# 'ObjectArray',
'Short',
'ShortArray',
'SystemTime',
'SystemTimeArray',
'String',
'StringArray',
} # The commented-out types cannot be used for setting or getting (see docs) and are thus not very useful here
# Translation table between common distinguished_property_set_id and property_set_id values. See
# https://docs.microsoft.com/en-us/office/client-developer/outlook/mapi/commonly-used-property-sets
# ID values must be lowercase.
DISTINGUISHED_SET_NAME_TO_ID_MAP = {
'Address': '00062004-0000-0000-c000-000000000046',
'AirSync': '71035549-0739-4dcb-9163-00f0580dbbdf',
'Appointment': '00062002-0000-0000-c000-000000000046',
'Common': '00062008-0000-0000-c000-000000000046',
'InternetHeaders': '00020386-0000-0000-c000-000000000046',
'Log': '0006200a-0000-0000-c000-000000000046',
'Mapi': '00020328-0000-0000-c000-000000000046',
'Meeting': '6ed8da90-450b-101b-98da-00aa003f1305',
'Messaging': '41f28f13-83f4-4114-a584-eedb5a6b0bff',
'Note': '0006200e-0000-0000-c000-000000000046',
'PostRss': '00062041-0000-0000-c000-000000000046',
'PublicStrings': '00020329-0000-0000-c000-000000000046',
'Remote': '00062014-0000-0000-c000-000000000046',
'Report': '00062013-0000-0000-c000-000000000046',
'Sharing': '00062040-0000-0000-c000-000000000046',
'Task': '00062003-0000-0000-c000-000000000046',
'UnifiedMessaging': '4442858e-a9e3-4e80-b900-317a210cc15b',
}
DISTINGUISHED_SET_ID_TO_NAME_MAP = {v: k for k, v in DISTINGUISHED_SET_NAME_TO_ID_MAP.items()}
distinguished_property_set_id = None
property_set_id = None
property_tag = None # hex integer (e.g. 0x8000) or string ('0x8000')
property_name = None
property_id = None # integer as hex-formatted int (e.g. 0x8000) or normal int (32768)
property_type = ''
__slots__ = 'value',
def __init__(self, *args, **kwargs):
if not kwargs:
# Allow to set attributes without keyword
kwargs = dict(zip(self._slots_keys, args))
self.value = kwargs.pop('value')
super().__init__(**kwargs)
@classmethod
def validate_cls(cls):
# Validate values of class attributes and their inter-dependencies
cls._validate_distinguished_property_set_id()
cls._validate_property_set_id()
cls._validate_property_tag()
cls._validate_property_name()
cls._validate_property_id()
cls._validate_property_type()
@classmethod
def _validate_distinguished_property_set_id(cls):
if cls.distinguished_property_set_id:
if any([cls.property_set_id, cls.property_tag]):
raise ValueError(
"When 'distinguished_property_set_id' is set, 'property_set_id' and 'property_tag' must be None"
)
if not any([cls.property_id, cls.property_name]):
raise ValueError(
"When 'distinguished_property_set_id' is set, 'property_id' or 'property_name' must also be set"
)
if cls.distinguished_property_set_id not in cls.DISTINGUISHED_SETS:
raise ValueError(
"'distinguished_property_set_id' %r must be one of %s"
% (cls.distinguished_property_set_id, sorted(cls.DISTINGUISHED_SETS))
)
@classmethod
def _validate_property_set_id(cls):
if cls.property_set_id:
if any([cls.distinguished_property_set_id, cls.property_tag]):
raise ValueError(
"When 'property_set_id' is set, 'distinguished_property_set_id' and 'property_tag' must be None"
)
if not any([cls.property_id, cls.property_name]):
raise ValueError(
"When 'property_set_id' is set, 'property_id' or 'property_name' must also be set"
)
@classmethod
def _validate_property_tag(cls):
if cls.property_tag:
if any([
cls.distinguished_property_set_id, cls.property_set_id, cls.property_name, cls.property_id
]):
raise ValueError("When 'property_tag' is set, only 'property_type' must be set")
if 0x8000 <= cls.property_tag_as_int() <= 0xFFFE:
raise ValueError(
"'property_tag' value '%s' is reserved for custom properties" % cls.property_tag_as_hex()
)
@classmethod
def _validate_property_name(cls):
if cls.property_name:
if any([cls.property_id, cls.property_tag]):
raise ValueError("When 'property_name' is set, 'property_id' and 'property_tag' must be None")
if not any([cls.distinguished_property_set_id, cls.property_set_id]):
raise ValueError(
"When 'property_name' is set, 'distinguished_property_set_id' or 'property_set_id' must also be set"
)
@classmethod
def _validate_property_id(cls):
if cls.property_id:
if any([cls.property_name, cls.property_tag]):
raise ValueError("When 'property_id' is set, 'property_name' and 'property_tag' must be None")
if not any([cls.distinguished_property_set_id, cls.property_set_id]):
raise ValueError(
"When 'property_id' is set, 'distinguished_property_set_id' or 'property_set_id' must also be set"
)
@classmethod
def _validate_property_type(cls):
if cls.property_type not in cls.PROPERTY_TYPES:
raise ValueError(
"'property_type' %r must be one of %s" % (cls.property_type, sorted(cls.PROPERTY_TYPES))
)
def clean(self, version=None):
self.validate_cls()
python_type = self.python_type()
if self.is_array_type():
if not is_iterable(self.value):
raise ValueError("'%s' value %r must be a list" % (self.__class__.__name__, self.value))
for v in self.value:
if not isinstance(v, python_type):
raise TypeError(
"'%s' value element %r must be an instance of %s" % (self.__class__.__name__, v, python_type))
else:
if not isinstance(self.value, python_type):
raise TypeError(
"'%s' value %r must be an instance of %s" % (self.__class__.__name__, self.value, python_type))
@classmethod
def _normalize_obj(cls, obj):
# Sometimes, EWS will helpfully translate a 'distinguished_property_set_id' value to a 'property_set_id' value
# and vice versa. Align these values on an ExtendedFieldURI instance.
try:
obj.property_set_id = cls.DISTINGUISHED_SET_NAME_TO_ID_MAP[obj.distinguished_property_set_id]
except KeyError:
try:
obj.distinguished_property_set_id = cls.DISTINGUISHED_SET_ID_TO_NAME_MAP[obj.property_set_id]
except KeyError:
pass
return obj
@classmethod
def is_property_instance(cls, elem):
"""Return whether an 'ExtendedProperty' element matches the definition for this class. Extended property fields
do not have a name, so we must match on the cls.property_* attributes to match a field in the request with a
field in the response.
"""
# We can't use ExtendedFieldURI.from_xml(). It clears the XML element but we may not want to consume it here.
kwargs = {
f.name: f.from_xml(elem=elem.find(ExtendedFieldURI.response_tag()), account=None)
for f in ExtendedFieldURI.FIELDS
}
xml_obj = ExtendedFieldURI(**kwargs)
cls_obj = cls.as_object()
return cls._normalize_obj(cls_obj) == cls._normalize_obj(xml_obj)
@classmethod
def from_xml(cls, elem, account):
# Gets value of this specific ExtendedProperty from a list of 'ExtendedProperty' XML elements
python_type = cls.python_type()
if cls.is_array_type():
values = elem.find('{%s}Values' % TNS)
return [
xml_text_to_value(value=val, value_type=python_type)
for val in get_xml_attrs(values, '{%s}Value' % TNS)
]
extended_field_value = xml_text_to_value(value=get_xml_attr(elem, '{%s}Value' % TNS), value_type=python_type)
if python_type == str and not extended_field_value:
# For string types, we want to return the empty string instead of None if the element was
# actually found, but there was no XML value. For other types, it would be more problematic
# to make that distinction, e.g. return False for bool, 0 for int, etc.
return ''
return extended_field_value
def to_xml(self, version):
if self.is_array_type():
values = create_element('t:Values')
for v in self.value:
add_xml_child(values, 't:Value', v)
return values
return set_xml_value(create_element('t:Value'), self.value, version=version)
@classmethod
def is_array_type(cls):
return cls.property_type.endswith('Array')
@classmethod
def property_tag_as_int(cls):
if isinstance(cls.property_tag, str):
return int(cls.property_tag, base=16)
return cls.property_tag
@classmethod
def property_tag_as_hex(cls):
return hex(cls.property_tag) if isinstance(cls.property_tag, int) else cls.property_tag
@classmethod
def python_type(cls):
# Return the best equivalent for a Python type for the property type of this class
base_type = cls.property_type[:-5] if cls.is_array_type() else cls.property_type
return {
'ApplicationTime': Decimal,
'Binary': bytes,
'Boolean': bool,
'CLSID': str,
'Currency': int,
'Double': Decimal,
'Float': Decimal,
'Integer': int,
'Long': int,
'Short': int,
'SystemTime': EWSDateTime,
'String': str,
}[base_type]
@classmethod
def as_object(cls):
# Return an object we can use to match with the incoming object from XML
return ExtendedFieldURI(
distinguished_property_set_id=cls.distinguished_property_set_id,
property_set_id=cls.property_set_id.lower() if cls.property_set_id else None,
property_tag=cls.property_tag_as_hex(),
property_name=cls.property_name,
property_id=value_to_xml_text(cls.property_id) if cls.property_id else None,
property_type=cls.property_type,
)
class ExternId(ExtendedProperty):
"""This is a custom extended property defined by us. It's useful for synchronization purposes, to attach a unique ID
from an external system.
"""
property_set_id = 'c11ff724-aa03-4555-9952-8fa248a11c3e' # This is arbitrary. We just want a unique UUID.
property_name = 'External ID'
property_type = 'String'
class Flag(ExtendedProperty):
"""This property returns None for Not Flagged messages, 1 for Completed messages and 2 for Flagged messages.
For a description of each status, see:
https://docs.microsoft.com/en-us/openspecs/exchange_server_protocols/ms-oxoflag/eda9fd25-6407-4cec-9e62-26e4f9d6a098
"""
property_tag = 0x1090
property_type = 'Integer'
Classes
class ExtendedProperty (*args, **kwargs)
-
MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/extendedproperty
Expand source code
class ExtendedProperty(EWSElement): """MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/extendedproperty""" ELEMENT_NAME = 'ExtendedProperty' # Enum values: https://docs.microsoft.com/en-us/dotnet/api/exchangewebservices.distinguishedpropertysettype DISTINGUISHED_SETS = { 'Address', 'Appointment', 'CalendarAssistant', 'Common', 'InternetHeaders', 'Meeting', 'PublicStrings', 'Sharing', 'Task', 'UnifiedMessaging', } # Enum values: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/extendedfielduri PROPERTY_TYPES = { 'ApplicationTime', 'Binary', 'BinaryArray', 'Boolean', 'CLSID', 'CLSIDArray', 'Currency', 'CurrencyArray', 'Double', 'DoubleArray', # 'Error', 'Float', 'FloatArray', 'Integer', 'IntegerArray', 'Long', 'LongArray', # 'Null', # 'Object', # 'ObjectArray', 'Short', 'ShortArray', 'SystemTime', 'SystemTimeArray', 'String', 'StringArray', } # The commented-out types cannot be used for setting or getting (see docs) and are thus not very useful here # Translation table between common distinguished_property_set_id and property_set_id values. See # https://docs.microsoft.com/en-us/office/client-developer/outlook/mapi/commonly-used-property-sets # ID values must be lowercase. DISTINGUISHED_SET_NAME_TO_ID_MAP = { 'Address': '00062004-0000-0000-c000-000000000046', 'AirSync': '71035549-0739-4dcb-9163-00f0580dbbdf', 'Appointment': '00062002-0000-0000-c000-000000000046', 'Common': '00062008-0000-0000-c000-000000000046', 'InternetHeaders': '00020386-0000-0000-c000-000000000046', 'Log': '0006200a-0000-0000-c000-000000000046', 'Mapi': '00020328-0000-0000-c000-000000000046', 'Meeting': '6ed8da90-450b-101b-98da-00aa003f1305', 'Messaging': '41f28f13-83f4-4114-a584-eedb5a6b0bff', 'Note': '0006200e-0000-0000-c000-000000000046', 'PostRss': '00062041-0000-0000-c000-000000000046', 'PublicStrings': '00020329-0000-0000-c000-000000000046', 'Remote': '00062014-0000-0000-c000-000000000046', 'Report': '00062013-0000-0000-c000-000000000046', 'Sharing': '00062040-0000-0000-c000-000000000046', 'Task': '00062003-0000-0000-c000-000000000046', 'UnifiedMessaging': '4442858e-a9e3-4e80-b900-317a210cc15b', } DISTINGUISHED_SET_ID_TO_NAME_MAP = {v: k for k, v in DISTINGUISHED_SET_NAME_TO_ID_MAP.items()} distinguished_property_set_id = None property_set_id = None property_tag = None # hex integer (e.g. 0x8000) or string ('0x8000') property_name = None property_id = None # integer as hex-formatted int (e.g. 0x8000) or normal int (32768) property_type = '' __slots__ = 'value', def __init__(self, *args, **kwargs): if not kwargs: # Allow to set attributes without keyword kwargs = dict(zip(self._slots_keys, args)) self.value = kwargs.pop('value') super().__init__(**kwargs) @classmethod def validate_cls(cls): # Validate values of class attributes and their inter-dependencies cls._validate_distinguished_property_set_id() cls._validate_property_set_id() cls._validate_property_tag() cls._validate_property_name() cls._validate_property_id() cls._validate_property_type() @classmethod def _validate_distinguished_property_set_id(cls): if cls.distinguished_property_set_id: if any([cls.property_set_id, cls.property_tag]): raise ValueError( "When 'distinguished_property_set_id' is set, 'property_set_id' and 'property_tag' must be None" ) if not any([cls.property_id, cls.property_name]): raise ValueError( "When 'distinguished_property_set_id' is set, 'property_id' or 'property_name' must also be set" ) if cls.distinguished_property_set_id not in cls.DISTINGUISHED_SETS: raise ValueError( "'distinguished_property_set_id' %r must be one of %s" % (cls.distinguished_property_set_id, sorted(cls.DISTINGUISHED_SETS)) ) @classmethod def _validate_property_set_id(cls): if cls.property_set_id: if any([cls.distinguished_property_set_id, cls.property_tag]): raise ValueError( "When 'property_set_id' is set, 'distinguished_property_set_id' and 'property_tag' must be None" ) if not any([cls.property_id, cls.property_name]): raise ValueError( "When 'property_set_id' is set, 'property_id' or 'property_name' must also be set" ) @classmethod def _validate_property_tag(cls): if cls.property_tag: if any([ cls.distinguished_property_set_id, cls.property_set_id, cls.property_name, cls.property_id ]): raise ValueError("When 'property_tag' is set, only 'property_type' must be set") if 0x8000 <= cls.property_tag_as_int() <= 0xFFFE: raise ValueError( "'property_tag' value '%s' is reserved for custom properties" % cls.property_tag_as_hex() ) @classmethod def _validate_property_name(cls): if cls.property_name: if any([cls.property_id, cls.property_tag]): raise ValueError("When 'property_name' is set, 'property_id' and 'property_tag' must be None") if not any([cls.distinguished_property_set_id, cls.property_set_id]): raise ValueError( "When 'property_name' is set, 'distinguished_property_set_id' or 'property_set_id' must also be set" ) @classmethod def _validate_property_id(cls): if cls.property_id: if any([cls.property_name, cls.property_tag]): raise ValueError("When 'property_id' is set, 'property_name' and 'property_tag' must be None") if not any([cls.distinguished_property_set_id, cls.property_set_id]): raise ValueError( "When 'property_id' is set, 'distinguished_property_set_id' or 'property_set_id' must also be set" ) @classmethod def _validate_property_type(cls): if cls.property_type not in cls.PROPERTY_TYPES: raise ValueError( "'property_type' %r must be one of %s" % (cls.property_type, sorted(cls.PROPERTY_TYPES)) ) def clean(self, version=None): self.validate_cls() python_type = self.python_type() if self.is_array_type(): if not is_iterable(self.value): raise ValueError("'%s' value %r must be a list" % (self.__class__.__name__, self.value)) for v in self.value: if not isinstance(v, python_type): raise TypeError( "'%s' value element %r must be an instance of %s" % (self.__class__.__name__, v, python_type)) else: if not isinstance(self.value, python_type): raise TypeError( "'%s' value %r must be an instance of %s" % (self.__class__.__name__, self.value, python_type)) @classmethod def _normalize_obj(cls, obj): # Sometimes, EWS will helpfully translate a 'distinguished_property_set_id' value to a 'property_set_id' value # and vice versa. Align these values on an ExtendedFieldURI instance. try: obj.property_set_id = cls.DISTINGUISHED_SET_NAME_TO_ID_MAP[obj.distinguished_property_set_id] except KeyError: try: obj.distinguished_property_set_id = cls.DISTINGUISHED_SET_ID_TO_NAME_MAP[obj.property_set_id] except KeyError: pass return obj @classmethod def is_property_instance(cls, elem): """Return whether an 'ExtendedProperty' element matches the definition for this class. Extended property fields do not have a name, so we must match on the cls.property_* attributes to match a field in the request with a field in the response. """ # We can't use ExtendedFieldURI.from_xml(). It clears the XML element but we may not want to consume it here. kwargs = { f.name: f.from_xml(elem=elem.find(ExtendedFieldURI.response_tag()), account=None) for f in ExtendedFieldURI.FIELDS } xml_obj = ExtendedFieldURI(**kwargs) cls_obj = cls.as_object() return cls._normalize_obj(cls_obj) == cls._normalize_obj(xml_obj) @classmethod def from_xml(cls, elem, account): # Gets value of this specific ExtendedProperty from a list of 'ExtendedProperty' XML elements python_type = cls.python_type() if cls.is_array_type(): values = elem.find('{%s}Values' % TNS) return [ xml_text_to_value(value=val, value_type=python_type) for val in get_xml_attrs(values, '{%s}Value' % TNS) ] extended_field_value = xml_text_to_value(value=get_xml_attr(elem, '{%s}Value' % TNS), value_type=python_type) if python_type == str and not extended_field_value: # For string types, we want to return the empty string instead of None if the element was # actually found, but there was no XML value. For other types, it would be more problematic # to make that distinction, e.g. return False for bool, 0 for int, etc. return '' return extended_field_value def to_xml(self, version): if self.is_array_type(): values = create_element('t:Values') for v in self.value: add_xml_child(values, 't:Value', v) return values return set_xml_value(create_element('t:Value'), self.value, version=version) @classmethod def is_array_type(cls): return cls.property_type.endswith('Array') @classmethod def property_tag_as_int(cls): if isinstance(cls.property_tag, str): return int(cls.property_tag, base=16) return cls.property_tag @classmethod def property_tag_as_hex(cls): return hex(cls.property_tag) if isinstance(cls.property_tag, int) else cls.property_tag @classmethod def python_type(cls): # Return the best equivalent for a Python type for the property type of this class base_type = cls.property_type[:-5] if cls.is_array_type() else cls.property_type return { 'ApplicationTime': Decimal, 'Binary': bytes, 'Boolean': bool, 'CLSID': str, 'Currency': int, 'Double': Decimal, 'Float': Decimal, 'Integer': int, 'Long': int, 'Short': int, 'SystemTime': EWSDateTime, 'String': str, }[base_type] @classmethod def as_object(cls): # Return an object we can use to match with the incoming object from XML return ExtendedFieldURI( distinguished_property_set_id=cls.distinguished_property_set_id, property_set_id=cls.property_set_id.lower() if cls.property_set_id else None, property_tag=cls.property_tag_as_hex(), property_name=cls.property_name, property_id=value_to_xml_text(cls.property_id) if cls.property_id else None, property_type=cls.property_type, )
Ancestors
Subclasses
Class variables
var DISTINGUISHED_SETS
var DISTINGUISHED_SET_ID_TO_NAME_MAP
var DISTINGUISHED_SET_NAME_TO_ID_MAP
var ELEMENT_NAME
var PROPERTY_TYPES
var distinguished_property_set_id
var property_id
var property_name
var property_set_id
var property_tag
var property_type
Static methods
def as_object()
-
Expand source code
@classmethod def as_object(cls): # Return an object we can use to match with the incoming object from XML return ExtendedFieldURI( distinguished_property_set_id=cls.distinguished_property_set_id, property_set_id=cls.property_set_id.lower() if cls.property_set_id else None, property_tag=cls.property_tag_as_hex(), property_name=cls.property_name, property_id=value_to_xml_text(cls.property_id) if cls.property_id else None, property_type=cls.property_type, )
def from_xml(elem, account)
-
Expand source code
@classmethod def from_xml(cls, elem, account): # Gets value of this specific ExtendedProperty from a list of 'ExtendedProperty' XML elements python_type = cls.python_type() if cls.is_array_type(): values = elem.find('{%s}Values' % TNS) return [ xml_text_to_value(value=val, value_type=python_type) for val in get_xml_attrs(values, '{%s}Value' % TNS) ] extended_field_value = xml_text_to_value(value=get_xml_attr(elem, '{%s}Value' % TNS), value_type=python_type) if python_type == str and not extended_field_value: # For string types, we want to return the empty string instead of None if the element was # actually found, but there was no XML value. For other types, it would be more problematic # to make that distinction, e.g. return False for bool, 0 for int, etc. return '' return extended_field_value
def is_array_type()
-
Expand source code
@classmethod def is_array_type(cls): return cls.property_type.endswith('Array')
def is_property_instance(elem)
-
Return whether an 'ExtendedProperty' element matches the definition for this class. Extended property fields do not have a name, so we must match on the cls.property_* attributes to match a field in the request with a field in the response.
Expand source code
@classmethod def is_property_instance(cls, elem): """Return whether an 'ExtendedProperty' element matches the definition for this class. Extended property fields do not have a name, so we must match on the cls.property_* attributes to match a field in the request with a field in the response. """ # We can't use ExtendedFieldURI.from_xml(). It clears the XML element but we may not want to consume it here. kwargs = { f.name: f.from_xml(elem=elem.find(ExtendedFieldURI.response_tag()), account=None) for f in ExtendedFieldURI.FIELDS } xml_obj = ExtendedFieldURI(**kwargs) cls_obj = cls.as_object() return cls._normalize_obj(cls_obj) == cls._normalize_obj(xml_obj)
def property_tag_as_hex()
-
Expand source code
@classmethod def property_tag_as_hex(cls): return hex(cls.property_tag) if isinstance(cls.property_tag, int) else cls.property_tag
def property_tag_as_int()
-
Expand source code
@classmethod def property_tag_as_int(cls): if isinstance(cls.property_tag, str): return int(cls.property_tag, base=16) return cls.property_tag
def python_type()
-
Expand source code
@classmethod def python_type(cls): # Return the best equivalent for a Python type for the property type of this class base_type = cls.property_type[:-5] if cls.is_array_type() else cls.property_type return { 'ApplicationTime': Decimal, 'Binary': bytes, 'Boolean': bool, 'CLSID': str, 'Currency': int, 'Double': Decimal, 'Float': Decimal, 'Integer': int, 'Long': int, 'Short': int, 'SystemTime': EWSDateTime, 'String': str, }[base_type]
def validate_cls()
-
Expand source code
@classmethod def validate_cls(cls): # Validate values of class attributes and their inter-dependencies cls._validate_distinguished_property_set_id() cls._validate_property_set_id() cls._validate_property_tag() cls._validate_property_name() cls._validate_property_id() cls._validate_property_type()
Instance variables
var value
-
Return an attribute of instance, which is of type owner.
Methods
def clean(self, version=None)
-
Expand source code
def clean(self, version=None): self.validate_cls() python_type = self.python_type() if self.is_array_type(): if not is_iterable(self.value): raise ValueError("'%s' value %r must be a list" % (self.__class__.__name__, self.value)) for v in self.value: if not isinstance(v, python_type): raise TypeError( "'%s' value element %r must be an instance of %s" % (self.__class__.__name__, v, python_type)) else: if not isinstance(self.value, python_type): raise TypeError( "'%s' value %r must be an instance of %s" % (self.__class__.__name__, self.value, python_type))
def to_xml(self, version)
-
Expand source code
def to_xml(self, version): if self.is_array_type(): values = create_element('t:Values') for v in self.value: add_xml_child(values, 't:Value', v) return values return set_xml_value(create_element('t:Value'), self.value, version=version)
Inherited members
class ExternId (*args, **kwargs)
-
This is a custom extended property defined by us. It's useful for synchronization purposes, to attach a unique ID from an external system.
Expand source code
class ExternId(ExtendedProperty): """This is a custom extended property defined by us. It's useful for synchronization purposes, to attach a unique ID from an external system. """ property_set_id = 'c11ff724-aa03-4555-9952-8fa248a11c3e' # This is arbitrary. We just want a unique UUID. property_name = 'External ID' property_type = 'String'
Ancestors
Class variables
var property_name
var property_set_id
var property_type
Inherited members
class Flag (*args, **kwargs)
-
This property returns None for Not Flagged messages, 1 for Completed messages and 2 for Flagged messages.
For a description of each status, see: https://docs.microsoft.com/en-us/openspecs/exchange_server_protocols/ms-oxoflag/eda9fd25-6407-4cec-9e62-26e4f9d6a098
Expand source code
class Flag(ExtendedProperty): """This property returns None for Not Flagged messages, 1 for Completed messages and 2 for Flagged messages. For a description of each status, see: https://docs.microsoft.com/en-us/openspecs/exchange_server_protocols/ms-oxoflag/eda9fd25-6407-4cec-9e62-26e4f9d6a098 """ property_tag = 0x1090 property_type = 'Integer'
Ancestors
Class variables
var property_tag
var property_type
Inherited members