diff --git a/CHANGELOG.md b/CHANGELOG.md index b9a65276..d3842602 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,10 +3,15 @@ Change Log HEAD ---- + + +4.7.2 +----- - Fixed field name to match API: `BaseReplyItem.received_by_representing` to -- `BaseReplyItem.received_representing` + `BaseReplyItem.received_representing` - Added fields `received_by` and `received_representing` to `MeetingRequest`, -- `MeetingMessage` and `MeetingCancellation` + `MeetingMessage` and `MeetingCancellation` +- Fixed `AppointmentStateField.CANCELLED` enum value. 4.7.1 diff --git a/docs/exchangelib/account.html b/docs/exchangelib/account.html index eaaa09f9..4d547a5b 100644 --- a/docs/exchangelib/account.html +++ b/docs/exchangelib/account.html @@ -33,23 +33,77 @@
exchangelib.account
exchangelib.account
exchangelib.account
exchangelib.account
exchangelib.account
exchangelib.account
exchangelib.account
exchangelib.account
exchangelib.account
exchangelib.account
exchangelib.account
exchangelib.account
exchangelib.account
exchangelib.account
exchangelib.account
exchangelib.account
exchangelib.account
exchangelib.account
exchangelib.account
class Account:
"""Models an Exchange server user account."""
- def __init__(self, primary_smtp_address, fullname=None, access_type=None, autodiscover=False, credentials=None,
- config=None, locale=None, default_timezone=None):
+ def __init__(
+ self,
+ primary_smtp_address,
+ fullname=None,
+ access_type=None,
+ autodiscover=False,
+ credentials=None,
+ config=None,
+ locale=None,
+ default_timezone=None,
+ ):
"""
:param primary_smtp_address: The primary email address associated with the account on the Exchange server
@@ -713,37 +852,37 @@ Classes
assume values to be in the provided timezone. Defaults to the timezone of the host.
:return:
"""
- if '@' not in primary_smtp_address:
+ if "@" not in primary_smtp_address:
raise ValueError(f"primary_smtp_address {primary_smtp_address!r} is not an email address")
self.fullname = fullname
# Assume delegate access if individual credentials are provided. Else, assume service user with impersonation
self.access_type = access_type or (DELEGATE if credentials else IMPERSONATION)
if self.access_type not in ACCESS_TYPES:
- raise InvalidEnumValue('access_type', self.access_type, ACCESS_TYPES)
+ raise InvalidEnumValue("access_type", self.access_type, ACCESS_TYPES)
try:
# get_locale() might not be able to determine the locale
self.locale = locale or stdlib_locale.getlocale()[0] or None
except ValueError as e:
# getlocale() may throw ValueError if it fails to parse the system locale
- log.warning('Failed to get locale (%s)', e)
+ log.warning("Failed to get locale (%s)", e)
self.locale = None
if not isinstance(self.locale, (type(None), str)):
- raise InvalidTypeError('locale', self.locale, str)
+ raise InvalidTypeError("locale", self.locale, str)
if default_timezone:
try:
self.default_timezone = EWSTimeZone.from_timezone(default_timezone)
except TypeError:
- raise InvalidTypeError('default_timezone', default_timezone, EWSTimeZone)
+ raise InvalidTypeError("default_timezone", default_timezone, EWSTimeZone)
else:
try:
self.default_timezone = EWSTimeZone.localzone()
except (ValueError, UnknownTimeZone) as e:
# There is no translation from local timezone name to Windows timezone name, or e failed to find the
# local timezone.
- log.warning('%s. Fallback to UTC', e.args[0])
+ log.warning("%s. Fallback to UTC", e.args[0])
self.default_timezone = UTC
if not isinstance(config, (Configuration, type(None))):
- raise InvalidTypeError('config', config, Configuration)
+ raise InvalidTypeError("config", config, Configuration)
if autodiscover:
if config:
auth_type, retry_policy, version = config.auth_type, config.retry_policy, config.version
@@ -763,7 +902,7 @@ Classes
primary_smtp_address = self.ad_response.autodiscover_smtp_address
else:
if not config:
- raise AttributeError('non-autodiscover requires a config')
+ raise AttributeError("non-autodiscover requires a config")
self.ad_response = None
self.protocol = Protocol(config=config)
@@ -777,7 +916,7 @@ Classes
# server version up-front but delegate account requests to an older backend server. Create a new instance to
# avoid changing the protocol version.
self.version = self.protocol.version.copy()
- log.debug('Added account: %s', self)
+ log.debug("Added account: %s", self)
@property
def primary_smtp_address(self):
@@ -985,7 +1124,7 @@ Classes
# We accept generators, so it's not always convenient for caller to know up-front if 'ids' is empty. Allow
# empty 'ids' and return early.
return
- kwargs['items'] = items
+ kwargs["items"] = items
yield from service_cls(account=self, chunk_size=chunk_size).call(**kwargs)
def export(self, items, chunk_size=None):
@@ -996,9 +1135,7 @@ Classes
:return: A list of strings, the exported representation of the object
"""
- return list(
- self._consume_item_service(service_cls=ExportItems, items=items, chunk_size=chunk_size, kwargs={})
- )
+ return list(self._consume_item_service(service_cls=ExportItems, items=items, chunk_size=chunk_size, kwargs={}))
def upload(self, data, chunk_size=None):
"""Upload objects retrieved from an export to the given folders.
@@ -1020,12 +1157,11 @@ Classes
-> [("idA", "changekey"), ("idB", "changekey"), ("idC", "changekey")]
"""
items = ((f, (None, False, d) if isinstance(d, str) else d) for f, d in data)
- return list(
- self._consume_item_service(service_cls=UploadItems, items=items, chunk_size=chunk_size, kwargs={})
- )
+ return list(self._consume_item_service(service_cls=UploadItems, items=items, chunk_size=chunk_size, kwargs={}))
- def bulk_create(self, folder, items, message_disposition=SAVE_ONLY, send_meeting_invitations=SEND_TO_NONE,
- chunk_size=None):
+ def bulk_create(
+ self, folder, items, message_disposition=SAVE_ONLY, send_meeting_invitations=SEND_TO_NONE, chunk_size=None
+ ):
"""Create new items in 'folder'.
:param folder: the folder to create the items in
@@ -1042,23 +1178,36 @@ Classes
"""
if isinstance(items, QuerySet):
# bulk_create() on a queryset does not make sense because it returns items that have already been created
- raise ValueError('Cannot bulk create items from a QuerySet')
+ raise ValueError("Cannot bulk create items from a QuerySet")
log.debug(
- 'Adding items for %s (folder %s, message_disposition: %s, send_meeting_invitations: %s)',
+ "Adding items for %s (folder %s, message_disposition: %s, send_meeting_invitations: %s)",
self,
folder,
message_disposition,
send_meeting_invitations,
)
- return list(self._consume_item_service(service_cls=CreateItem, items=items, chunk_size=chunk_size, kwargs=dict(
- folder=folder,
- message_disposition=message_disposition,
- send_meeting_invitations=send_meeting_invitations,
- )))
-
- def bulk_update(self, items, conflict_resolution=AUTO_RESOLVE, message_disposition=SAVE_ONLY,
- send_meeting_invitations_or_cancellations=SEND_TO_NONE, suppress_read_receipts=True,
- chunk_size=None):
+ return list(
+ self._consume_item_service(
+ service_cls=CreateItem,
+ items=items,
+ chunk_size=chunk_size,
+ kwargs=dict(
+ folder=folder,
+ message_disposition=message_disposition,
+ send_meeting_invitations=send_meeting_invitations,
+ ),
+ )
+ )
+
+ def bulk_update(
+ self,
+ items,
+ conflict_resolution=AUTO_RESOLVE,
+ message_disposition=SAVE_ONLY,
+ send_meeting_invitations_or_cancellations=SEND_TO_NONE,
+ suppress_read_receipts=True,
+ chunk_size=None,
+ ):
"""Bulk update existing items.
:param items: a list of (Item, fieldnames) tuples, where 'Item' is an Item object, and 'fieldnames' is a list
@@ -1078,23 +1227,37 @@ Classes
# fact, it could be dangerous if the queryset contains an '.only()'. This would wipe out certain fields
# entirely.
if isinstance(items, QuerySet):
- raise ValueError('Cannot bulk update on a queryset')
+ raise ValueError("Cannot bulk update on a queryset")
log.debug(
- 'Updating items for %s (conflict_resolution %s, message_disposition: %s, send_meeting_invitations: %s)',
+ "Updating items for %s (conflict_resolution %s, message_disposition: %s, send_meeting_invitations: %s)",
self,
conflict_resolution,
message_disposition,
send_meeting_invitations_or_cancellations,
)
- return list(self._consume_item_service(service_cls=UpdateItem, items=items, chunk_size=chunk_size, kwargs=dict(
- conflict_resolution=conflict_resolution,
- message_disposition=message_disposition,
- send_meeting_invitations_or_cancellations=send_meeting_invitations_or_cancellations,
- suppress_read_receipts=suppress_read_receipts,
- )))
-
- def bulk_delete(self, ids, delete_type=HARD_DELETE, send_meeting_cancellations=SEND_TO_NONE,
- affected_task_occurrences=ALL_OCCURRENCES, suppress_read_receipts=True, chunk_size=None):
+ return list(
+ self._consume_item_service(
+ service_cls=UpdateItem,
+ items=items,
+ chunk_size=chunk_size,
+ kwargs=dict(
+ conflict_resolution=conflict_resolution,
+ message_disposition=message_disposition,
+ send_meeting_invitations_or_cancellations=send_meeting_invitations_or_cancellations,
+ suppress_read_receipts=suppress_read_receipts,
+ ),
+ )
+ )
+
+ def bulk_delete(
+ self,
+ ids,
+ delete_type=HARD_DELETE,
+ send_meeting_cancellations=SEND_TO_NONE,
+ affected_task_occurrences=ALL_OCCURRENCES,
+ suppress_read_receipts=True,
+ chunk_size=None,
+ ):
"""Bulk delete items.
:param ids: an iterable of either (id, changekey) tuples or Item objects.
@@ -1110,19 +1273,24 @@ Classes
:return: a list of either True or exception instances, in the same order as the input
"""
log.debug(
- 'Deleting items for %s (delete_type: %s, send_meeting_invitations: %s, affected_task_occurrences: %s)',
+ "Deleting items for %s (delete_type: %s, send_meeting_invitations: %s, affected_task_occurrences: %s)",
self,
delete_type,
send_meeting_cancellations,
affected_task_occurrences,
)
return list(
- self._consume_item_service(service_cls=DeleteItem, items=ids, chunk_size=chunk_size, kwargs=dict(
- delete_type=delete_type,
- send_meeting_cancellations=send_meeting_cancellations,
- affected_task_occurrences=affected_task_occurrences,
- suppress_read_receipts=suppress_read_receipts,
- ))
+ self._consume_item_service(
+ service_cls=DeleteItem,
+ items=ids,
+ chunk_size=chunk_size,
+ kwargs=dict(
+ delete_type=delete_type,
+ send_meeting_cancellations=send_meeting_cancellations,
+ affected_task_occurrences=affected_task_occurrences,
+ suppress_read_receipts=suppress_read_receipts,
+ ),
+ )
)
def bulk_send(self, ids, save_copy=True, copy_to_folder=None, chunk_size=None):
@@ -1140,9 +1308,14 @@ Classes
if save_copy and not copy_to_folder:
copy_to_folder = self.sent # 'Sent' is default EWS behaviour
return list(
- self._consume_item_service(service_cls=SendItem, items=ids, chunk_size=chunk_size, kwargs=dict(
- saved_item_folder=copy_to_folder,
- ))
+ self._consume_item_service(
+ service_cls=SendItem,
+ items=ids,
+ chunk_size=chunk_size,
+ kwargs=dict(
+ saved_item_folder=copy_to_folder,
+ ),
+ )
)
def bulk_copy(self, ids, to_folder, chunk_size=None):
@@ -1154,9 +1327,16 @@ Classes
:return: Status for each send operation, in the same order as the input
"""
- return list(self._consume_item_service(service_cls=CopyItem, items=ids, chunk_size=chunk_size, kwargs=dict(
- to_folder=to_folder,
- )))
+ return list(
+ self._consume_item_service(
+ service_cls=CopyItem,
+ items=ids,
+ chunk_size=chunk_size,
+ kwargs=dict(
+ to_folder=to_folder,
+ ),
+ )
+ )
def bulk_move(self, ids, to_folder, chunk_size=None):
"""Move items to another folder.
@@ -1168,9 +1348,16 @@ Classes
:return: The new IDs of the moved items, in the same order as the input. If 'to_folder' is a public folder or a
folder in a different mailbox, an empty list is returned.
"""
- return list(self._consume_item_service(service_cls=MoveItem, items=ids, chunk_size=chunk_size, kwargs=dict(
- to_folder=to_folder,
- )))
+ return list(
+ self._consume_item_service(
+ service_cls=MoveItem,
+ items=ids,
+ chunk_size=chunk_size,
+ kwargs=dict(
+ to_folder=to_folder,
+ ),
+ )
+ )
def bulk_archive(self, ids, to_folder, chunk_size=None):
"""Archive items to a folder in the archive mailbox. An archive mailbox must be enabled in order for this
@@ -1182,9 +1369,15 @@ Classes
:return: A list containing True or an exception instance in stable order of the requested items
"""
- return list(self._consume_item_service(service_cls=ArchiveItem, items=ids, chunk_size=chunk_size, kwargs=dict(
- to_folder=to_folder,
- ))
+ return list(
+ self._consume_item_service(
+ service_cls=ArchiveItem,
+ items=ids,
+ chunk_size=chunk_size,
+ kwargs=dict(
+ to_folder=to_folder,
+ ),
+ )
)
def bulk_mark_as_junk(self, ids, is_junk, move_item, chunk_size=None):
@@ -1198,10 +1391,17 @@ Classes
:return: A list containing the new IDs of the moved items, if items were moved, or True, or an exception
instance, in stable order of the requested items.
"""
- return list(self._consume_item_service(service_cls=MarkAsJunk, items=ids, chunk_size=chunk_size, kwargs=dict(
- is_junk=is_junk,
- move_item=move_item,
- )))
+ return list(
+ self._consume_item_service(
+ service_cls=MarkAsJunk,
+ items=ids,
+ chunk_size=chunk_size,
+ kwargs=dict(
+ is_junk=is_junk,
+ move_item=move_item,
+ ),
+ )
+ )
def fetch(self, ids, folder=None, only_fields=None, chunk_size=None):
"""Fetch items by ID.
@@ -1226,13 +1426,19 @@ Classes
for field in only_fields:
validation_folder.validate_item_field(field=field, version=self.version)
# Remove ItemId and ChangeKey. We get them unconditionally
- additional_fields = {f for f in validation_folder.normalize_fields(fields=only_fields)
- if not f.field.is_attribute}
+ additional_fields = {
+ f for f in validation_folder.normalize_fields(fields=only_fields) if not f.field.is_attribute
+ }
# Always use IdOnly here, because AllProperties doesn't actually get *all* properties
- yield from self._consume_item_service(service_cls=GetItem, items=ids, chunk_size=chunk_size, kwargs=dict(
+ yield from self._consume_item_service(
+ service_cls=GetItem,
+ items=ids,
+ chunk_size=chunk_size,
+ kwargs=dict(
additional_fields=additional_fields,
shape=ID_ONLY,
- ))
+ ),
+ )
def fetch_personas(self, ids):
"""Fetch personas by ID.
@@ -1256,7 +1462,7 @@ Classes
return GetMailTips(protocol=self.protocol).get(
sending_as=SendingAs(email_address=self.primary_smtp_address),
recipients=[Mailbox(email_address=self.primary_smtp_address)],
- mail_tips_requested='All',
+ mail_tips_requested="All",
)
@property
@@ -1266,7 +1472,7 @@ Classes
def __str__(self):
if self.fullname:
- return f'{self.primary_smtp_address} ({self.fullname})'
+ return f"{self.primary_smtp_address} ({self.fullname})"
return self.primary_smtp_address
@@ -2388,8 +2607,9 @@ Methods
Expand source code
-def bulk_create(self, folder, items, message_disposition=SAVE_ONLY, send_meeting_invitations=SEND_TO_NONE,
- chunk_size=None):
+def bulk_create(
+ self, folder, items, message_disposition=SAVE_ONLY, send_meeting_invitations=SEND_TO_NONE, chunk_size=None
+):
"""Create new items in 'folder'.
:param folder: the folder to create the items in
@@ -2406,19 +2626,26 @@ Methods
"""
if isinstance(items, QuerySet):
# bulk_create() on a queryset does not make sense because it returns items that have already been created
- raise ValueError('Cannot bulk create items from a QuerySet')
+ raise ValueError("Cannot bulk create items from a QuerySet")
log.debug(
- 'Adding items for %s (folder %s, message_disposition: %s, send_meeting_invitations: %s)',
+ "Adding items for %s (folder %s, message_disposition: %s, send_meeting_invitations: %s)",
self,
folder,
message_disposition,
send_meeting_invitations,
)
- return list(self._consume_item_service(service_cls=CreateItem, items=items, chunk_size=chunk_size, kwargs=dict(
- folder=folder,
- message_disposition=message_disposition,
- send_meeting_invitations=send_meeting_invitations,
- )))
+ return list(
+ self._consume_item_service(
+ service_cls=CreateItem,
+ items=items,
+ chunk_size=chunk_size,
+ kwargs=dict(
+ folder=folder,
+ message_disposition=message_disposition,
+ send_meeting_invitations=send_meeting_invitations,
+ ),
+ )
+ )
@@ -2440,8 +2667,15 @@ Methods
Expand source code
-def bulk_delete(self, ids, delete_type=HARD_DELETE, send_meeting_cancellations=SEND_TO_NONE,
- affected_task_occurrences=ALL_OCCURRENCES, suppress_read_receipts=True, chunk_size=None):
+def bulk_delete(
+ self,
+ ids,
+ delete_type=HARD_DELETE,
+ send_meeting_cancellations=SEND_TO_NONE,
+ affected_task_occurrences=ALL_OCCURRENCES,
+ suppress_read_receipts=True,
+ chunk_size=None,
+):
"""Bulk delete items.
:param ids: an iterable of either (id, changekey) tuples or Item objects.
@@ -2457,19 +2691,24 @@ Methods
:return: a list of either True or exception instances, in the same order as the input
"""
log.debug(
- 'Deleting items for %s (delete_type: %s, send_meeting_invitations: %s, affected_task_occurrences: %s)',
+ "Deleting items for %s (delete_type: %s, send_meeting_invitations: %s, affected_task_occurrences: %s)",
self,
delete_type,
send_meeting_cancellations,
affected_task_occurrences,
)
return list(
- self._consume_item_service(service_cls=DeleteItem, items=ids, chunk_size=chunk_size, kwargs=dict(
- delete_type=delete_type,
- send_meeting_cancellations=send_meeting_cancellations,
- affected_task_occurrences=affected_task_occurrences,
- suppress_read_receipts=suppress_read_receipts,
- ))
+ self._consume_item_service(
+ service_cls=DeleteItem,
+ items=ids,
+ chunk_size=chunk_size,
+ kwargs=dict(
+ delete_type=delete_type,
+ send_meeting_cancellations=send_meeting_cancellations,
+ affected_task_occurrences=affected_task_occurrences,
+ suppress_read_receipts=suppress_read_receipts,
+ ),
+ )
)
@@ -2499,10 +2738,17 @@ Methods
:return: A list containing the new IDs of the moved items, if items were moved, or True, or an exception
instance, in stable order of the requested items.
"""
- return list(self._consume_item_service(service_cls=MarkAsJunk, items=ids, chunk_size=chunk_size, kwargs=dict(
- is_junk=is_junk,
- move_item=move_item,
- )))
+ return list(
+ self._consume_item_service(
+ service_cls=MarkAsJunk,
+ items=ids,
+ chunk_size=chunk_size,
+ kwargs=dict(
+ is_junk=is_junk,
+ move_item=move_item,
+ ),
+ )
+ )
@@ -2529,9 +2775,16 @@ Methods
:return: The new IDs of the moved items, in the same order as the input. If 'to_folder' is a public folder or a
folder in a different mailbox, an empty list is returned.
"""
- return list(self._consume_item_service(service_cls=MoveItem, items=ids, chunk_size=chunk_size, kwargs=dict(
- to_folder=to_folder,
- )))
+ return list(
+ self._consume_item_service(
+ service_cls=MoveItem,
+ items=ids,
+ chunk_size=chunk_size,
+ kwargs=dict(
+ to_folder=to_folder,
+ ),
+ )
+ )
@@ -2563,9 +2816,14 @@ Methods
if save_copy and not copy_to_folder:
copy_to_folder = self.sent # 'Sent' is default EWS behaviour
return list(
- self._consume_item_service(service_cls=SendItem, items=ids, chunk_size=chunk_size, kwargs=dict(
- saved_item_folder=copy_to_folder,
- ))
+ self._consume_item_service(
+ service_cls=SendItem,
+ items=ids,
+ chunk_size=chunk_size,
+ kwargs=dict(
+ saved_item_folder=copy_to_folder,
+ ),
+ )
)
@@ -2589,9 +2847,15 @@ def bulk_update(self, items, conflict_resolution=AUTO_RESOLVE, message_disposition=SAVE_ONLY,
- send_meeting_invitations_or_cancellations=SEND_TO_NONE, suppress_read_receipts=True,
- chunk_size=None):
+def bulk_update(
+ self,
+ items,
+ conflict_resolution=AUTO_RESOLVE,
+ message_disposition=SAVE_ONLY,
+ send_meeting_invitations_or_cancellations=SEND_TO_NONE,
+ suppress_read_receipts=True,
+ chunk_size=None,
+):
"""Bulk update existing items.
:param items: a list of (Item, fieldnames) tuples, where 'Item' is an Item object, and 'fieldnames' is a list
@@ -2611,20 +2875,27 @@ Methods
# fact, it could be dangerous if the queryset contains an '.only()'. This would wipe out certain fields
# entirely.
if isinstance(items, QuerySet):
- raise ValueError('Cannot bulk update on a queryset')
+ raise ValueError("Cannot bulk update on a queryset")
log.debug(
- 'Updating items for %s (conflict_resolution %s, message_disposition: %s, send_meeting_invitations: %s)',
+ "Updating items for %s (conflict_resolution %s, message_disposition: %s, send_meeting_invitations: %s)",
self,
conflict_resolution,
message_disposition,
send_meeting_invitations_or_cancellations,
)
- return list(self._consume_item_service(service_cls=UpdateItem, items=items, chunk_size=chunk_size, kwargs=dict(
- conflict_resolution=conflict_resolution,
- message_disposition=message_disposition,
- send_meeting_invitations_or_cancellations=send_meeting_invitations_or_cancellations,
- suppress_read_receipts=suppress_read_receipts,
- )))
+ return list(
+ self._consume_item_service(
+ service_cls=UpdateItem,
+ items=items,
+ chunk_size=chunk_size,
+ kwargs=dict(
+ conflict_resolution=conflict_resolution,
+ message_disposition=message_disposition,
+ send_meeting_invitations_or_cancellations=send_meeting_invitations_or_cancellations,
+ suppress_read_receipts=suppress_read_receipts,
+ ),
+ )
+ )
@@ -2647,9 +2918,7 @@ Methods
:return: A list of strings, the exported representation of the object
"""
- return list(
- self._consume_item_service(service_cls=ExportItems, items=items, chunk_size=chunk_size, kwargs={})
- )
+ return list(self._consume_item_service(service_cls=ExportItems, items=items, chunk_size=chunk_size, kwargs={}))
@@ -2689,13 +2958,19 @@ Methods
for field in only_fields:
validation_folder.validate_item_field(field=field, version=self.version)
# Remove ItemId and ChangeKey. We get them unconditionally
- additional_fields = {f for f in validation_folder.normalize_fields(fields=only_fields)
- if not f.field.is_attribute}
+ additional_fields = {
+ f for f in validation_folder.normalize_fields(fields=only_fields) if not f.field.is_attribute
+ }
# Always use IdOnly here, because AllProperties doesn't actually get *all* properties
- yield from self._consume_item_service(service_cls=GetItem, items=ids, chunk_size=chunk_size, kwargs=dict(
+ yield from self._consume_item_service(
+ service_cls=GetItem,
+ items=ids,
+ chunk_size=chunk_size,
+ kwargs=dict(
additional_fields=additional_fields,
shape=ID_ONLY,
- ))
+ ),
+ )
@@ -2768,9 +3043,7 @@ Methods
-> [("idA", "changekey"), ("idB", "changekey"), ("idC", "changekey")]
"""
items = ((f, (None, False, d) if isinstance(d, str) else d) for f, d in data)
- return list(
- self._consume_item_service(service_cls=UploadItems, items=items, chunk_size=chunk_size, kwargs={})
- )
+ return list(self._consume_item_service(service_cls=UploadItems, items=items, chunk_size=chunk_size, kwargs={}))
diff --git a/docs/exchangelib/attachments.html b/docs/exchangelib/attachments.html
index ee303c78..4f0fe14d 100644
--- a/docs/exchangelib/attachments.html
+++ b/docs/exchangelib/attachments.html
@@ -31,8 +31,18 @@ exchangelib.attachments
exchangelib.attachments
exchangelib.attachments
exchangelib.attachments
exchangelib.attachments
exchangelib.attachments
exchangelib.attachments
exchangelib.attachments
exchangelib.attachments
exchangelib.attachments
exchangelib.attachments
def attach(self):
from .services import CreateAttachment
+
# Adds this attachment to an item and updates the changekey of the parent item
if self.attachment_id:
- raise ValueError('This attachment has already been created')
+ raise ValueError("This attachment has already been created")
if not self.parent_item or not self.parent_item.account:
- raise ValueError(f'Parent item {self.parent_item} must have an account')
+ raise ValueError(f"Parent item {self.parent_item} must have an account")
item = CreateAttachment(account=self.parent_item.account).get(parent_item=self.parent_item, items=[self])
attachment_id = item.attachment_id
self.parent_item.changekey = attachment_id.root_changekey
@@ -462,10 +485,11 @@ Methods
def clean(self, version=None):
from .items import Item
+
if self.parent_item is not None and not isinstance(self.parent_item, Item):
- raise InvalidTypeError('parent_item', self.parent_item, Item)
+ raise InvalidTypeError("parent_item", self.parent_item, Item)
if self.content_type is None and self.name is not None:
- self.content_type = mimetypes.guess_type(self.name)[0] or 'application/octet-stream'
+ self.content_type = mimetypes.guess_type(self.name)[0] or "application/octet-stream"
super().clean(version=version)
@@ -480,11 +504,12 @@ Methods
def detach(self):
from .services import DeleteAttachment
+
# Deletes an attachment remotely and updates the changekey of the parent item
if not self.attachment_id:
- raise ValueError('This attachment has not been created')
+ raise ValueError("This attachment has not been created")
if not self.parent_item or not self.parent_item.account:
- raise ValueError(f'Parent item {self.parent_item} must have an account')
+ raise ValueError(f"Parent item {self.parent_item} must have an account")
DeleteAttachment(account=self.parent_item.account).get(items=[self.attachment_id])
self.parent_item = None
self.attachment_id = None
@@ -520,11 +545,11 @@ Inherited members
MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/attachmentid
"""
- ELEMENT_NAME = 'AttachmentId'
+ ELEMENT_NAME = "AttachmentId"
- ID_ATTR = 'Id'
- ROOT_ID_ATTR = 'RootItemId'
- ROOT_CHANGEKEY_ATTR = 'RootItemChangeKey'
+ ID_ATTR = "Id"
+ ROOT_ID_ATTR = "RootItemId"
+ ROOT_CHANGEKEY_ATTR = "RootItemChangeKey"
id = IdField(field_uri=ID_ATTR, is_required=True)
root_id = IdField(field_uri=ROOT_ID_ATTR)
@@ -603,15 +628,15 @@ Inherited members
class FileAttachment(Attachment):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/fileattachment"""
- ELEMENT_NAME = 'FileAttachment'
+ ELEMENT_NAME = "FileAttachment"
- is_contact_photo = BooleanField(field_uri='IsContactPhoto')
- _content = Base64Field(field_uri='Content')
+ is_contact_photo = BooleanField(field_uri="IsContactPhoto")
+ _content = Base64Field(field_uri="Content")
- __slots__ = '_fp',
+ __slots__ = ("_fp",)
def __init__(self, **kwargs):
- kwargs['_content'] = kwargs.pop('content', None)
+ kwargs["_content"] = kwargs.pop("content", None)
super().__init__(**kwargs)
self._fp = None
@@ -626,7 +651,7 @@ Inherited members
# Create a file-like object for the attachment content. We try hard to reduce memory consumption so we never
# store the full attachment content in-memory.
if not self.parent_item or not self.parent_item.account:
- raise ValueError(f'{self.__class__.__name__} must have an account')
+ raise ValueError(f"{self.__class__.__name__} must have an account")
self._fp = FileAttachmentIO(attachment=self)
@property
@@ -647,13 +672,13 @@ Inherited members
def content(self, value):
"""Replace the attachment content."""
if not isinstance(value, bytes):
- raise InvalidTypeError('value', value, bytes)
+ raise InvalidTypeError("value", value, bytes)
self._content = value
@classmethod
def from_xml(cls, elem, account):
kwargs = {f.name: f.from_xml(elem=elem, account=account) for f in cls.FIELDS}
- kwargs['content'] = kwargs.pop('_content')
+ kwargs["content"] = kwargs.pop("_content")
cls._clear(elem)
return cls(**kwargs)
@@ -664,7 +689,7 @@ Inherited members
def __getstate__(self):
# The fp does not need to be pickled
state = {k: getattr(self, k) for k in self._slots_keys}
- del state['_fp']
+ del state["_fp"]
return state
def __setstate__(self, state):
@@ -703,7 +728,7 @@ Static methods
@classmethod
def from_xml(cls, elem, account):
kwargs = {f.name: f.from_xml(elem=elem, account=account) for f in cls.FIELDS}
- kwargs['content'] = kwargs.pop('_content')
+ kwargs["content"] = kwargs.pop("_content")
cls._clear(elem)
return cls(**kwargs)
@@ -817,11 +842,12 @@ Inherited members
return 0
else:
output, self._overflow = chunk[:buf_size], chunk[buf_size:]
- b[:len(output)] = output
+ b[: len(output)] = output
return len(output)
def __enter__(self):
from .services import GetAttachment
+
self._stream = GetAttachment(account=self._attachment.parent_item.account).stream_file_content(
attachment_id=self._attachment.attachment_id
)
@@ -887,7 +913,7 @@ Methods
return 0
else:
output, self._overflow = chunk[:buf_size], chunk[buf_size:]
- b[:len(output)] = output
+ b[: len(output)] = output
return len(output)
@@ -906,30 +932,34 @@ Methods
class ItemAttachment(Attachment):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/itemattachment"""
- ELEMENT_NAME = 'ItemAttachment'
+ ELEMENT_NAME = "ItemAttachment"
- _item = ItemField(field_uri='Item')
+ _item = ItemField(field_uri="Item")
def __init__(self, **kwargs):
- kwargs['_item'] = kwargs.pop('item', None)
+ kwargs["_item"] = kwargs.pop("item", None)
super().__init__(**kwargs)
@property
def item(self):
from .folders import BaseFolder
from .services import GetAttachment
+
if self.attachment_id is None:
return self._item
if self._item is not None:
return self._item
# We have an ID to the data but still haven't called GetAttachment to get the actual data. Do that now.
if not self.parent_item or not self.parent_item.account:
- raise ValueError(f'{self.__class__.__name__} must have an account')
+ raise ValueError(f"{self.__class__.__name__} must have an account")
additional_fields = {
FieldPath(field=f) for f in BaseFolder.allowed_item_fields(version=self.parent_item.account.version)
}
attachment = GetAttachment(account=self.parent_item.account).get(
- items=[self.attachment_id], include_mime_content=True, body_type=None, filter_html_content=None,
+ items=[self.attachment_id],
+ include_mime_content=True,
+ body_type=None,
+ filter_html_content=None,
additional_fields=additional_fields,
)
self._item = attachment.item
@@ -938,14 +968,15 @@ Methods
@item.setter
def item(self, value):
from .items import Item
+
if not isinstance(value, Item):
- raise InvalidTypeError('value', value, Item)
+ raise InvalidTypeError("value", value, Item)
self._item = value
@classmethod
def from_xml(cls, elem, account):
kwargs = {f.name: f.from_xml(elem=elem, account=account) for f in cls.FIELDS}
- kwargs['item'] = kwargs.pop('_item')
+ kwargs["item"] = kwargs.pop("_item")
cls._clear(elem)
return cls(**kwargs)
@@ -979,7 +1010,7 @@ Static methods
@classmethod
def from_xml(cls, elem, account):
kwargs = {f.name: f.from_xml(elem=elem, account=account) for f in cls.FIELDS}
- kwargs['item'] = kwargs.pop('_item')
+ kwargs["item"] = kwargs.pop("_item")
cls._clear(elem)
return cls(**kwargs)
@@ -998,18 +1029,22 @@ Instance variables
def item(self):
from .folders import BaseFolder
from .services import GetAttachment
+
if self.attachment_id is None:
return self._item
if self._item is not None:
return self._item
# We have an ID to the data but still haven't called GetAttachment to get the actual data. Do that now.
if not self.parent_item or not self.parent_item.account:
- raise ValueError(f'{self.__class__.__name__} must have an account')
+ raise ValueError(f"{self.__class__.__name__} must have an account")
additional_fields = {
FieldPath(field=f) for f in BaseFolder.allowed_item_fields(version=self.parent_item.account.version)
}
attachment = GetAttachment(account=self.parent_item.account).get(
- items=[self.attachment_id], include_mime_content=True, body_type=None, filter_html_content=None,
+ items=[self.attachment_id],
+ include_mime_content=True,
+ body_type=None,
+ filter_html_content=None,
additional_fields=additional_fields,
)
self._item = attachment.item
diff --git a/docs/exchangelib/autodiscover/cache.html b/docs/exchangelib/autodiscover/cache.html
index ce548cae..e7ddaec1 100644
--- a/docs/exchangelib/autodiscover/cache.html
+++ b/docs/exchangelib/autodiscover/cache.html
@@ -36,8 +36,8 @@ Module exchangelib.autodiscover.cache
from contextlib import contextmanager
from threading import RLock
-from .protocol import AutodiscoverProtocol
from ..configuration import Configuration
+from .protocol import AutodiscoverProtocol
log = logging.getLogger(__name__)
@@ -53,8 +53,8 @@ Module exchangelib.autodiscover.cache
user = getpass.getuser()
except KeyError:
# getuser() fails on some systems. Provide a sane default. See issue #448
- user = 'exchangelib'
- return f'exchangelib.{version}.cache.{user}.py{major}{minor}'
+ user = "exchangelib"
+ return f"exchangelib.{version}.cache.{user}.py{major}{minor}"
AUTODISCOVER_PERSISTENT_STORAGE = os.path.join(tempfile.gettempdir(), shelve_filename())
@@ -70,13 +70,13 @@ Module exchangelib.autodiscover.cache
# Try to actually use the shelve. Some implementations may allow opening the file but then throw
# errors on access.
try:
- _ = shelve_handle['']
+ _ = shelve_handle[""]
except KeyError:
# The entry doesn't exist. This is expected.
pass
except Exception as e:
- for f in glob.glob(filename + '*'):
- log.warning('Deleting invalid cache file %s (%r)', f, e)
+ for f in glob.glob(filename + "*"):
+ log.warning("Deleting invalid cache file %s (%r)", f, e)
os.unlink(f)
shelve_handle = shelve.open(filename)
yield shelve_handle
@@ -128,9 +128,11 @@ Module exchangelib.autodiscover.cache
domain, credentials = key
with shelve_open_with_failover(self._storage_file) as db:
endpoint, auth_type, retry_policy = db[str(domain)] # It's OK to fail with KeyError here
- protocol = AutodiscoverProtocol(config=Configuration(
- service_endpoint=endpoint, credentials=credentials, auth_type=auth_type, retry_policy=retry_policy
- ))
+ protocol = AutodiscoverProtocol(
+ config=Configuration(
+ service_endpoint=endpoint, credentials=credentials, auth_type=auth_type, retry_policy=retry_policy
+ )
+ )
self._protocols[key] = protocol
return protocol
@@ -159,7 +161,7 @@ Module exchangelib.autodiscover.cache
def close(self):
# Close all open connections
for (domain, _), protocol in self._protocols.items():
- log.debug('Domain %s: Closing sessions', domain)
+ log.debug("Domain %s: Closing sessions", domain)
protocol.close()
del protocol
self._protocols.clear()
@@ -212,8 +214,8 @@ Functions
user = getpass.getuser()
except KeyError:
# getuser() fails on some systems. Provide a sane default. See issue #448
- user = 'exchangelib'
- return f'exchangelib.{version}.cache.{user}.py{major}{minor}'
+ user = "exchangelib"
+ return f"exchangelib.{version}.cache.{user}.py{major}{minor}"
@@ -235,13 +237,13 @@ Functions
# Try to actually use the shelve. Some implementations may allow opening the file but then throw
# errors on access.
try:
- _ = shelve_handle['']
+ _ = shelve_handle[""]
except KeyError:
# The entry doesn't exist. This is expected.
pass
except Exception as e:
- for f in glob.glob(filename + '*'):
- log.warning('Deleting invalid cache file %s (%r)', f, e)
+ for f in glob.glob(filename + "*"):
+ log.warning("Deleting invalid cache file %s (%r)", f, e)
os.unlink(f)
shelve_handle = shelve.open(filename)
yield shelve_handle
@@ -317,9 +319,11 @@ def close(self):
# Close all open connections
for (domain, _), protocol in self._protocols.items():
- log.debug('Domain %s: Closing sessions', domain)
+ log.debug("Domain %s: Closing sessions", domain)
protocol.close()
del protocol
self._protocols.clear()
diff --git a/docs/exchangelib/autodiscover/discovery.html b/docs/exchangelib/autodiscover/discovery.html
index ed62ba7f..91649b6d 100644
--- a/docs/exchangelib/autodiscover/discovery.html
+++ b/docs/exchangelib/autodiscover/discovery.html
@@ -30,27 +30,33 @@ exchangelib.autodiscover.discovery
exchangelib.autodiscover.discovery
exchangelib.autodiscover.discovery
exchangelib.autodiscover.discovery
exchangelib.autodiscover.discovery
exchangelib.autodiscover.discovery
exchangelib.autodiscover.discovery
exchangelib.autodiscover.discovery
exchangelib.autodiscover.discovery
exchangelib.autodiscover.discovery
exchangelib.autodiscover.discovery
exchangelib.autodiscover.discovery
exchangelib.autodiscover.discovery
exchangelib.autodiscover.discovery
exchangelib.autodiscover.discovery
exchangelib.autodiscover.discovery
exchangelib.autodiscover.discovery
exchangelib.autodiscover.discovery
exchangelib.autodiscover.discovery
exchangelib.autodiscover.discovery
exchangelib.autodiscover.discovery
def discover(email, credentials=None, auth_type=None, retry_policy=None):
- ad_response, protocol = Autodiscovery(
- email=email, credentials=credentials
- ).discover()
+ ad_response, protocol = Autodiscovery(email=email, credentials=credentials).discover()
protocol.config.auth_typ = auth_type
protocol.config.retry_policy = retry_policy
return ad_response, protocol
@@ -671,7 +683,7 @@ exchangelib.autodiscover
def discover(email, credentials=None, auth_type=None, retry_policy=None):
- ad_response, protocol = Autodiscovery(
- email=email, credentials=credentials
- ).discover()
+ ad_response, protocol = Autodiscovery(email=email, credentials=credentials).discover()
protocol.config.auth_typ = auth_type
protocol.config.retry_policy = retry_policy
return ad_response, protocol
@@ -189,9 +192,11 @@ def close(self):
# Close all open connections
for (domain, _), protocol in self._protocols.items():
- log.debug('Domain %s: Closing sessions', domain)
+ log.debug("Domain %s: Closing sessions", domain)
protocol.close()
del protocol
self._protocols.clear()
@@ -296,9 +301,9 @@ exchangelib.autodiscover.properties
from ..errors import ErrorNonExistentMailbox, AutoDiscoverFailed
-from ..fields import TextField, EmailAddressField, ChoiceField, Choice, EWSElementField, OnOffField, BooleanField, \
- IntegerField, BuildField, ProtocolListField
+from ..errors import AutoDiscoverFailed, ErrorNonExistentMailbox
+from ..fields import (
+ BooleanField,
+ BuildField,
+ Choice,
+ ChoiceField,
+ EmailAddressField,
+ EWSElementField,
+ IntegerField,
+ OnOffField,
+ ProtocolListField,
+ TextField,
+)
from ..properties import EWSElement
-from ..transport import DEFAULT_ENCODING, NOAUTH, NTLM, BASIC, GSSAPI, SSPI, CBA
-from ..util import create_element, add_xml_child, to_xml, is_xml, xml_to_str, AUTODISCOVER_REQUEST_NS, \
- AUTODISCOVER_BASE_NS, AUTODISCOVER_RESPONSE_NS as RNS, ParseError
+from ..transport import BASIC, CBA, DEFAULT_ENCODING, GSSAPI, NOAUTH, NTLM, SSPI
+from ..util import AUTODISCOVER_BASE_NS, AUTODISCOVER_REQUEST_NS
+from ..util import AUTODISCOVER_RESPONSE_NS as RNS
+from ..util import ParseError, add_xml_child, create_element, is_xml, to_xml, xml_to_str
from ..version import Version
@@ -43,40 +54,40 @@ Module exchangelib.autodiscover.properties
class User(AutodiscoverBase):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/user-pox"""
- ELEMENT_NAME = 'User'
+ ELEMENT_NAME = "User"
- display_name = TextField(field_uri='DisplayName', namespace=RNS)
- legacy_dn = TextField(field_uri='LegacyDN', namespace=RNS)
- deployment_id = TextField(field_uri='DeploymentId', namespace=RNS) # GUID format
- autodiscover_smtp_address = EmailAddressField(field_uri='AutoDiscoverSMTPAddress', namespace=RNS)
+ display_name = TextField(field_uri="DisplayName", namespace=RNS)
+ legacy_dn = TextField(field_uri="LegacyDN", namespace=RNS)
+ deployment_id = TextField(field_uri="DeploymentId", namespace=RNS) # GUID format
+ autodiscover_smtp_address = EmailAddressField(field_uri="AutoDiscoverSMTPAddress", namespace=RNS)
class IntExtUrlBase(AutodiscoverBase):
- external_url = TextField(field_uri='ExternalUrl', namespace=RNS)
- internal_url = TextField(field_uri='InternalUrl', namespace=RNS)
+ external_url = TextField(field_uri="ExternalUrl", namespace=RNS)
+ internal_url = TextField(field_uri="InternalUrl", namespace=RNS)
class AddressBook(IntExtUrlBase):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/addressbook-pox"""
- ELEMENT_NAME = 'AddressBook'
+ ELEMENT_NAME = "AddressBook"
class MailStore(IntExtUrlBase):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/mailstore-pox"""
- ELEMENT_NAME = 'MailStore'
+ ELEMENT_NAME = "MailStore"
class NetworkRequirements(AutodiscoverBase):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/networkrequirements-pox"""
- ELEMENT_NAME = 'NetworkRequirements'
+ ELEMENT_NAME = "NetworkRequirements"
- ipv4_start = TextField(field_uri='IPv4Start', namespace=RNS)
- ipv4_end = TextField(field_uri='IPv4End', namespace=RNS)
- ipv6_start = TextField(field_uri='IPv6Start', namespace=RNS)
- ipv6_end = TextField(field_uri='IPv6End', namespace=RNS)
+ ipv4_start = TextField(field_uri="IPv4Start", namespace=RNS)
+ ipv4_end = TextField(field_uri="IPv4End", namespace=RNS)
+ ipv6_start = TextField(field_uri="IPv6Start", namespace=RNS)
+ ipv6_end = TextField(field_uri="IPv6End", namespace=RNS)
class SimpleProtocol(AutodiscoverBase):
@@ -85,84 +96,86 @@ Module exchangelib.autodiscover.properties
Used for the 'Internal' and 'External' elements that may contain a stripped-down version of the Protocol element.
"""
- ELEMENT_NAME = 'Protocol'
- WEB = 'WEB'
- EXCH = 'EXCH'
- EXPR = 'EXPR'
- EXHTTP = 'EXHTTP'
+ ELEMENT_NAME = "Protocol"
+ WEB = "WEB"
+ EXCH = "EXCH"
+ EXPR = "EXPR"
+ EXHTTP = "EXHTTP"
TYPES = (WEB, EXCH, EXPR, EXHTTP)
- type = ChoiceField(field_uri='Type', choices={Choice(c) for c in TYPES}, namespace=RNS)
- as_url = TextField(field_uri='ASUrl', namespace=RNS)
+ type = ChoiceField(field_uri="Type", choices={Choice(c) for c in TYPES}, namespace=RNS)
+ as_url = TextField(field_uri="ASUrl", namespace=RNS)
class IntExtBase(AutodiscoverBase):
# TODO: 'OWAUrl' also has an AuthenticationMethod enum-style XML attribute with values:
# WindowsIntegrated, FBA, NTLM, Digest, Basic
- owa_url = TextField(field_uri='OWAUrl', namespace=RNS)
+ owa_url = TextField(field_uri="OWAUrl", namespace=RNS)
protocol = EWSElementField(value_cls=SimpleProtocol)
class Internal(IntExtBase):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/internal-pox"""
- ELEMENT_NAME = 'Internal'
+ ELEMENT_NAME = "Internal"
class External(IntExtBase):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/external-pox"""
- ELEMENT_NAME = 'External'
+ ELEMENT_NAME = "External"
class Protocol(SimpleProtocol):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/protocol-pox"""
# Attribute 'Type' is ignored here. Has a name conflict with the child element and does not seem useful.
- version = TextField(field_uri='Version', is_attribute=True, namespace=RNS)
+ version = TextField(field_uri="Version", is_attribute=True, namespace=RNS)
internal = EWSElementField(value_cls=Internal)
external = EWSElementField(value_cls=External)
- ttl = IntegerField(field_uri='TTL', namespace=RNS, default=1) # TTL for this autodiscover response, in hours
- server = TextField(field_uri='Server', namespace=RNS)
- server_dn = TextField(field_uri='ServerDN', namespace=RNS)
- server_version = BuildField(field_uri='ServerVersion', namespace=RNS)
- mdb_dn = TextField(field_uri='MdbDN', namespace=RNS)
- public_folder_server = TextField(field_uri='PublicFolderServer', namespace=RNS)
- port = IntegerField(field_uri='Port', namespace=RNS, min=1, max=65535)
- directory_port = IntegerField(field_uri='DirectoryPort', namespace=RNS, min=1, max=65535)
- referral_port = IntegerField(field_uri='ReferralPort', namespace=RNS, min=1, max=65535)
- ews_url = TextField(field_uri='EwsUrl', namespace=RNS)
- emws_url = TextField(field_uri='EmwsUrl', namespace=RNS)
- sharing_url = TextField(field_uri='SharingUrl', namespace=RNS)
- ecp_url = TextField(field_uri='EcpUrl', namespace=RNS)
- ecp_url_um = TextField(field_uri='EcpUrl-um', namespace=RNS)
- ecp_url_aggr = TextField(field_uri='EcpUrl-aggr', namespace=RNS)
- ecp_url_mt = TextField(field_uri='EcpUrl-mt', namespace=RNS)
- ecp_url_ret = TextField(field_uri='EcpUrl-ret', namespace=RNS)
- ecp_url_sms = TextField(field_uri='EcpUrl-sms', namespace=RNS)
- ecp_url_publish = TextField(field_uri='EcpUrl-publish', namespace=RNS)
- ecp_url_photo = TextField(field_uri='EcpUrl-photo', namespace=RNS)
- ecp_url_tm = TextField(field_uri='EcpUrl-tm', namespace=RNS)
- ecp_url_tm_creating = TextField(field_uri='EcpUrl-tmCreating', namespace=RNS)
- ecp_url_tm_hiding = TextField(field_uri='EcpUrl-tmHiding', namespace=RNS)
- ecp_url_tm_editing = TextField(field_uri='EcpUrl-tmEditing', namespace=RNS)
- ecp_url_extinstall = TextField(field_uri='EcpUrl-extinstall', namespace=RNS)
- oof_url = TextField(field_uri='OOFUrl', namespace=RNS)
- oab_url = TextField(field_uri='OABUrl', namespace=RNS)
- um_url = TextField(field_uri='UMUrl', namespace=RNS)
- ews_partner_url = TextField(field_uri='EwsPartnerUrl', namespace=RNS)
- login_name = TextField(field_uri='LoginName', namespace=RNS)
- domain_required = OnOffField(field_uri='DomainRequired', namespace=RNS)
- domain_name = TextField(field_uri='DomainName', namespace=RNS)
- spa = OnOffField(field_uri='SPA', namespace=RNS, default=True)
- auth_package = ChoiceField(field_uri='AuthPackage', namespace=RNS, choices={
- Choice(c) for c in ('basic', 'kerb', 'kerbntlm', 'ntlm', 'certificate', 'negotiate', 'nego2')
- })
- cert_principal_name = TextField(field_uri='CertPrincipalName', namespace=RNS)
- ssl = OnOffField(field_uri='SSL', namespace=RNS, default=True)
- auth_required = OnOffField(field_uri='AuthRequired', namespace=RNS, default=True)
- use_pop_path = OnOffField(field_uri='UsePOPAuth', namespace=RNS)
- smtp_last = OnOffField(field_uri='SMTPLast', namespace=RNS, default=False)
+ ttl = IntegerField(field_uri="TTL", namespace=RNS, default=1) # TTL for this autodiscover response, in hours
+ server = TextField(field_uri="Server", namespace=RNS)
+ server_dn = TextField(field_uri="ServerDN", namespace=RNS)
+ server_version = BuildField(field_uri="ServerVersion", namespace=RNS)
+ mdb_dn = TextField(field_uri="MdbDN", namespace=RNS)
+ public_folder_server = TextField(field_uri="PublicFolderServer", namespace=RNS)
+ port = IntegerField(field_uri="Port", namespace=RNS, min=1, max=65535)
+ directory_port = IntegerField(field_uri="DirectoryPort", namespace=RNS, min=1, max=65535)
+ referral_port = IntegerField(field_uri="ReferralPort", namespace=RNS, min=1, max=65535)
+ ews_url = TextField(field_uri="EwsUrl", namespace=RNS)
+ emws_url = TextField(field_uri="EmwsUrl", namespace=RNS)
+ sharing_url = TextField(field_uri="SharingUrl", namespace=RNS)
+ ecp_url = TextField(field_uri="EcpUrl", namespace=RNS)
+ ecp_url_um = TextField(field_uri="EcpUrl-um", namespace=RNS)
+ ecp_url_aggr = TextField(field_uri="EcpUrl-aggr", namespace=RNS)
+ ecp_url_mt = TextField(field_uri="EcpUrl-mt", namespace=RNS)
+ ecp_url_ret = TextField(field_uri="EcpUrl-ret", namespace=RNS)
+ ecp_url_sms = TextField(field_uri="EcpUrl-sms", namespace=RNS)
+ ecp_url_publish = TextField(field_uri="EcpUrl-publish", namespace=RNS)
+ ecp_url_photo = TextField(field_uri="EcpUrl-photo", namespace=RNS)
+ ecp_url_tm = TextField(field_uri="EcpUrl-tm", namespace=RNS)
+ ecp_url_tm_creating = TextField(field_uri="EcpUrl-tmCreating", namespace=RNS)
+ ecp_url_tm_hiding = TextField(field_uri="EcpUrl-tmHiding", namespace=RNS)
+ ecp_url_tm_editing = TextField(field_uri="EcpUrl-tmEditing", namespace=RNS)
+ ecp_url_extinstall = TextField(field_uri="EcpUrl-extinstall", namespace=RNS)
+ oof_url = TextField(field_uri="OOFUrl", namespace=RNS)
+ oab_url = TextField(field_uri="OABUrl", namespace=RNS)
+ um_url = TextField(field_uri="UMUrl", namespace=RNS)
+ ews_partner_url = TextField(field_uri="EwsPartnerUrl", namespace=RNS)
+ login_name = TextField(field_uri="LoginName", namespace=RNS)
+ domain_required = OnOffField(field_uri="DomainRequired", namespace=RNS)
+ domain_name = TextField(field_uri="DomainName", namespace=RNS)
+ spa = OnOffField(field_uri="SPA", namespace=RNS, default=True)
+ auth_package = ChoiceField(
+ field_uri="AuthPackage",
+ namespace=RNS,
+ choices={Choice(c) for c in ("basic", "kerb", "kerbntlm", "ntlm", "certificate", "negotiate", "nego2")},
+ )
+ cert_principal_name = TextField(field_uri="CertPrincipalName", namespace=RNS)
+ ssl = OnOffField(field_uri="SSL", namespace=RNS, default=True)
+ auth_required = OnOffField(field_uri="AuthRequired", namespace=RNS, default=True)
+ use_pop_path = OnOffField(field_uri="UsePOPAuth", namespace=RNS)
+ smtp_last = OnOffField(field_uri="SMTPLast", namespace=RNS, default=False)
network_requirements = EWSElementField(value_cls=NetworkRequirements)
address_book = EWSElementField(value_cls=AddressBook)
mail_store = EWSElementField(value_cls=MailStore)
@@ -176,56 +189,56 @@ Module exchangelib.autodiscover.properties
return None
return {
# Missing in list are DIGEST and OAUTH2
- 'basic': BASIC,
- 'kerb': GSSAPI,
- 'kerbntlm': NTLM, # Means client can chose between NTLM and GSSAPI
- 'ntlm': NTLM,
- 'certificate': CBA,
- 'negotiate': SSPI, # Unsure about this one
- 'nego2': GSSAPI,
- 'anonymous': NOAUTH, # Seen in some docs even though it's not mentioned in MSDN
+ "basic": BASIC,
+ "kerb": GSSAPI,
+ "kerbntlm": NTLM, # Means client can chose between NTLM and GSSAPI
+ "ntlm": NTLM,
+ "certificate": CBA,
+ "negotiate": SSPI, # Unsure about this one
+ "nego2": GSSAPI,
+ "anonymous": NOAUTH, # Seen in some docs even though it's not mentioned in MSDN
}.get(self.auth_package.lower())
class Error(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/error-pox"""
- ELEMENT_NAME = 'Error'
+ ELEMENT_NAME = "Error"
NAMESPACE = AUTODISCOVER_BASE_NS
- id = TextField(field_uri='Id', namespace=AUTODISCOVER_BASE_NS, is_attribute=True)
- time = TextField(field_uri='Time', namespace=AUTODISCOVER_BASE_NS, is_attribute=True)
- code = TextField(field_uri='ErrorCode', namespace=AUTODISCOVER_BASE_NS)
- message = TextField(field_uri='Message', namespace=AUTODISCOVER_BASE_NS)
- debug_data = TextField(field_uri='DebugData', namespace=AUTODISCOVER_BASE_NS)
+ id = TextField(field_uri="Id", namespace=AUTODISCOVER_BASE_NS, is_attribute=True)
+ time = TextField(field_uri="Time", namespace=AUTODISCOVER_BASE_NS, is_attribute=True)
+ code = TextField(field_uri="ErrorCode", namespace=AUTODISCOVER_BASE_NS)
+ message = TextField(field_uri="Message", namespace=AUTODISCOVER_BASE_NS)
+ debug_data = TextField(field_uri="DebugData", namespace=AUTODISCOVER_BASE_NS)
class Account(AutodiscoverBase):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/account-pox"""
- ELEMENT_NAME = 'Account'
- REDIRECT_URL = 'redirectUrl'
- REDIRECT_ADDR = 'redirectAddr'
- SETTINGS = 'settings'
+ ELEMENT_NAME = "Account"
+ REDIRECT_URL = "redirectUrl"
+ REDIRECT_ADDR = "redirectAddr"
+ SETTINGS = "settings"
ACTIONS = (REDIRECT_URL, REDIRECT_ADDR, SETTINGS)
- type = ChoiceField(field_uri='AccountType', namespace=RNS, choices={Choice('email')})
- action = ChoiceField(field_uri='Action', namespace=RNS, choices={Choice(p) for p in ACTIONS})
- microsoft_online = BooleanField(field_uri='MicrosoftOnline', namespace=RNS)
- redirect_url = TextField(field_uri='RedirectURL', namespace=RNS)
- redirect_address = EmailAddressField(field_uri='RedirectAddr', namespace=RNS)
- image = TextField(field_uri='Image', namespace=RNS) # Path to image used for branding
- service_home = TextField(field_uri='ServiceHome', namespace=RNS) # URL to website of ISP
+ type = ChoiceField(field_uri="AccountType", namespace=RNS, choices={Choice("email")})
+ action = ChoiceField(field_uri="Action", namespace=RNS, choices={Choice(p) for p in ACTIONS})
+ microsoft_online = BooleanField(field_uri="MicrosoftOnline", namespace=RNS)
+ redirect_url = TextField(field_uri="RedirectURL", namespace=RNS)
+ redirect_address = EmailAddressField(field_uri="RedirectAddr", namespace=RNS)
+ image = TextField(field_uri="Image", namespace=RNS) # Path to image used for branding
+ service_home = TextField(field_uri="ServiceHome", namespace=RNS) # URL to website of ISP
protocols = ProtocolListField()
# 'SmtpAddress' is inside the 'PublicFolderInformation' element
- public_folder_smtp_address = TextField(field_uri='SmtpAddress', namespace=RNS)
+ public_folder_smtp_address = TextField(field_uri="SmtpAddress", namespace=RNS)
@classmethod
def from_xml(cls, elem, account):
kwargs = {}
- public_folder_information = elem.find(f'{{{cls.NAMESPACE}}}PublicFolderInformation')
+ public_folder_information = elem.find(f"{{{cls.NAMESPACE}}}PublicFolderInformation")
for f in cls.FIELDS:
- if f.name == 'public_folder_smtp_address':
+ if f.name == "public_folder_smtp_address":
if public_folder_information is None:
continue
kwargs[f.name] = f.from_xml(elem=public_folder_information, account=account)
@@ -238,7 +251,7 @@ Module exchangelib.autodiscover.properties
class Response(AutodiscoverBase):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/response-pox"""
- ELEMENT_NAME = 'Response'
+ ELEMENT_NAME = "Response"
user = EWSElementField(value_cls=User)
account = EWSElementField(value_cls=Account)
@@ -300,7 +313,7 @@ Module exchangelib.autodiscover.properties
if Protocol.EXCH in protocols:
return protocols[Protocol.EXCH]
raise ValueError(
- f'No EWS URL found in any of the available protocols: {[str(p) for p in self.account.protocols]}'
+ f"No EWS URL found in any of the available protocols: {[str(p) for p in self.account.protocols]}"
)
@@ -310,14 +323,14 @@ Module exchangelib.autodiscover.properties
Like 'Response', but with a different namespace.
"""
- ELEMENT_NAME = 'Response'
+ ELEMENT_NAME = "Response"
NAMESPACE = AUTODISCOVER_BASE_NS
error = EWSElementField(value_cls=Error)
class Autodiscover(EWSElement):
- ELEMENT_NAME = 'Autodiscover'
+ ELEMENT_NAME = "Autodiscover"
NAMESPACE = AUTODISCOVER_BASE_NS
response = EWSElementField(value_cls=Response)
@@ -337,10 +350,10 @@ Module exchangelib.autodiscover.properties
:return:
"""
if not is_xml(bytes_content):
- raise ParseError(f'Response is not XML: {bytes_content}', '<not from file>', -1, 0)
+ raise ParseError(f"Response is not XML: {bytes_content}", "<not from file>", -1, 0)
root = to_xml(bytes_content).getroot() # May raise ParseError
if root.tag != cls.response_tag():
- raise ParseError(f'Unknown root element in XML: {bytes_content}', '<not from file>', -1, 0)
+ raise ParseError(f"Unknown root element in XML: {bytes_content}", "<not from file>", -1, 0)
return cls.from_xml(elem=root, account=None)
def raise_errors(self):
@@ -348,19 +361,19 @@ Module exchangelib.autodiscover.properties
try:
errorcode = self.error_response.error.code
message = self.error_response.error.message
- if message in ('The e-mail address cannot be found.', "The email address can't be found."):
- raise ErrorNonExistentMailbox('The SMTP address has no mailbox associated with it')
- raise AutoDiscoverFailed(f'Unknown error {errorcode}: {message}')
+ if message in ("The e-mail address cannot be found.", "The email address can't be found."):
+ raise ErrorNonExistentMailbox("The SMTP address has no mailbox associated with it")
+ raise AutoDiscoverFailed(f"Unknown error {errorcode}: {message}")
except AttributeError:
- raise AutoDiscoverFailed(f'Unknown autodiscover error response: {self.error_response}')
+ raise AutoDiscoverFailed(f"Unknown autodiscover error response: {self.error_response}")
@staticmethod
def payload(email):
# Builds a full Autodiscover XML request
- payload = create_element('Autodiscover', attrs=dict(xmlns=AUTODISCOVER_REQUEST_NS))
- request = create_element('Request')
- add_xml_child(request, 'EMailAddress', email)
- add_xml_child(request, 'AcceptableResponseSchema', RNS)
+ payload = create_element("Autodiscover", attrs=dict(xmlns=AUTODISCOVER_REQUEST_NS))
+ request = create_element("Request")
+ add_xml_child(request, "EMailAddress", email)
+ add_xml_child(request, "AcceptableResponseSchema", RNS)
payload.append(request)
return xml_to_str(payload, encoding=DEFAULT_ENCODING, xml_declaration=True)
@@ -387,29 +400,29 @@ Classes
class Account(AutodiscoverBase):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/account-pox"""
- ELEMENT_NAME = 'Account'
- REDIRECT_URL = 'redirectUrl'
- REDIRECT_ADDR = 'redirectAddr'
- SETTINGS = 'settings'
+ ELEMENT_NAME = "Account"
+ REDIRECT_URL = "redirectUrl"
+ REDIRECT_ADDR = "redirectAddr"
+ SETTINGS = "settings"
ACTIONS = (REDIRECT_URL, REDIRECT_ADDR, SETTINGS)
- type = ChoiceField(field_uri='AccountType', namespace=RNS, choices={Choice('email')})
- action = ChoiceField(field_uri='Action', namespace=RNS, choices={Choice(p) for p in ACTIONS})
- microsoft_online = BooleanField(field_uri='MicrosoftOnline', namespace=RNS)
- redirect_url = TextField(field_uri='RedirectURL', namespace=RNS)
- redirect_address = EmailAddressField(field_uri='RedirectAddr', namespace=RNS)
- image = TextField(field_uri='Image', namespace=RNS) # Path to image used for branding
- service_home = TextField(field_uri='ServiceHome', namespace=RNS) # URL to website of ISP
+ type = ChoiceField(field_uri="AccountType", namespace=RNS, choices={Choice("email")})
+ action = ChoiceField(field_uri="Action", namespace=RNS, choices={Choice(p) for p in ACTIONS})
+ microsoft_online = BooleanField(field_uri="MicrosoftOnline", namespace=RNS)
+ redirect_url = TextField(field_uri="RedirectURL", namespace=RNS)
+ redirect_address = EmailAddressField(field_uri="RedirectAddr", namespace=RNS)
+ image = TextField(field_uri="Image", namespace=RNS) # Path to image used for branding
+ service_home = TextField(field_uri="ServiceHome", namespace=RNS) # URL to website of ISP
protocols = ProtocolListField()
# 'SmtpAddress' is inside the 'PublicFolderInformation' element
- public_folder_smtp_address = TextField(field_uri='SmtpAddress', namespace=RNS)
+ public_folder_smtp_address = TextField(field_uri="SmtpAddress", namespace=RNS)
@classmethod
def from_xml(cls, elem, account):
kwargs = {}
- public_folder_information = elem.find(f'{{{cls.NAMESPACE}}}PublicFolderInformation')
+ public_folder_information = elem.find(f"{{{cls.NAMESPACE}}}PublicFolderInformation")
for f in cls.FIELDS:
- if f.name == 'public_folder_smtp_address':
+ if f.name == "public_folder_smtp_address":
if public_folder_information is None:
continue
kwargs[f.name] = f.from_xml(elem=public_folder_information, account=account)
@@ -464,9 +477,9 @@ Static methods
@classmethod
def from_xml(cls, elem, account):
kwargs = {}
- public_folder_information = elem.find(f'{{{cls.NAMESPACE}}}PublicFolderInformation')
+ public_folder_information = elem.find(f"{{{cls.NAMESPACE}}}PublicFolderInformation")
for f in cls.FIELDS:
- if f.name == 'public_folder_smtp_address':
+ if f.name == "public_folder_smtp_address":
if public_folder_information is None:
continue
kwargs[f.name] = f.from_xml(elem=public_folder_information, account=account)
@@ -541,7 +554,7 @@ Inherited members
class AddressBook(IntExtUrlBase):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/addressbook-pox"""
- ELEMENT_NAME = 'AddressBook'
+ ELEMENT_NAME = "AddressBook"
Ancestors
@@ -579,7 +592,7 @@ Inherited members
Expand source code
class Autodiscover(EWSElement):
- ELEMENT_NAME = 'Autodiscover'
+ ELEMENT_NAME = "Autodiscover"
NAMESPACE = AUTODISCOVER_BASE_NS
response = EWSElementField(value_cls=Response)
@@ -599,10 +612,10 @@ Inherited members
:return:
"""
if not is_xml(bytes_content):
- raise ParseError(f'Response is not XML: {bytes_content}', '<not from file>', -1, 0)
+ raise ParseError(f"Response is not XML: {bytes_content}", "<not from file>", -1, 0)
root = to_xml(bytes_content).getroot() # May raise ParseError
if root.tag != cls.response_tag():
- raise ParseError(f'Unknown root element in XML: {bytes_content}', '<not from file>', -1, 0)
+ raise ParseError(f"Unknown root element in XML: {bytes_content}", "<not from file>", -1, 0)
return cls.from_xml(elem=root, account=None)
def raise_errors(self):
@@ -610,19 +623,19 @@ Inherited members
try:
errorcode = self.error_response.error.code
message = self.error_response.error.message
- if message in ('The e-mail address cannot be found.', "The email address can't be found."):
- raise ErrorNonExistentMailbox('The SMTP address has no mailbox associated with it')
- raise AutoDiscoverFailed(f'Unknown error {errorcode}: {message}')
+ if message in ("The e-mail address cannot be found.", "The email address can't be found."):
+ raise ErrorNonExistentMailbox("The SMTP address has no mailbox associated with it")
+ raise AutoDiscoverFailed(f"Unknown error {errorcode}: {message}")
except AttributeError:
- raise AutoDiscoverFailed(f'Unknown autodiscover error response: {self.error_response}')
+ raise AutoDiscoverFailed(f"Unknown autodiscover error response: {self.error_response}")
@staticmethod
def payload(email):
# Builds a full Autodiscover XML request
- payload = create_element('Autodiscover', attrs=dict(xmlns=AUTODISCOVER_REQUEST_NS))
- request = create_element('Request')
- add_xml_child(request, 'EMailAddress', email)
- add_xml_child(request, 'AcceptableResponseSchema', RNS)
+ payload = create_element("Autodiscover", attrs=dict(xmlns=AUTODISCOVER_REQUEST_NS))
+ request = create_element("Request")
+ add_xml_child(request, "EMailAddress", email)
+ add_xml_child(request, "AcceptableResponseSchema", RNS)
payload.append(request)
return xml_to_str(payload, encoding=DEFAULT_ENCODING, xml_declaration=True)
@@ -668,10 +681,10 @@ Static methods
:return:
"""
if not is_xml(bytes_content):
- raise ParseError(f'Response is not XML: {bytes_content}', '<not from file>', -1, 0)
+ raise ParseError(f"Response is not XML: {bytes_content}", "<not from file>", -1, 0)
root = to_xml(bytes_content).getroot() # May raise ParseError
if root.tag != cls.response_tag():
- raise ParseError(f'Unknown root element in XML: {bytes_content}', '<not from file>', -1, 0)
+ raise ParseError(f"Unknown root element in XML: {bytes_content}", "<not from file>", -1, 0)
return cls.from_xml(elem=root, account=None)
@@ -687,10 +700,10 @@ Static methods
@staticmethod
def payload(email):
# Builds a full Autodiscover XML request
- payload = create_element('Autodiscover', attrs=dict(xmlns=AUTODISCOVER_REQUEST_NS))
- request = create_element('Request')
- add_xml_child(request, 'EMailAddress', email)
- add_xml_child(request, 'AcceptableResponseSchema', RNS)
+ payload = create_element("Autodiscover", attrs=dict(xmlns=AUTODISCOVER_REQUEST_NS))
+ request = create_element("Request")
+ add_xml_child(request, "EMailAddress", email)
+ add_xml_child(request, "AcceptableResponseSchema", RNS)
payload.append(request)
return xml_to_str(payload, encoding=DEFAULT_ENCODING, xml_declaration=True)
@@ -723,11 +736,11 @@ Methods
try:
errorcode = self.error_response.error.code
message = self.error_response.error.message
- if message in ('The e-mail address cannot be found.', "The email address can't be found."):
- raise ErrorNonExistentMailbox('The SMTP address has no mailbox associated with it')
- raise AutoDiscoverFailed(f'Unknown error {errorcode}: {message}')
+ if message in ("The e-mail address cannot be found.", "The email address can't be found."):
+ raise ErrorNonExistentMailbox("The SMTP address has no mailbox associated with it")
+ raise AutoDiscoverFailed(f"Unknown error {errorcode}: {message}")
except AttributeError:
- raise AutoDiscoverFailed(f'Unknown autodiscover error response: {self.error_response}')
+ raise AutoDiscoverFailed(f"Unknown autodiscover error response: {self.error_response}")
class Error(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/error-pox"""
- ELEMENT_NAME = 'Error'
+ ELEMENT_NAME = "Error"
NAMESPACE = AUTODISCOVER_BASE_NS
- id = TextField(field_uri='Id', namespace=AUTODISCOVER_BASE_NS, is_attribute=True)
- time = TextField(field_uri='Time', namespace=AUTODISCOVER_BASE_NS, is_attribute=True)
- code = TextField(field_uri='ErrorCode', namespace=AUTODISCOVER_BASE_NS)
- message = TextField(field_uri='Message', namespace=AUTODISCOVER_BASE_NS)
- debug_data = TextField(field_uri='DebugData', namespace=AUTODISCOVER_BASE_NS)
+ id = TextField(field_uri="Id", namespace=AUTODISCOVER_BASE_NS, is_attribute=True)
+ time = TextField(field_uri="Time", namespace=AUTODISCOVER_BASE_NS, is_attribute=True)
+ code = TextField(field_uri="ErrorCode", namespace=AUTODISCOVER_BASE_NS)
+ message = TextField(field_uri="Message", namespace=AUTODISCOVER_BASE_NS)
+ debug_data = TextField(field_uri="DebugData", namespace=AUTODISCOVER_BASE_NS)
class External(IntExtBase):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/external-pox"""
- ELEMENT_NAME = 'External'
+ ELEMENT_NAME = "External"
class IntExtBase(AutodiscoverBase):
# TODO: 'OWAUrl' also has an AuthenticationMethod enum-style XML attribute with values:
# WindowsIntegrated, FBA, NTLM, Digest, Basic
- owa_url = TextField(field_uri='OWAUrl', namespace=RNS)
+ owa_url = TextField(field_uri="OWAUrl", namespace=RNS)
protocol = EWSElementField(value_cls=SimpleProtocol)
class IntExtUrlBase(AutodiscoverBase):
- external_url = TextField(field_uri='ExternalUrl', namespace=RNS)
- internal_url = TextField(field_uri='InternalUrl', namespace=RNS)
+ external_url = TextField(field_uri="ExternalUrl", namespace=RNS)
+ internal_url = TextField(field_uri="InternalUrl", namespace=RNS)
class Internal(IntExtBase):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/internal-pox"""
- ELEMENT_NAME = 'Internal'
+ ELEMENT_NAME = "Internal"
class MailStore(IntExtUrlBase):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/mailstore-pox"""
- ELEMENT_NAME = 'MailStore'
+ ELEMENT_NAME = "MailStore"
class NetworkRequirements(AutodiscoverBase):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/networkrequirements-pox"""
- ELEMENT_NAME = 'NetworkRequirements'
+ ELEMENT_NAME = "NetworkRequirements"
- ipv4_start = TextField(field_uri='IPv4Start', namespace=RNS)
- ipv4_end = TextField(field_uri='IPv4End', namespace=RNS)
- ipv6_start = TextField(field_uri='IPv6Start', namespace=RNS)
- ipv6_end = TextField(field_uri='IPv6End', namespace=RNS)
+ ipv4_start = TextField(field_uri="IPv4Start", namespace=RNS)
+ ipv4_end = TextField(field_uri="IPv4End", namespace=RNS)
+ ipv6_start = TextField(field_uri="IPv6Start", namespace=RNS)
+ ipv6_end = TextField(field_uri="IPv6End", namespace=RNS)
class Response(AutodiscoverBase):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/response-pox"""
- ELEMENT_NAME = 'Response'
+ ELEMENT_NAME = "Response"
user = EWSElementField(value_cls=User)
account = EWSElementField(value_cls=Account)
@@ -1613,7 +1628,7 @@ Inherited members
if Protocol.EXCH in protocols:
return protocols[Protocol.EXCH]
raise ValueError(
- f'No EWS URL found in any of the available protocols: {[str(p) for p in self.account.protocols]}'
+ f"No EWS URL found in any of the available protocols: {[str(p) for p in self.account.protocols]}"
)
class User(AutodiscoverBase):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/user-pox"""
- ELEMENT_NAME = 'User'
+ ELEMENT_NAME = "User"
- display_name = TextField(field_uri='DisplayName', namespace=RNS)
- legacy_dn = TextField(field_uri='LegacyDN', namespace=RNS)
- deployment_id = TextField(field_uri='DeploymentId', namespace=RNS) # GUID format
- autodiscover_smtp_address = EmailAddressField(field_uri='AutoDiscoverSMTPAddress', namespace=RNS)
+ display_name = TextField(field_uri="DisplayName", namespace=RNS)
+ legacy_dn = TextField(field_uri="LegacyDN", namespace=RNS)
+ deployment_id = TextField(field_uri="DeploymentId", namespace=RNS) # GUID format
+ autodiscover_smtp_address = EmailAddressField(field_uri="AutoDiscoverSMTPAddress", namespace=RNS)
exchangelib.autodiscover.protocol
exchangelib.configuration
exchangelib.configuration
exchangelib.configuration
exchangelib.credentials
exchangelib.credentials
exchangelib.credentials
exchangelib.credentials
exchangelib.credentials
exchangelib.credentials
exchangelib.credentials
exchangelib.errors
# flake8: noqa
-"""Stores errors specific to this package, and mirrors all the possible errors that EWS can return."""
+"""Stores errors specific to this package, and mirrors all the possible errors that EWS can return."""
from urllib.parse import urlparse
@@ -48,7 +47,7 @@ Module exchangelib.errors
super().__init__(str(self))
def __str__(self):
- return f'{self.field_name!r} {self.value!r} must be one of {sorted(self.choices)}'
+ return f"{self.field_name!r} {self.value!r} must be one of {sorted(self.choices)}"
class InvalidTypeError(TypeError):
@@ -59,7 +58,7 @@ Module exchangelib.errors
super().__init__(str(self))
def __str__(self):
- return f'{self.field_name!r} {self.value!r} must be of type {self.valid_type}'
+ return f"{self.field_name!r} {self.value!r} must be of type {self.valid_type}"
class EWSError(Exception):
@@ -94,8 +93,10 @@ Module exchangelib.errors
self.total_wait = total_wait
def __str__(self):
- return f'{self.value} (gave up after {self.total_wait:.3f} seconds. ' \
- f'URL {self.url} returned status code {self.status_code})'
+ return (
+ f"{self.value} (gave up after {self.total_wait:.3f} seconds. "
+ f"URL {self.url} returned status code {self.status_code})"
+ )
class SOAPError(TransportError):
@@ -115,11 +116,11 @@ Module exchangelib.errors
parsed_url = urlparse(url)
self.url = url
self.server = parsed_url.hostname.lower()
- self.has_ssl = parsed_url.scheme == 'https'
+ self.has_ssl = parsed_url.scheme == "https"
super().__init__(str(self))
def __str__(self):
- return f'We were redirected to {self.url}'
+ return f"We were redirected to {self.url}"
class RelativeRedirect(TransportError):
@@ -175,403 +176,1548 @@ Module exchangelib.errors
super().__init__(str(self))
def __str__(self):
- return f'CAS error: {self.cas_error}'
+ return f"CAS error: {self.cas_error}"
# Somewhat-authoritative list of possible response message error types from EWS. See full list at
# https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/responsecode
#
-class ErrorAccessDenied(ResponseMessageError): pass
-class ErrorAccessModeSpecified(ResponseMessageError): pass
-class ErrorAccountDisabled(ResponseMessageError): pass
-class ErrorAddDelegatesFailed(ResponseMessageError): pass
-class ErrorAddressSpaceNotFound(ResponseMessageError): pass
-class ErrorADOperation(ResponseMessageError): pass
-class ErrorADSessionFilter(ResponseMessageError): pass
-class ErrorADUnavailable(ResponseMessageError): pass
-class ErrorAffectedTaskOccurrencesRequired(ResponseMessageError): pass
-class ErrorApplyConversationActionFailed(ResponseMessageError): pass
-class ErrorAttachmentSizeLimitExceeded(ResponseMessageError): pass
-class ErrorAutoDiscoverFailed(ResponseMessageError): pass
-class ErrorAvailabilityConfigNotFound(ResponseMessageError): pass
-class ErrorBatchProcessingStopped(ResponseMessageError): pass
-class ErrorCalendarCannotMoveOrCopyOccurrence(ResponseMessageError): pass
-class ErrorCalendarCannotUpdateDeletedItem(ResponseMessageError): pass
-class ErrorCalendarCannotUseIdForOccurrenceId(ResponseMessageError): pass
-class ErrorCalendarCannotUseIdForRecurringMasterId(ResponseMessageError): pass
-class ErrorCalendarDurationIsTooLong(ResponseMessageError): pass
-class ErrorCalendarEndDateIsEarlierThanStartDate(ResponseMessageError): pass
-class ErrorCalendarFolderIsInvalidForCalendarView(ResponseMessageError): pass
-class ErrorCalendarInvalidAttributeValue(ResponseMessageError): pass
-class ErrorCalendarInvalidDayForTimeChangePattern(ResponseMessageError): pass
-class ErrorCalendarInvalidDayForWeeklyRecurrence(ResponseMessageError): pass
-class ErrorCalendarInvalidPropertyState(ResponseMessageError): pass
-class ErrorCalendarInvalidPropertyValue(ResponseMessageError): pass
-class ErrorCalendarInvalidRecurrence(ResponseMessageError): pass
-class ErrorCalendarInvalidTimeZone(ResponseMessageError): pass
-class ErrorCalendarIsCancelledForAccept(ResponseMessageError): pass
-class ErrorCalendarIsCancelledForDecline(ResponseMessageError): pass
-class ErrorCalendarIsCancelledForRemove(ResponseMessageError): pass
-class ErrorCalendarIsCancelledForTentative(ResponseMessageError): pass
-class ErrorCalendarIsDelegatedForAccept(ResponseMessageError): pass
-class ErrorCalendarIsDelegatedForDecline(ResponseMessageError): pass
-class ErrorCalendarIsDelegatedForRemove(ResponseMessageError): pass
-class ErrorCalendarIsDelegatedForTentative(ResponseMessageError): pass
-class ErrorCalendarIsNotOrganizer(ResponseMessageError): pass
-class ErrorCalendarIsOrganizerForAccept(ResponseMessageError): pass
-class ErrorCalendarIsOrganizerForDecline(ResponseMessageError): pass
-class ErrorCalendarIsOrganizerForRemove(ResponseMessageError): pass
-class ErrorCalendarIsOrganizerForTentative(ResponseMessageError): pass
-class ErrorCalendarMeetingRequestIsOutOfDate(ResponseMessageError): pass
-class ErrorCalendarOccurrenceIndexIsOutOfRecurrenceRange(ResponseMessageError): pass
-class ErrorCalendarOccurrenceIsDeletedFromRecurrence(ResponseMessageError): pass
-class ErrorCalendarOutOfRange(ResponseMessageError): pass
-class ErrorCalendarViewRangeTooBig(ResponseMessageError): pass
-class ErrorCallerIsInvalidADAccount(ResponseMessageError): pass
-class ErrorCannotCreateCalendarItemInNonCalendarFolder(ResponseMessageError): pass
-class ErrorCannotCreateContactInNonContactFolder(ResponseMessageError): pass
-class ErrorCannotCreatePostItemInNonMailFolder(ResponseMessageError): pass
-class ErrorCannotCreateTaskInNonTaskFolder(ResponseMessageError): pass
-class ErrorCannotDeleteObject(ResponseMessageError): pass
-class ErrorCannotDeleteTaskOccurrence(ResponseMessageError): pass
-class ErrorCannotEmptyFolder(ResponseMessageError): pass
-class ErrorCannotOpenFileAttachment(ResponseMessageError): pass
-class ErrorCannotSetCalendarPermissionOnNonCalendarFolder(ResponseMessageError): pass
-class ErrorCannotSetNonCalendarPermissionOnCalendarFolder(ResponseMessageError): pass
-class ErrorCannotSetPermissionUnknownEntries(ResponseMessageError): pass
-class ErrorCannotUseFolderIdForItemId(ResponseMessageError): pass
-class ErrorCannotUseItemIdForFolderId(ResponseMessageError): pass
-class ErrorChangeKeyRequired(ResponseMessageError): pass
-class ErrorChangeKeyRequiredForWriteOperations(ResponseMessageError): pass
-class ErrorClientDisconnected(ResponseMessageError): pass
-class ErrorConnectionFailed(ResponseMessageError): pass
-class ErrorConnectionFailedTransientError(ResponseMessageError): pass
-class ErrorContainsFilterWrongType(ResponseMessageError): pass
-class ErrorContentConversionFailed(ResponseMessageError): pass
-class ErrorCorruptData(ResponseMessageError): pass
-class ErrorCreateItemAccessDenied(ResponseMessageError): pass
-class ErrorCreateManagedFolderPartialCompletion(ResponseMessageError): pass
-class ErrorCreateSubfolderAccessDenied(ResponseMessageError): pass
-class ErrorCrossMailboxMoveCopy(ResponseMessageError): pass
-class ErrorCrossSiteRequest(ResponseMessageError): pass
-class ErrorDataSizeLimitExceeded(ResponseMessageError): pass
-class ErrorDataSourceOperation(ResponseMessageError): pass
-class ErrorDelegateAlreadyExists(ResponseMessageError): pass
-class ErrorDelegateCannotAddOwner(ResponseMessageError): pass
-class ErrorDelegateMissingConfiguration(ResponseMessageError): pass
-class ErrorDelegateNoUser(ResponseMessageError): pass
-class ErrorDelegateValidationFailed(ResponseMessageError): pass
-class ErrorDeleteDistinguishedFolder(ResponseMessageError): pass
-class ErrorDeleteItemsFailed(ResponseMessageError): pass
-class ErrorDistinguishedUserNotSupported(ResponseMessageError): pass
-class ErrorDistributionListMemberNotExist(ResponseMessageError): pass
-class ErrorDuplicateInputFolderNames(ResponseMessageError): pass
-class ErrorDuplicateSOAPHeader(ResponseMessageError): pass
-class ErrorDuplicateUserIdsSpecified(ResponseMessageError): pass
-class ErrorEmailAddressMismatch(ResponseMessageError): pass
-class ErrorEventNotFound(ResponseMessageError): pass
-class ErrorExceededConnectionCount(ResponseMessageError): pass
-class ErrorExceededFindCountLimit(ResponseMessageError): pass
-class ErrorExceededSubscriptionCount(ResponseMessageError): pass
-class ErrorExpiredSubscription(ResponseMessageError): pass
-class ErrorFolderCorrupt(ResponseMessageError): pass
-class ErrorFolderExists(ResponseMessageError): pass
-class ErrorFolderNotFound(ResponseMessageError): pass
-class ErrorFolderPropertyRequestFailed(ResponseMessageError): pass
-class ErrorFolderSave(ResponseMessageError): pass
-class ErrorFolderSaveFailed(ResponseMessageError): pass
-class ErrorFolderSavePropertyError(ResponseMessageError): pass
-class ErrorFreeBusyDLLimitReached(ResponseMessageError): pass
-class ErrorFreeBusyGenerationFailed(ResponseMessageError): pass
-class ErrorGetServerSecurityDescriptorFailed(ResponseMessageError): pass
-class ErrorImpersonateUserDenied(ResponseMessageError): pass
-class ErrorImpersonationDenied(ResponseMessageError): pass
-class ErrorImpersonationFailed(ResponseMessageError): pass
-class ErrorInboxRulesValidationError(ResponseMessageError): pass
-class ErrorIncorrectSchemaVersion(ResponseMessageError): pass
-class ErrorIncorrectUpdatePropertyCount(ResponseMessageError): pass
-class ErrorIndividualMailboxLimitReached(ResponseMessageError): pass
-class ErrorInsufficientResources(ResponseMessageError): pass
-class ErrorInternalServerError(ResponseMessageError): pass
-class ErrorInternalServerTransientError(ResponseMessageError): pass
-class ErrorInvalidAccessLevel(ResponseMessageError): pass
-class ErrorInvalidArgument(ResponseMessageError): pass
-class ErrorInvalidAttachmentId(ResponseMessageError): pass
-class ErrorInvalidAttachmentSubfilter(ResponseMessageError): pass
-class ErrorInvalidAttachmentSubfilterTextFilter(ResponseMessageError): pass
-class ErrorInvalidAuthorizationContext(ResponseMessageError): pass
-class ErrorInvalidChangeKey(ResponseMessageError): pass
-class ErrorInvalidClientSecurityContext(ResponseMessageError): pass
-class ErrorInvalidCompleteDate(ResponseMessageError): pass
-class ErrorInvalidContactEmailAddress(ResponseMessageError): pass
-class ErrorInvalidContactEmailIndex(ResponseMessageError): pass
-class ErrorInvalidCrossForestCredentials(ResponseMessageError): pass
-class ErrorInvalidDelegatePermission(ResponseMessageError): pass
-class ErrorInvalidDelegateUserId(ResponseMessageError): pass
-class ErrorInvalidExchangeImpersonationHeaderData(ResponseMessageError): pass
-class ErrorInvalidExcludesRestriction(ResponseMessageError): pass
-class ErrorInvalidExpressionTypeForSubFilter(ResponseMessageError): pass
-class ErrorInvalidExtendedProperty(ResponseMessageError): pass
-class ErrorInvalidExtendedPropertyValue(ResponseMessageError): pass
-class ErrorInvalidExternalSharingInitiator(ResponseMessageError): pass
-class ErrorInvalidExternalSharingSubscriber(ResponseMessageError): pass
-class ErrorInvalidFederatedOrganizationId(ResponseMessageError): pass
-class ErrorInvalidFolderId(ResponseMessageError): pass
-class ErrorInvalidFolderTypeForOperation(ResponseMessageError): pass
-class ErrorInvalidFractionalPagingParameters(ResponseMessageError): pass
-class ErrorInvalidFreeBusyViewType(ResponseMessageError): pass
-class ErrorInvalidGetSharingFolderRequest(ResponseMessageError): pass
-class ErrorInvalidId(ResponseMessageError): pass
-class ErrorInvalidIdEmpty(ResponseMessageError): pass
-class ErrorInvalidIdMalformed(ResponseMessageError): pass
-class ErrorInvalidIdMalformedEwsLegacyIdFormat(ResponseMessageError): pass
-class ErrorInvalidIdMonikerTooLong(ResponseMessageError): pass
-class ErrorInvalidIdNotAnItemAttachmentId(ResponseMessageError): pass
-class ErrorInvalidIdReturnedByResolveNames(ResponseMessageError): pass
-class ErrorInvalidIdStoreObjectIdTooLong(ResponseMessageError): pass
-class ErrorInvalidIdTooManyAttachmentLevels(ResponseMessageError): pass
-class ErrorInvalidIdXml(ResponseMessageError): pass
-class ErrorInvalidIndexedPagingParameters(ResponseMessageError): pass
-class ErrorInvalidInternetHeaderChildNodes(ResponseMessageError): pass
-class ErrorInvalidItemForOperationAcceptItem(ResponseMessageError): pass
-class ErrorInvalidItemForOperationCancelItem(ResponseMessageError): pass
-class ErrorInvalidItemForOperationCreateItem(ResponseMessageError): pass
-class ErrorInvalidItemForOperationCreateItemAttachment(ResponseMessageError): pass
-class ErrorInvalidItemForOperationDeclineItem(ResponseMessageError): pass
-class ErrorInvalidItemForOperationExpandDL(ResponseMessageError): pass
-class ErrorInvalidItemForOperationRemoveItem(ResponseMessageError): pass
-class ErrorInvalidItemForOperationSendItem(ResponseMessageError): pass
-class ErrorInvalidItemForOperationTentative(ResponseMessageError): pass
-class ErrorInvalidLicense(ResponseMessageError): pass
-class ErrorInvalidLogonType(ResponseMessageError): pass
-class ErrorInvalidMailbox(ResponseMessageError): pass
-class ErrorInvalidManagedFolderProperty(ResponseMessageError): pass
-class ErrorInvalidManagedFolderQuota(ResponseMessageError): pass
-class ErrorInvalidManagedFolderSize(ResponseMessageError): pass
-class ErrorInvalidMergedFreeBusyInterval(ResponseMessageError): pass
-class ErrorInvalidNameForNameResolution(ResponseMessageError): pass
-class ErrorInvalidNetworkServiceContext(ResponseMessageError): pass
-class ErrorInvalidOofParameter(ResponseMessageError): pass
-class ErrorInvalidOperation(ResponseMessageError): pass
-class ErrorInvalidOrganizationRelationshipForFreeBusy(ResponseMessageError): pass
-class ErrorInvalidPagingMaxRows(ResponseMessageError): pass
-class ErrorInvalidParentFolder(ResponseMessageError): pass
-class ErrorInvalidPercentCompleteValue(ResponseMessageError): pass
-class ErrorInvalidPermissionSettings(ResponseMessageError): pass
-class ErrorInvalidPhoneCallId(ResponseMessageError): pass
-class ErrorInvalidPhoneNumber(ResponseMessageError): pass
-class ErrorInvalidPropertyAppend(ResponseMessageError): pass
-class ErrorInvalidPropertyDelete(ResponseMessageError): pass
-class ErrorInvalidPropertyForExists(ResponseMessageError): pass
-class ErrorInvalidPropertyForOperation(ResponseMessageError): pass
-class ErrorInvalidPropertyRequest(ResponseMessageError): pass
-class ErrorInvalidPropertySet(ResponseMessageError): pass
-class ErrorInvalidPropertyUpdateSentMessage(ResponseMessageError): pass
-class ErrorInvalidProxySecurityContext(ResponseMessageError): pass
-class ErrorInvalidPullSubscriptionId(ResponseMessageError): pass
-class ErrorInvalidPushSubscriptionUrl(ResponseMessageError): pass
-class ErrorInvalidRecipients(ResponseMessageError): pass
-class ErrorInvalidRecipientSubfilter(ResponseMessageError): pass
-class ErrorInvalidRecipientSubfilterComparison(ResponseMessageError): pass
-class ErrorInvalidRecipientSubfilterOrder(ResponseMessageError): pass
-class ErrorInvalidRecipientSubfilterTextFilter(ResponseMessageError): pass
-class ErrorInvalidReferenceItem(ResponseMessageError): pass
-class ErrorInvalidRequest(ResponseMessageError): pass
-class ErrorInvalidRestriction(ResponseMessageError): pass
-class ErrorInvalidRoutingType(ResponseMessageError): pass
-class ErrorInvalidScheduledOofDuration(ResponseMessageError): pass
-class ErrorInvalidSchemaVersionForMailboxVersion(ResponseMessageError): pass
-class ErrorInvalidSecurityDescriptor(ResponseMessageError): pass
-class ErrorInvalidSendItemSaveSettings(ResponseMessageError): pass
-class ErrorInvalidSerializedAccessToken(ResponseMessageError): pass
-class ErrorInvalidServerVersion(ResponseMessageError): pass
-class ErrorInvalidSharingData(ResponseMessageError): pass
-class ErrorInvalidSharingMessage(ResponseMessageError): pass
-class ErrorInvalidSid(ResponseMessageError): pass
-class ErrorInvalidSIPUri(ResponseMessageError): pass
-class ErrorInvalidSmtpAddress(ResponseMessageError): pass
-class ErrorInvalidSubfilterType(ResponseMessageError): pass
-class ErrorInvalidSubfilterTypeNotAttendeeType(ResponseMessageError): pass
-class ErrorInvalidSubfilterTypeNotRecipientType(ResponseMessageError): pass
-class ErrorInvalidSubscription(ResponseMessageError): pass
-class ErrorInvalidSubscriptionRequest(ResponseMessageError): pass
-class ErrorInvalidSyncStateData(ResponseMessageError): pass
-class ErrorInvalidTimeInterval(ResponseMessageError): pass
-class ErrorInvalidUserInfo(ResponseMessageError): pass
-class ErrorInvalidUserOofSettings(ResponseMessageError): pass
-class ErrorInvalidUserPrincipalName(ResponseMessageError): pass
-class ErrorInvalidUserSid(ResponseMessageError): pass
-class ErrorInvalidUserSidMissingUPN(ResponseMessageError): pass
-class ErrorInvalidValueForProperty(ResponseMessageError): pass
-class ErrorInvalidWatermark(ResponseMessageError): pass
-class ErrorIPGatewayNotFound(ResponseMessageError): pass
-class ErrorIrresolvableConflict(ResponseMessageError): pass
-class ErrorItemCorrupt(ResponseMessageError): pass
-class ErrorItemNotFound(ResponseMessageError): pass
-class ErrorItemPropertyRequestFailed(ResponseMessageError): pass
-class ErrorItemSave(ResponseMessageError): pass
-class ErrorItemSavePropertyError(ResponseMessageError): pass
-class ErrorLegacyMailboxFreeBusyViewTypeNotMerged(ResponseMessageError): pass
-class ErrorLocalServerObjectNotFound(ResponseMessageError): pass
-class ErrorLogonAsNetworkServiceFailed(ResponseMessageError): pass
-class ErrorMailboxConfiguration(ResponseMessageError): pass
-class ErrorMailboxDataArrayEmpty(ResponseMessageError): pass
-class ErrorMailboxDataArrayTooBig(ResponseMessageError): pass
-class ErrorMailboxFailover(ResponseMessageError): pass
-class ErrorMailboxLogonFailed(ResponseMessageError): pass
-class ErrorMailboxMoveInProgress(ResponseMessageError): pass
-class ErrorMailboxStoreUnavailable(ResponseMessageError): pass
-class ErrorMailRecipientNotFound(ResponseMessageError): pass
-class ErrorMailTipsDisabled(ResponseMessageError): pass
-class ErrorManagedFolderAlreadyExists(ResponseMessageError): pass
-class ErrorManagedFolderNotFound(ResponseMessageError): pass
-class ErrorManagedFoldersRootFailure(ResponseMessageError): pass
-class ErrorMeetingSuggestionGenerationFailed(ResponseMessageError): pass
-class ErrorMessageDispositionRequired(ResponseMessageError): pass
-class ErrorMessageSizeExceeded(ResponseMessageError): pass
-class ErrorMessageTrackingNoSuchDomain(ResponseMessageError): pass
-class ErrorMessageTrackingPermanentError(ResponseMessageError): pass
-class ErrorMessageTrackingTransientError(ResponseMessageError): pass
-class ErrorMimeContentConversionFailed(ResponseMessageError): pass
-class ErrorMimeContentInvalid(ResponseMessageError): pass
-class ErrorMimeContentInvalidBase64String(ResponseMessageError): pass
-class ErrorMissedNotificationEvents(ResponseMessageError): pass
-class ErrorMissingArgument(ResponseMessageError): pass
-class ErrorMissingEmailAddress(ResponseMessageError): pass
-class ErrorMissingEmailAddressForManagedFolder(ResponseMessageError): pass
-class ErrorMissingInformationEmailAddress(ResponseMessageError): pass
-class ErrorMissingInformationReferenceItemId(ResponseMessageError): pass
-class ErrorMissingInformationSharingFolderId(ResponseMessageError): pass
-class ErrorMissingItemForCreateItemAttachment(ResponseMessageError): pass
-class ErrorMissingManagedFolderId(ResponseMessageError): pass
-class ErrorMissingRecipients(ResponseMessageError): pass
-class ErrorMissingUserIdInformation(ResponseMessageError): pass
-class ErrorMoreThanOneAccessModeSpecified(ResponseMessageError): pass
-class ErrorMoveCopyFailed(ResponseMessageError): pass
-class ErrorMoveDistinguishedFolder(ResponseMessageError): pass
-class ErrorNameResolutionMultipleResults(ResponseMessageError): pass
-class ErrorNameResolutionNoMailbox(ResponseMessageError): pass
-class ErrorNameResolutionNoResults(ResponseMessageError): pass
-class ErrorNewEventStreamConnectionOpened(ResponseMessageError): pass
-class ErrorNoApplicableProxyCASServersAvailable(ResponseMessageError): pass
-class ErrorNoCalendar(ResponseMessageError): pass
-class ErrorNoDestinationCASDueToKerberosRequirements(ResponseMessageError): pass
-class ErrorNoDestinationCASDueToSSLRequirements(ResponseMessageError): pass
-class ErrorNoDestinationCASDueToVersionMismatch(ResponseMessageError): pass
-class ErrorNoFolderClassOverride(ResponseMessageError): pass
-class ErrorNoFreeBusyAccess(ResponseMessageError): pass
-class ErrorNonExistentMailbox(ResponseMessageError): pass
-class ErrorNonPrimarySmtpAddress(ResponseMessageError): pass
-class ErrorNoPropertyTagForCustomProperties(ResponseMessageError): pass
-class ErrorNoPublicFolderReplicaAvailable(ResponseMessageError): pass
-class ErrorNoPublicFolderServerAvailable(ResponseMessageError): pass
-class ErrorNoRespondingCASInDestinationSite(ResponseMessageError): pass
-class ErrorNotAllowedExternalSharingByPolicy(ResponseMessageError): pass
-class ErrorNotDelegate(ResponseMessageError): pass
-class ErrorNotEnoughMemory(ResponseMessageError): pass
-class ErrorNotSupportedSharingMessage(ResponseMessageError): pass
-class ErrorObjectTypeChanged(ResponseMessageError): pass
-class ErrorOccurrenceCrossingBoundary(ResponseMessageError): pass
-class ErrorOccurrenceTimeSpanTooBig(ResponseMessageError): pass
-class ErrorOperationNotAllowedWithPublicFolderRoot(ResponseMessageError): pass
-class ErrorOrganizationNotFederated(ResponseMessageError): pass
-class ErrorOutlookRuleBlobExists(ResponseMessageError): pass
-class ErrorParentFolderIdRequired(ResponseMessageError): pass
-class ErrorParentFolderNotFound(ResponseMessageError): pass
-class ErrorPasswordChangeRequired(ResponseMessageError): pass
-class ErrorPasswordExpired(ResponseMessageError): pass
-class ErrorPermissionNotAllowedByPolicy(ResponseMessageError): pass
-class ErrorPhoneNumberNotDialable(ResponseMessageError): pass
-class ErrorPropertyUpdate(ResponseMessageError): pass
-class ErrorPropertyValidationFailure(ResponseMessageError): pass
-class ErrorProxiedSubscriptionCallFailure(ResponseMessageError): pass
-class ErrorProxyCallFailed(ResponseMessageError): pass
-class ErrorProxyGroupSidLimitExceeded(ResponseMessageError): pass
-class ErrorProxyRequestNotAllowed(ResponseMessageError): pass
-class ErrorProxyRequestProcessingFailed(ResponseMessageError): pass
-class ErrorProxyServiceDiscoveryFailed(ResponseMessageError): pass
-class ErrorProxyTokenExpired(ResponseMessageError): pass
-class ErrorPublicFolderRequestProcessingFailed(ResponseMessageError): pass
-class ErrorPublicFolderServerNotFound(ResponseMessageError): pass
-class ErrorQueryFilterTooLong(ResponseMessageError): pass
-class ErrorQuotaExceeded(ResponseMessageError): pass
-class ErrorReadEventsFailed(ResponseMessageError): pass
-class ErrorReadReceiptNotPending(ResponseMessageError): pass
-class ErrorRecurrenceEndDateTooBig(ResponseMessageError): pass
-class ErrorRecurrenceHasNoOccurrence(ResponseMessageError): pass
-class ErrorRemoveDelegatesFailed(ResponseMessageError): pass
-class ErrorRequestAborted(ResponseMessageError): pass
-class ErrorRequestStreamTooBig(ResponseMessageError): pass
-class ErrorRequiredPropertyMissing(ResponseMessageError): pass
-class ErrorResolveNamesInvalidFolderType(ResponseMessageError): pass
-class ErrorResolveNamesOnlyOneContactsFolderAllowed(ResponseMessageError): pass
-class ErrorResponseSchemaValidation(ResponseMessageError): pass
-class ErrorRestrictionTooComplex(ResponseMessageError): pass
-class ErrorRestrictionTooLong(ResponseMessageError): pass
-class ErrorResultSetTooBig(ResponseMessageError): pass
-class ErrorRulesOverQuota(ResponseMessageError): pass
-class ErrorSavedItemFolderNotFound(ResponseMessageError): pass
-class ErrorSchemaValidation(ResponseMessageError): pass
-class ErrorSearchFolderNotInitialized(ResponseMessageError): pass
-class ErrorSendAsDenied(ResponseMessageError): pass
-class ErrorSendMeetingCancellationsRequired(ResponseMessageError): pass
-class ErrorSendMeetingInvitationsOrCancellationsRequired(ResponseMessageError): pass
-class ErrorSendMeetingInvitationsRequired(ResponseMessageError): pass
-class ErrorSentMeetingRequestUpdate(ResponseMessageError): pass
-class ErrorSentTaskRequestUpdate(ResponseMessageError): pass
+class ErrorAccessDenied(ResponseMessageError):
+ pass
+
+
+class ErrorAccessModeSpecified(ResponseMessageError):
+ pass
+
+
+class ErrorAccountDisabled(ResponseMessageError):
+ pass
+
+
+class ErrorAddDelegatesFailed(ResponseMessageError):
+ pass
+
+
+class ErrorAddressSpaceNotFound(ResponseMessageError):
+ pass
+
+
+class ErrorADOperation(ResponseMessageError):
+ pass
+
+
+class ErrorADSessionFilter(ResponseMessageError):
+ pass
+
+
+class ErrorADUnavailable(ResponseMessageError):
+ pass
+
+
+class ErrorAffectedTaskOccurrencesRequired(ResponseMessageError):
+ pass
+
+
+class ErrorApplyConversationActionFailed(ResponseMessageError):
+ pass
+
+
+class ErrorAttachmentSizeLimitExceeded(ResponseMessageError):
+ pass
+
+
+class ErrorAutoDiscoverFailed(ResponseMessageError):
+ pass
+
+
+class ErrorAvailabilityConfigNotFound(ResponseMessageError):
+ pass
+
+
+class ErrorBatchProcessingStopped(ResponseMessageError):
+ pass
+
+
+class ErrorCalendarCannotMoveOrCopyOccurrence(ResponseMessageError):
+ pass
+
+
+class ErrorCalendarCannotUpdateDeletedItem(ResponseMessageError):
+ pass
+
+
+class ErrorCalendarCannotUseIdForOccurrenceId(ResponseMessageError):
+ pass
+
+
+class ErrorCalendarCannotUseIdForRecurringMasterId(ResponseMessageError):
+ pass
+
+
+class ErrorCalendarDurationIsTooLong(ResponseMessageError):
+ pass
+
+
+class ErrorCalendarEndDateIsEarlierThanStartDate(ResponseMessageError):
+ pass
+
+
+class ErrorCalendarFolderIsInvalidForCalendarView(ResponseMessageError):
+ pass
+
+
+class ErrorCalendarInvalidAttributeValue(ResponseMessageError):
+ pass
+
+
+class ErrorCalendarInvalidDayForTimeChangePattern(ResponseMessageError):
+ pass
+
+
+class ErrorCalendarInvalidDayForWeeklyRecurrence(ResponseMessageError):
+ pass
+
+
+class ErrorCalendarInvalidPropertyState(ResponseMessageError):
+ pass
+
+
+class ErrorCalendarInvalidPropertyValue(ResponseMessageError):
+ pass
+
+
+class ErrorCalendarInvalidRecurrence(ResponseMessageError):
+ pass
+
+
+class ErrorCalendarInvalidTimeZone(ResponseMessageError):
+ pass
+
+
+class ErrorCalendarIsCancelledForAccept(ResponseMessageError):
+ pass
+
+
+class ErrorCalendarIsCancelledForDecline(ResponseMessageError):
+ pass
+
+
+class ErrorCalendarIsCancelledForRemove(ResponseMessageError):
+ pass
+
+
+class ErrorCalendarIsCancelledForTentative(ResponseMessageError):
+ pass
+
+
+class ErrorCalendarIsDelegatedForAccept(ResponseMessageError):
+ pass
+
+
+class ErrorCalendarIsDelegatedForDecline(ResponseMessageError):
+ pass
+
+
+class ErrorCalendarIsDelegatedForRemove(ResponseMessageError):
+ pass
+
+
+class ErrorCalendarIsDelegatedForTentative(ResponseMessageError):
+ pass
+
+
+class ErrorCalendarIsNotOrganizer(ResponseMessageError):
+ pass
+
+
+class ErrorCalendarIsOrganizerForAccept(ResponseMessageError):
+ pass
+
+
+class ErrorCalendarIsOrganizerForDecline(ResponseMessageError):
+ pass
+
+
+class ErrorCalendarIsOrganizerForRemove(ResponseMessageError):
+ pass
+
+
+class ErrorCalendarIsOrganizerForTentative(ResponseMessageError):
+ pass
+
+
+class ErrorCalendarMeetingRequestIsOutOfDate(ResponseMessageError):
+ pass
+
+
+class ErrorCalendarOccurrenceIndexIsOutOfRecurrenceRange(ResponseMessageError):
+ pass
+
+
+class ErrorCalendarOccurrenceIsDeletedFromRecurrence(ResponseMessageError):
+ pass
+
+
+class ErrorCalendarOutOfRange(ResponseMessageError):
+ pass
+
+
+class ErrorCalendarViewRangeTooBig(ResponseMessageError):
+ pass
+
+
+class ErrorCallerIsInvalidADAccount(ResponseMessageError):
+ pass
+
+
+class ErrorCannotCreateCalendarItemInNonCalendarFolder(ResponseMessageError):
+ pass
+
+
+class ErrorCannotCreateContactInNonContactFolder(ResponseMessageError):
+ pass
+
+
+class ErrorCannotCreatePostItemInNonMailFolder(ResponseMessageError):
+ pass
+
+
+class ErrorCannotCreateTaskInNonTaskFolder(ResponseMessageError):
+ pass
+
+
+class ErrorCannotDeleteObject(ResponseMessageError):
+ pass
+
+
+class ErrorCannotDeleteTaskOccurrence(ResponseMessageError):
+ pass
+
+
+class ErrorCannotEmptyFolder(ResponseMessageError):
+ pass
+
+
+class ErrorCannotOpenFileAttachment(ResponseMessageError):
+ pass
+
+
+class ErrorCannotSetCalendarPermissionOnNonCalendarFolder(ResponseMessageError):
+ pass
+
+
+class ErrorCannotSetNonCalendarPermissionOnCalendarFolder(ResponseMessageError):
+ pass
+
+
+class ErrorCannotSetPermissionUnknownEntries(ResponseMessageError):
+ pass
+
+
+class ErrorCannotUseFolderIdForItemId(ResponseMessageError):
+ pass
+
+
+class ErrorCannotUseItemIdForFolderId(ResponseMessageError):
+ pass
+
+
+class ErrorChangeKeyRequired(ResponseMessageError):
+ pass
+
+
+class ErrorChangeKeyRequiredForWriteOperations(ResponseMessageError):
+ pass
+
+
+class ErrorClientDisconnected(ResponseMessageError):
+ pass
+
+
+class ErrorConnectionFailed(ResponseMessageError):
+ pass
+
+
+class ErrorConnectionFailedTransientError(ResponseMessageError):
+ pass
+
+
+class ErrorContainsFilterWrongType(ResponseMessageError):
+ pass
+
+
+class ErrorContentConversionFailed(ResponseMessageError):
+ pass
+
+
+class ErrorCorruptData(ResponseMessageError):
+ pass
+
+
+class ErrorCreateItemAccessDenied(ResponseMessageError):
+ pass
+
+
+class ErrorCreateManagedFolderPartialCompletion(ResponseMessageError):
+ pass
+
+
+class ErrorCreateSubfolderAccessDenied(ResponseMessageError):
+ pass
+
+
+class ErrorCrossMailboxMoveCopy(ResponseMessageError):
+ pass
+
+
+class ErrorCrossSiteRequest(ResponseMessageError):
+ pass
+
+
+class ErrorDataSizeLimitExceeded(ResponseMessageError):
+ pass
+
+
+class ErrorDataSourceOperation(ResponseMessageError):
+ pass
+
+
+class ErrorDelegateAlreadyExists(ResponseMessageError):
+ pass
+
+
+class ErrorDelegateCannotAddOwner(ResponseMessageError):
+ pass
+
+
+class ErrorDelegateMissingConfiguration(ResponseMessageError):
+ pass
+
+
+class ErrorDelegateNoUser(ResponseMessageError):
+ pass
+
+
+class ErrorDelegateValidationFailed(ResponseMessageError):
+ pass
+
+
+class ErrorDeleteDistinguishedFolder(ResponseMessageError):
+ pass
+
+
+class ErrorDeleteItemsFailed(ResponseMessageError):
+ pass
+
+
+class ErrorDistinguishedUserNotSupported(ResponseMessageError):
+ pass
+
+
+class ErrorDistributionListMemberNotExist(ResponseMessageError):
+ pass
+
+
+class ErrorDuplicateInputFolderNames(ResponseMessageError):
+ pass
+
+
+class ErrorDuplicateSOAPHeader(ResponseMessageError):
+ pass
+
+
+class ErrorDuplicateUserIdsSpecified(ResponseMessageError):
+ pass
+
+
+class ErrorEmailAddressMismatch(ResponseMessageError):
+ pass
+
+
+class ErrorEventNotFound(ResponseMessageError):
+ pass
+
+
+class ErrorExceededConnectionCount(ResponseMessageError):
+ pass
+
+
+class ErrorExceededFindCountLimit(ResponseMessageError):
+ pass
+
+
+class ErrorExceededSubscriptionCount(ResponseMessageError):
+ pass
+
+
+class ErrorExpiredSubscription(ResponseMessageError):
+ pass
+
+
+class ErrorFolderCorrupt(ResponseMessageError):
+ pass
+
+
+class ErrorFolderExists(ResponseMessageError):
+ pass
+
+
+class ErrorFolderNotFound(ResponseMessageError):
+ pass
+
+
+class ErrorFolderPropertyRequestFailed(ResponseMessageError):
+ pass
+
+
+class ErrorFolderSave(ResponseMessageError):
+ pass
+
+
+class ErrorFolderSaveFailed(ResponseMessageError):
+ pass
+
+
+class ErrorFolderSavePropertyError(ResponseMessageError):
+ pass
+
+
+class ErrorFreeBusyDLLimitReached(ResponseMessageError):
+ pass
+
+
+class ErrorFreeBusyGenerationFailed(ResponseMessageError):
+ pass
+
+
+class ErrorGetServerSecurityDescriptorFailed(ResponseMessageError):
+ pass
+
+
+class ErrorImpersonateUserDenied(ResponseMessageError):
+ pass
+
+
+class ErrorImpersonationDenied(ResponseMessageError):
+ pass
+
+
+class ErrorImpersonationFailed(ResponseMessageError):
+ pass
+
+
+class ErrorInboxRulesValidationError(ResponseMessageError):
+ pass
+
+
+class ErrorIncorrectSchemaVersion(ResponseMessageError):
+ pass
+
+
+class ErrorIncorrectUpdatePropertyCount(ResponseMessageError):
+ pass
+
+
+class ErrorIndividualMailboxLimitReached(ResponseMessageError):
+ pass
+
+
+class ErrorInsufficientResources(ResponseMessageError):
+ pass
+
+
+class ErrorInternalServerError(ResponseMessageError):
+ pass
+
+
+class ErrorInternalServerTransientError(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidAccessLevel(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidArgument(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidAttachmentId(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidAttachmentSubfilter(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidAttachmentSubfilterTextFilter(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidAuthorizationContext(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidChangeKey(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidClientSecurityContext(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidCompleteDate(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidContactEmailAddress(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidContactEmailIndex(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidCrossForestCredentials(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidDelegatePermission(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidDelegateUserId(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidExchangeImpersonationHeaderData(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidExcludesRestriction(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidExpressionTypeForSubFilter(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidExtendedProperty(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidExtendedPropertyValue(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidExternalSharingInitiator(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidExternalSharingSubscriber(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidFederatedOrganizationId(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidFolderId(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidFolderTypeForOperation(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidFractionalPagingParameters(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidFreeBusyViewType(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidGetSharingFolderRequest(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidId(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidIdEmpty(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidIdMalformed(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidIdMalformedEwsLegacyIdFormat(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidIdMonikerTooLong(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidIdNotAnItemAttachmentId(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidIdReturnedByResolveNames(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidIdStoreObjectIdTooLong(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidIdTooManyAttachmentLevels(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidIdXml(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidIndexedPagingParameters(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidInternetHeaderChildNodes(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidItemForOperationAcceptItem(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidItemForOperationCancelItem(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidItemForOperationCreateItem(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidItemForOperationCreateItemAttachment(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidItemForOperationDeclineItem(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidItemForOperationExpandDL(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidItemForOperationRemoveItem(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidItemForOperationSendItem(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidItemForOperationTentative(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidLicense(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidLogonType(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidMailbox(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidManagedFolderProperty(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidManagedFolderQuota(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidManagedFolderSize(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidMergedFreeBusyInterval(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidNameForNameResolution(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidNetworkServiceContext(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidOofParameter(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidOperation(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidOrganizationRelationshipForFreeBusy(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidPagingMaxRows(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidParentFolder(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidPercentCompleteValue(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidPermissionSettings(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidPhoneCallId(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidPhoneNumber(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidPropertyAppend(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidPropertyDelete(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidPropertyForExists(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidPropertyForOperation(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidPropertyRequest(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidPropertySet(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidPropertyUpdateSentMessage(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidProxySecurityContext(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidPullSubscriptionId(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidPushSubscriptionUrl(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidRecipients(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidRecipientSubfilter(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidRecipientSubfilterComparison(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidRecipientSubfilterOrder(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidRecipientSubfilterTextFilter(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidReferenceItem(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidRequest(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidRestriction(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidRoutingType(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidScheduledOofDuration(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidSchemaVersionForMailboxVersion(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidSecurityDescriptor(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidSendItemSaveSettings(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidSerializedAccessToken(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidServerVersion(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidSharingData(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidSharingMessage(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidSid(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidSIPUri(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidSmtpAddress(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidSubfilterType(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidSubfilterTypeNotAttendeeType(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidSubfilterTypeNotRecipientType(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidSubscription(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidSubscriptionRequest(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidSyncStateData(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidTimeInterval(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidUserInfo(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidUserOofSettings(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidUserPrincipalName(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidUserSid(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidUserSidMissingUPN(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidValueForProperty(ResponseMessageError):
+ pass
+
+
+class ErrorInvalidWatermark(ResponseMessageError):
+ pass
+
+
+class ErrorIPGatewayNotFound(ResponseMessageError):
+ pass
+
+
+class ErrorIrresolvableConflict(ResponseMessageError):
+ pass
+
+
+class ErrorItemCorrupt(ResponseMessageError):
+ pass
+
+
+class ErrorItemNotFound(ResponseMessageError):
+ pass
+
+
+class ErrorItemPropertyRequestFailed(ResponseMessageError):
+ pass
+
+
+class ErrorItemSave(ResponseMessageError):
+ pass
+
+
+class ErrorItemSavePropertyError(ResponseMessageError):
+ pass
+
+
+class ErrorLegacyMailboxFreeBusyViewTypeNotMerged(ResponseMessageError):
+ pass
+
+
+class ErrorLocalServerObjectNotFound(ResponseMessageError):
+ pass
+
+
+class ErrorLogonAsNetworkServiceFailed(ResponseMessageError):
+ pass
+
+
+class ErrorMailboxConfiguration(ResponseMessageError):
+ pass
+
+
+class ErrorMailboxDataArrayEmpty(ResponseMessageError):
+ pass
+
+
+class ErrorMailboxDataArrayTooBig(ResponseMessageError):
+ pass
+
+
+class ErrorMailboxFailover(ResponseMessageError):
+ pass
+
+
+class ErrorMailboxLogonFailed(ResponseMessageError):
+ pass
+
+
+class ErrorMailboxMoveInProgress(ResponseMessageError):
+ pass
+
+
+class ErrorMailboxStoreUnavailable(ResponseMessageError):
+ pass
+
+
+class ErrorMailRecipientNotFound(ResponseMessageError):
+ pass
+
+
+class ErrorMailTipsDisabled(ResponseMessageError):
+ pass
+
+
+class ErrorManagedFolderAlreadyExists(ResponseMessageError):
+ pass
+
+
+class ErrorManagedFolderNotFound(ResponseMessageError):
+ pass
+
+
+class ErrorManagedFoldersRootFailure(ResponseMessageError):
+ pass
+
+
+class ErrorMeetingSuggestionGenerationFailed(ResponseMessageError):
+ pass
+
+
+class ErrorMessageDispositionRequired(ResponseMessageError):
+ pass
+
+
+class ErrorMessageSizeExceeded(ResponseMessageError):
+ pass
+
+
+class ErrorMessageTrackingNoSuchDomain(ResponseMessageError):
+ pass
+
+
+class ErrorMessageTrackingPermanentError(ResponseMessageError):
+ pass
+
+
+class ErrorMessageTrackingTransientError(ResponseMessageError):
+ pass
+
+
+class ErrorMimeContentConversionFailed(ResponseMessageError):
+ pass
+
+
+class ErrorMimeContentInvalid(ResponseMessageError):
+ pass
+
+
+class ErrorMimeContentInvalidBase64String(ResponseMessageError):
+ pass
+
+
+class ErrorMissedNotificationEvents(ResponseMessageError):
+ pass
+
+
+class ErrorMissingArgument(ResponseMessageError):
+ pass
+
+
+class ErrorMissingEmailAddress(ResponseMessageError):
+ pass
+
+
+class ErrorMissingEmailAddressForManagedFolder(ResponseMessageError):
+ pass
+
+
+class ErrorMissingInformationEmailAddress(ResponseMessageError):
+ pass
+
+
+class ErrorMissingInformationReferenceItemId(ResponseMessageError):
+ pass
+
+
+class ErrorMissingInformationSharingFolderId(ResponseMessageError):
+ pass
+
+
+class ErrorMissingItemForCreateItemAttachment(ResponseMessageError):
+ pass
+
+
+class ErrorMissingManagedFolderId(ResponseMessageError):
+ pass
+
+
+class ErrorMissingRecipients(ResponseMessageError):
+ pass
+
+
+class ErrorMissingUserIdInformation(ResponseMessageError):
+ pass
+
+
+class ErrorMoreThanOneAccessModeSpecified(ResponseMessageError):
+ pass
+
+
+class ErrorMoveCopyFailed(ResponseMessageError):
+ pass
+
+
+class ErrorMoveDistinguishedFolder(ResponseMessageError):
+ pass
+
+
+class ErrorNameResolutionMultipleResults(ResponseMessageError):
+ pass
+
+
+class ErrorNameResolutionNoMailbox(ResponseMessageError):
+ pass
+
+
+class ErrorNameResolutionNoResults(ResponseMessageError):
+ pass
+
+
+class ErrorNewEventStreamConnectionOpened(ResponseMessageError):
+ pass
+
+
+class ErrorNoApplicableProxyCASServersAvailable(ResponseMessageError):
+ pass
+
+
+class ErrorNoCalendar(ResponseMessageError):
+ pass
+
+
+class ErrorNoDestinationCASDueToKerberosRequirements(ResponseMessageError):
+ pass
+
+
+class ErrorNoDestinationCASDueToSSLRequirements(ResponseMessageError):
+ pass
+
+
+class ErrorNoDestinationCASDueToVersionMismatch(ResponseMessageError):
+ pass
+
+
+class ErrorNoFolderClassOverride(ResponseMessageError):
+ pass
+
+
+class ErrorNoFreeBusyAccess(ResponseMessageError):
+ pass
+
+
+class ErrorNonExistentMailbox(ResponseMessageError):
+ pass
+
+
+class ErrorNonPrimarySmtpAddress(ResponseMessageError):
+ pass
+
+
+class ErrorNoPropertyTagForCustomProperties(ResponseMessageError):
+ pass
+
+
+class ErrorNoPublicFolderReplicaAvailable(ResponseMessageError):
+ pass
+
+
+class ErrorNoPublicFolderServerAvailable(ResponseMessageError):
+ pass
+
+
+class ErrorNoRespondingCASInDestinationSite(ResponseMessageError):
+ pass
+
+
+class ErrorNotAllowedExternalSharingByPolicy(ResponseMessageError):
+ pass
+
+
+class ErrorNotDelegate(ResponseMessageError):
+ pass
+
+
+class ErrorNotEnoughMemory(ResponseMessageError):
+ pass
+
+
+class ErrorNotSupportedSharingMessage(ResponseMessageError):
+ pass
+
+
+class ErrorObjectTypeChanged(ResponseMessageError):
+ pass
+
+
+class ErrorOccurrenceCrossingBoundary(ResponseMessageError):
+ pass
+
+
+class ErrorOccurrenceTimeSpanTooBig(ResponseMessageError):
+ pass
+
+
+class ErrorOperationNotAllowedWithPublicFolderRoot(ResponseMessageError):
+ pass
+
+
+class ErrorOrganizationNotFederated(ResponseMessageError):
+ pass
+
+
+class ErrorOutlookRuleBlobExists(ResponseMessageError):
+ pass
+
+
+class ErrorParentFolderIdRequired(ResponseMessageError):
+ pass
+
+
+class ErrorParentFolderNotFound(ResponseMessageError):
+ pass
+
+
+class ErrorPasswordChangeRequired(ResponseMessageError):
+ pass
+
+
+class ErrorPasswordExpired(ResponseMessageError):
+ pass
+
+
+class ErrorPermissionNotAllowedByPolicy(ResponseMessageError):
+ pass
+
+
+class ErrorPhoneNumberNotDialable(ResponseMessageError):
+ pass
+
+
+class ErrorPropertyUpdate(ResponseMessageError):
+ pass
+
+
+class ErrorPropertyValidationFailure(ResponseMessageError):
+ pass
+
+
+class ErrorProxiedSubscriptionCallFailure(ResponseMessageError):
+ pass
+
+
+class ErrorProxyCallFailed(ResponseMessageError):
+ pass
+
+
+class ErrorProxyGroupSidLimitExceeded(ResponseMessageError):
+ pass
+
+
+class ErrorProxyRequestNotAllowed(ResponseMessageError):
+ pass
+
+
+class ErrorProxyRequestProcessingFailed(ResponseMessageError):
+ pass
+
+
+class ErrorProxyServiceDiscoveryFailed(ResponseMessageError):
+ pass
+
+
+class ErrorProxyTokenExpired(ResponseMessageError):
+ pass
+
+
+class ErrorPublicFolderRequestProcessingFailed(ResponseMessageError):
+ pass
+
+
+class ErrorPublicFolderServerNotFound(ResponseMessageError):
+ pass
+
+
+class ErrorQueryFilterTooLong(ResponseMessageError):
+ pass
+
+
+class ErrorQuotaExceeded(ResponseMessageError):
+ pass
+
+
+class ErrorReadEventsFailed(ResponseMessageError):
+ pass
+
+
+class ErrorReadReceiptNotPending(ResponseMessageError):
+ pass
+
+
+class ErrorRecurrenceEndDateTooBig(ResponseMessageError):
+ pass
+
+
+class ErrorRecurrenceHasNoOccurrence(ResponseMessageError):
+ pass
+
+
+class ErrorRemoveDelegatesFailed(ResponseMessageError):
+ pass
+
+
+class ErrorRequestAborted(ResponseMessageError):
+ pass
+
+
+class ErrorRequestStreamTooBig(ResponseMessageError):
+ pass
+
+
+class ErrorRequiredPropertyMissing(ResponseMessageError):
+ pass
+
+
+class ErrorResolveNamesInvalidFolderType(ResponseMessageError):
+ pass
+
+
+class ErrorResolveNamesOnlyOneContactsFolderAllowed(ResponseMessageError):
+ pass
+
+
+class ErrorResponseSchemaValidation(ResponseMessageError):
+ pass
+
+
+class ErrorRestrictionTooComplex(ResponseMessageError):
+ pass
+
+
+class ErrorRestrictionTooLong(ResponseMessageError):
+ pass
+
+
+class ErrorResultSetTooBig(ResponseMessageError):
+ pass
+
+
+class ErrorRulesOverQuota(ResponseMessageError):
+ pass
+
+
+class ErrorSavedItemFolderNotFound(ResponseMessageError):
+ pass
+
+
+class ErrorSchemaValidation(ResponseMessageError):
+ pass
+
+
+class ErrorSearchFolderNotInitialized(ResponseMessageError):
+ pass
+
+
+class ErrorSendAsDenied(ResponseMessageError):
+ pass
+
+
+class ErrorSendMeetingCancellationsRequired(ResponseMessageError):
+ pass
+
+
+class ErrorSendMeetingInvitationsOrCancellationsRequired(ResponseMessageError):
+ pass
+
+
+class ErrorSendMeetingInvitationsRequired(ResponseMessageError):
+ pass
+
+
+class ErrorSentMeetingRequestUpdate(ResponseMessageError):
+ pass
+
+
+class ErrorSentTaskRequestUpdate(ResponseMessageError):
+ pass
+
+
+class ErrorServerBusy(ResponseMessageError):
+ def __init__(self, *args, **kwargs):
+ self.back_off = kwargs.pop("back_off", None) # Requested back off value in seconds
+ super().__init__(*args, **kwargs)
+
+
+class ErrorServiceDiscoveryFailed(ResponseMessageError):
+ pass
+
+
+class ErrorSharingNoExternalEwsAvailable(ResponseMessageError):
+ pass
-class ErrorServerBusy(ResponseMessageError):
- def __init__(self, *args, **kwargs):
- self.back_off = kwargs.pop('back_off', None) # Requested back off value in seconds
- super().__init__(*args, **kwargs)
+class ErrorSharingSynchronizationFailed(ResponseMessageError):
+ pass
+
+
+class ErrorStaleObject(ResponseMessageError):
+ pass
+
+
+class ErrorSubmissionQuotaExceeded(ResponseMessageError):
+ pass
+
+
+class ErrorSubscriptionAccessDenied(ResponseMessageError):
+ pass
+
+
+class ErrorSubscriptionDelegateAccessNotSupported(ResponseMessageError):
+ pass
+
+
+class ErrorSubscriptionNotFound(ResponseMessageError):
+ pass
+
+
+class ErrorSubscriptionUnsubsribed(ResponseMessageError):
+ pass
+
+
+class ErrorSyncFolderNotFound(ResponseMessageError):
+ pass
+
+
+class ErrorTimeIntervalTooBig(ResponseMessageError):
+ pass
+
+
+class ErrorTimeoutExpired(ResponseMessageError):
+ pass
+
+
+class ErrorTimeZone(ResponseMessageError):
+ pass
+
+
+class ErrorToFolderNotFound(ResponseMessageError):
+ pass
+
+
+class ErrorTokenSerializationDenied(ResponseMessageError):
+ pass
+
+
+class ErrorTooManyObjectsOpened(ResponseMessageError):
+ pass
+
+
+class ErrorUnableToGetUserOofSettings(ResponseMessageError):
+ pass
+
+
+class ErrorUnifiedMessagingDialPlanNotFound(ResponseMessageError):
+ pass
+
+
+class ErrorUnifiedMessagingRequestFailed(ResponseMessageError):
+ pass
+
+
+class ErrorUnifiedMessagingServerNotFound(ResponseMessageError):
+ pass
+
+
+class ErrorUnsupportedCulture(ResponseMessageError):
+ pass
+
+
+class ErrorUnsupportedMapiPropertyType(ResponseMessageError):
+ pass
+
+
+class ErrorUnsupportedMimeConversion(ResponseMessageError):
+ pass
+
+
+class ErrorUnsupportedPathForQuery(ResponseMessageError):
+ pass
+
+
+class ErrorUnsupportedPathForSortGroup(ResponseMessageError):
+ pass
+
+
+class ErrorUnsupportedPropertyDefinition(ResponseMessageError):
+ pass
+
+
+class ErrorUnsupportedQueryFilter(ResponseMessageError):
+ pass
+
+
+class ErrorUnsupportedRecurrence(ResponseMessageError):
+ pass
+
+
+class ErrorUnsupportedSubFilter(ResponseMessageError):
+ pass
+
+
+class ErrorUnsupportedTypeForConversion(ResponseMessageError):
+ pass
+
+
+class ErrorUpdateDelegatesFailed(ResponseMessageError):
+ pass
+
+
+class ErrorUpdatePropertyMismatch(ResponseMessageError):
+ pass
+
+
+class ErrorUserNotAllowedByPolicy(ResponseMessageError):
+ pass
+
+
+class ErrorUserNotUnifiedMessagingEnabled(ResponseMessageError):
+ pass
+
+
+class ErrorUserWithoutFederatedProxyAddress(ResponseMessageError):
+ pass
+
+
+class ErrorValueOutOfRange(ResponseMessageError):
+ pass
+
+
+class ErrorVirusDetected(ResponseMessageError):
+ pass
+
+
+class ErrorVirusMessageDeleted(ResponseMessageError):
+ pass
+
+
+class ErrorVoiceMailNotImplemented(ResponseMessageError):
+ pass
+
+
+class ErrorWebRequestInInvalidState(ResponseMessageError):
+ pass
+
+
+class ErrorWin32InteropError(ResponseMessageError):
+ pass
+
+
+class ErrorWorkingHoursSaveFailed(ResponseMessageError):
+ pass
+
+
+class ErrorWorkingHoursXmlMalformed(ResponseMessageError):
+ pass
+
+
+class ErrorWrongServerVersion(ResponseMessageError):
+ pass
-class ErrorServiceDiscoveryFailed(ResponseMessageError): pass
-class ErrorSharingNoExternalEwsAvailable(ResponseMessageError): pass
-class ErrorSharingSynchronizationFailed(ResponseMessageError): pass
-class ErrorStaleObject(ResponseMessageError): pass
-class ErrorSubmissionQuotaExceeded(ResponseMessageError): pass
-class ErrorSubscriptionAccessDenied(ResponseMessageError): pass
-class ErrorSubscriptionDelegateAccessNotSupported(ResponseMessageError): pass
-class ErrorSubscriptionNotFound(ResponseMessageError): pass
-class ErrorSubscriptionUnsubsribed(ResponseMessageError): pass
-class ErrorSyncFolderNotFound(ResponseMessageError): pass
-class ErrorTimeIntervalTooBig(ResponseMessageError): pass
-class ErrorTimeoutExpired(ResponseMessageError): pass
-class ErrorTimeZone(ResponseMessageError): pass
-class ErrorToFolderNotFound(ResponseMessageError): pass
-class ErrorTokenSerializationDenied(ResponseMessageError): pass
-class ErrorTooManyObjectsOpened(ResponseMessageError): pass
-class ErrorUnableToGetUserOofSettings(ResponseMessageError): pass
-class ErrorUnifiedMessagingDialPlanNotFound(ResponseMessageError): pass
-class ErrorUnifiedMessagingRequestFailed(ResponseMessageError): pass
-class ErrorUnifiedMessagingServerNotFound(ResponseMessageError): pass
-class ErrorUnsupportedCulture(ResponseMessageError): pass
-class ErrorUnsupportedMapiPropertyType(ResponseMessageError): pass
-class ErrorUnsupportedMimeConversion(ResponseMessageError): pass
-class ErrorUnsupportedPathForQuery(ResponseMessageError): pass
-class ErrorUnsupportedPathForSortGroup(ResponseMessageError): pass
-class ErrorUnsupportedPropertyDefinition(ResponseMessageError): pass
-class ErrorUnsupportedQueryFilter(ResponseMessageError): pass
-class ErrorUnsupportedRecurrence(ResponseMessageError): pass
-class ErrorUnsupportedSubFilter(ResponseMessageError): pass
-class ErrorUnsupportedTypeForConversion(ResponseMessageError): pass
-class ErrorUpdateDelegatesFailed(ResponseMessageError): pass
-class ErrorUpdatePropertyMismatch(ResponseMessageError): pass
-class ErrorUserNotAllowedByPolicy(ResponseMessageError): pass
-class ErrorUserNotUnifiedMessagingEnabled(ResponseMessageError): pass
-class ErrorUserWithoutFederatedProxyAddress(ResponseMessageError): pass
-class ErrorValueOutOfRange(ResponseMessageError): pass
-class ErrorVirusDetected(ResponseMessageError): pass
-class ErrorVirusMessageDeleted(ResponseMessageError): pass
-class ErrorVoiceMailNotImplemented(ResponseMessageError): pass
-class ErrorWebRequestInInvalidState(ResponseMessageError): pass
-class ErrorWin32InteropError(ResponseMessageError): pass
-class ErrorWorkingHoursSaveFailed(ResponseMessageError): pass
-class ErrorWorkingHoursXmlMalformed(ResponseMessageError): pass
-class ErrorWrongServerVersion(ResponseMessageError): pass
-class ErrorWrongServerVersionDelegate(ResponseMessageError): pass
+class ErrorWrongServerVersionDelegate(ResponseMessageError):
+ pass
# Microsoft recommends to cache the autodiscover data around 24 hours and perform autodiscover
@@ -695,7 +1841,7 @@ Ancestors
super().__init__(str(self))
def __str__(self):
- return f'CAS error: {self.cas_error}'
+ return f"CAS error: {self.cas_error}"
class ErrorADOperation(ResponseMessageError): pass
+class ErrorADOperation(ResponseMessageError):
+ pass
class ErrorADSessionFilter(ResponseMessageError): pass
+class ErrorADSessionFilter(ResponseMessageError):
+ pass
class ErrorADUnavailable(ResponseMessageError): pass
+class ErrorADUnavailable(ResponseMessageError):
+ pass
class ErrorAccessDenied(ResponseMessageError): pass
+class ErrorAccessDenied(ResponseMessageError):
+ pass
class ErrorAccessModeSpecified(ResponseMessageError): pass
+class ErrorAccessModeSpecified(ResponseMessageError):
+ pass
class ErrorAccountDisabled(ResponseMessageError): pass
+class ErrorAccountDisabled(ResponseMessageError):
+ pass
class ErrorAddDelegatesFailed(ResponseMessageError): pass
+class ErrorAddDelegatesFailed(ResponseMessageError):
+ pass
class ErrorAddressSpaceNotFound(ResponseMessageError): pass
+class ErrorAddressSpaceNotFound(ResponseMessageError):
+ pass
class ErrorAffectedTaskOccurrencesRequired(ResponseMessageError): pass
+class ErrorAffectedTaskOccurrencesRequired(ResponseMessageError):
+ pass
class ErrorApplyConversationActionFailed(ResponseMessageError): pass
+class ErrorApplyConversationActionFailed(ResponseMessageError):
+ pass
class ErrorAttachmentSizeLimitExceeded(ResponseMessageError): pass
+class ErrorAttachmentSizeLimitExceeded(ResponseMessageError):
+ pass
class ErrorAutoDiscoverFailed(ResponseMessageError): pass
+class ErrorAutoDiscoverFailed(ResponseMessageError):
+ pass
class ErrorAvailabilityConfigNotFound(ResponseMessageError): pass
+class ErrorAvailabilityConfigNotFound(ResponseMessageError):
+ pass
class ErrorBatchProcessingStopped(ResponseMessageError): pass
+class ErrorBatchProcessingStopped(ResponseMessageError):
+ pass
class ErrorCalendarCannotMoveOrCopyOccurrence(ResponseMessageError): pass
+class ErrorCalendarCannotMoveOrCopyOccurrence(ResponseMessageError):
+ pass
class ErrorCalendarCannotUpdateDeletedItem(ResponseMessageError): pass
+class ErrorCalendarCannotUpdateDeletedItem(ResponseMessageError):
+ pass
class ErrorCalendarCannotUseIdForOccurrenceId(ResponseMessageError): pass
+class ErrorCalendarCannotUseIdForOccurrenceId(ResponseMessageError):
+ pass
class ErrorCalendarCannotUseIdForRecurringMasterId(ResponseMessageError): pass
+class ErrorCalendarCannotUseIdForRecurringMasterId(ResponseMessageError):
+ pass
class ErrorCalendarDurationIsTooLong(ResponseMessageError): pass
+class ErrorCalendarDurationIsTooLong(ResponseMessageError):
+ pass
class ErrorCalendarEndDateIsEarlierThanStartDate(ResponseMessageError): pass
+class ErrorCalendarEndDateIsEarlierThanStartDate(ResponseMessageError):
+ pass
class ErrorCalendarFolderIsInvalidForCalendarView(ResponseMessageError): pass
+class ErrorCalendarFolderIsInvalidForCalendarView(ResponseMessageError):
+ pass
class ErrorCalendarInvalidAttributeValue(ResponseMessageError): pass
+class ErrorCalendarInvalidAttributeValue(ResponseMessageError):
+ pass
class ErrorCalendarInvalidDayForTimeChangePattern(ResponseMessageError): pass
+class ErrorCalendarInvalidDayForTimeChangePattern(ResponseMessageError):
+ pass
class ErrorCalendarInvalidDayForWeeklyRecurrence(ResponseMessageError): pass
+class ErrorCalendarInvalidDayForWeeklyRecurrence(ResponseMessageError):
+ pass
class ErrorCalendarInvalidPropertyState(ResponseMessageError): pass
+class ErrorCalendarInvalidPropertyState(ResponseMessageError):
+ pass
class ErrorCalendarInvalidPropertyValue(ResponseMessageError): pass
+class ErrorCalendarInvalidPropertyValue(ResponseMessageError):
+ pass
class ErrorCalendarInvalidRecurrence(ResponseMessageError): pass
+class ErrorCalendarInvalidRecurrence(ResponseMessageError):
+ pass
class ErrorCalendarInvalidTimeZone(ResponseMessageError): pass
+class ErrorCalendarInvalidTimeZone(ResponseMessageError):
+ pass
class ErrorCalendarIsCancelledForAccept(ResponseMessageError): pass
+class ErrorCalendarIsCancelledForAccept(ResponseMessageError):
+ pass
class ErrorCalendarIsCancelledForDecline(ResponseMessageError): pass
+class ErrorCalendarIsCancelledForDecline(ResponseMessageError):
+ pass
class ErrorCalendarIsCancelledForRemove(ResponseMessageError): pass
+class ErrorCalendarIsCancelledForRemove(ResponseMessageError):
+ pass
class ErrorCalendarIsCancelledForTentative(ResponseMessageError): pass
+class ErrorCalendarIsCancelledForTentative(ResponseMessageError):
+ pass
class ErrorCalendarIsDelegatedForAccept(ResponseMessageError): pass
+class ErrorCalendarIsDelegatedForAccept(ResponseMessageError):
+ pass
class ErrorCalendarIsDelegatedForDecline(ResponseMessageError): pass
+class ErrorCalendarIsDelegatedForDecline(ResponseMessageError):
+ pass
class ErrorCalendarIsDelegatedForRemove(ResponseMessageError): pass
+class ErrorCalendarIsDelegatedForRemove(ResponseMessageError):
+ pass
class ErrorCalendarIsDelegatedForTentative(ResponseMessageError): pass
+class ErrorCalendarIsDelegatedForTentative(ResponseMessageError):
+ pass
class ErrorCalendarIsNotOrganizer(ResponseMessageError): pass
+class ErrorCalendarIsNotOrganizer(ResponseMessageError):
+ pass
class ErrorCalendarIsOrganizerForAccept(ResponseMessageError): pass
+class ErrorCalendarIsOrganizerForAccept(ResponseMessageError):
+ pass
class ErrorCalendarIsOrganizerForDecline(ResponseMessageError): pass
+class ErrorCalendarIsOrganizerForDecline(ResponseMessageError):
+ pass
class ErrorCalendarIsOrganizerForRemove(ResponseMessageError): pass
+class ErrorCalendarIsOrganizerForRemove(ResponseMessageError):
+ pass
class ErrorCalendarIsOrganizerForTentative(ResponseMessageError): pass
+class ErrorCalendarIsOrganizerForTentative(ResponseMessageError):
+ pass
class ErrorCalendarMeetingRequestIsOutOfDate(ResponseMessageError): pass
+class ErrorCalendarMeetingRequestIsOutOfDate(ResponseMessageError):
+ pass
class ErrorCalendarOccurrenceIndexIsOutOfRecurrenceRange(ResponseMessageError): pass
+class ErrorCalendarOccurrenceIndexIsOutOfRecurrenceRange(ResponseMessageError):
+ pass
class ErrorCalendarOccurrenceIsDeletedFromRecurrence(ResponseMessageError): pass
+class ErrorCalendarOccurrenceIsDeletedFromRecurrence(ResponseMessageError):
+ pass
class ErrorCalendarOutOfRange(ResponseMessageError): pass
+class ErrorCalendarOutOfRange(ResponseMessageError):
+ pass
class ErrorCalendarViewRangeTooBig(ResponseMessageError): pass
+class ErrorCalendarViewRangeTooBig(ResponseMessageError):
+ pass
class ErrorCallerIsInvalidADAccount(ResponseMessageError): pass
+class ErrorCallerIsInvalidADAccount(ResponseMessageError):
+ pass
class ErrorCannotCreateCalendarItemInNonCalendarFolder(ResponseMessageError): pass
+class ErrorCannotCreateCalendarItemInNonCalendarFolder(ResponseMessageError):
+ pass
class ErrorCannotCreateContactInNonContactFolder(ResponseMessageError): pass
+class ErrorCannotCreateContactInNonContactFolder(ResponseMessageError):
+ pass
class ErrorCannotCreatePostItemInNonMailFolder(ResponseMessageError): pass
+class ErrorCannotCreatePostItemInNonMailFolder(ResponseMessageError):
+ pass
class ErrorCannotCreateTaskInNonTaskFolder(ResponseMessageError): pass
+class ErrorCannotCreateTaskInNonTaskFolder(ResponseMessageError):
+ pass
class ErrorCannotDeleteObject(ResponseMessageError): pass
+class ErrorCannotDeleteObject(ResponseMessageError):
+ pass
class ErrorCannotDeleteTaskOccurrence(ResponseMessageError): pass
+class ErrorCannotDeleteTaskOccurrence(ResponseMessageError):
+ pass
class ErrorCannotEmptyFolder(ResponseMessageError): pass
+class ErrorCannotEmptyFolder(ResponseMessageError):
+ pass
class ErrorCannotOpenFileAttachment(ResponseMessageError): pass
+class ErrorCannotOpenFileAttachment(ResponseMessageError):
+ pass
class ErrorCannotSetCalendarPermissionOnNonCalendarFolder(ResponseMessageError): pass
+class ErrorCannotSetCalendarPermissionOnNonCalendarFolder(ResponseMessageError):
+ pass
class ErrorCannotSetNonCalendarPermissionOnCalendarFolder(ResponseMessageError): pass
+class ErrorCannotSetNonCalendarPermissionOnCalendarFolder(ResponseMessageError):
+ pass
class ErrorCannotSetPermissionUnknownEntries(ResponseMessageError): pass
+class ErrorCannotSetPermissionUnknownEntries(ResponseMessageError):
+ pass
class ErrorCannotUseFolderIdForItemId(ResponseMessageError): pass
+class ErrorCannotUseFolderIdForItemId(ResponseMessageError):
+ pass
class ErrorCannotUseItemIdForFolderId(ResponseMessageError): pass
+class ErrorCannotUseItemIdForFolderId(ResponseMessageError):
+ pass
class ErrorChangeKeyRequired(ResponseMessageError): pass
+class ErrorChangeKeyRequired(ResponseMessageError):
+ pass
class ErrorChangeKeyRequiredForWriteOperations(ResponseMessageError): pass
+class ErrorChangeKeyRequiredForWriteOperations(ResponseMessageError):
+ pass
class ErrorClientDisconnected(ResponseMessageError): pass
+class ErrorClientDisconnected(ResponseMessageError):
+ pass
class ErrorConnectionFailed(ResponseMessageError): pass
+class ErrorConnectionFailed(ResponseMessageError):
+ pass
class ErrorConnectionFailedTransientError(ResponseMessageError): pass
+class ErrorConnectionFailedTransientError(ResponseMessageError):
+ pass
class ErrorContainsFilterWrongType(ResponseMessageError): pass
+class ErrorContainsFilterWrongType(ResponseMessageError):
+ pass
class ErrorContentConversionFailed(ResponseMessageError): pass
+class ErrorContentConversionFailed(ResponseMessageError):
+ pass
class ErrorCorruptData(ResponseMessageError): pass
+class ErrorCorruptData(ResponseMessageError):
+ pass
class ErrorCreateItemAccessDenied(ResponseMessageError): pass
+class ErrorCreateItemAccessDenied(ResponseMessageError):
+ pass
class ErrorCreateManagedFolderPartialCompletion(ResponseMessageError): pass
+class ErrorCreateManagedFolderPartialCompletion(ResponseMessageError):
+ pass
class ErrorCreateSubfolderAccessDenied(ResponseMessageError): pass
+class ErrorCreateSubfolderAccessDenied(ResponseMessageError):
+ pass
class ErrorCrossMailboxMoveCopy(ResponseMessageError): pass
+class ErrorCrossMailboxMoveCopy(ResponseMessageError):
+ pass
class ErrorCrossSiteRequest(ResponseMessageError): pass
+class ErrorCrossSiteRequest(ResponseMessageError):
+ pass
class ErrorDataSizeLimitExceeded(ResponseMessageError): pass
+class ErrorDataSizeLimitExceeded(ResponseMessageError):
+ pass
class ErrorDataSourceOperation(ResponseMessageError): pass
+class ErrorDataSourceOperation(ResponseMessageError):
+ pass
class ErrorDelegateAlreadyExists(ResponseMessageError): pass
+class ErrorDelegateAlreadyExists(ResponseMessageError):
+ pass
class ErrorDelegateCannotAddOwner(ResponseMessageError): pass
+class ErrorDelegateCannotAddOwner(ResponseMessageError):
+ pass
class ErrorDelegateMissingConfiguration(ResponseMessageError): pass
+class ErrorDelegateMissingConfiguration(ResponseMessageError):
+ pass
class ErrorDelegateNoUser(ResponseMessageError): pass
+class ErrorDelegateNoUser(ResponseMessageError):
+ pass
class ErrorDelegateValidationFailed(ResponseMessageError): pass
+class ErrorDelegateValidationFailed(ResponseMessageError):
+ pass
class ErrorDeleteDistinguishedFolder(ResponseMessageError): pass
+class ErrorDeleteDistinguishedFolder(ResponseMessageError):
+ pass
class ErrorDeleteItemsFailed(ResponseMessageError): pass
+class ErrorDeleteItemsFailed(ResponseMessageError):
+ pass
class ErrorDistinguishedUserNotSupported(ResponseMessageError): pass
+class ErrorDistinguishedUserNotSupported(ResponseMessageError):
+ pass
class ErrorDistributionListMemberNotExist(ResponseMessageError): pass
+class ErrorDistributionListMemberNotExist(ResponseMessageError):
+ pass
class ErrorDuplicateInputFolderNames(ResponseMessageError): pass
+class ErrorDuplicateInputFolderNames(ResponseMessageError):
+ pass
class ErrorDuplicateSOAPHeader(ResponseMessageError): pass
+class ErrorDuplicateSOAPHeader(ResponseMessageError):
+ pass
class ErrorDuplicateUserIdsSpecified(ResponseMessageError): pass
+class ErrorDuplicateUserIdsSpecified(ResponseMessageError):
+ pass
class ErrorEmailAddressMismatch(ResponseMessageError): pass
+class ErrorEmailAddressMismatch(ResponseMessageError):
+ pass
class ErrorEventNotFound(ResponseMessageError): pass
+class ErrorEventNotFound(ResponseMessageError):
+ pass
class ErrorExceededConnectionCount(ResponseMessageError): pass
+class ErrorExceededConnectionCount(ResponseMessageError):
+ pass
class ErrorExceededFindCountLimit(ResponseMessageError): pass
+class ErrorExceededFindCountLimit(ResponseMessageError):
+ pass
class ErrorExceededSubscriptionCount(ResponseMessageError): pass
+class ErrorExceededSubscriptionCount(ResponseMessageError):
+ pass
class ErrorExpiredSubscription(ResponseMessageError): pass
+class ErrorExpiredSubscription(ResponseMessageError):
+ pass
class ErrorFolderCorrupt(ResponseMessageError): pass
+class ErrorFolderCorrupt(ResponseMessageError):
+ pass
class ErrorFolderExists(ResponseMessageError): pass
+class ErrorFolderExists(ResponseMessageError):
+ pass
class ErrorFolderNotFound(ResponseMessageError): pass
+class ErrorFolderNotFound(ResponseMessageError):
+ pass
class ErrorFolderPropertyRequestFailed(ResponseMessageError): pass
+class ErrorFolderPropertyRequestFailed(ResponseMessageError):
+ pass
class ErrorFolderSave(ResponseMessageError): pass
+class ErrorFolderSave(ResponseMessageError):
+ pass
class ErrorFolderSaveFailed(ResponseMessageError): pass
+class ErrorFolderSaveFailed(ResponseMessageError):
+ pass
class ErrorFolderSavePropertyError(ResponseMessageError): pass
+class ErrorFolderSavePropertyError(ResponseMessageError):
+ pass
class ErrorFreeBusyDLLimitReached(ResponseMessageError): pass
+class ErrorFreeBusyDLLimitReached(ResponseMessageError):
+ pass
class ErrorFreeBusyGenerationFailed(ResponseMessageError): pass
+class ErrorFreeBusyGenerationFailed(ResponseMessageError):
+ pass
class ErrorGetServerSecurityDescriptorFailed(ResponseMessageError): pass
+class ErrorGetServerSecurityDescriptorFailed(ResponseMessageError):
+ pass
class ErrorIPGatewayNotFound(ResponseMessageError): pass
+class ErrorIPGatewayNotFound(ResponseMessageError):
+ pass
class ErrorImpersonateUserDenied(ResponseMessageError): pass
+class ErrorImpersonateUserDenied(ResponseMessageError):
+ pass
class ErrorImpersonationDenied(ResponseMessageError): pass
+class ErrorImpersonationDenied(ResponseMessageError):
+ pass
class ErrorImpersonationFailed(ResponseMessageError): pass
+class ErrorImpersonationFailed(ResponseMessageError):
+ pass
class ErrorInboxRulesValidationError(ResponseMessageError): pass
+class ErrorInboxRulesValidationError(ResponseMessageError):
+ pass
class ErrorIncorrectSchemaVersion(ResponseMessageError): pass
+class ErrorIncorrectSchemaVersion(ResponseMessageError):
+ pass
class ErrorIncorrectUpdatePropertyCount(ResponseMessageError): pass
+class ErrorIncorrectUpdatePropertyCount(ResponseMessageError):
+ pass
class ErrorIndividualMailboxLimitReached(ResponseMessageError): pass
+class ErrorIndividualMailboxLimitReached(ResponseMessageError):
+ pass
class ErrorInsufficientResources(ResponseMessageError): pass
+class ErrorInsufficientResources(ResponseMessageError):
+ pass
class ErrorInternalServerError(ResponseMessageError): pass
+class ErrorInternalServerError(ResponseMessageError):
+ pass
class ErrorInternalServerTransientError(ResponseMessageError): pass
+class ErrorInternalServerTransientError(ResponseMessageError):
+ pass
class ErrorInvalidAccessLevel(ResponseMessageError): pass
+class ErrorInvalidAccessLevel(ResponseMessageError):
+ pass
class ErrorInvalidArgument(ResponseMessageError): pass
+class ErrorInvalidArgument(ResponseMessageError):
+ pass
class ErrorInvalidAttachmentId(ResponseMessageError): pass
+class ErrorInvalidAttachmentId(ResponseMessageError):
+ pass
class ErrorInvalidAttachmentSubfilter(ResponseMessageError): pass
+class ErrorInvalidAttachmentSubfilter(ResponseMessageError):
+ pass
class ErrorInvalidAttachmentSubfilterTextFilter(ResponseMessageError): pass
+class ErrorInvalidAttachmentSubfilterTextFilter(ResponseMessageError):
+ pass
class ErrorInvalidAuthorizationContext(ResponseMessageError): pass
+class ErrorInvalidAuthorizationContext(ResponseMessageError):
+ pass
class ErrorInvalidChangeKey(ResponseMessageError): pass
+class ErrorInvalidChangeKey(ResponseMessageError):
+ pass
class ErrorInvalidClientSecurityContext(ResponseMessageError): pass
+class ErrorInvalidClientSecurityContext(ResponseMessageError):
+ pass
class ErrorInvalidCompleteDate(ResponseMessageError): pass
+class ErrorInvalidCompleteDate(ResponseMessageError):
+ pass
class ErrorInvalidContactEmailAddress(ResponseMessageError): pass
+class ErrorInvalidContactEmailAddress(ResponseMessageError):
+ pass
class ErrorInvalidContactEmailIndex(ResponseMessageError): pass
+class ErrorInvalidContactEmailIndex(ResponseMessageError):
+ pass
class ErrorInvalidCrossForestCredentials(ResponseMessageError): pass
+class ErrorInvalidCrossForestCredentials(ResponseMessageError):
+ pass
class ErrorInvalidDelegatePermission(ResponseMessageError): pass
+class ErrorInvalidDelegatePermission(ResponseMessageError):
+ pass
class ErrorInvalidDelegateUserId(ResponseMessageError): pass
+class ErrorInvalidDelegateUserId(ResponseMessageError):
+ pass
class ErrorInvalidExchangeImpersonationHeaderData(ResponseMessageError): pass
+class ErrorInvalidExchangeImpersonationHeaderData(ResponseMessageError):
+ pass
class ErrorInvalidExcludesRestriction(ResponseMessageError): pass
+class ErrorInvalidExcludesRestriction(ResponseMessageError):
+ pass
class ErrorInvalidExpressionTypeForSubFilter(ResponseMessageError): pass
+class ErrorInvalidExpressionTypeForSubFilter(ResponseMessageError):
+ pass
class ErrorInvalidExtendedProperty(ResponseMessageError): pass
+class ErrorInvalidExtendedProperty(ResponseMessageError):
+ pass
class ErrorInvalidExtendedPropertyValue(ResponseMessageError): pass
+class ErrorInvalidExtendedPropertyValue(ResponseMessageError):
+ pass
class ErrorInvalidExternalSharingInitiator(ResponseMessageError): pass
+class ErrorInvalidExternalSharingInitiator(ResponseMessageError):
+ pass
class ErrorInvalidExternalSharingSubscriber(ResponseMessageError): pass
+class ErrorInvalidExternalSharingSubscriber(ResponseMessageError):
+ pass
class ErrorInvalidFederatedOrganizationId(ResponseMessageError): pass
+class ErrorInvalidFederatedOrganizationId(ResponseMessageError):
+ pass
class ErrorInvalidFolderId(ResponseMessageError): pass
+class ErrorInvalidFolderId(ResponseMessageError):
+ pass
class ErrorInvalidFolderTypeForOperation(ResponseMessageError): pass
+class ErrorInvalidFolderTypeForOperation(ResponseMessageError):
+ pass
class ErrorInvalidFractionalPagingParameters(ResponseMessageError): pass
+class ErrorInvalidFractionalPagingParameters(ResponseMessageError):
+ pass
class ErrorInvalidFreeBusyViewType(ResponseMessageError): pass
+class ErrorInvalidFreeBusyViewType(ResponseMessageError):
+ pass
class ErrorInvalidGetSharingFolderRequest(ResponseMessageError): pass
+class ErrorInvalidGetSharingFolderRequest(ResponseMessageError):
+ pass
class ErrorInvalidId(ResponseMessageError): pass
+class ErrorInvalidId(ResponseMessageError):
+ pass
class ErrorInvalidIdEmpty(ResponseMessageError): pass
+class ErrorInvalidIdEmpty(ResponseMessageError):
+ pass
class ErrorInvalidIdMalformed(ResponseMessageError): pass
+class ErrorInvalidIdMalformed(ResponseMessageError):
+ pass
class ErrorInvalidIdMalformedEwsLegacyIdFormat(ResponseMessageError): pass
+class ErrorInvalidIdMalformedEwsLegacyIdFormat(ResponseMessageError):
+ pass
class ErrorInvalidIdMonikerTooLong(ResponseMessageError): pass
+class ErrorInvalidIdMonikerTooLong(ResponseMessageError):
+ pass
class ErrorInvalidIdNotAnItemAttachmentId(ResponseMessageError): pass
+class ErrorInvalidIdNotAnItemAttachmentId(ResponseMessageError):
+ pass
class ErrorInvalidIdReturnedByResolveNames(ResponseMessageError): pass
+class ErrorInvalidIdReturnedByResolveNames(ResponseMessageError):
+ pass
class ErrorInvalidIdStoreObjectIdTooLong(ResponseMessageError): pass
+class ErrorInvalidIdStoreObjectIdTooLong(ResponseMessageError):
+ pass
class ErrorInvalidIdTooManyAttachmentLevels(ResponseMessageError): pass
+class ErrorInvalidIdTooManyAttachmentLevels(ResponseMessageError):
+ pass
class ErrorInvalidIdXml(ResponseMessageError): pass
+class ErrorInvalidIdXml(ResponseMessageError):
+ pass
class ErrorInvalidIndexedPagingParameters(ResponseMessageError): pass
+class ErrorInvalidIndexedPagingParameters(ResponseMessageError):
+ pass
class ErrorInvalidInternetHeaderChildNodes(ResponseMessageError): pass
+class ErrorInvalidInternetHeaderChildNodes(ResponseMessageError):
+ pass
class ErrorInvalidItemForOperationAcceptItem(ResponseMessageError): pass
+class ErrorInvalidItemForOperationAcceptItem(ResponseMessageError):
+ pass
class ErrorInvalidItemForOperationCancelItem(ResponseMessageError): pass
+class ErrorInvalidItemForOperationCancelItem(ResponseMessageError):
+ pass
class ErrorInvalidItemForOperationCreateItem(ResponseMessageError): pass
+class ErrorInvalidItemForOperationCreateItem(ResponseMessageError):
+ pass
class ErrorInvalidItemForOperationCreateItemAttachment(ResponseMessageError): pass
+class ErrorInvalidItemForOperationCreateItemAttachment(ResponseMessageError):
+ pass
class ErrorInvalidItemForOperationDeclineItem(ResponseMessageError): pass
+class ErrorInvalidItemForOperationDeclineItem(ResponseMessageError):
+ pass
class ErrorInvalidItemForOperationExpandDL(ResponseMessageError): pass
+class ErrorInvalidItemForOperationExpandDL(ResponseMessageError):
+ pass
class ErrorInvalidItemForOperationRemoveItem(ResponseMessageError): pass
+class ErrorInvalidItemForOperationRemoveItem(ResponseMessageError):
+ pass
class ErrorInvalidItemForOperationSendItem(ResponseMessageError): pass
+class ErrorInvalidItemForOperationSendItem(ResponseMessageError):
+ pass
class ErrorInvalidItemForOperationTentative(ResponseMessageError): pass
+class ErrorInvalidItemForOperationTentative(ResponseMessageError):
+ pass
class ErrorInvalidLicense(ResponseMessageError): pass
+class ErrorInvalidLicense(ResponseMessageError):
+ pass
class ErrorInvalidLogonType(ResponseMessageError): pass
+class ErrorInvalidLogonType(ResponseMessageError):
+ pass
class ErrorInvalidMailbox(ResponseMessageError): pass
+class ErrorInvalidMailbox(ResponseMessageError):
+ pass
class ErrorInvalidManagedFolderProperty(ResponseMessageError): pass
+class ErrorInvalidManagedFolderProperty(ResponseMessageError):
+ pass
class ErrorInvalidManagedFolderQuota(ResponseMessageError): pass
+class ErrorInvalidManagedFolderQuota(ResponseMessageError):
+ pass
class ErrorInvalidManagedFolderSize(ResponseMessageError): pass
+class ErrorInvalidManagedFolderSize(ResponseMessageError):
+ pass
class ErrorInvalidMergedFreeBusyInterval(ResponseMessageError): pass
+class ErrorInvalidMergedFreeBusyInterval(ResponseMessageError):
+ pass
class ErrorInvalidNameForNameResolution(ResponseMessageError): pass
+class ErrorInvalidNameForNameResolution(ResponseMessageError):
+ pass
class ErrorInvalidNetworkServiceContext(ResponseMessageError): pass
+class ErrorInvalidNetworkServiceContext(ResponseMessageError):
+ pass
class ErrorInvalidOofParameter(ResponseMessageError): pass
+class ErrorInvalidOofParameter(ResponseMessageError):
+ pass
class ErrorInvalidOperation(ResponseMessageError): pass
+class ErrorInvalidOperation(ResponseMessageError):
+ pass
class ErrorInvalidOrganizationRelationshipForFreeBusy(ResponseMessageError): pass
+class ErrorInvalidOrganizationRelationshipForFreeBusy(ResponseMessageError):
+ pass
class ErrorInvalidPagingMaxRows(ResponseMessageError): pass
+class ErrorInvalidPagingMaxRows(ResponseMessageError):
+ pass
class ErrorInvalidParentFolder(ResponseMessageError): pass
+class ErrorInvalidParentFolder(ResponseMessageError):
+ pass
class ErrorInvalidPercentCompleteValue(ResponseMessageError): pass
+class ErrorInvalidPercentCompleteValue(ResponseMessageError):
+ pass
class ErrorInvalidPermissionSettings(ResponseMessageError): pass
+class ErrorInvalidPermissionSettings(ResponseMessageError):
+ pass
class ErrorInvalidPhoneCallId(ResponseMessageError): pass
+class ErrorInvalidPhoneCallId(ResponseMessageError):
+ pass
class ErrorInvalidPhoneNumber(ResponseMessageError): pass
+class ErrorInvalidPhoneNumber(ResponseMessageError):
+ pass
class ErrorInvalidPropertyAppend(ResponseMessageError): pass
+class ErrorInvalidPropertyAppend(ResponseMessageError):
+ pass
class ErrorInvalidPropertyDelete(ResponseMessageError): pass
+class ErrorInvalidPropertyDelete(ResponseMessageError):
+ pass
class ErrorInvalidPropertyForExists(ResponseMessageError): pass
+class ErrorInvalidPropertyForExists(ResponseMessageError):
+ pass
class ErrorInvalidPropertyForOperation(ResponseMessageError): pass
+class ErrorInvalidPropertyForOperation(ResponseMessageError):
+ pass
class ErrorInvalidPropertyRequest(ResponseMessageError): pass
+class ErrorInvalidPropertyRequest(ResponseMessageError):
+ pass
class ErrorInvalidPropertySet(ResponseMessageError): pass
+class ErrorInvalidPropertySet(ResponseMessageError):
+ pass
class ErrorInvalidPropertyUpdateSentMessage(ResponseMessageError): pass
+class ErrorInvalidPropertyUpdateSentMessage(ResponseMessageError):
+ pass
class ErrorInvalidProxySecurityContext(ResponseMessageError): pass
+class ErrorInvalidProxySecurityContext(ResponseMessageError):
+ pass
class ErrorInvalidPullSubscriptionId(ResponseMessageError): pass
+class ErrorInvalidPullSubscriptionId(ResponseMessageError):
+ pass
class ErrorInvalidPushSubscriptionUrl(ResponseMessageError): pass
+class ErrorInvalidPushSubscriptionUrl(ResponseMessageError):
+ pass
class ErrorInvalidRecipientSubfilter(ResponseMessageError): pass
+class ErrorInvalidRecipientSubfilter(ResponseMessageError):
+ pass
class ErrorInvalidRecipientSubfilterComparison(ResponseMessageError): pass
+class ErrorInvalidRecipientSubfilterComparison(ResponseMessageError):
+ pass
class ErrorInvalidRecipientSubfilterOrder(ResponseMessageError): pass
+class ErrorInvalidRecipientSubfilterOrder(ResponseMessageError):
+ pass
class ErrorInvalidRecipientSubfilterTextFilter(ResponseMessageError): pass
+class ErrorInvalidRecipientSubfilterTextFilter(ResponseMessageError):
+ pass
class ErrorInvalidRecipients(ResponseMessageError): pass
+class ErrorInvalidRecipients(ResponseMessageError):
+ pass
class ErrorInvalidReferenceItem(ResponseMessageError): pass
+class ErrorInvalidReferenceItem(ResponseMessageError):
+ pass
class ErrorInvalidRequest(ResponseMessageError): pass
+class ErrorInvalidRequest(ResponseMessageError):
+ pass
class ErrorInvalidRestriction(ResponseMessageError): pass
+class ErrorInvalidRestriction(ResponseMessageError):
+ pass
class ErrorInvalidRoutingType(ResponseMessageError): pass
+class ErrorInvalidRoutingType(ResponseMessageError):
+ pass
class ErrorInvalidSIPUri(ResponseMessageError): pass
+class ErrorInvalidSIPUri(ResponseMessageError):
+ pass
class ErrorInvalidScheduledOofDuration(ResponseMessageError): pass
+class ErrorInvalidScheduledOofDuration(ResponseMessageError):
+ pass
class ErrorInvalidSchemaVersionForMailboxVersion(ResponseMessageError): pass
+class ErrorInvalidSchemaVersionForMailboxVersion(ResponseMessageError):
+ pass
class ErrorInvalidSecurityDescriptor(ResponseMessageError): pass
+class ErrorInvalidSecurityDescriptor(ResponseMessageError):
+ pass
class ErrorInvalidSendItemSaveSettings(ResponseMessageError): pass
+class ErrorInvalidSendItemSaveSettings(ResponseMessageError):
+ pass
class ErrorInvalidSerializedAccessToken(ResponseMessageError): pass
+class ErrorInvalidSerializedAccessToken(ResponseMessageError):
+ pass
class ErrorInvalidServerVersion(ResponseMessageError): pass
+class ErrorInvalidServerVersion(ResponseMessageError):
+ pass
class ErrorInvalidSharingData(ResponseMessageError): pass
+class ErrorInvalidSharingData(ResponseMessageError):
+ pass
class ErrorInvalidSharingMessage(ResponseMessageError): pass
+class ErrorInvalidSharingMessage(ResponseMessageError):
+ pass
class ErrorInvalidSid(ResponseMessageError): pass
+class ErrorInvalidSid(ResponseMessageError):
+ pass
class ErrorInvalidSmtpAddress(ResponseMessageError): pass
+class ErrorInvalidSmtpAddress(ResponseMessageError):
+ pass
class ErrorInvalidSubfilterType(ResponseMessageError): pass
+class ErrorInvalidSubfilterType(ResponseMessageError):
+ pass
class ErrorInvalidSubfilterTypeNotAttendeeType(ResponseMessageError): pass
+class ErrorInvalidSubfilterTypeNotAttendeeType(ResponseMessageError):
+ pass
class ErrorInvalidSubfilterTypeNotRecipientType(ResponseMessageError): pass
+class ErrorInvalidSubfilterTypeNotRecipientType(ResponseMessageError):
+ pass
class ErrorInvalidSubscription(ResponseMessageError): pass
+class ErrorInvalidSubscription(ResponseMessageError):
+ pass
class ErrorInvalidSubscriptionRequest(ResponseMessageError): pass
+class ErrorInvalidSubscriptionRequest(ResponseMessageError):
+ pass
class ErrorInvalidSyncStateData(ResponseMessageError): pass
+class ErrorInvalidSyncStateData(ResponseMessageError):
+ pass
class ErrorInvalidTimeInterval(ResponseMessageError): pass
+class ErrorInvalidTimeInterval(ResponseMessageError):
+ pass
class ErrorInvalidUserInfo(ResponseMessageError): pass
+class ErrorInvalidUserInfo(ResponseMessageError):
+ pass
class ErrorInvalidUserOofSettings(ResponseMessageError): pass
+class ErrorInvalidUserOofSettings(ResponseMessageError):
+ pass
class ErrorInvalidUserPrincipalName(ResponseMessageError): pass
+class ErrorInvalidUserPrincipalName(ResponseMessageError):
+ pass
class ErrorInvalidUserSid(ResponseMessageError): pass
+class ErrorInvalidUserSid(ResponseMessageError):
+ pass
class ErrorInvalidUserSidMissingUPN(ResponseMessageError): pass
+class ErrorInvalidUserSidMissingUPN(ResponseMessageError):
+ pass
class ErrorInvalidValueForProperty(ResponseMessageError): pass
+class ErrorInvalidValueForProperty(ResponseMessageError):
+ pass
class ErrorInvalidWatermark(ResponseMessageError): pass
+class ErrorInvalidWatermark(ResponseMessageError):
+ pass
class ErrorIrresolvableConflict(ResponseMessageError): pass
+class ErrorIrresolvableConflict(ResponseMessageError):
+ pass
class ErrorItemCorrupt(ResponseMessageError): pass
+class ErrorItemCorrupt(ResponseMessageError):
+ pass
class ErrorItemNotFound(ResponseMessageError): pass
+class ErrorItemNotFound(ResponseMessageError):
+ pass
class ErrorItemPropertyRequestFailed(ResponseMessageError): pass
+class ErrorItemPropertyRequestFailed(ResponseMessageError):
+ pass
class ErrorItemSave(ResponseMessageError): pass
+class ErrorItemSave(ResponseMessageError):
+ pass
class ErrorItemSavePropertyError(ResponseMessageError): pass
+class ErrorItemSavePropertyError(ResponseMessageError):
+ pass
class ErrorLegacyMailboxFreeBusyViewTypeNotMerged(ResponseMessageError): pass
+class ErrorLegacyMailboxFreeBusyViewTypeNotMerged(ResponseMessageError):
+ pass
class ErrorLocalServerObjectNotFound(ResponseMessageError): pass
+class ErrorLocalServerObjectNotFound(ResponseMessageError):
+ pass
class ErrorLogonAsNetworkServiceFailed(ResponseMessageError): pass
+class ErrorLogonAsNetworkServiceFailed(ResponseMessageError):
+ pass
class ErrorMailRecipientNotFound(ResponseMessageError): pass
+class ErrorMailRecipientNotFound(ResponseMessageError):
+ pass
class ErrorMailTipsDisabled(ResponseMessageError): pass
+class ErrorMailTipsDisabled(ResponseMessageError):
+ pass
class ErrorMailboxConfiguration(ResponseMessageError): pass
+class ErrorMailboxConfiguration(ResponseMessageError):
+ pass
class ErrorMailboxDataArrayEmpty(ResponseMessageError): pass
+class ErrorMailboxDataArrayEmpty(ResponseMessageError):
+ pass
class ErrorMailboxDataArrayTooBig(ResponseMessageError): pass
+class ErrorMailboxDataArrayTooBig(ResponseMessageError):
+ pass
class ErrorMailboxFailover(ResponseMessageError): pass
+class ErrorMailboxFailover(ResponseMessageError):
+ pass
class ErrorMailboxLogonFailed(ResponseMessageError): pass
+class ErrorMailboxLogonFailed(ResponseMessageError):
+ pass
class ErrorMailboxMoveInProgress(ResponseMessageError): pass
+class ErrorMailboxMoveInProgress(ResponseMessageError):
+ pass
class ErrorMailboxStoreUnavailable(ResponseMessageError): pass
+class ErrorMailboxStoreUnavailable(ResponseMessageError):
+ pass
class ErrorManagedFolderAlreadyExists(ResponseMessageError): pass
+class ErrorManagedFolderAlreadyExists(ResponseMessageError):
+ pass
class ErrorManagedFolderNotFound(ResponseMessageError): pass
+class ErrorManagedFolderNotFound(ResponseMessageError):
+ pass
class ErrorManagedFoldersRootFailure(ResponseMessageError): pass
+class ErrorManagedFoldersRootFailure(ResponseMessageError):
+ pass
class ErrorMeetingSuggestionGenerationFailed(ResponseMessageError): pass
+class ErrorMeetingSuggestionGenerationFailed(ResponseMessageError):
+ pass
class ErrorMessageDispositionRequired(ResponseMessageError): pass
+class ErrorMessageDispositionRequired(ResponseMessageError):
+ pass
class ErrorMessageSizeExceeded(ResponseMessageError): pass
+class ErrorMessageSizeExceeded(ResponseMessageError):
+ pass
class ErrorMessageTrackingNoSuchDomain(ResponseMessageError): pass
+class ErrorMessageTrackingNoSuchDomain(ResponseMessageError):
+ pass
class ErrorMessageTrackingPermanentError(ResponseMessageError): pass
+class ErrorMessageTrackingPermanentError(ResponseMessageError):
+ pass
class ErrorMessageTrackingTransientError(ResponseMessageError): pass
+class ErrorMessageTrackingTransientError(ResponseMessageError):
+ pass
class ErrorMimeContentConversionFailed(ResponseMessageError): pass
+class ErrorMimeContentConversionFailed(ResponseMessageError):
+ pass
class ErrorMimeContentInvalid(ResponseMessageError): pass
+class ErrorMimeContentInvalid(ResponseMessageError):
+ pass
class ErrorMimeContentInvalidBase64String(ResponseMessageError): pass
+class ErrorMimeContentInvalidBase64String(ResponseMessageError):
+ pass
class ErrorMissedNotificationEvents(ResponseMessageError): pass
+class ErrorMissedNotificationEvents(ResponseMessageError):
+ pass
class ErrorMissingArgument(ResponseMessageError): pass
+class ErrorMissingArgument(ResponseMessageError):
+ pass
class ErrorMissingEmailAddress(ResponseMessageError): pass
+class ErrorMissingEmailAddress(ResponseMessageError):
+ pass
class ErrorMissingEmailAddressForManagedFolder(ResponseMessageError): pass
+class ErrorMissingEmailAddressForManagedFolder(ResponseMessageError):
+ pass
class ErrorMissingInformationEmailAddress(ResponseMessageError): pass
+class ErrorMissingInformationEmailAddress(ResponseMessageError):
+ pass
class ErrorMissingInformationReferenceItemId(ResponseMessageError): pass
+class ErrorMissingInformationReferenceItemId(ResponseMessageError):
+ pass
class ErrorMissingInformationSharingFolderId(ResponseMessageError): pass
+class ErrorMissingInformationSharingFolderId(ResponseMessageError):
+ pass
class ErrorMissingItemForCreateItemAttachment(ResponseMessageError): pass
+class ErrorMissingItemForCreateItemAttachment(ResponseMessageError):
+ pass
class ErrorMissingManagedFolderId(ResponseMessageError): pass
+class ErrorMissingManagedFolderId(ResponseMessageError):
+ pass
class ErrorMissingRecipients(ResponseMessageError): pass
+class ErrorMissingRecipients(ResponseMessageError):
+ pass
class ErrorMissingUserIdInformation(ResponseMessageError): pass
+class ErrorMissingUserIdInformation(ResponseMessageError):
+ pass
class ErrorMoreThanOneAccessModeSpecified(ResponseMessageError): pass
+class ErrorMoreThanOneAccessModeSpecified(ResponseMessageError):
+ pass
class ErrorMoveCopyFailed(ResponseMessageError): pass
+class ErrorMoveCopyFailed(ResponseMessageError):
+ pass
class ErrorMoveDistinguishedFolder(ResponseMessageError): pass
+class ErrorMoveDistinguishedFolder(ResponseMessageError):
+ pass
class ErrorNameResolutionMultipleResults(ResponseMessageError): pass
+class ErrorNameResolutionMultipleResults(ResponseMessageError):
+ pass
class ErrorNameResolutionNoMailbox(ResponseMessageError): pass
+class ErrorNameResolutionNoMailbox(ResponseMessageError):
+ pass
class ErrorNameResolutionNoResults(ResponseMessageError): pass
+class ErrorNameResolutionNoResults(ResponseMessageError):
+ pass
class ErrorNewEventStreamConnectionOpened(ResponseMessageError): pass
+class ErrorNewEventStreamConnectionOpened(ResponseMessageError):
+ pass
class ErrorNoApplicableProxyCASServersAvailable(ResponseMessageError): pass
+class ErrorNoApplicableProxyCASServersAvailable(ResponseMessageError):
+ pass
class ErrorNoCalendar(ResponseMessageError): pass
+class ErrorNoCalendar(ResponseMessageError):
+ pass
class ErrorNoDestinationCASDueToKerberosRequirements(ResponseMessageError): pass
+class ErrorNoDestinationCASDueToKerberosRequirements(ResponseMessageError):
+ pass
class ErrorNoDestinationCASDueToSSLRequirements(ResponseMessageError): pass
+class ErrorNoDestinationCASDueToSSLRequirements(ResponseMessageError):
+ pass
class ErrorNoDestinationCASDueToVersionMismatch(ResponseMessageError): pass
+class ErrorNoDestinationCASDueToVersionMismatch(ResponseMessageError):
+ pass
class ErrorNoFolderClassOverride(ResponseMessageError): pass
+class ErrorNoFolderClassOverride(ResponseMessageError):
+ pass
class ErrorNoFreeBusyAccess(ResponseMessageError): pass
+class ErrorNoFreeBusyAccess(ResponseMessageError):
+ pass
class ErrorNoPropertyTagForCustomProperties(ResponseMessageError): pass
+class ErrorNoPropertyTagForCustomProperties(ResponseMessageError):
+ pass
class ErrorNoPublicFolderReplicaAvailable(ResponseMessageError): pass
+class ErrorNoPublicFolderReplicaAvailable(ResponseMessageError):
+ pass
class ErrorNoPublicFolderServerAvailable(ResponseMessageError): pass
+class ErrorNoPublicFolderServerAvailable(ResponseMessageError):
+ pass
class ErrorNoRespondingCASInDestinationSite(ResponseMessageError): pass
+class ErrorNoRespondingCASInDestinationSite(ResponseMessageError):
+ pass
class ErrorNonExistentMailbox(ResponseMessageError): pass
+class ErrorNonExistentMailbox(ResponseMessageError):
+ pass
class ErrorNonPrimarySmtpAddress(ResponseMessageError): pass
+class ErrorNonPrimarySmtpAddress(ResponseMessageError):
+ pass
class ErrorNotAllowedExternalSharingByPolicy(ResponseMessageError): pass
+class ErrorNotAllowedExternalSharingByPolicy(ResponseMessageError):
+ pass
class ErrorNotDelegate(ResponseMessageError): pass
+class ErrorNotDelegate(ResponseMessageError):
+ pass
class ErrorNotEnoughMemory(ResponseMessageError): pass
+class ErrorNotEnoughMemory(ResponseMessageError):
+ pass
class ErrorNotSupportedSharingMessage(ResponseMessageError): pass
+class ErrorNotSupportedSharingMessage(ResponseMessageError):
+ pass
class ErrorObjectTypeChanged(ResponseMessageError): pass
+class ErrorObjectTypeChanged(ResponseMessageError):
+ pass
class ErrorOccurrenceCrossingBoundary(ResponseMessageError): pass
+class ErrorOccurrenceCrossingBoundary(ResponseMessageError):
+ pass
class ErrorOccurrenceTimeSpanTooBig(ResponseMessageError): pass
+class ErrorOccurrenceTimeSpanTooBig(ResponseMessageError):
+ pass
class ErrorOperationNotAllowedWithPublicFolderRoot(ResponseMessageError): pass
+class ErrorOperationNotAllowedWithPublicFolderRoot(ResponseMessageError):
+ pass
class ErrorOrganizationNotFederated(ResponseMessageError): pass
+class ErrorOrganizationNotFederated(ResponseMessageError):
+ pass
class ErrorOutlookRuleBlobExists(ResponseMessageError): pass
+class ErrorOutlookRuleBlobExists(ResponseMessageError):
+ pass
class ErrorParentFolderIdRequired(ResponseMessageError): pass
+class ErrorParentFolderIdRequired(ResponseMessageError):
+ pass
class ErrorParentFolderNotFound(ResponseMessageError): pass
+class ErrorParentFolderNotFound(ResponseMessageError):
+ pass
class ErrorPasswordChangeRequired(ResponseMessageError): pass
+class ErrorPasswordChangeRequired(ResponseMessageError):
+ pass
class ErrorPasswordExpired(ResponseMessageError): pass
+class ErrorPasswordExpired(ResponseMessageError):
+ pass
class ErrorPermissionNotAllowedByPolicy(ResponseMessageError): pass
+class ErrorPermissionNotAllowedByPolicy(ResponseMessageError):
+ pass
class ErrorPhoneNumberNotDialable(ResponseMessageError): pass
+class ErrorPhoneNumberNotDialable(ResponseMessageError):
+ pass
class ErrorPropertyUpdate(ResponseMessageError): pass
+class ErrorPropertyUpdate(ResponseMessageError):
+ pass
class ErrorPropertyValidationFailure(ResponseMessageError): pass
+class ErrorPropertyValidationFailure(ResponseMessageError):
+ pass
class ErrorProxiedSubscriptionCallFailure(ResponseMessageError): pass
+class ErrorProxiedSubscriptionCallFailure(ResponseMessageError):
+ pass
class ErrorProxyCallFailed(ResponseMessageError): pass
+class ErrorProxyCallFailed(ResponseMessageError):
+ pass
class ErrorProxyGroupSidLimitExceeded(ResponseMessageError): pass
+class ErrorProxyGroupSidLimitExceeded(ResponseMessageError):
+ pass
class ErrorProxyRequestNotAllowed(ResponseMessageError): pass
+class ErrorProxyRequestNotAllowed(ResponseMessageError):
+ pass
class ErrorProxyRequestProcessingFailed(ResponseMessageError): pass
+class ErrorProxyRequestProcessingFailed(ResponseMessageError):
+ pass
class ErrorProxyServiceDiscoveryFailed(ResponseMessageError): pass
+class ErrorProxyServiceDiscoveryFailed(ResponseMessageError):
+ pass
class ErrorProxyTokenExpired(ResponseMessageError): pass
+class ErrorProxyTokenExpired(ResponseMessageError):
+ pass
class ErrorPublicFolderRequestProcessingFailed(ResponseMessageError): pass
+class ErrorPublicFolderRequestProcessingFailed(ResponseMessageError):
+ pass
class ErrorPublicFolderServerNotFound(ResponseMessageError): pass
+class ErrorPublicFolderServerNotFound(ResponseMessageError):
+ pass
class ErrorQueryFilterTooLong(ResponseMessageError): pass
+class ErrorQueryFilterTooLong(ResponseMessageError):
+ pass
class ErrorQuotaExceeded(ResponseMessageError): pass
+class ErrorQuotaExceeded(ResponseMessageError):
+ pass
class ErrorReadEventsFailed(ResponseMessageError): pass
+class ErrorReadEventsFailed(ResponseMessageError):
+ pass
class ErrorReadReceiptNotPending(ResponseMessageError): pass
+class ErrorReadReceiptNotPending(ResponseMessageError):
+ pass
class ErrorRecurrenceEndDateTooBig(ResponseMessageError): pass
+class ErrorRecurrenceEndDateTooBig(ResponseMessageError):
+ pass
class ErrorRecurrenceHasNoOccurrence(ResponseMessageError): pass
+class ErrorRecurrenceHasNoOccurrence(ResponseMessageError):
+ pass
class ErrorRemoveDelegatesFailed(ResponseMessageError): pass
+class ErrorRemoveDelegatesFailed(ResponseMessageError):
+ pass
class ErrorRequestAborted(ResponseMessageError): pass
+class ErrorRequestAborted(ResponseMessageError):
+ pass
class ErrorRequestStreamTooBig(ResponseMessageError): pass
+class ErrorRequestStreamTooBig(ResponseMessageError):
+ pass
class ErrorRequiredPropertyMissing(ResponseMessageError): pass
+class ErrorRequiredPropertyMissing(ResponseMessageError):
+ pass
class ErrorResolveNamesInvalidFolderType(ResponseMessageError): pass
+class ErrorResolveNamesInvalidFolderType(ResponseMessageError):
+ pass
class ErrorResolveNamesOnlyOneContactsFolderAllowed(ResponseMessageError): pass
+class ErrorResolveNamesOnlyOneContactsFolderAllowed(ResponseMessageError):
+ pass
class ErrorResponseSchemaValidation(ResponseMessageError): pass
+class ErrorResponseSchemaValidation(ResponseMessageError):
+ pass
class ErrorRestrictionTooComplex(ResponseMessageError): pass
+class ErrorRestrictionTooComplex(ResponseMessageError):
+ pass
class ErrorRestrictionTooLong(ResponseMessageError): pass
+class ErrorRestrictionTooLong(ResponseMessageError):
+ pass
class ErrorResultSetTooBig(ResponseMessageError): pass
+class ErrorResultSetTooBig(ResponseMessageError):
+ pass
class ErrorRulesOverQuota(ResponseMessageError): pass
+class ErrorRulesOverQuota(ResponseMessageError):
+ pass
class ErrorSavedItemFolderNotFound(ResponseMessageError): pass
+class ErrorSavedItemFolderNotFound(ResponseMessageError):
+ pass
class ErrorSchemaValidation(ResponseMessageError): pass
+class ErrorSchemaValidation(ResponseMessageError):
+ pass
class ErrorSearchFolderNotInitialized(ResponseMessageError): pass
+class ErrorSearchFolderNotInitialized(ResponseMessageError):
+ pass
class ErrorSendAsDenied(ResponseMessageError): pass
+class ErrorSendAsDenied(ResponseMessageError):
+ pass
class ErrorSendMeetingCancellationsRequired(ResponseMessageError): pass
+class ErrorSendMeetingCancellationsRequired(ResponseMessageError):
+ pass
class ErrorSendMeetingInvitationsOrCancellationsRequired(ResponseMessageError): pass
+class ErrorSendMeetingInvitationsOrCancellationsRequired(ResponseMessageError):
+ pass
class ErrorSendMeetingInvitationsRequired(ResponseMessageError): pass
+class ErrorSendMeetingInvitationsRequired(ResponseMessageError):
+ pass
class ErrorSentMeetingRequestUpdate(ResponseMessageError): pass
+class ErrorSentMeetingRequestUpdate(ResponseMessageError):
+ pass
class ErrorSentTaskRequestUpdate(ResponseMessageError): pass
+class ErrorSentTaskRequestUpdate(ResponseMessageError):
+ pass
class ErrorServerBusy(ResponseMessageError):
def __init__(self, *args, **kwargs):
- self.back_off = kwargs.pop('back_off', None) # Requested back off value in seconds
+ self.back_off = kwargs.pop("back_off", None) # Requested back off value in seconds
super().__init__(*args, **kwargs)
class ErrorServiceDiscoveryFailed(ResponseMessageError): pass
+class ErrorServiceDiscoveryFailed(ResponseMessageError):
+ pass
class ErrorSharingNoExternalEwsAvailable(ResponseMessageError): pass
+class ErrorSharingNoExternalEwsAvailable(ResponseMessageError):
+ pass
class ErrorSharingSynchronizationFailed(ResponseMessageError): pass
+class ErrorSharingSynchronizationFailed(ResponseMessageError):
+ pass
class ErrorStaleObject(ResponseMessageError): pass
+class ErrorStaleObject(ResponseMessageError):
+ pass
class ErrorSubmissionQuotaExceeded(ResponseMessageError): pass
+class ErrorSubmissionQuotaExceeded(ResponseMessageError):
+ pass
class ErrorSubscriptionAccessDenied(ResponseMessageError): pass
+class ErrorSubscriptionAccessDenied(ResponseMessageError):
+ pass
class ErrorSubscriptionDelegateAccessNotSupported(ResponseMessageError): pass
+class ErrorSubscriptionDelegateAccessNotSupported(ResponseMessageError):
+ pass
class ErrorSubscriptionNotFound(ResponseMessageError): pass
+class ErrorSubscriptionNotFound(ResponseMessageError):
+ pass
class ErrorSubscriptionUnsubsribed(ResponseMessageError): pass
+class ErrorSubscriptionUnsubsribed(ResponseMessageError):
+ pass
class ErrorSyncFolderNotFound(ResponseMessageError): pass
+class ErrorSyncFolderNotFound(ResponseMessageError):
+ pass
class ErrorTimeIntervalTooBig(ResponseMessageError): pass
+class ErrorTimeIntervalTooBig(ResponseMessageError):
+ pass
class ErrorTimeZone(ResponseMessageError): pass
+class ErrorTimeZone(ResponseMessageError):
+ pass
class ErrorTimeoutExpired(ResponseMessageError): pass
+class ErrorTimeoutExpired(ResponseMessageError):
+ pass
class ErrorToFolderNotFound(ResponseMessageError): pass
+class ErrorToFolderNotFound(ResponseMessageError):
+ pass
class ErrorTokenSerializationDenied(ResponseMessageError): pass
+class ErrorTokenSerializationDenied(ResponseMessageError):
+ pass
class ErrorTooManyObjectsOpened(ResponseMessageError): pass
+class ErrorTooManyObjectsOpened(ResponseMessageError):
+ pass
class ErrorUnableToGetUserOofSettings(ResponseMessageError): pass
+class ErrorUnableToGetUserOofSettings(ResponseMessageError):
+ pass
class ErrorUnifiedMessagingDialPlanNotFound(ResponseMessageError): pass
+class ErrorUnifiedMessagingDialPlanNotFound(ResponseMessageError):
+ pass
class ErrorUnifiedMessagingRequestFailed(ResponseMessageError): pass
+class ErrorUnifiedMessagingRequestFailed(ResponseMessageError):
+ pass
class ErrorUnifiedMessagingServerNotFound(ResponseMessageError): pass
+class ErrorUnifiedMessagingServerNotFound(ResponseMessageError):
+ pass
class ErrorUnsupportedCulture(ResponseMessageError): pass
+class ErrorUnsupportedCulture(ResponseMessageError):
+ pass
class ErrorUnsupportedMapiPropertyType(ResponseMessageError): pass
+class ErrorUnsupportedMapiPropertyType(ResponseMessageError):
+ pass
class ErrorUnsupportedMimeConversion(ResponseMessageError): pass
+class ErrorUnsupportedMimeConversion(ResponseMessageError):
+ pass
class ErrorUnsupportedPathForQuery(ResponseMessageError): pass
+class ErrorUnsupportedPathForQuery(ResponseMessageError):
+ pass
class ErrorUnsupportedPathForSortGroup(ResponseMessageError): pass
+class ErrorUnsupportedPathForSortGroup(ResponseMessageError):
+ pass
class ErrorUnsupportedPropertyDefinition(ResponseMessageError): pass
+class ErrorUnsupportedPropertyDefinition(ResponseMessageError):
+ pass
class ErrorUnsupportedQueryFilter(ResponseMessageError): pass
+class ErrorUnsupportedQueryFilter(ResponseMessageError):
+ pass
class ErrorUnsupportedRecurrence(ResponseMessageError): pass
+class ErrorUnsupportedRecurrence(ResponseMessageError):
+ pass
class ErrorUnsupportedSubFilter(ResponseMessageError): pass
+class ErrorUnsupportedSubFilter(ResponseMessageError):
+ pass
class ErrorUnsupportedTypeForConversion(ResponseMessageError): pass
+class ErrorUnsupportedTypeForConversion(ResponseMessageError):
+ pass
class ErrorUpdateDelegatesFailed(ResponseMessageError): pass
+class ErrorUpdateDelegatesFailed(ResponseMessageError):
+ pass
class ErrorUpdatePropertyMismatch(ResponseMessageError): pass
+class ErrorUpdatePropertyMismatch(ResponseMessageError):
+ pass
class ErrorUserNotAllowedByPolicy(ResponseMessageError): pass
+class ErrorUserNotAllowedByPolicy(ResponseMessageError):
+ pass
class ErrorUserNotUnifiedMessagingEnabled(ResponseMessageError): pass
+class ErrorUserNotUnifiedMessagingEnabled(ResponseMessageError):
+ pass
class ErrorUserWithoutFederatedProxyAddress(ResponseMessageError): pass
+class ErrorUserWithoutFederatedProxyAddress(ResponseMessageError):
+ pass
class ErrorValueOutOfRange(ResponseMessageError): pass
+class ErrorValueOutOfRange(ResponseMessageError):
+ pass
class ErrorVirusDetected(ResponseMessageError): pass
+class ErrorVirusDetected(ResponseMessageError):
+ pass
class ErrorVirusMessageDeleted(ResponseMessageError): pass
+class ErrorVirusMessageDeleted(ResponseMessageError):
+ pass
class ErrorVoiceMailNotImplemented(ResponseMessageError): pass
+class ErrorVoiceMailNotImplemented(ResponseMessageError):
+ pass
class ErrorWebRequestInInvalidState(ResponseMessageError): pass
+class ErrorWebRequestInInvalidState(ResponseMessageError):
+ pass
class ErrorWin32InteropError(ResponseMessageError): pass
+class ErrorWin32InteropError(ResponseMessageError):
+ pass
class ErrorWorkingHoursSaveFailed(ResponseMessageError): pass
+class ErrorWorkingHoursSaveFailed(ResponseMessageError):
+ pass
class ErrorWorkingHoursXmlMalformed(ResponseMessageError): pass
+class ErrorWorkingHoursXmlMalformed(ResponseMessageError):
+ pass
class ErrorWrongServerVersion(ResponseMessageError): pass
+class ErrorWrongServerVersion(ResponseMessageError):
+ pass
class ErrorWrongServerVersionDelegate(ResponseMessageError): pass
+class ErrorWrongServerVersionDelegate(ResponseMessageError):
+ pass
exchangelib.ewsdatetime
exchangelib.ewsdatetime
exchangelib.ewsdatetime
exchangelib.ewsdatetime
exchangelib.ewsdatetime
exchangelib.ewsdatetime
exchangelib.ewsdatetime
exchangelib.ewsdatetime
exchangelib.ewsdatetime
exchangelib.ewsdatetime
exchangelib.ewsdatetime
exchangelib.ewsdatetime
class EWSDate(datetime.date):
"""Extends the normal date implementation to satisfy EWS."""
- __slots__ = '_year', '_month', '_day', '_hashcode'
+ __slots__ = "_year", "_month", "_day", "_hashcode"
def ewsformat(self):
"""ISO 8601 format to satisfy xs:date as interpreted by EWS. Example: 2009-01-15."""
@@ -407,21 +408,21 @@ Classes
@classmethod
def from_date(cls, d):
if type(d) is not datetime.date:
- raise InvalidTypeError('d', d, datetime.date)
+ raise InvalidTypeError("d", d, datetime.date)
return cls(d.year, d.month, d.day)
@classmethod
def from_string(cls, date_string):
# Sometimes, we'll receive a date string with timezone information. Not very useful.
- if date_string.endswith('Z'):
- date_fmt = '%Y-%m-%dZ'
- elif ':' in date_string:
- if '+' in date_string:
- date_fmt = '%Y-%m-%d+%H:%M'
+ if date_string.endswith("Z"):
+ date_fmt = "%Y-%m-%dZ"
+ elif ":" in date_string:
+ if "+" in date_string:
+ date_fmt = "%Y-%m-%d+%H:%M"
else:
- date_fmt = '%Y-%m-%d-%H:%M'
+ date_fmt = "%Y-%m-%d-%H:%M"
else:
- date_fmt = '%Y-%m-%d'
+ date_fmt = "%Y-%m-%d"
d = datetime.datetime.strptime(date_string, date_fmt).date()
if isinstance(d, cls):
return d
@@ -445,7 +446,7 @@ Static methods
@classmethod
def from_date(cls, d):
if type(d) is not datetime.date:
- raise InvalidTypeError('d', d, datetime.date)
+ raise InvalidTypeError("d", d, datetime.date)
return cls(d.year, d.month, d.day)
@@ -461,15 +462,15 @@ Static methods
@classmethod
def from_string(cls, date_string):
# Sometimes, we'll receive a date string with timezone information. Not very useful.
- if date_string.endswith('Z'):
- date_fmt = '%Y-%m-%dZ'
- elif ':' in date_string:
- if '+' in date_string:
- date_fmt = '%Y-%m-%d+%H:%M'
+ if date_string.endswith("Z"):
+ date_fmt = "%Y-%m-%dZ"
+ elif ":" in date_string:
+ if "+" in date_string:
+ date_fmt = "%Y-%m-%d+%H:%M"
else:
- date_fmt = '%Y-%m-%d-%H:%M'
+ date_fmt = "%Y-%m-%d-%H:%M"
else:
- date_fmt = '%Y-%m-%d'
+ date_fmt = "%Y-%m-%d"
d = datetime.datetime.strptime(date_string, date_fmt).date()
if isinstance(d, cls):
return d
@@ -525,7 +526,7 @@ Methods
class EWSDateTime(datetime.datetime):
"""Extends the normal datetime implementation to satisfy EWS."""
- __slots__ = '_year', '_month', '_day', '_hour', '_minute', '_second', '_microsecond', '_tzinfo', '_hashcode'
+ __slots__ = "_year", "_month", "_day", "_hour", "_minute", "_second", "_microsecond", "_tzinfo", "_hashcode"
def __new__(cls, *args, **kwargs):
# pylint: disable=arguments-differ
@@ -533,16 +534,16 @@ Methods
if len(args) == 8:
tzinfo = args[7]
else:
- tzinfo = kwargs.get('tzinfo')
+ tzinfo = kwargs.get("tzinfo")
if isinstance(tzinfo, zoneinfo.ZoneInfo):
# Don't allow pytz or dateutil timezones here. They are not safe to use as direct input for datetime()
tzinfo = EWSTimeZone.from_timezone(tzinfo)
if not isinstance(tzinfo, (EWSTimeZone, type(None))):
- raise InvalidTypeError('tzinfo', tzinfo, EWSTimeZone)
+ raise InvalidTypeError("tzinfo", tzinfo, EWSTimeZone)
if len(args) == 8:
args = args[:7] + (tzinfo,)
else:
- kwargs['tzinfo'] = tzinfo
+ kwargs["tzinfo"] = tzinfo
return super().__new__(cls, *args, **kwargs)
def ewsformat(self):
@@ -551,17 +552,17 @@ Methods
* 2009-01-15T13:45:56+01:00
"""
if not self.tzinfo:
- raise ValueError(f'{self!r} must be timezone-aware')
- if self.tzinfo.key == 'UTC':
+ raise ValueError(f"{self!r} must be timezone-aware")
+ if self.tzinfo.key == "UTC":
if self.microsecond:
- return self.strftime('%Y-%m-%dT%H:%M:%S.%fZ')
- return self.strftime('%Y-%m-%dT%H:%M:%SZ')
+ return self.strftime("%Y-%m-%dT%H:%M:%S.%fZ")
+ return self.strftime("%Y-%m-%dT%H:%M:%SZ")
return self.isoformat()
@classmethod
def from_datetime(cls, d):
if type(d) is not datetime.datetime:
- raise InvalidTypeError('d', d, datetime.datetime)
+ raise InvalidTypeError("d", d, datetime.datetime)
if d.tzinfo is None:
tz = None
elif isinstance(d.tzinfo, EWSTimeZone):
@@ -601,12 +602,12 @@ Methods
@classmethod
def from_string(cls, date_string):
# Parses several common datetime formats and returns timezone-aware EWSDateTime objects
- if date_string.endswith('Z'):
+ if date_string.endswith("Z"):
# UTC datetime
- return super().strptime(date_string, '%Y-%m-%dT%H:%M:%SZ').replace(tzinfo=UTC)
+ return super().strptime(date_string, "%Y-%m-%dT%H:%M:%SZ").replace(tzinfo=UTC)
if len(date_string) == 19:
# This is probably a naive datetime. Don't allow this, but signal caller with an appropriate error
- local_dt = super().strptime(date_string, '%Y-%m-%dT%H:%M:%S')
+ local_dt = super().strptime(date_string, "%Y-%m-%dT%H:%M:%S")
raise NaiveDateTimeNotAllowed(local_dt)
# This is probably a datetime value with timezone information. This comes in the form '+/-HH:MM'.
aware_dt = datetime.datetime.fromisoformat(date_string).astimezone(UTC).replace(tzinfo=UTC)
@@ -667,7 +668,7 @@ Static methods
@classmethod
def from_datetime(cls, d):
if type(d) is not datetime.datetime:
- raise InvalidTypeError('d', d, datetime.datetime)
+ raise InvalidTypeError("d", d, datetime.datetime)
if d.tzinfo is None:
tz = None
elif isinstance(d.tzinfo, EWSTimeZone):
@@ -689,12 +690,12 @@ Static methods
@classmethod
def from_string(cls, date_string):
# Parses several common datetime formats and returns timezone-aware EWSDateTime objects
- if date_string.endswith('Z'):
+ if date_string.endswith("Z"):
# UTC datetime
- return super().strptime(date_string, '%Y-%m-%dT%H:%M:%SZ').replace(tzinfo=UTC)
+ return super().strptime(date_string, "%Y-%m-%dT%H:%M:%SZ").replace(tzinfo=UTC)
if len(date_string) == 19:
# This is probably a naive datetime. Don't allow this, but signal caller with an appropriate error
- local_dt = super().strptime(date_string, '%Y-%m-%dT%H:%M:%S')
+ local_dt = super().strptime(date_string, "%Y-%m-%dT%H:%M:%S")
raise NaiveDateTimeNotAllowed(local_dt)
# This is probably a datetime value with timezone information. This comes in the form '+/-HH:MM'.
aware_dt = datetime.datetime.fromisoformat(date_string).astimezone(UTC).replace(tzinfo=UTC)
@@ -828,11 +829,11 @@ Methods
* 2009-01-15T13:45:56+01:00
"""
if not self.tzinfo:
- raise ValueError(f'{self!r} must be timezone-aware')
- if self.tzinfo.key == 'UTC':
+ raise ValueError(f"{self!r} must be timezone-aware")
+ if self.tzinfo.key == "UTC":
if self.microsecond:
- return self.strftime('%Y-%m-%dT%H:%M:%S.%fZ')
- return self.strftime('%Y-%m-%dT%H:%M:%SZ')
+ return self.strftime("%Y-%m-%dT%H:%M:%S.%fZ")
+ return self.strftime("%Y-%m-%dT%H:%M:%SZ")
return self.isoformat()
@@ -865,12 +866,12 @@ Methods
try:
instance.ms_id = cls.IANA_TO_MS_MAP[instance.key][0]
except KeyError:
- raise UnknownTimeZone(f'No Windows timezone name found for timezone {instance.key!r}')
+ raise UnknownTimeZone(f"No Windows timezone name found for timezone {instance.key!r}")
# We don't need the Windows long-format timezone name in long format. It's used in timezone XML elements, but
# EWS happily accepts empty strings. For a full list of timezones supported by the target server, including
# long-format names, see output of services.GetServerTimeZones(account.protocol).call()
- instance.ms_name = ''
+ instance.ms_name = ""
return instance
def __eq__(self, other):
@@ -888,11 +889,11 @@ Methods
try:
return cls(cls.MS_TO_IANA_MAP[ms_id])
except KeyError:
- if '/' in ms_id:
+ if "/" in ms_id:
# EWS sometimes returns an ID that has a region/location format, e.g. 'Europe/Copenhagen'. Try the
# string unaltered.
return cls(ms_id)
- raise UnknownTimeZone(f'Windows timezone ID {ms_id!r} is unknown by CLDR')
+ raise UnknownTimeZone(f"Windows timezone ID {ms_id!r} is unknown by CLDR")
@classmethod
def from_pytz(cls, tz):
@@ -907,8 +908,8 @@ Methods
def from_dateutil(cls, tz):
# Objects returned by dateutil.tz.tzlocal() and dateutil.tz.gettz() are not supported. They
# don't contain enough information to reliably match them with a CLDR timezone.
- if hasattr(tz, '_filename'):
- key = '/'.join(tz._filename.split('/')[-2:])
+ if hasattr(tz, "_filename"):
+ key = "/".join(tz._filename.split("/")[-2:])
return cls(key)
return cls(tz.tzname(datetime.datetime.now()))
@@ -920,19 +921,19 @@ Methods
def from_timezone(cls, tz):
# Support multiple tzinfo implementations. We could use isinstance(), but then we'd have to have pytz
# and dateutil as dependencies for this package.
- tz_module = tz.__class__.__module__.split('.')[0]
+ tz_module = tz.__class__.__module__.split(".")[0]
try:
return {
- cls.__module__.split('.')[0]: lambda z: z,
- 'backports': cls.from_zoneinfo,
- 'datetime': cls.from_datetime,
- 'dateutil': cls.from_dateutil,
- 'pytz': cls.from_pytz,
- 'zoneinfo': cls.from_zoneinfo,
- 'pytz_deprecation_shim': lambda z: cls.from_timezone(z.unwrap_shim())
+ cls.__module__.split(".")[0]: lambda z: z,
+ "backports": cls.from_zoneinfo,
+ "datetime": cls.from_datetime,
+ "dateutil": cls.from_dateutil,
+ "pytz": cls.from_pytz,
+ "zoneinfo": cls.from_zoneinfo,
+ "pytz_deprecation_shim": lambda z: cls.from_timezone(z.unwrap_shim()),
}[tz_module](tz)
except KeyError:
- raise TypeError(f'Unsupported tzinfo type: {tz!r}')
+ raise TypeError(f"Unsupported tzinfo type: {tz!r}")
@classmethod
def localzone(cls):
@@ -996,8 +997,8 @@ Static methods
def from_dateutil(cls, tz):
# Objects returned by dateutil.tz.tzlocal() and dateutil.tz.gettz() are not supported. They
# don't contain enough information to reliably match them with a CLDR timezone.
- if hasattr(tz, '_filename'):
- key = '/'.join(tz._filename.split('/')[-2:])
+ if hasattr(tz, "_filename"):
+ key = "/".join(tz._filename.split("/")[-2:])
return cls(key)
return cls(tz.tzname(datetime.datetime.now()))
@@ -1018,11 +1019,11 @@ Static methods
try:
return cls(cls.MS_TO_IANA_MAP[ms_id])
except KeyError:
- if '/' in ms_id:
+ if "/" in ms_id:
# EWS sometimes returns an ID that has a region/location format, e.g. 'Europe/Copenhagen'. Try the
# string unaltered.
return cls(ms_id)
- raise UnknownTimeZone(f'Windows timezone ID {ms_id!r} is unknown by CLDR')
+ raise UnknownTimeZone(f"Windows timezone ID {ms_id!r} is unknown by CLDR")
@@ -1052,19 +1053,19 @@ Static methods
def from_timezone(cls, tz):
# Support multiple tzinfo implementations. We could use isinstance(), but then we'd have to have pytz
# and dateutil as dependencies for this package.
- tz_module = tz.__class__.__module__.split('.')[0]
+ tz_module = tz.__class__.__module__.split(".")[0]
try:
return {
- cls.__module__.split('.')[0]: lambda z: z,
- 'backports': cls.from_zoneinfo,
- 'datetime': cls.from_datetime,
- 'dateutil': cls.from_dateutil,
- 'pytz': cls.from_pytz,
- 'zoneinfo': cls.from_zoneinfo,
- 'pytz_deprecation_shim': lambda z: cls.from_timezone(z.unwrap_shim())
+ cls.__module__.split(".")[0]: lambda z: z,
+ "backports": cls.from_zoneinfo,
+ "datetime": cls.from_datetime,
+ "dateutil": cls.from_dateutil,
+ "pytz": cls.from_pytz,
+ "zoneinfo": cls.from_zoneinfo,
+ "pytz_deprecation_shim": lambda z: cls.from_timezone(z.unwrap_shim()),
}[tz_module](tz)
except KeyError:
- raise TypeError(f'Unsupported tzinfo type: {tz!r}')
+ raise TypeError(f"Unsupported tzinfo type: {tz!r}")
diff --git a/docs/exchangelib/extended_properties.html b/docs/exchangelib/extended_properties.html
index f085765f..0a9595d8 100644
--- a/docs/exchangelib/extended_properties.html
+++ b/docs/exchangelib/extended_properties.html
@@ -32,8 +32,17 @@ Module exchangelib.extended_properties
from .errors import InvalidEnumValue
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
+from .util import (
+ TNS,
+ add_xml_child,
+ create_element,
+ get_xml_attr,
+ get_xml_attrs,
+ is_iterable,
+ set_xml_value,
+ value_to_xml_text,
+ xml_text_to_value,
+)
log = logging.getLogger(__name__)
@@ -41,72 +50,73 @@ Module exchangelib.extended_properties
class ExtendedProperty(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/extendedproperty"""
- ELEMENT_NAME = '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',
+ "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
+ # The following types cannot be used for setting or getting (see docs) and are thus not very useful here:
+ # 'Error'
+ # 'Null'
+ # 'Object'
+ # 'ObjectArray'
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
+ "ApplicationTime",
+ "Binary",
+ "BinaryArray",
+ "Boolean",
+ "CLSID",
+ "CLSIDArray",
+ "Currency",
+ "CurrencyArray",
+ "Double",
+ "DoubleArray",
+ "Float",
+ "FloatArray",
+ "Integer",
+ "IntegerArray",
+ "Long",
+ "LongArray",
+ "Short",
+ "ShortArray",
+ "SystemTime",
+ "SystemTimeArray",
+ "String",
+ "StringArray",
+ }
# 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',
+ "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()}
@@ -115,15 +125,15 @@ Module exchangelib.extended_properties
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 = ''
+ property_type = ""
- __slots__ = 'value',
+ __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')
+ self.value = kwargs.pop("value")
super().__init__(**kwargs)
@classmethod
@@ -149,7 +159,7 @@ Module exchangelib.extended_properties
)
if cls.distinguished_property_set_id not in cls.DISTINGUISHED_SETS:
raise InvalidEnumValue(
- 'distinguished_property_set_id', cls.distinguished_property_set_id, cls.DISTINGUISHED_SETS
+ "distinguished_property_set_id", cls.distinguished_property_set_id, cls.DISTINGUISHED_SETS
)
@classmethod
@@ -160,16 +170,12 @@ Module exchangelib.extended_properties
"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"
- )
+ 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
- ]):
+ 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(
@@ -199,7 +205,7 @@ Module exchangelib.extended_properties
@classmethod
def _validate_property_type(cls):
if cls.property_type not in cls.PROPERTY_TYPES:
- raise InvalidEnumValue('property_type', cls.property_type, cls.PROPERTY_TYPES)
+ raise InvalidEnumValue("property_type", cls.property_type, cls.PROPERTY_TYPES)
def clean(self, version=None):
self.validate_cls()
@@ -247,30 +253,29 @@ Module exchangelib.extended_properties
# 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(f'{{{TNS}}}Values')
+ values = elem.find(f"{{{TNS}}}Values")
return [
- xml_text_to_value(value=val, value_type=python_type)
- for val in get_xml_attrs(values, f'{{{TNS}}}Value')
+ xml_text_to_value(value=val, value_type=python_type) for val in get_xml_attrs(values, f"{{{TNS}}}Value")
]
- extended_field_value = xml_text_to_value(value=get_xml_attr(elem, f'{{{TNS}}}Value'), value_type=python_type)
+ extended_field_value = xml_text_to_value(value=get_xml_attr(elem, f"{{{TNS}}}Value"), 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 ""
return extended_field_value
def to_xml(self, version):
if self.is_array_type():
- values = create_element('t:Values')
+ values = create_element("t:Values")
for v in self.value:
- add_xml_child(values, 't:Value', v)
+ add_xml_child(values, "t:Value", v)
return values
- return set_xml_value(create_element('t:Value'), self.value, version=version)
+ return set_xml_value(create_element("t:Value"), self.value, version=version)
@classmethod
def is_array_type(cls):
- return cls.property_type.endswith('Array')
+ return cls.property_type.endswith("Array")
@classmethod
def property_tag_as_int(cls):
@@ -287,18 +292,18 @@ Module exchangelib.extended_properties
# 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,
+ "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
@@ -319,9 +324,9 @@ Module exchangelib.extended_properties
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'
+ 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):
@@ -332,7 +337,7 @@ Module exchangelib.extended_properties
"""
property_tag = 0x1090
- property_type = 'Integer'
+ property_type = "Integer"
class ExtendedProperty(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/extendedproperty"""
- ELEMENT_NAME = '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',
+ "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
+ # The following types cannot be used for setting or getting (see docs) and are thus not very useful here:
+ # 'Error'
+ # 'Null'
+ # 'Object'
+ # 'ObjectArray'
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
+ "ApplicationTime",
+ "Binary",
+ "BinaryArray",
+ "Boolean",
+ "CLSID",
+ "CLSIDArray",
+ "Currency",
+ "CurrencyArray",
+ "Double",
+ "DoubleArray",
+ "Float",
+ "FloatArray",
+ "Integer",
+ "IntegerArray",
+ "Long",
+ "LongArray",
+ "Short",
+ "ShortArray",
+ "SystemTime",
+ "SystemTimeArray",
+ "String",
+ "StringArray",
+ }
# 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',
+ "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()}
@@ -431,15 +437,15 @@ Classes
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 = ''
+ property_type = ""
- __slots__ = 'value',
+ __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')
+ self.value = kwargs.pop("value")
super().__init__(**kwargs)
@classmethod
@@ -465,7 +471,7 @@ Classes
)
if cls.distinguished_property_set_id not in cls.DISTINGUISHED_SETS:
raise InvalidEnumValue(
- 'distinguished_property_set_id', cls.distinguished_property_set_id, cls.DISTINGUISHED_SETS
+ "distinguished_property_set_id", cls.distinguished_property_set_id, cls.DISTINGUISHED_SETS
)
@classmethod
@@ -476,16 +482,12 @@ Classes
"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"
- )
+ 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
- ]):
+ 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(
@@ -515,7 +517,7 @@ Classes
@classmethod
def _validate_property_type(cls):
if cls.property_type not in cls.PROPERTY_TYPES:
- raise InvalidEnumValue('property_type', cls.property_type, cls.PROPERTY_TYPES)
+ raise InvalidEnumValue("property_type", cls.property_type, cls.PROPERTY_TYPES)
def clean(self, version=None):
self.validate_cls()
@@ -563,30 +565,29 @@ Classes
# 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(f'{{{TNS}}}Values')
+ values = elem.find(f"{{{TNS}}}Values")
return [
- xml_text_to_value(value=val, value_type=python_type)
- for val in get_xml_attrs(values, f'{{{TNS}}}Value')
+ xml_text_to_value(value=val, value_type=python_type) for val in get_xml_attrs(values, f"{{{TNS}}}Value")
]
- extended_field_value = xml_text_to_value(value=get_xml_attr(elem, f'{{{TNS}}}Value'), value_type=python_type)
+ extended_field_value = xml_text_to_value(value=get_xml_attr(elem, f"{{{TNS}}}Value"), 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 ""
return extended_field_value
def to_xml(self, version):
if self.is_array_type():
- values = create_element('t:Values')
+ values = create_element("t:Values")
for v in self.value:
- add_xml_child(values, 't:Value', v)
+ add_xml_child(values, "t:Value", v)
return values
- return set_xml_value(create_element('t:Value'), self.value, version=version)
+ return set_xml_value(create_element("t:Value"), self.value, version=version)
@classmethod
def is_array_type(cls):
- return cls.property_type.endswith('Array')
+ return cls.property_type.endswith("Array")
@classmethod
def property_tag_as_int(cls):
@@ -603,18 +604,18 @@ Classes
# 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,
+ "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
@@ -723,17 +724,16 @@ Static methods
# 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(f'{{{TNS}}}Values')
+ values = elem.find(f"{{{TNS}}}Values")
return [
- xml_text_to_value(value=val, value_type=python_type)
- for val in get_xml_attrs(values, f'{{{TNS}}}Value')
+ xml_text_to_value(value=val, value_type=python_type) for val in get_xml_attrs(values, f"{{{TNS}}}Value")
]
- extended_field_value = xml_text_to_value(value=get_xml_attr(elem, f'{{{TNS}}}Value'), value_type=python_type)
+ extended_field_value = xml_text_to_value(value=get_xml_attr(elem, f"{{{TNS}}}Value"), 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 ""
return extended_field_value
@@ -748,7 +748,7 @@ @classmethod
def is_array_type(cls):
- return cls.property_type.endswith('Array')
+ return cls.property_type.endswith("Array")
@@ -822,18 +822,18 @@ Static methods
# 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,
+ "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]
@@ -901,11 +901,11 @@ def to_xml(self, version):
if self.is_array_type():
- values = create_element('t:Values')
+ values = create_element("t:Values")
for v in self.value:
- add_xml_child(values, 't:Value', v)
+ add_xml_child(values, "t:Value", v)
return values
- return set_xml_value(create_element('t:Value'), self.value, version=version)
+ return set_xml_value(create_element("t:Value"), self.value, version=version)
exchangelib.fields
exchangelib.fields
exchangelib.fields
exchangelib.fields
exchangelib.fields
exchangelib.fields
exchangelib.fields
exchangelib.fields
exchangelib.fields
exchangelib.fields
exchangelib.fields
exchangelib.fields
exchangelib.fields
exchangelib.fields
exchangelib.fields
exchangelib.fields
exchangelib.fields
exchangelib.fields
exchangelib.fields
exchangelib.fields
exchangelib.fields
exchangelib.fields
exchangelib.fields
exchangelib.fields
exchangelib.fields
exchangelib.fields
exchangelib.fields
exchangelib.fields
exchangelib.fields
exchangelib.fields
exchangelib.fields
exchangelib.fields
exchangelib.fields
exchangelib.fields
exchangelib.fields
exchangelib.fields
exchangelib.fields
exchangelib.fields
exchangelib.fields
exchangelib.fields
exchangelib.fields
exchangelib.fields
exchangelib.fields
exchangelib.fields
exchangelib.fields
exchangelib.fields
exchangelib.fields
exchangelib.fields
exchangelib.fields
exchangelib.fields
exchangelib.fields
exchangelib.fields
exchangelib.fields
exchangelib.fields
exchangelib.fields
exchangelib.fields
exchangelib.fields
exchangelib.fields
exchangelib.fields
exchangelib.fields
exchangelib.fields
exchangelib.fields
exchangelib.fields
exchangelib.fields
exchangelib.fields
exchangelib.fields
exchangelib.fields
exchangelib.fields
exchangelib.fields
exchangelib.fields
exchangelib.fields
class AppointmentStateField(IntegerField):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/appointmentstate"""
- NONE = 'None'
- MEETING = 'Meeting'
- RECEIVED = 'Received'
- CANCELLED = 'Cancelled'
+ NONE = "None"
+ MEETING = "Meeting"
+ RECEIVED = "Received"
+ CANCELLED = "Canceled"
STATES = {
NONE: 0x0000,
MEETING: 0x0001,
@@ -1915,7 +1997,8 @@ Inherited members
def __init__(self, *args, **kwargs):
from .properties import AssociatedCalendarItemId
- kwargs['value_cls'] = AssociatedCalendarItemId
+
+ kwargs["value_cls"] = AssociatedCalendarItemId
super().__init__(*args, **kwargs)
def to_xml(self, value, version):
@@ -1959,11 +2042,13 @@ Inherited members
def __init__(self, *args, **kwargs):
from .attachments import Attachment
- kwargs['value_cls'] = Attachment
+
+ kwargs["value_cls"] = Attachment
super().__init__(*args, **kwargs)
def from_xml(self, elem, account):
from .attachments import FileAttachment, ItemAttachment
+
iter_elem = elem.find(self.response_tag())
# Look for both FileAttachment and ItemAttachment
if iter_elem is not None:
@@ -2005,14 +2090,18 @@ Inherited members
class AttendeesField(EWSElementListField):
def __init__(self, *args, **kwargs):
from .properties import Attendee
- kwargs['value_cls'] = Attendee
+
+ kwargs["value_cls"] = Attendee
super().__init__(*args, **kwargs)
def clean(self, value, version=None):
from .properties import Mailbox
+
if value is not None:
- value = [self.value_cls(mailbox=Mailbox(email_address=s), response_type='Accept')
- if isinstance(s, str) else s for s in value]
+ value = [
+ self.value_cls(mailbox=Mailbox(email_address=s), response_type="Accept") if isinstance(s, str) else s
+ for s in value
+ ]
return super().clean(value, version=version)
Ancestors
@@ -2035,9 +2124,12 @@ Methods
def clean(self, value, version=None):
from .properties import Mailbox
+
if value is not None:
- value = [self.value_cls(mailbox=Mailbox(email_address=s), response_type='Accept')
- if isinstance(s, str) else s for s in value]
+ value = [
+ self.value_cls(mailbox=Mailbox(email_address=s), response_type="Accept") if isinstance(s, str) else s
+ for s in value
+ ]
return super().clean(value, version=version)
@@ -2069,8 +2161,8 @@ Inherited members
is_complex = True
def __init__(self, *args, **kwargs):
- if 'is_searchable' not in kwargs:
- kwargs['is_searchable'] = False
+ if "is_searchable" not in kwargs:
+ kwargs["is_searchable"] = False
super().__init__(*args, **kwargs)
class EffectiveRightsField(EWSElementField):
def __init__(self, *args, **kwargs):
from .properties import EffectiveRights
- kwargs['value_cls'] = EffectiveRights
+
+ kwargs["value_cls"] = EffectiveRights
super().__init__(*args, **kwargs)
class EmailAddressAttributedValueField(EWSElementListField):
def __init__(self, *args, **kwargs):
from .properties import EmailAddressAttributedValue
- kwargs['value_cls'] = EmailAddressAttributedValue
+
+ kwargs["value_cls"] = EmailAddressAttributedValue
super().__init__(*args, **kwargs)
class EmailField(BaseEmailField):
def __init__(self, *args, **kwargs):
from .properties import Email
- kwargs['value_cls'] = Email
+
+ kwargs["value_cls"] = Email
super().__init__(*args, **kwargs)
def field_uri_xml(self):
from .properties import ExtendedFieldURI
+
cls = self.value_cls
return ExtendedFieldURI(
distinguished_property_set_id=cls.distinguished_property_set_id,
@@ -4004,9 +4107,19 @@ Inherited members
#
is_complex = False
- def __init__(self, name=None, is_required=False, is_required_after_save=False, is_read_only=False,
- is_read_only_after_send=False, is_searchable=True, is_attribute=False, default=None,
- supported_from=None, deprecated_from=None):
+ def __init__(
+ self,
+ name=None,
+ is_required=False,
+ is_required_after_save=False,
+ is_read_only=False,
+ is_read_only_after_send=False,
+ is_searchable=True,
+ is_attribute=False,
+ default=None,
+ supported_from=None,
+ deprecated_from=None,
+ ):
self.name = name # Usually set by the EWSMeta metaclass
self.default = default # Default value if none is given
self.is_required = is_required
@@ -4024,12 +4137,12 @@ Inherited members
# The Exchange build when this field was introduced. When talking with versions prior to this version,
# we will ignore this field.
if supported_from is not None and not isinstance(supported_from, Build):
- raise InvalidTypeError('supported_from', supported_from, Build)
+ raise InvalidTypeError("supported_from", supported_from, Build)
self.supported_from = supported_from
# The Exchange build when this field was deprecated. When talking with versions at or later than this version,
# we will ignore this field.
if deprecated_from is not None and not isinstance(deprecated_from, Build):
- raise InvalidTypeError('deprecated_from', deprecated_from, Build)
+ raise InvalidTypeError("deprecated_from", deprecated_from, Build)
self.deprecated_from = deprecated_from
def clean(self, value, version=None):
@@ -4047,12 +4160,12 @@ Inherited members
for v in value:
if not isinstance(v, self.value_cls):
raise TypeError(f"Field {self.name!r} value {v!r} must be of type {self.value_cls}")
- if hasattr(v, 'clean'):
+ if hasattr(v, "clean"):
v.clean(version=version)
else:
if not isinstance(value, self.value_cls):
raise TypeError(f"Field {self.name!r} value {value!r} must be of type {self.value_cls}")
- if hasattr(value, 'clean'):
+ if hasattr(value, "clean"):
value.clean(version=version)
return value
@@ -4080,9 +4193,10 @@ Inherited members
"""Field instances must be hashable"""
def __repr__(self):
- args_str = ', '.join(f'{f}={getattr(self, f)!r}' for f in (
- 'name', 'value_cls', 'is_list', 'is_complex', 'default'))
- return f'{self.__class__.__name__}({args_str})'
+ args_str = ", ".join(
+ f"{f}={getattr(self, f)!r}" for f in ("name", "value_cls", "is_list", "is_complex", "default")
+ )
+ return f"{self.__class__.__name__}({args_str})"
class FieldOrder:
"""Holds values needed to call server-side sorting on a single field path."""
+
def __init__(self, field_path, reverse=False):
"""
@@ -4215,12 +4330,12 @@ Methods
@classmethod
def from_string(cls, field_path, folder):
return cls(
- field_path=FieldPath.from_string(field_path=field_path.lstrip('-'), folder=folder, strict=True),
- reverse=field_path.startswith('-')
+ field_path=FieldPath.from_string(field_path=field_path.lstrip("-"), folder=folder, strict=True),
+ reverse=field_path.startswith("-"),
)
def to_xml(self):
- field_order = create_element('t:FieldOrder', attrs=dict(Order='Descending' if self.reverse else 'Ascending'))
+ field_order = create_element("t:FieldOrder", attrs=dict(Order="Descending" if self.reverse else "Ascending"))
field_order.append(self.field_path.to_xml())
return field_order
@@ -4238,8 +4353,8 @@ @classmethod
def from_string(cls, field_path, folder):
return cls(
- field_path=FieldPath.from_string(field_path=field_path.lstrip('-'), folder=folder, strict=True),
- reverse=field_path.startswith('-')
+ field_path=FieldPath.from_string(field_path=field_path.lstrip("-"), folder=folder, strict=True),
+ reverse=field_path.startswith("-"),
)
@@ -4256,7 +4371,7 @@ def to_xml(self):
- field_order = create_element('t:FieldOrder', attrs=dict(Order='Descending' if self.reverse else 'Ascending'))
+ field_order = create_element("t:FieldOrder", attrs=dict(Order="Descending" if self.reverse else "Ascending"))
field_order.append(self.field_path.to_xml())
return field_order
@@ -4331,8 +4446,11 @@ def field_uri_xml(self):
from .properties import FieldURI
+
if not self.field_uri:
raise ValueError(f"'field_uri' value is missing on field '{self.name}'")
return FieldURI(field_uri=self.field_uri).to_xml(version=None)
@@ -4602,7 +4727,7 @@ def request_tag(self):
if not self.field_uri_postfix:
raise ValueError(f"'field_uri_postfix' value is missing on field '{self.name}'")
- return f't:{self.field_uri_postfix}'
+ return f"t:{self.field_uri_postfix}"
@@ -4617,7 +4742,7 @@ Methods
def response_tag(self):
if not self.field_uri_postfix:
raise ValueError(f"'field_uri_postfix' value is missing on field '{self.name}'")
- return f'{{{self.namespace}}}{self.field_uri_postfix}'
+ return f"{{{self.namespace}}}{self.field_uri_postfix}"
@@ -4645,7 +4770,7 @@ class IdElementField(EWSElementField):
def __init__(self, *args, **kwargs):
- kwargs['is_searchable'] = False
- kwargs['is_read_only'] = True
+ kwargs["is_searchable"] = False
+ kwargs["is_read_only"] = True
super().__init__(*args, **kwargs)
def response_tag(self):
- return f'{{{self.namespace}}}{self.PARENT_ELEMENT_NAME}'
+ return f"{{{self.namespace}}}{self.PARENT_ELEMENT_NAME}"
@@ -4897,14 +5038,13 @@ @property
def value_cls(self):
from .items import Item
+
return Item
@@ -5159,7 +5302,8 @@ class MailboxField(BaseEmailField):
def __init__(self, *args, **kwargs):
from .properties import Mailbox
- kwargs['value_cls'] = Mailbox
+
+ kwargs["value_cls"] = Mailbox
super().__init__(*args, **kwargs)
class MailboxListField(EWSElementListField):
def __init__(self, *args, **kwargs):
from .properties import Mailbox
- kwargs['value_cls'] = Mailbox
+
+ kwargs["value_cls"] = Mailbox
super().__init__(*args, **kwargs)
def clean(self, value, version=None):
@@ -5248,15 +5393,15 @@ Inherited members
class MemberListField(EWSElementListField):
def __init__(self, *args, **kwargs):
from .properties import Member
- kwargs['value_cls'] = Member
+
+ kwargs["value_cls"] = Member
super().__init__(*args, **kwargs)
def clean(self, value, version=None):
from .properties import Mailbox
+
if value is not None:
- value = [
- self.value_cls(mailbox=Mailbox(email_address=s)) if isinstance(s, str) else s for s in value
- ]
+ value = [self.value_cls(mailbox=Mailbox(email_address=s)) if isinstance(s, str) else s for s in value]
return super().clean(value, version=version)
Ancestors
@@ -5279,10 +5424,9 @@ Methods
def clean(self, value, version=None):
from .properties import Mailbox
+
if value is not None:
- value = [
- self.value_cls(mailbox=Mailbox(email_address=s)) if isinstance(s, str) else s for s in value
- ]
+ value = [self.value_cls(mailbox=Mailbox(email_address=s)) if isinstance(s, str) else s for s in value]
return super().clean(value, version=version)
@@ -5310,20 +5454,20 @@ Inherited members
class MessageField(TextField):
"""A field that handles the Message element."""
- INNER_ELEMENT_NAME = 'Message'
+ INNER_ELEMENT_NAME = "Message"
def from_xml(self, elem, account):
reply = elem.find(self.response_tag())
if reply is None:
return None
- message = reply.find(f'{{{TNS}}}{self.INNER_ELEMENT_NAME}')
+ message = reply.find(f"{{{TNS}}}{self.INNER_ELEMENT_NAME}")
if message is None:
return None
return message.text
def to_xml(self, value, version):
field_elem = create_element(self.request_tag())
- message = create_element(f't:{self.INNER_ELEMENT_NAME}')
+ message = create_element(f"t:{self.INNER_ELEMENT_NAME}")
message.text = value
return set_xml_value(field_elem, message, version=version)
@@ -5364,7 +5508,8 @@ Inherited members
class MessageHeaderField(EWSElementListField):
def __init__(self, *args, **kwargs):
from .properties import MessageHeader
- kwargs['value_cls'] = MessageHeader
+
+ kwargs["value_cls"] = MessageHeader
super().__init__(*args, **kwargs)
Ancestors
@@ -5435,8 +5580,8 @@ Inherited members
value_cls = str
def __init__(self, *args, **kwargs):
- self.field_uri = kwargs.pop('field_uri')
- if ':' in self.field_uri:
+ self.field_uri = kwargs.pop("field_uri")
+ if ":" in self.field_uri:
raise ValueError("'field_uri' value must not contain a colon")
super().__init__(*args, **kwargs)
@@ -5453,13 +5598,14 @@ Inherited members
def field_uri_xml(self, field_uri, label):
from .properties import IndexedFieldURI
- return IndexedFieldURI(field_uri=f'{field_uri}:{self.field_uri}', field_index=label).to_xml(version=None)
+
+ return IndexedFieldURI(field_uri=f"{field_uri}:{self.field_uri}", field_index=label).to_xml(version=None)
def request_tag(self):
- return f't:{self.field_uri}'
+ return f"t:{self.field_uri}"
def response_tag(self):
- return f'{{{self.namespace}}}{self.field_uri}'
+ return f"{{{self.namespace}}}{self.field_uri}"
def field_uri_xml(self, field_uri, label):
from .properties import IndexedFieldURI
- return IndexedFieldURI(field_uri=f'{field_uri}:{self.field_uri}', field_index=label).to_xml(version=None)
+
+ return IndexedFieldURI(field_uri=f"{field_uri}:{self.field_uri}", field_index=label).to_xml(version=None)
@@ -5492,7 +5639,7 @@ Methods
Expand source code
def request_tag(self):
- return f't:{self.field_uri}'
+ return f"t:{self.field_uri}"
@@ -5505,7 +5652,7 @@ Methods
Expand source code
def response_tag(self):
- return f'{{{self.namespace}}}{self.field_uri}'
+ return f"{{{self.namespace}}}{self.field_uri}"
@@ -5642,7 +5789,8 @@ class PhoneNumberAttributedValueField(EWSElementListField):
def __init__(self, *args, **kwargs):
from .properties import PhoneNumberAttributedValue
- kwargs['value_cls'] = PhoneNumberAttributedValue
+
+ kwargs["value_cls"] = PhoneNumberAttributedValue
super().__init__(*args, **kwargs)
class PostalAddressAttributedValueField(EWSElementListField):
def __init__(self, *args, **kwargs):
from .properties import PostalAddressAttributedValue
- kwargs['value_cls'] = PostalAddressAttributedValue
+
+ kwargs["value_cls"] = PostalAddressAttributedValue
super().__init__(*args, **kwargs)
class RecipientAddressField(BaseEmailField):
def __init__(self, *args, **kwargs):
from .properties import RecipientAddress
- kwargs['value_cls'] = RecipientAddress
+
+ kwargs["value_cls"] = RecipientAddress
super().__init__(*args, **kwargs)
class RoutingTypeField(ChoiceField):
def __init__(self, *args, **kwargs):
- kwargs['choices'] = {Choice('SMTP'), Choice('EX')}
- kwargs['default'] = 'SMTP'
+ kwargs["choices"] = {Choice("SMTP"), Choice("EX")}
+ kwargs["default"] = "SMTP"
super().__init__(*args, **kwargs)
class StringAttributedValueField(EWSElementListField):
def __init__(self, *args, **kwargs):
from .properties import StringAttributedValue
- kwargs['value_cls'] = StringAttributedValue
+
+ kwargs["value_cls"] = StringAttributedValue
super().__init__(*args, **kwargs)
@staticmethod
def field_uri_xml(field_uri, label):
from .properties import IndexedFieldURI
+
return IndexedFieldURI(field_uri=field_uri, field_index=label).to_xml(version=None)
@@ -6203,7 +6363,7 @@ def clean(self, value, version=None):
value = super().clean(value, version=version)
if self.is_required and not value:
- raise ValueError(f'Value for subfield {self.name!r} must be non-empty')
+ raise ValueError(f"Value for subfield {self.name!r} must be non-empty")
return value
@@ -6233,7 +6393,8 @@ def list_elem_request_tag(self):
- return f't:{self.list_elem_name}'
+ return f"t:{self.list_elem_name}"
@@ -6399,7 +6560,7 @@ Methods
Expand source code
def list_elem_response_tag(self):
- return f'{{{self.namespace}}}{self.list_elem_name}'
+ return f"{{{self.namespace}}}{self.list_elem_name}"
@@ -6430,14 +6591,13 @@ def clean(self, value, version=None):
if self.min is not None and value < self.min:
- raise ValueError(
- f"Value {value!r} on field {self.name!r} must be greater than {self.min}")
+ raise ValueError(f"Value {value!r} on field {self.name!r} must be greater than {self.min}")
if self.max is not None and value > self.max:
raise ValueError(f"Value {value!r} on field {self.name!r} must be less than {self.max}")
return super().clean(value, version=version)
@@ -6504,9 +6663,9 @@ class TransitionListField(EWSElementListField):
def __init__(self, *args, **kwargs):
from .properties import BaseTransition
- kwargs['value_cls'] = BaseTransition
+
+ kwargs["value_cls"] = BaseTransition
super().__init__(*args, **kwargs)
def from_xml(self, elem, account):
@@ -6676,47 +6838,47 @@ Inherited members
"""This field type has no value_cls because values may have many different types."""
TYPES_MAP = {
- 'Boolean': bool,
- 'Integer32': int,
- 'UnsignedInteger32': int,
- 'Integer64': int,
- 'UnsignedInteger64': int,
+ "Boolean": bool,
+ "Integer32": int,
+ "UnsignedInteger32": int,
+ "Integer64": int,
+ "UnsignedInteger64": int,
# Python doesn't have a single-byte type to represent 'Byte'
- 'ByteArray': bytes,
- 'String': str,
- 'StringArray': str, # A list of strings
- 'DateTime': EWSDateTime,
+ "ByteArray": bytes,
+ "String": str,
+ "StringArray": str, # A list of strings
+ "DateTime": EWSDateTime,
}
TYPES_MAP_REVERSED = {
- bool: 'Boolean',
- int: 'Integer64',
+ bool: "Boolean",
+ int: "Integer64",
# Python doesn't have a single-byte type to represent 'Byte'
- bytes: 'ByteArray',
- str: 'String',
- datetime.datetime: 'DateTime',
- EWSDateTime: 'DateTime',
+ bytes: "ByteArray",
+ str: "String",
+ datetime.datetime: "DateTime",
+ EWSDateTime: "DateTime",
}
@classmethod
def get_type(cls, value):
if isinstance(value, bytes) and len(value) == 1:
# This is a single byte. Translate it to the 'Byte' type
- return 'Byte'
+ return "Byte"
if is_iterable(value):
# We don't allow generators as values, so keep the logic simple
try:
first = next(iter(value))
except StopIteration:
first = None
- value_type = f'{cls.TYPES_MAP_REVERSED[type(first)]}Array'
+ value_type = f"{cls.TYPES_MAP_REVERSED[type(first)]}Array"
if value_type not in cls.TYPES_MAP:
- raise ValueError(f'{value!r} is not a supported type')
+ raise ValueError(f"{value!r} is not a supported type")
return value_type
return cls.TYPES_MAP_REVERSED[type(value)]
@classmethod
def is_array_type(cls, value_type):
- return value_type == 'StringArray'
+ return value_type == "StringArray"
def clean(self, value, version=None):
if value is None:
@@ -6729,30 +6891,30 @@ Inherited members
field_elem = elem.find(self.response_tag())
if field_elem is None:
return self.default
- value_type_str = get_xml_attr(field_elem, f'{{{TNS}}}Type')
- value = get_xml_attr(field_elem, f'{{{TNS}}}Value')
- if value_type_str == 'Byte':
+ value_type_str = get_xml_attr(field_elem, f"{{{TNS}}}Type")
+ value = get_xml_attr(field_elem, f"{{{TNS}}}Value")
+ if value_type_str == "Byte":
try:
# The value is an unsigned integer in the range 0 -> 255. Convert it to a single byte
- return xml_text_to_value(value, int).to_bytes(1, 'little', signed=False)
+ return xml_text_to_value(value, int).to_bytes(1, "little", signed=False)
except OverflowError as e:
- log.warning('Invalid byte value %r (%e)', value, e)
+ log.warning("Invalid byte value %r (%e)", value, e)
return None
value_type = self.TYPES_MAP[value_type_str]
- if self. is_array_type(value_type_str):
- return tuple(xml_text_to_value(value=v, value_type=value_type) for v in value.split(' '))
+ if self.is_array_type(value_type_str):
+ return tuple(xml_text_to_value(value=v, value_type=value_type) for v in value.split(" "))
return xml_text_to_value(value=value, value_type=value_type)
def to_xml(self, value, version):
value_type_str = self.get_type(value)
- if value_type_str == 'Byte':
+ if value_type_str == "Byte":
# A single byte is encoded to an unsigned integer in the range 0 -> 255
- value = int.from_bytes(value, byteorder='little', signed=False)
+ value = int.from_bytes(value, byteorder="little", signed=False)
elif is_iterable(value):
- value = ' '.join(value_to_xml_text(v) for v in value)
+ value = " ".join(value_to_xml_text(v) for v in value)
field_elem = create_element(self.request_tag())
- field_elem.append(set_xml_value(create_element('t:Type'), value_type_str, version=version))
- field_elem.append(set_xml_value(create_element('t:Value'), value, version=version))
+ field_elem.append(set_xml_value(create_element("t:Type"), value_type_str, version=version))
+ field_elem.append(set_xml_value(create_element("t:Value"), value, version=version))
return field_elem
@classmethod
def is_array_type(cls, value_type):
- return value_type == 'StringArray'
+ return value_type == "StringArray"
@@ -6890,7 +7052,7 @@ class UnknownEntriesField(CharListField):
def list_elem_tag(self):
- return f'{{{self.namespace}}}UnknownEntry'
+ return f"{{{self.namespace}}}UnknownEntry"
def list_elem_tag(self):
- return f'{{{self.namespace}}}UnknownEntry'
+ return f"{{{self.namespace}}}UnknownEntry"
diff --git a/docs/exchangelib/folders/base.html b/docs/exchangelib/folders/base.html
index fc009503..df412a1b 100644
--- a/docs/exchangelib/folders/base.html
+++ b/docs/exchangelib/folders/base.html
@@ -31,18 +31,47 @@ exchangelib.folders.base
exchangelib.folders.base
exchangelib.folders.base
exchangelib.folders.base
exchangelib.folders.base
exchangelib.folders.base
exchangelib.folders.base
exchangelib.folders.base
exchangelib.folders.base
exchangelib.folders.base
exchangelib.folders.base
exchangelib.folders.base
exchangelib.folders.base
exchangelib.folders.base
exchangelib.folders.base
exchangelib.folders.base
exchangelib.folders.base
exchangelib.folders.base
exchangelib.folders.base
exchangelib.folders.base
exchangelib.folders.base
exchangelib.folders.base
exchangelib.folders.base
exchangelib.folders.base
exchangelib.folders.base
exchangelib.folders.base
exchangelib.folders.base
exchangelib.folders.base
exchangelib.folders.base
exchangelib.folders.base
exchangelib.folders.base
exchangelib.folders.base
exchangelib.folders.base
exchangelib.folders.base
exchangelib.folders.base
exchangelib.folders.base
class BaseFolder(RegisterMixIn, SearchableMixIn, metaclass=EWSMeta):
"""Base class for all classes that implement a folder."""
- ELEMENT_NAME = 'Folder'
+ ELEMENT_NAME = "Folder"
NAMESPACE = TNS
# See https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/distinguishedfolderid
DISTINGUISHED_FOLDER_ID = None
@@ -892,24 +968,23 @@ Classes
ITEM_MODEL_MAP = {cls.response_tag(): cls for cls in ITEM_CLASSES}
ID_ELEMENT_CLS = FolderId
- _id = IdElementField(field_uri='folder:FolderId', value_cls=ID_ELEMENT_CLS)
- parent_folder_id = EWSElementField(field_uri='folder:ParentFolderId', value_cls=ParentFolderId,
- is_read_only=True)
- folder_class = CharField(field_uri='folder:FolderClass', is_required_after_save=True)
- name = CharField(field_uri='folder:DisplayName')
- total_count = IntegerField(field_uri='folder:TotalCount', is_read_only=True)
- child_folder_count = IntegerField(field_uri='folder:ChildFolderCount', is_read_only=True)
- unread_count = IntegerField(field_uri='folder:UnreadCount', is_read_only=True)
+ _id = IdElementField(field_uri="folder:FolderId", value_cls=ID_ELEMENT_CLS)
+ parent_folder_id = EWSElementField(field_uri="folder:ParentFolderId", value_cls=ParentFolderId, is_read_only=True)
+ folder_class = CharField(field_uri="folder:FolderClass", is_required_after_save=True)
+ name = CharField(field_uri="folder:DisplayName")
+ total_count = IntegerField(field_uri="folder:TotalCount", is_read_only=True)
+ child_folder_count = IntegerField(field_uri="folder:ChildFolderCount", is_read_only=True)
+ unread_count = IntegerField(field_uri="folder:UnreadCount", is_read_only=True)
- __slots__ = 'is_distinguished', 'item_sync_state', 'folder_sync_state'
+ __slots__ = "is_distinguished", "item_sync_state", "folder_sync_state"
# Used to register extended properties
- INSERT_AFTER_FIELD = 'child_folder_count'
+ INSERT_AFTER_FIELD = "child_folder_count"
def __init__(self, **kwargs):
- self.is_distinguished = kwargs.pop('is_distinguished', False)
- self.item_sync_state = kwargs.pop('item_sync_state', None)
- self.folder_sync_state = kwargs.pop('folder_sync_state', None)
+ self.is_distinguished = kwargs.pop("is_distinguished", False)
+ self.item_sync_state = kwargs.pop("item_sync_state", None)
+ self.folder_sync_state = kwargs.pop("folder_sync_state", None)
super().__init__(**kwargs)
@property
@@ -954,7 +1029,7 @@ Classes
@property
def absolute(self):
- return ''.join(f'/{p.name}' for p in self.parts)
+ return "".join(f"/{p.name}" for p in self.parts)
def _walk(self):
for c in self.children:
@@ -965,23 +1040,23 @@ Classes
return FolderCollection(account=self.account, folders=self._walk())
def _glob(self, pattern):
- split_pattern = pattern.rsplit('/', 1)
+ split_pattern = pattern.rsplit("/", 1)
head, tail = (split_pattern[0], None) if len(split_pattern) == 1 else split_pattern
- if head == '':
+ if head == "":
# We got an absolute path. Restart globbing at root
- yield from self.root.glob(tail or '*')
- elif head == '..':
+ yield from self.root.glob(tail or "*")
+ elif head == "..":
# Relative path with reference to parent. Restart globbing at parent
if not self.parent:
- raise ValueError('Already at top')
- yield from self.parent.glob(tail or '*')
- elif head == '**':
+ raise ValueError("Already at top")
+ yield from self.parent.glob(tail or "*")
+ elif head == "**":
# Match anything here or in any subfolder at arbitrary depth
for c in self.walk():
# fnmatch() may be case-sensitive depending on operating system:
# force a case-insensitive match since case appears not to
# matter for folders in Exchange
- if fnmatch(c.name.lower(), (tail or '*').lower()):
+ if fnmatch(c.name.lower(), (tail or "*").lower()):
yield c
else:
# Regular pattern
@@ -1008,22 +1083,22 @@ Classes
├── exchangelib issues
└── Mom
"""
- tree = f'{self.name}\n'
+ tree = f"{self.name}\n"
children = list(self.children)
- for i, c in enumerate(sorted(children, key=attrgetter('name')), start=1):
- nodes = c.tree().split('\n')
+ for i, c in enumerate(sorted(children, key=attrgetter("name")), start=1):
+ nodes = c.tree().split("\n")
for j, node in enumerate(nodes, start=1):
if i != len(children) and j == 1:
# Not the last child, but the first node, which is the name of the child
- tree += f'├── {node}\n'
+ tree += f"├── {node}\n"
elif i != len(children) and j > 1:
# Not the last child, and not name of child
- tree += f'│ {node}\n'
+ tree += f"│ {node}\n"
elif i == len(children) and j == 1:
# Not the last child, but the first node, which is the name of the child
- tree += f'└── {node}\n'
+ tree += f"└── {node}\n"
else: # Last child, and not name of child
- tree += f' {node}\n'
+ tree += f" {node}\n"
return tree.strip()
@classmethod
@@ -1051,11 +1126,29 @@ Classes
:param container_class:
:return:
"""
- from .known_folders import Messages, Tasks, Calendar, ConversationSettings, Contacts, GALContacts, Reminders, \
- RecipientCache, RSSFeeds
+ from .known_folders import (
+ Calendar,
+ Contacts,
+ ConversationSettings,
+ GALContacts,
+ Messages,
+ RecipientCache,
+ Reminders,
+ RSSFeeds,
+ Tasks,
+ )
+
for folder_cls in (
- Messages, Tasks, Calendar, ConversationSettings, Contacts, GALContacts, Reminders, RecipientCache,
- RSSFeeds):
+ Messages,
+ Tasks,
+ Calendar,
+ ConversationSettings,
+ Contacts,
+ GALContacts,
+ Reminders,
+ RecipientCache,
+ RSSFeeds,
+ ):
if folder_cls.CONTAINER_CLASS == container_class:
return folder_cls
raise KeyError()
@@ -1065,7 +1158,7 @@ Classes
try:
return cls.ITEM_MODEL_MAP[tag]
except KeyError:
- raise ValueError(f'Item type {tag} was unexpected in a {cls.__name__} folder')
+ raise ValueError(f"Item type {tag} was unexpected in a {cls.__name__} folder")
@classmethod
def allowed_item_fields(cls, version):
@@ -1091,9 +1184,9 @@ Classes
elif isinstance(field_path, Field):
field_path = FieldPath(field=field_path)
fields[i] = field_path
- if field_path.field.name == 'start':
+ if field_path.field.name == "start":
has_start = True
- elif field_path.field.name == 'end':
+ elif field_path.field.name == "end":
has_end = True
# For CalendarItem items, we want to inject internal timezone fields. See also CalendarItem.clean()
@@ -1142,6 +1235,7 @@ Classes
def save(self, update_fields=None):
from ..services import CreateFolder, UpdateFolder
+
if self.id is None:
# New folder
if update_fields:
@@ -1160,7 +1254,7 @@ Classes
# These cannot be changed
continue
if (f.is_required or f.is_required_after_save) and (
- getattr(self, f.name) is None or (f.is_list and not getattr(self, f.name))
+ getattr(self, f.name) is None or (f.is_list and not getattr(self, f.name))
):
# These are required and cannot be deleted
continue
@@ -1168,7 +1262,7 @@ Classes
res = UpdateFolder(account=self.account).get(folders=[(self, update_fields)])
folder_id, changekey = res.id, res.changekey
if self.id != folder_id:
- raise ValueError('ID mismatch')
+ raise ValueError("ID mismatch")
# Don't check changekey value. It may not change on no-op updates
self.changekey = changekey
self.root.update_folder(self) # Update the folder in the cache
@@ -1176,10 +1270,11 @@ Classes
def move(self, to_folder):
from ..services import MoveFolder
+
res = MoveFolder(account=self.account).get(folders=[self], to_folder=to_folder)
folder_id, changekey = res.id, res.changekey
if self.id != folder_id:
- raise ValueError('ID mismatch')
+ raise ValueError("ID mismatch")
# Don't check changekey value. It may not change on no-op moves
self.changekey = changekey
self.parent_folder_id = ParentFolderId(id=to_folder.id, changekey=to_folder.changekey)
@@ -1187,12 +1282,14 @@ Classes
def delete(self, delete_type=HARD_DELETE):
from ..services import DeleteFolder
+
DeleteFolder(account=self.account).get(folders=[self], delete_type=delete_type)
self.root.remove_folder(self) # Remove the updated folder from the cache
self._id = None
def empty(self, delete_type=HARD_DELETE, delete_sub_folders=False):
from ..services import EmptyFolder
+
EmptyFolder(account=self.account).get(
folders=[self], delete_type=delete_type, delete_sub_folders=delete_sub_folders
)
@@ -1205,11 +1302,11 @@ Classes
# distinguished folders from being deleted. Use with caution!
_seen = _seen or set()
if self.id in _seen:
- raise RecursionError(f'We already tried to wipe {self}')
+ raise RecursionError(f"We already tried to wipe {self}")
if _level > 16:
- raise RecursionError(f'Max recursion level reached: {_level}')
+ raise RecursionError(f"Max recursion level reached: {_level}")
_seen.add(self.id)
- log.warning('Wiping %s', self)
+ log.warning("Wiping %s", self)
has_distinguished_subfolders = any(f.is_distinguished for f in self.children)
try:
if has_distinguished_subfolders:
@@ -1222,26 +1319,26 @@ Classes
raise # We already tried this
self.empty(delete_sub_folders=False)
except (ErrorAccessDenied, ErrorCannotEmptyFolder, ErrorItemNotFound):
- log.warning('Not allowed to empty %s. Trying to delete items instead', self)
+ log.warning("Not allowed to empty %s. Trying to delete items instead", self)
kwargs = {}
if page_size is not None:
- kwargs['page_size'] = page_size
+ kwargs["page_size"] = page_size
if chunk_size is not None:
- kwargs['chunk_size'] = chunk_size
+ kwargs["chunk_size"] = chunk_size
try:
self.all().delete(**kwargs)
except (ErrorAccessDenied, ErrorCannotDeleteObject, ErrorItemNotFound):
- log.warning('Not allowed to delete items in %s', self)
+ log.warning("Not allowed to delete items in %s", self)
_level += 1
for f in self.children:
f.wipe(page_size=page_size, chunk_size=chunk_size, _seen=_seen, _level=_level)
# Remove non-distinguished children that are empty and have no subfolders
if f.is_deletable and not f.children:
- log.warning('Deleting folder %s', f)
+ log.warning("Deleting folder %s", f)
try:
f.delete()
except ErrorDeleteDistinguishedFolder:
- log.warning('Tried to delete a distinguished folder (%s)', f)
+ log.warning("Tried to delete a distinguished folder (%s)", f)
def test_access(self):
"""Does a simple FindItem to test (read) access to the folder. Maybe the account doesn't exist, maybe the
@@ -1253,12 +1350,12 @@ Classes
@classmethod
def _kwargs_from_elem(cls, elem, account):
# Check for 'DisplayName' element before collecting kwargs because because that clears the elements
- has_name_elem = elem.find(cls.get_field_by_fieldname('name').response_tag()) is not None
+ has_name_elem = elem.find(cls.get_field_by_fieldname("name").response_tag()) is not None
kwargs = {f.name: f.from_xml(elem=elem, account=account) for f in cls.FIELDS}
- if has_name_elem and not kwargs['name']:
+ if has_name_elem and not kwargs["name"]:
# When we request the 'DisplayName' property, some folders may still be returned with an empty value.
# Assign a default name to these folders.
- kwargs['name'] = cls.DISTINGUISHED_FOLDER_ID
+ kwargs["name"] = cls.DISTINGUISHED_FOLDER_ID
return kwargs
def to_id(self):
@@ -1267,22 +1364,21 @@ Classes
# the folder content since we fetched the changekey.
if self.account:
return DistinguishedFolderId(
- id=self.DISTINGUISHED_FOLDER_ID,
- mailbox=Mailbox(email_address=self.account.primary_smtp_address)
+ id=self.DISTINGUISHED_FOLDER_ID, mailbox=Mailbox(email_address=self.account.primary_smtp_address)
)
return DistinguishedFolderId(id=self.DISTINGUISHED_FOLDER_ID)
if self.id:
return FolderId(id=self.id, changekey=self.changekey)
- raise ValueError('Must be a distinguished folder or have an ID')
+ raise ValueError("Must be a distinguished folder or have an ID")
@classmethod
def resolve(cls, account, folder):
# Resolve a single folder
folders = list(FolderCollection(account=account, folders=[folder]).resolve())
if not folders:
- raise ErrorFolderNotFound(f'Could not find folder {folder!r}')
+ raise ErrorFolderNotFound(f"Could not find folder {folder!r}")
if len(folders) != 1:
- raise ValueError(f'Expected result length 1, but got {folders}')
+ raise ValueError(f"Expected result length 1, but got {folders}")
f = folders[0]
if isinstance(f, Exception):
raise f
@@ -1294,7 +1390,7 @@ Classes
def refresh(self):
fresh_folder = self.resolve(account=self.account, folder=self)
if self.id != fresh_folder.id:
- raise ValueError('ID mismatch')
+ raise ValueError("ID mismatch")
# Apparently, the changekey may get updated
for f in self.FIELDS:
setattr(self, f.name, getattr(fresh_folder, f.name))
@@ -1304,6 +1400,7 @@ Classes
def get_user_configuration(self, name, properties=None):
from ..services import GetUserConfiguration
from ..services.get_user_configuration import ALL
+
if properties is None:
properties = ALL
return GetUserConfiguration(account=self.account).get(
@@ -1314,6 +1411,7 @@ Classes
@require_id
def create_user_configuration(self, name, dictionary=None, xml_data=None, binary_data=None):
from ..services import CreateUserConfiguration
+
user_configuration = UserConfiguration(
user_configuration_name=UserConfigurationName(name=name, folder=self),
dictionary=dictionary,
@@ -1325,6 +1423,7 @@ Classes
@require_id
def update_user_configuration(self, name, dictionary=None, xml_data=None, binary_data=None):
from ..services import UpdateUserConfiguration
+
user_configuration = UserConfiguration(
user_configuration_name=UserConfigurationName(name=name, folder=self),
dictionary=dictionary,
@@ -1336,6 +1435,7 @@ Classes
@require_id
def delete_user_configuration(self, name):
from ..services import DeleteUserConfiguration
+
return DeleteUserConfiguration(account=self.account).get(
user_configuration_name=UserConfigurationNameMNS(name=name, folder=self)
)
@@ -1351,10 +1451,13 @@ Classes
:return: The subscription ID and a watermark
"""
from ..services import SubscribeToPull
+
if event_types is None:
event_types = SubscribeToPull.EVENT_TYPES
return FolderCollection(account=self.account, folders=[self]).subscribe_to_pull(
- event_types=event_types, watermark=watermark, timeout=timeout,
+ event_types=event_types,
+ watermark=watermark,
+ timeout=timeout,
)
@require_id
@@ -1368,10 +1471,14 @@ Classes
:return: The subscription ID and a watermark
"""
from ..services import SubscribeToPush
+
if event_types is None:
event_types = SubscribeToPush.EVENT_TYPES
return FolderCollection(account=self.account, folders=[self]).subscribe_to_push(
- event_types=event_types, watermark=watermark, status_frequency=status_frequency, callback_url=callback_url,
+ event_types=event_types,
+ watermark=watermark,
+ status_frequency=status_frequency,
+ callback_url=callback_url,
)
@require_id
@@ -1382,6 +1489,7 @@ Classes
:return: The subscription ID
"""
from ..services import SubscribeToStreaming
+
if event_types is None:
event_types = SubscribeToStreaming.EVENT_TYPES
return FolderCollection(account=self.account, folders=[self]).subscribe_to_streaming(event_types=event_types)
@@ -1408,6 +1516,7 @@ Classes
sync methods.
"""
from ..services import Unsubscribe
+
return Unsubscribe(account=self.account).get(subscription_id=subscription_id)
def sync_items(self, sync_state=None, only_fields=None, ignore=None, max_changes_returned=None, sync_scope=None):
@@ -1467,6 +1576,7 @@ Classes
sync methods.
"""
from ..services import GetEvents
+
svc = GetEvents(account=self.account)
while True:
notification = svc.get(subscription_id=subscription_id, watermark=watermark)
@@ -1488,12 +1598,15 @@ Classes
sync methods.
"""
from ..services import GetStreamingEvents
+
svc = GetStreamingEvents(account=self.account)
- subscription_ids = subscription_id_or_ids if is_iterable(subscription_id_or_ids, generators_allowed=True) \
+ subscription_ids = (
+ subscription_id_or_ids
+ if is_iterable(subscription_id_or_ids, generators_allowed=True)
else [subscription_id_or_ids]
+ )
for i, notification in enumerate(
- svc.call(subscription_ids=subscription_ids, connection_timeout=connection_timeout),
- start=1
+ svc.call(subscription_ids=subscription_ids, connection_timeout=connection_timeout), start=1
):
yield notification
if max_notifications_returned and i >= max_notifications_returned:
@@ -1510,10 +1623,10 @@ Classes
:param other:
:return:
"""
- if other == '..':
- raise ValueError('Cannot get parent without a folder cache')
+ if other == "..":
+ raise ValueError("Cannot get parent without a folder cache")
- if other == '.':
+ if other == ".":
return self
# Assume an exact match on the folder name in a shallow search will only return at most one folder
@@ -1524,11 +1637,11 @@ Classes
def __truediv__(self, other):
"""Support the some_folder / 'child_folder' / 'child_of_child_folder' navigation syntax."""
- if other == '..':
+ if other == "..":
if not self.parent:
- raise ValueError('Already at top')
+ raise ValueError("Already at top")
return self.parent
- if other == '.':
+ if other == ".":
return self
for c in self.children:
if c.name == other:
@@ -1536,12 +1649,21 @@ Classes
raise ErrorFolderNotFound(f"No subfolder with name {other!r}")
def __repr__(self):
- return self.__class__.__name__ + \
- repr((self.root, self.name, self.total_count, self.unread_count, self.child_folder_count,
- self.folder_class, self.id, self.changekey))
+ return self.__class__.__name__ + repr(
+ (
+ self.root,
+ self.name,
+ self.total_count,
+ self.unread_count,
+ self.child_folder_count,
+ self.folder_class,
+ self.id,
+ self.changekey,
+ )
+ )
def __str__(self):
- return f'{self.__class__.__name__} ({self.name})'
+ return f"{self.__class__.__name__} ({self.name})"
@@ -1730,9 +1870,9 @@ Static methods
# Resolve a single folder
folders = list(FolderCollection(account=account, folders=[folder]).resolve())
if not folders:
- raise ErrorFolderNotFound(f'Could not find folder {folder!r}')
+ raise ErrorFolderNotFound(f"Could not find folder {folder!r}")
if len(folders) != 1:
- raise ValueError(f'Expected result length 1, but got {folders}')
+ raise ValueError(f"Expected result length 1, but got {folders}")
f = folders[0]
if isinstance(f, Exception):
raise f
@@ -1770,7 +1910,7 @@ Instance variables
@property
def absolute(self):
- return ''.join(f'/{p.name}' for p in self.parts)
+ return "".join(f"/{p.name}" for p in self.parts)
var account
@require_id
def create_user_configuration(self, name, dictionary=None, xml_data=None, binary_data=None):
from ..services import CreateUserConfiguration
+
user_configuration = UserConfiguration(
user_configuration_name=UserConfigurationName(name=name, folder=self),
dictionary=dictionary,
@@ -1967,6 +2108,7 @@ Methods
def delete(self, delete_type=HARD_DELETE):
from ..services import DeleteFolder
+
DeleteFolder(account=self.account).get(folders=[self], delete_type=delete_type)
self.root.remove_folder(self) # Remove the updated folder from the cache
self._id = None
@@ -1984,6 +2126,7 @@ Methods
@require_id
def delete_user_configuration(self, name):
from ..services import DeleteUserConfiguration
+
return DeleteUserConfiguration(account=self.account).get(
user_configuration_name=UserConfigurationNameMNS(name=name, folder=self)
)
@@ -2000,6 +2143,7 @@ Methods
def empty(self, delete_type=HARD_DELETE, delete_sub_folders=False):
from ..services import EmptyFolder
+
EmptyFolder(account=self.account).get(
folders=[self], delete_type=delete_type, delete_sub_folders=delete_sub_folders
)
@@ -2033,6 +2177,7 @@ Methods
sync methods.
"""
from ..services import GetEvents
+
svc = GetEvents(account=self.account)
while True:
notification = svc.get(subscription_id=subscription_id, watermark=watermark)
@@ -2072,12 +2217,15 @@ Methods
sync methods.
"""
from ..services import GetStreamingEvents
+
svc = GetStreamingEvents(account=self.account)
- subscription_ids = subscription_id_or_ids if is_iterable(subscription_id_or_ids, generators_allowed=True) \
+ subscription_ids = (
+ subscription_id_or_ids
+ if is_iterable(subscription_id_or_ids, generators_allowed=True)
else [subscription_id_or_ids]
+ )
for i, notification in enumerate(
- svc.call(subscription_ids=subscription_ids, connection_timeout=connection_timeout),
- start=1
+ svc.call(subscription_ids=subscription_ids, connection_timeout=connection_timeout), start=1
):
yield notification
if max_notifications_returned and i >= max_notifications_returned:
@@ -2098,6 +2246,7 @@ Methods
def get_user_configuration(self, name, properties=None):
from ..services import GetUserConfiguration
from ..services.get_user_configuration import ALL
+
if properties is None:
properties = ALL
return GetUserConfiguration(account=self.account).get(
@@ -2130,10 +2279,11 @@ Methods
def move(self, to_folder):
from ..services import MoveFolder
+
res = MoveFolder(account=self.account).get(folders=[self], to_folder=to_folder)
folder_id, changekey = res.id, res.changekey
if self.id != folder_id:
- raise ValueError('ID mismatch')
+ raise ValueError("ID mismatch")
# Don't check changekey value. It may not change on no-op moves
self.changekey = changekey
self.parent_folder_id = ParentFolderId(id=to_folder.id, changekey=to_folder.changekey)
@@ -2162,9 +2312,9 @@ Methods
elif isinstance(field_path, Field):
field_path = FieldPath(field=field_path)
fields[i] = field_path
- if field_path.field.name == 'start':
+ if field_path.field.name == "start":
has_start = True
- elif field_path.field.name == 'end':
+ elif field_path.field.name == "end":
has_end = True
# For CalendarItem items, we want to inject internal timezone fields. See also CalendarItem.clean()
@@ -2222,7 +2372,7 @@ Methods
def refresh(self):
fresh_folder = self.resolve(account=self.account, folder=self)
if self.id != fresh_folder.id:
- raise ValueError('ID mismatch')
+ raise ValueError("ID mismatch")
# Apparently, the changekey may get updated
for f in self.FIELDS:
setattr(self, f.name, getattr(fresh_folder, f.name))
@@ -2240,6 +2390,7 @@ Methods
def save(self, update_fields=None):
from ..services import CreateFolder, UpdateFolder
+
if self.id is None:
# New folder
if update_fields:
@@ -2258,7 +2409,7 @@ Methods
# These cannot be changed
continue
if (f.is_required or f.is_required_after_save) and (
- getattr(self, f.name) is None or (f.is_list and not getattr(self, f.name))
+ getattr(self, f.name) is None or (f.is_list and not getattr(self, f.name))
):
# These are required and cannot be deleted
continue
@@ -2266,7 +2417,7 @@ Methods
res = UpdateFolder(account=self.account).get(folders=[(self, update_fields)])
folder_id, changekey = res.id, res.changekey
if self.id != folder_id:
- raise ValueError('ID mismatch')
+ raise ValueError("ID mismatch")
# Don't check changekey value. It may not change on no-op updates
self.changekey = changekey
self.root.update_folder(self) # Update the folder in the cache
@@ -2312,10 +2463,13 @@ Methods
:return: The subscription ID and a watermark
"""
from ..services import SubscribeToPull
+
if event_types is None:
event_types = SubscribeToPull.EVENT_TYPES
return FolderCollection(account=self.account, folders=[self]).subscribe_to_pull(
- event_types=event_types, watermark=watermark, timeout=timeout,
+ event_types=event_types,
+ watermark=watermark,
+ timeout=timeout,
)
@@ -2344,10 +2498,14 @@ Methods
:return: The subscription ID and a watermark
"""
from ..services import SubscribeToPush
+
if event_types is None:
event_types = SubscribeToPush.EVENT_TYPES
return FolderCollection(account=self.account, folders=[self]).subscribe_to_push(
- event_types=event_types, watermark=watermark, status_frequency=status_frequency, callback_url=callback_url,
+ event_types=event_types,
+ watermark=watermark,
+ status_frequency=status_frequency,
+ callback_url=callback_url,
)
@@ -2370,6 +2528,7 @@ Methods
:return: The subscription ID
"""
from ..services import SubscribeToStreaming
+
if event_types is None:
event_types = SubscribeToStreaming.EVENT_TYPES
return FolderCollection(account=self.account, folders=[self]).subscribe_to_streaming(event_types=event_types)
@@ -2487,13 +2646,12 @@ Methods
# the folder content since we fetched the changekey.
if self.account:
return DistinguishedFolderId(
- id=self.DISTINGUISHED_FOLDER_ID,
- mailbox=Mailbox(email_address=self.account.primary_smtp_address)
+ id=self.DISTINGUISHED_FOLDER_ID, mailbox=Mailbox(email_address=self.account.primary_smtp_address)
)
return DistinguishedFolderId(id=self.DISTINGUISHED_FOLDER_ID)
if self.id:
return FolderId(id=self.id, changekey=self.changekey)
- raise ValueError('Must be a distinguished folder or have an ID')
+ raise ValueError("Must be a distinguished folder or have an ID")
@@ -2524,22 +2682,22 @@ Methods
├── exchangelib issues
└── Mom
"""
- tree = f'{self.name}\n'
+ tree = f"{self.name}\n"
children = list(self.children)
- for i, c in enumerate(sorted(children, key=attrgetter('name')), start=1):
- nodes = c.tree().split('\n')
+ for i, c in enumerate(sorted(children, key=attrgetter("name")), start=1):
+ nodes = c.tree().split("\n")
for j, node in enumerate(nodes, start=1):
if i != len(children) and j == 1:
# Not the last child, but the first node, which is the name of the child
- tree += f'├── {node}\n'
+ tree += f"├── {node}\n"
elif i != len(children) and j > 1:
# Not the last child, and not name of child
- tree += f'│ {node}\n'
+ tree += f"│ {node}\n"
elif i == len(children) and j == 1:
# Not the last child, but the first node, which is the name of the child
- tree += f'└── {node}\n'
+ tree += f"└── {node}\n"
else: # Last child, and not name of child
- tree += f' {node}\n'
+ tree += f" {node}\n"
return tree.strip()
@@ -2566,6 +2724,7 @@ @require_id
def update_user_configuration(self, name, dictionary=None, xml_data=None, binary_data=None):
from ..services import UpdateUserConfiguration
+
user_configuration = UserConfiguration(
user_configuration_name=UserConfigurationName(name=name, folder=self),
dictionary=dictionary,
@@ -2630,11 +2790,11 @@ Methods
# distinguished folders from being deleted. Use with caution!
_seen = _seen or set()
if self.id in _seen:
- raise RecursionError(f'We already tried to wipe {self}')
+ raise RecursionError(f"We already tried to wipe {self}")
if _level > 16:
- raise RecursionError(f'Max recursion level reached: {_level}')
+ raise RecursionError(f"Max recursion level reached: {_level}")
_seen.add(self.id)
- log.warning('Wiping %s', self)
+ log.warning("Wiping %s", self)
has_distinguished_subfolders = any(f.is_distinguished for f in self.children)
try:
if has_distinguished_subfolders:
@@ -2647,26 +2807,26 @@ Methods
raise # We already tried this
self.empty(delete_sub_folders=False)
except (ErrorAccessDenied, ErrorCannotEmptyFolder, ErrorItemNotFound):
- log.warning('Not allowed to empty %s. Trying to delete items instead', self)
+ log.warning("Not allowed to empty %s. Trying to delete items instead", self)
kwargs = {}
if page_size is not None:
- kwargs['page_size'] = page_size
+ kwargs["page_size"] = page_size
if chunk_size is not None:
- kwargs['chunk_size'] = chunk_size
+ kwargs["chunk_size"] = chunk_size
try:
self.all().delete(**kwargs)
except (ErrorAccessDenied, ErrorCannotDeleteObject, ErrorItemNotFound):
- log.warning('Not allowed to delete items in %s', self)
+ log.warning("Not allowed to delete items in %s", self)
_level += 1
for f in self.children:
f.wipe(page_size=page_size, chunk_size=chunk_size, _seen=_seen, _level=_level)
# Remove non-distinguished children that are empty and have no subfolders
if f.is_deletable and not f.children:
- log.warning('Deleting folder %s', f)
+ log.warning("Deleting folder %s", f)
try:
f.delete()
except ErrorDeleteDistinguishedFolder:
- log.warning('Tried to delete a distinguished folder (%s)', f)
+ log.warning("Tried to delete a distinguished folder (%s)", f)
@@ -2707,24 +2867,25 @@ class Folder(BaseFolder):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/folder"""
- permission_set = PermissionSetField(field_uri='folder:PermissionSet', supported_from=EXCHANGE_2007_SP1)
- effective_rights = EffectiveRightsField(field_uri='folder:EffectiveRights', is_read_only=True,
- supported_from=EXCHANGE_2007_SP1)
+ permission_set = PermissionSetField(field_uri="folder:PermissionSet", supported_from=EXCHANGE_2007_SP1)
+ effective_rights = EffectiveRightsField(
+ field_uri="folder:EffectiveRights", is_read_only=True, supported_from=EXCHANGE_2007_SP1
+ )
- __slots__ = '_root',
+ __slots__ = ("_root",)
def __init__(self, **kwargs):
- self._root = kwargs.pop('root', None) # This is a pointer to the root of the folder hierarchy
- parent = kwargs.pop('parent', None)
+ self._root = kwargs.pop("root", None) # This is a pointer to the root of the folder hierarchy
+ parent = kwargs.pop("parent", None)
if parent:
if self.root:
if parent.root != self.root:
raise ValueError("'parent.root' must match 'root'")
else:
self.root = parent.root
- if 'parent_folder_id' in kwargs and parent.id != kwargs['parent_folder_id']:
+ if "parent_folder_id" in kwargs and parent.id != kwargs["parent_folder_id"]:
raise ValueError("'parent_folder_id' must match 'parent' ID")
- kwargs['parent_folder_id'] = ParentFolderId(id=parent.id, changekey=parent.changekey)
+ kwargs["parent_folder_id"] = ParentFolderId(id=parent.id, changekey=parent.changekey)
super().__init__(**kwargs)
@property
@@ -2744,13 +2905,13 @@ Inherited members
@classmethod
def register(cls, *args, **kwargs):
if cls is not Folder:
- raise TypeError('For folders, custom fields must be registered on the Folder class')
+ raise TypeError("For folders, custom fields must be registered on the Folder class")
return super().register(*args, **kwargs)
@classmethod
def deregister(cls, *args, **kwargs):
if cls is not Folder:
- raise TypeError('For folders, custom fields must be registered on the Folder class')
+ raise TypeError("For folders, custom fields must be registered on the Folder class")
return super().deregister(*args, **kwargs)
@classmethod
@@ -2762,11 +2923,10 @@ Inherited members
"""
try:
return cls.resolve(
- account=root.account,
- folder=cls(root=root, name=cls.DISTINGUISHED_FOLDER_ID, is_distinguished=True)
+ account=root.account, folder=cls(root=root, name=cls.DISTINGUISHED_FOLDER_ID, is_distinguished=True)
)
except MISSING_FOLDER_ERRORS:
- raise ErrorFolderNotFound(f'Could not find distinguished folder {cls.DISTINGUISHED_FOLDER_ID!r}')
+ raise ErrorFolderNotFound(f"Could not find distinguished folder {cls.DISTINGUISHED_FOLDER_ID!r}")
@property
def parent(self):
@@ -2783,15 +2943,16 @@ Inherited members
self.parent_folder_id = None
else:
if not isinstance(value, BaseFolder):
- raise InvalidTypeError('value', value, BaseFolder)
+ raise InvalidTypeError("value", value, BaseFolder)
self.root = value.root
self.parent_folder_id = ParentFolderId(id=value.id, changekey=value.changekey)
def clean(self, version=None):
from .roots import RootOfHierarchy
+
super().clean(version=version)
if self.root and not isinstance(self.root, RootOfHierarchy):
- raise InvalidTypeError('root', self.root, RootOfHierarchy)
+ raise InvalidTypeError("root", self.root, RootOfHierarchy)
@classmethod
def from_xml_with_root(cls, elem, root):
@@ -2817,20 +2978,20 @@ Inherited members
if folder.name:
try:
# TODO: fld_class.LOCALIZED_NAMES is most definitely neither complete nor authoritative
- folder_cls = root.folder_cls_from_folder_name(folder_name=folder.name,
- locale=root.account.locale)
- log.debug('Folder class %s matches localized folder name %s', folder_cls, folder.name)
+ folder_cls = root.folder_cls_from_folder_name(folder_name=folder.name, locale=root.account.locale)
+ log.debug("Folder class %s matches localized folder name %s", folder_cls, folder.name)
except KeyError:
pass
if folder.folder_class and folder_cls == Folder:
try:
folder_cls = cls.folder_cls_from_container_class(container_class=folder.folder_class)
- log.debug('Folder class %s matches container class %s (%s)', folder_cls, folder.folder_class,
- folder.name)
+ log.debug(
+ "Folder class %s matches container class %s (%s)", folder_cls, folder.folder_class, folder.name
+ )
except KeyError:
pass
if folder_cls == Folder:
- log.debug('Fallback to class Folder (folder_class %s, name %s)', folder.folder_class, folder.name)
+ log.debug("Fallback to class Folder (folder_class %s, name %s)", folder.folder_class, folder.name)
return folder_cls(root=root, **{f.name: getattr(folder, f.name) for f in folder.FIELDS})
def clean(self, version=None):
from .roots import RootOfHierarchy
+
super().clean(version=version)
if self.root and not isinstance(self.root, RootOfHierarchy):
- raise InvalidTypeError('root', self.root, RootOfHierarchy)
+ raise InvalidTypeError("root", self.root, RootOfHierarchy)
diff --git a/docs/exchangelib/folders/collections.html b/docs/exchangelib/folders/collections.html
index 3a871adc..a1d05210 100644
--- a/docs/exchangelib/folders/collections.html
+++ b/docs/exchangelib/folders/collections.html
@@ -33,9 +33,9 @@ exchangelib.folders.collections
exchangelib.folders.collections
exchangelib.folders.collections
exchangelib.folders.collections
exchangelib.folders.collections
exchangelib.folders.collections
exchangelib.folders.collections
exchangelib.folders.collections
exchangelib.folders.collections
exchangelib.folders.collections
exchangelib.folders.collections
exchangelib.folders.collections
@require_account
-def find_folders(self, q=None, shape=ID_ONLY, depth=None, additional_fields=None, page_size=None, max_items=None,
- offset=0):
+def find_folders(
+ self, q=None, shape=ID_ONLY, depth=None, additional_fields=None, page_size=None, max_items=None, offset=0
+):
from ..services import FindFolder
+
# 'depth' controls whether to return direct children or recurse into sub-folders
from .base import BaseFolder, Folder
+
if q is None:
q = Q()
if not self.folders:
- log.debug('Folder list is empty')
+ log.debug("Folder list is empty")
return
if q.is_never():
- log.debug('Query will never return results')
+ log.debug("Query will never return results")
return
if q.is_empty():
restriction = None
@@ -1260,13 +1341,13 @@ Examples
)
yield from FindFolder(account=self.account, page_size=page_size).call(
- folders=self.folders,
- additional_fields=additional_fields,
- restriction=restriction,
- shape=shape,
- depth=depth,
- max_items=max_items,
- offset=offset,
+ folders=self.folders,
+ additional_fields=additional_fields,
+ restriction=restriction,
+ shape=shape,
+ depth=depth,
+ max_items=max_items,
+ offset=offset,
)
@@ -1291,8 +1372,18 @@ def find_items(self, q, shape=ID_ONLY, depth=None, additional_fields=None, order_fields=None,
- calendar_view=None, page_size=None, max_items=None, offset=0):
+def find_items(
+ self,
+ q,
+ shape=ID_ONLY,
+ depth=None,
+ additional_fields=None,
+ order_fields=None,
+ calendar_view=None,
+ page_size=None,
+ max_items=None,
+ offset=0,
+):
"""Private method to call the FindItem service.
:param q: a Q instance containing any restrictions
@@ -1310,21 +1401,21 @@ Examples
:return: a generator for the returned item IDs or items
"""
from ..services import FindItem
+
if not self.folders:
- log.debug('Folder list is empty')
+ log.debug("Folder list is empty")
return
if q.is_never():
- log.debug('Query will never return results')
+ log.debug("Query will never return results")
return
depth, restriction, query_string = self._rinse_args(
- q=q, depth=depth, additional_fields=additional_fields,
- field_validator=self.validate_item_field
+ q=q, depth=depth, additional_fields=additional_fields, field_validator=self.validate_item_field
)
if calendar_view is not None and not isinstance(calendar_view, CalendarView):
- raise InvalidTypeError('calendar_view', calendar_view, CalendarView)
+ raise InvalidTypeError("calendar_view", calendar_view, CalendarView)
log.debug(
- 'Finding %s items in folders %s (shape: %s, depth: %s, additional_fields: %s, restriction: %s)',
+ "Finding %s items in folders %s (shape: %s, depth: %s, additional_fields: %s, restriction: %s)",
self.account,
self.folders,
shape,
@@ -1365,8 +1456,17 @@ Examples
Expand source code
-def find_people(self, q, shape=ID_ONLY, depth=None, additional_fields=None, order_fields=None,
- page_size=None, max_items=None, offset=0):
+def find_people(
+ self,
+ q,
+ shape=ID_ONLY,
+ depth=None,
+ additional_fields=None,
+ order_fields=None,
+ page_size=None,
+ max_items=None,
+ offset=0,
+):
"""Private method to call the FindPeople service.
:param q: a Q instance containing any restrictions
@@ -1382,25 +1482,25 @@ Examples
:return: a generator for the returned personas
"""
from ..services import FindPeople
+
folder = self._get_single_folder()
if q.is_never():
- log.debug('Query will never return results')
+ log.debug("Query will never return results")
return
depth, restriction, query_string = self._rinse_args(
- q=q, depth=depth, additional_fields=additional_fields,
- field_validator=Persona.validate_field
+ q=q, depth=depth, additional_fields=additional_fields, field_validator=Persona.validate_field
)
yield from FindPeople(account=self.account, page_size=page_size).call(
- folder=folder,
- additional_fields=additional_fields,
- restriction=restriction,
- order_fields=order_fields,
- shape=shape,
- query_string=query_string,
- depth=depth,
- max_items=max_items,
- offset=offset,
+ folder=folder,
+ additional_fields=additional_fields,
+ restriction=restriction,
+ order_fields=order_fields,
+ shape=shape,
+ query_string=query_string,
+ depth=depth,
+ max_items=max_items,
+ offset=offset,
)
@@ -1415,7 +1515,8 @@ Examples
def get_folder_fields(self, target_cls, is_complex=None):
return {
- FieldPath(field=f) for f in target_cls.supported_fields(version=self.account.version)
+ FieldPath(field=f)
+ for f in target_cls.supported_fields(version=self.account.version)
if is_complex is None or f.is_complex is is_complex
}
@@ -1431,10 +1532,12 @@ Examples
def get_folders(self, additional_fields=None):
from ..services import GetFolder
+
# Expand folders with their full set of properties
from .base import BaseFolder
+
if not self.folders:
- log.debug('Folder list is empty')
+ log.debug("Folder list is empty")
return
if additional_fields is None:
# Default to all complex properties
@@ -1446,9 +1549,9 @@ Examples
)
yield from GetFolder(account=self.account).call(
- folders=self.folders,
- additional_fields=additional_fields,
- shape=ID_ONLY,
+ folders=self.folders,
+ additional_fields=additional_fields,
+ shape=ID_ONLY,
)
@@ -1490,17 +1593,18 @@ Examples
def resolve(self):
# Looks up the folders or folder IDs in the collection and returns full Folder instances with all fields set.
from .base import BaseFolder
+
resolveable_folders = []
for f in self.folders:
if isinstance(f, BaseFolder) and not f.get_folder_allowed:
- log.debug('GetFolder not allowed on folder %s. Non-complex fields must be fetched with FindFolder', f)
+ log.debug("GetFolder not allowed on folder %s. Non-complex fields must be fetched with FindFolder", f)
yield f
else:
resolveable_folders.append(f)
# Fetch all properties for the remaining folders of folder IDs
additional_fields = self.get_folder_fields(target_cls=self._get_target_cls(), is_complex=None)
yield from self.__class__(account=self.account, folders=resolveable_folders).get_folders(
- additional_fields=additional_fields
+ additional_fields=additional_fields
)
@@ -1528,13 +1632,17 @@ Examples
def subscribe_to_pull(self, event_types=None, watermark=None, timeout=60):
from ..services import SubscribeToPull
+
if not self.folders:
- log.debug('Folder list is empty')
+ log.debug("Folder list is empty")
return None
if event_types is None:
event_types = SubscribeToPull.EVENT_TYPES
return SubscribeToPull(account=self.account).get(
- folders=self.folders, event_types=event_types, watermark=watermark, timeout=timeout,
+ folders=self.folders,
+ event_types=event_types,
+ watermark=watermark,
+ timeout=timeout,
)
@@ -1549,13 +1657,17 @@ Examples
def subscribe_to_push(self, callback_url, event_types=None, watermark=None, status_frequency=1):
from ..services import SubscribeToPush
+
if not self.folders:
- log.debug('Folder list is empty')
+ log.debug("Folder list is empty")
return None
if event_types is None:
event_types = SubscribeToPush.EVENT_TYPES
return SubscribeToPush(account=self.account).get(
- folders=self.folders, event_types=event_types, watermark=watermark, status_frequency=status_frequency,
+ folders=self.folders,
+ event_types=event_types,
+ watermark=watermark,
+ status_frequency=status_frequency,
url=callback_url,
)
@@ -1571,8 +1683,9 @@ Examples
def subscribe_to_streaming(self, event_types=None):
from ..services import SubscribeToStreaming
+
if not self.folders:
- log.debug('Folder list is empty')
+ log.debug("Folder list is empty")
return None
if event_types is None:
event_types = SubscribeToStreaming.EVENT_TYPES
@@ -1590,6 +1703,7 @@ Examples
def sync_hierarchy(self, sync_state=None, only_fields=None):
from ..services import SyncFolderHierarchy
+
folder = self._get_single_folder()
if only_fields is None:
# We didn't restrict list of field paths. Get all fields from the server, including extended properties.
@@ -1636,6 +1750,7 @@ Examples
def sync_items(self, sync_state=None, only_fields=None, ignore=None, max_changes_returned=None, sync_scope=None):
from ..services import SyncFolderItems
+
folder = self._get_single_folder()
if only_fields is None:
# We didn't restrict list of field paths. Get all fields from the server, including extended properties.
@@ -1689,6 +1804,7 @@ Examples
sync methods.
"""
from ..services import Unsubscribe
+
return Unsubscribe(account=self.account).get(subscription_id=subscription_id)
diff --git a/docs/exchangelib/folders/index.html b/docs/exchangelib/folders/index.html
index 98d925b3..d29c8485 100644
--- a/docs/exchangelib/folders/index.html
+++ b/docs/exchangelib/folders/index.html
@@ -26,44 +26,186 @@ Module exchangelib.folders
Expand source code
-from .base import BaseFolder, Folder
+from ..properties import DistinguishedFolderId, FolderId
+from .base import BaseFolder, Folder
from .collections import FolderCollection
-from .known_folders import AdminAuditLogs, AllContacts, AllItems, ArchiveDeletedItems, ArchiveInbox, \
- ArchiveMsgFolderRoot, ArchiveRecoverableItemsDeletions, ArchiveRecoverableItemsPurges, \
- ArchiveRecoverableItemsRoot, ArchiveRecoverableItemsVersions, Audits, Calendar, CalendarLogging, CommonViews, \
- Conflicts, Contacts, ConversationHistory, ConversationSettings, DefaultFoldersChangeHistory, DeferredAction, \
- DeletedItems, Directory, Drafts, ExchangeSyncData, Favorites, Files, FreebusyData, Friends, GALContacts, \
- GraphAnalytics, IMContactList, Inbox, Journal, JunkEmail, LocalFailures, Location, MailboxAssociations, Messages, \
- MsgFolderRoot, MyContacts, MyContactsExtended, NonDeletableFolderMixin, Notes, Outbox, ParkedMessages, \
- PassThroughSearchResults, PdpProfileV2Secured, PeopleConnect, QuickContacts, RSSFeeds, RecipientCache, \
- RecoverableItemsDeletions, RecoverableItemsPurges, RecoverableItemsRoot, RecoverableItemsVersions, Reminders, \
- Schedule, SearchFolders, SentItems, ServerFailures, Sharing, Shortcuts, Signal, SmsAndChatsSync, SpoolerQueue, \
- SyncIssues, System, Tasks, TemporarySaves, ToDoSearch, Views, VoiceMail, WellknownFolder, WorkingSet, \
- Companies, OrganizationalContacts, PeopleCentricConversationBuddies, NON_DELETABLE_FOLDERS
-from .queryset import FolderQuerySet, SingleFolderQuerySet, FOLDER_TRAVERSAL_CHOICES, SHALLOW, DEEP, SOFT_DELETED
-from .roots import Root, ArchiveRoot, PublicFoldersRoot, RootOfHierarchy
-from ..properties import FolderId, DistinguishedFolderId
+from .known_folders import (
+ NON_DELETABLE_FOLDERS,
+ AdminAuditLogs,
+ AllContacts,
+ AllItems,
+ ArchiveDeletedItems,
+ ArchiveInbox,
+ ArchiveMsgFolderRoot,
+ ArchiveRecoverableItemsDeletions,
+ ArchiveRecoverableItemsPurges,
+ ArchiveRecoverableItemsRoot,
+ ArchiveRecoverableItemsVersions,
+ Audits,
+ Calendar,
+ CalendarLogging,
+ CommonViews,
+ Companies,
+ Conflicts,
+ Contacts,
+ ConversationHistory,
+ ConversationSettings,
+ DefaultFoldersChangeHistory,
+ DeferredAction,
+ DeletedItems,
+ Directory,
+ Drafts,
+ ExchangeSyncData,
+ Favorites,
+ Files,
+ FreebusyData,
+ Friends,
+ GALContacts,
+ GraphAnalytics,
+ IMContactList,
+ Inbox,
+ Journal,
+ JunkEmail,
+ LocalFailures,
+ Location,
+ MailboxAssociations,
+ Messages,
+ MsgFolderRoot,
+ MyContacts,
+ MyContactsExtended,
+ NonDeletableFolderMixin,
+ Notes,
+ OrganizationalContacts,
+ Outbox,
+ ParkedMessages,
+ PassThroughSearchResults,
+ PdpProfileV2Secured,
+ PeopleCentricConversationBuddies,
+ PeopleConnect,
+ QuickContacts,
+ RecipientCache,
+ RecoverableItemsDeletions,
+ RecoverableItemsPurges,
+ RecoverableItemsRoot,
+ RecoverableItemsVersions,
+ Reminders,
+ RSSFeeds,
+ Schedule,
+ SearchFolders,
+ SentItems,
+ ServerFailures,
+ Sharing,
+ Shortcuts,
+ Signal,
+ SmsAndChatsSync,
+ SpoolerQueue,
+ SyncIssues,
+ System,
+ Tasks,
+ TemporarySaves,
+ ToDoSearch,
+ Views,
+ VoiceMail,
+ WellknownFolder,
+ WorkingSet,
+)
+from .queryset import DEEP, FOLDER_TRAVERSAL_CHOICES, SHALLOW, SOFT_DELETED, FolderQuerySet, SingleFolderQuerySet
+from .roots import ArchiveRoot, PublicFoldersRoot, Root, RootOfHierarchy
__all__ = [
- 'FolderId', 'DistinguishedFolderId',
- 'FolderCollection',
- 'BaseFolder', 'Folder',
- 'AdminAuditLogs', 'AllContacts', 'AllItems', 'ArchiveDeletedItems', 'ArchiveInbox', 'ArchiveMsgFolderRoot',
- 'ArchiveRecoverableItemsDeletions', 'ArchiveRecoverableItemsPurges', 'ArchiveRecoverableItemsRoot',
- 'ArchiveRecoverableItemsVersions', 'Audits', 'Calendar', 'CalendarLogging', 'CommonViews', 'Conflicts',
- 'Contacts', 'ConversationHistory', 'ConversationSettings', 'DefaultFoldersChangeHistory', 'DeferredAction',
- 'DeletedItems', 'Directory', 'Drafts', 'ExchangeSyncData', 'Favorites', 'Files', 'FreebusyData', 'Friends',
- 'GALContacts', 'GraphAnalytics', 'IMContactList', 'Inbox', 'Journal', 'JunkEmail', 'LocalFailures',
- 'Location', 'MailboxAssociations', 'Messages', 'MsgFolderRoot', 'MyContacts', 'MyContactsExtended',
- 'NonDeletableFolderMixin', 'Notes', 'Outbox', 'ParkedMessages', 'PassThroughSearchResults',
- 'PdpProfileV2Secured', 'PeopleConnect', 'QuickContacts', 'RSSFeeds', 'RecipientCache',
- 'RecoverableItemsDeletions', 'RecoverableItemsPurges', 'RecoverableItemsRoot', 'RecoverableItemsVersions',
- 'Reminders', 'Schedule', 'SearchFolders', 'SentItems', 'ServerFailures', 'Sharing', 'Shortcuts', 'Signal',
- 'SmsAndChatsSync', 'SpoolerQueue', 'SyncIssues', 'System', 'Tasks', 'TemporarySaves', 'ToDoSearch', 'Views',
- 'VoiceMail', 'WellknownFolder', 'WorkingSet', 'Companies', 'OrganizationalContacts',
- 'PeopleCentricConversationBuddies', 'NON_DELETABLE_FOLDERS',
- 'FolderQuerySet', 'SingleFolderQuerySet', 'FOLDER_TRAVERSAL_CHOICES', 'SHALLOW', 'DEEP', 'SOFT_DELETED',
- 'Root', 'ArchiveRoot', 'PublicFoldersRoot', 'RootOfHierarchy',
+ "FolderId",
+ "DistinguishedFolderId",
+ "FolderCollection",
+ "BaseFolder",
+ "Folder",
+ "AdminAuditLogs",
+ "AllContacts",
+ "AllItems",
+ "ArchiveDeletedItems",
+ "ArchiveInbox",
+ "ArchiveMsgFolderRoot",
+ "ArchiveRecoverableItemsDeletions",
+ "ArchiveRecoverableItemsPurges",
+ "ArchiveRecoverableItemsRoot",
+ "ArchiveRecoverableItemsVersions",
+ "Audits",
+ "Calendar",
+ "CalendarLogging",
+ "CommonViews",
+ "Conflicts",
+ "Contacts",
+ "ConversationHistory",
+ "ConversationSettings",
+ "DefaultFoldersChangeHistory",
+ "DeferredAction",
+ "DeletedItems",
+ "Directory",
+ "Drafts",
+ "ExchangeSyncData",
+ "Favorites",
+ "Files",
+ "FreebusyData",
+ "Friends",
+ "GALContacts",
+ "GraphAnalytics",
+ "IMContactList",
+ "Inbox",
+ "Journal",
+ "JunkEmail",
+ "LocalFailures",
+ "Location",
+ "MailboxAssociations",
+ "Messages",
+ "MsgFolderRoot",
+ "MyContacts",
+ "MyContactsExtended",
+ "NonDeletableFolderMixin",
+ "Notes",
+ "Outbox",
+ "ParkedMessages",
+ "PassThroughSearchResults",
+ "PdpProfileV2Secured",
+ "PeopleConnect",
+ "QuickContacts",
+ "RSSFeeds",
+ "RecipientCache",
+ "RecoverableItemsDeletions",
+ "RecoverableItemsPurges",
+ "RecoverableItemsRoot",
+ "RecoverableItemsVersions",
+ "Reminders",
+ "Schedule",
+ "SearchFolders",
+ "SentItems",
+ "ServerFailures",
+ "Sharing",
+ "Shortcuts",
+ "Signal",
+ "SmsAndChatsSync",
+ "SpoolerQueue",
+ "SyncIssues",
+ "System",
+ "Tasks",
+ "TemporarySaves",
+ "ToDoSearch",
+ "Views",
+ "VoiceMail",
+ "WellknownFolder",
+ "WorkingSet",
+ "Companies",
+ "OrganizationalContacts",
+ "PeopleCentricConversationBuddies",
+ "NON_DELETABLE_FOLDERS",
+ "FolderQuerySet",
+ "SingleFolderQuerySet",
+ "FOLDER_TRAVERSAL_CHOICES",
+ "SHALLOW",
+ "DEEP",
+ "SOFT_DELETED",
+ "Root",
+ "ArchiveRoot",
+ "PublicFoldersRoot",
+ "RootOfHierarchy",
]
@@ -110,7 +252,7 @@ Classes
Expand source code
class AdminAuditLogs(WellknownFolder):
- DISTINGUISHED_FOLDER_ID = 'adminauditlogs'
+ DISTINGUISHED_FOLDER_ID = "adminauditlogs"
supported_from = EXCHANGE_2013
get_folder_allowed = False
@@ -189,10 +331,10 @@ Inherited members
Expand source code
class AllContacts(NonDeletableFolderMixin, Contacts):
- CONTAINER_CLASS = 'IPF.Note'
+ CONTAINER_CLASS = "IPF.Note"
LOCALIZED_NAMES = {
- None: ('AllContacts',),
+ None: ("AllContacts",),
}
Ancestors
@@ -267,10 +409,10 @@ Inherited members
Expand source code
class AllItems(NonDeletableFolderMixin, Folder):
- CONTAINER_CLASS = 'IPF'
+ CONTAINER_CLASS = "IPF"
LOCALIZED_NAMES = {
- None: ('AllItems',),
+ None: ("AllItems",),
}
Ancestors
@@ -344,7 +486,7 @@ Inherited members
Expand source code
class ArchiveDeletedItems(WellknownFolder):
- DISTINGUISHED_FOLDER_ID = 'archivedeleteditems'
+ DISTINGUISHED_FOLDER_ID = "archivedeleteditems"
supported_from = EXCHANGE_2010_SP1
Ancestors
@@ -418,7 +560,7 @@ Inherited members
Expand source code
class ArchiveInbox(WellknownFolder):
- DISTINGUISHED_FOLDER_ID = 'archiveinbox'
+ DISTINGUISHED_FOLDER_ID = "archiveinbox"
supported_from = EXCHANGE_2013_SP1
Ancestors
@@ -492,7 +634,7 @@ Inherited members
Expand source code
class ArchiveMsgFolderRoot(WellknownFolder):
- DISTINGUISHED_FOLDER_ID = 'archivemsgfolderroot'
+ DISTINGUISHED_FOLDER_ID = "archivemsgfolderroot"
supported_from = EXCHANGE_2010_SP1
Ancestors
@@ -566,7 +708,7 @@ Inherited members
Expand source code
class ArchiveRecoverableItemsDeletions(WellknownFolder):
- DISTINGUISHED_FOLDER_ID = 'archiverecoverableitemsdeletions'
+ DISTINGUISHED_FOLDER_ID = "archiverecoverableitemsdeletions"
supported_from = EXCHANGE_2010_SP1
Ancestors
@@ -640,7 +782,7 @@ Inherited members
Expand source code
class ArchiveRecoverableItemsPurges(WellknownFolder):
- DISTINGUISHED_FOLDER_ID = 'archiverecoverableitemspurges'
+ DISTINGUISHED_FOLDER_ID = "archiverecoverableitemspurges"
supported_from = EXCHANGE_2010_SP1
Ancestors
@@ -714,7 +856,7 @@ Inherited members
Expand source code
class ArchiveRecoverableItemsRoot(WellknownFolder):
- DISTINGUISHED_FOLDER_ID = 'archiverecoverableitemsroot'
+ DISTINGUISHED_FOLDER_ID = "archiverecoverableitemsroot"
supported_from = EXCHANGE_2010_SP1
Ancestors
@@ -788,7 +930,7 @@ Inherited members
Expand source code
class ArchiveRecoverableItemsVersions(WellknownFolder):
- DISTINGUISHED_FOLDER_ID = 'archiverecoverableitemsversions'
+ DISTINGUISHED_FOLDER_ID = "archiverecoverableitemsversions"
supported_from = EXCHANGE_2010_SP1
Ancestors
@@ -864,7 +1006,7 @@ Inherited members
class ArchiveRoot(RootOfHierarchy):
"""The root of the archive folders hierarchy. Not available on all mailboxes."""
- DISTINGUISHED_FOLDER_ID = 'archiveroot'
+ DISTINGUISHED_FOLDER_ID = "archiveroot"
supported_from = EXCHANGE_2010_SP1
WELLKNOWN_FOLDERS = WELLKNOWN_FOLDERS_IN_ARCHIVE_ROOT
@@ -945,7 +1087,7 @@ Inherited members
class Audits(NonDeletableFolderMixin, Folder):
LOCALIZED_NAMES = {
- None: ('Audits',),
+ None: ("Audits",),
}
get_folder_allowed = False
@@ -1022,7 +1164,7 @@ Inherited members
class BaseFolder(RegisterMixIn, SearchableMixIn, metaclass=EWSMeta):
"""Base class for all classes that implement a folder."""
- ELEMENT_NAME = 'Folder'
+ ELEMENT_NAME = "Folder"
NAMESPACE = TNS
# See https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/distinguishedfolderid
DISTINGUISHED_FOLDER_ID = None
@@ -1041,24 +1183,23 @@ Inherited members
ITEM_MODEL_MAP = {cls.response_tag(): cls for cls in ITEM_CLASSES}
ID_ELEMENT_CLS = FolderId
- _id = IdElementField(field_uri='folder:FolderId', value_cls=ID_ELEMENT_CLS)
- parent_folder_id = EWSElementField(field_uri='folder:ParentFolderId', value_cls=ParentFolderId,
- is_read_only=True)
- folder_class = CharField(field_uri='folder:FolderClass', is_required_after_save=True)
- name = CharField(field_uri='folder:DisplayName')
- total_count = IntegerField(field_uri='folder:TotalCount', is_read_only=True)
- child_folder_count = IntegerField(field_uri='folder:ChildFolderCount', is_read_only=True)
- unread_count = IntegerField(field_uri='folder:UnreadCount', is_read_only=True)
+ _id = IdElementField(field_uri="folder:FolderId", value_cls=ID_ELEMENT_CLS)
+ parent_folder_id = EWSElementField(field_uri="folder:ParentFolderId", value_cls=ParentFolderId, is_read_only=True)
+ folder_class = CharField(field_uri="folder:FolderClass", is_required_after_save=True)
+ name = CharField(field_uri="folder:DisplayName")
+ total_count = IntegerField(field_uri="folder:TotalCount", is_read_only=True)
+ child_folder_count = IntegerField(field_uri="folder:ChildFolderCount", is_read_only=True)
+ unread_count = IntegerField(field_uri="folder:UnreadCount", is_read_only=True)
- __slots__ = 'is_distinguished', 'item_sync_state', 'folder_sync_state'
+ __slots__ = "is_distinguished", "item_sync_state", "folder_sync_state"
# Used to register extended properties
- INSERT_AFTER_FIELD = 'child_folder_count'
+ INSERT_AFTER_FIELD = "child_folder_count"
def __init__(self, **kwargs):
- self.is_distinguished = kwargs.pop('is_distinguished', False)
- self.item_sync_state = kwargs.pop('item_sync_state', None)
- self.folder_sync_state = kwargs.pop('folder_sync_state', None)
+ self.is_distinguished = kwargs.pop("is_distinguished", False)
+ self.item_sync_state = kwargs.pop("item_sync_state", None)
+ self.folder_sync_state = kwargs.pop("folder_sync_state", None)
super().__init__(**kwargs)
@property
@@ -1103,7 +1244,7 @@ Inherited members
@property
def absolute(self):
- return ''.join(f'/{p.name}' for p in self.parts)
+ return "".join(f"/{p.name}" for p in self.parts)
def _walk(self):
for c in self.children:
@@ -1114,23 +1255,23 @@ Inherited members
return FolderCollection(account=self.account, folders=self._walk())
def _glob(self, pattern):
- split_pattern = pattern.rsplit('/', 1)
+ split_pattern = pattern.rsplit("/", 1)
head, tail = (split_pattern[0], None) if len(split_pattern) == 1 else split_pattern
- if head == '':
+ if head == "":
# We got an absolute path. Restart globbing at root
- yield from self.root.glob(tail or '*')
- elif head == '..':
+ yield from self.root.glob(tail or "*")
+ elif head == "..":
# Relative path with reference to parent. Restart globbing at parent
if not self.parent:
- raise ValueError('Already at top')
- yield from self.parent.glob(tail or '*')
- elif head == '**':
+ raise ValueError("Already at top")
+ yield from self.parent.glob(tail or "*")
+ elif head == "**":
# Match anything here or in any subfolder at arbitrary depth
for c in self.walk():
# fnmatch() may be case-sensitive depending on operating system:
# force a case-insensitive match since case appears not to
# matter for folders in Exchange
- if fnmatch(c.name.lower(), (tail or '*').lower()):
+ if fnmatch(c.name.lower(), (tail or "*").lower()):
yield c
else:
# Regular pattern
@@ -1157,22 +1298,22 @@ Inherited members
├── exchangelib issues
└── Mom
"""
- tree = f'{self.name}\n'
+ tree = f"{self.name}\n"
children = list(self.children)
- for i, c in enumerate(sorted(children, key=attrgetter('name')), start=1):
- nodes = c.tree().split('\n')
+ for i, c in enumerate(sorted(children, key=attrgetter("name")), start=1):
+ nodes = c.tree().split("\n")
for j, node in enumerate(nodes, start=1):
if i != len(children) and j == 1:
# Not the last child, but the first node, which is the name of the child
- tree += f'├── {node}\n'
+ tree += f"├── {node}\n"
elif i != len(children) and j > 1:
# Not the last child, and not name of child
- tree += f'│ {node}\n'
+ tree += f"│ {node}\n"
elif i == len(children) and j == 1:
# Not the last child, but the first node, which is the name of the child
- tree += f'└── {node}\n'
+ tree += f"└── {node}\n"
else: # Last child, and not name of child
- tree += f' {node}\n'
+ tree += f" {node}\n"
return tree.strip()
@classmethod
@@ -1200,11 +1341,29 @@ Inherited members
:param container_class:
:return:
"""
- from .known_folders import Messages, Tasks, Calendar, ConversationSettings, Contacts, GALContacts, Reminders, \
- RecipientCache, RSSFeeds
+ from .known_folders import (
+ Calendar,
+ Contacts,
+ ConversationSettings,
+ GALContacts,
+ Messages,
+ RecipientCache,
+ Reminders,
+ RSSFeeds,
+ Tasks,
+ )
+
for folder_cls in (
- Messages, Tasks, Calendar, ConversationSettings, Contacts, GALContacts, Reminders, RecipientCache,
- RSSFeeds):
+ Messages,
+ Tasks,
+ Calendar,
+ ConversationSettings,
+ Contacts,
+ GALContacts,
+ Reminders,
+ RecipientCache,
+ RSSFeeds,
+ ):
if folder_cls.CONTAINER_CLASS == container_class:
return folder_cls
raise KeyError()
@@ -1214,7 +1373,7 @@ Inherited members
try:
return cls.ITEM_MODEL_MAP[tag]
except KeyError:
- raise ValueError(f'Item type {tag} was unexpected in a {cls.__name__} folder')
+ raise ValueError(f"Item type {tag} was unexpected in a {cls.__name__} folder")
@classmethod
def allowed_item_fields(cls, version):
@@ -1240,9 +1399,9 @@ Inherited members
elif isinstance(field_path, Field):
field_path = FieldPath(field=field_path)
fields[i] = field_path
- if field_path.field.name == 'start':
+ if field_path.field.name == "start":
has_start = True
- elif field_path.field.name == 'end':
+ elif field_path.field.name == "end":
has_end = True
# For CalendarItem items, we want to inject internal timezone fields. See also CalendarItem.clean()
@@ -1291,6 +1450,7 @@ Inherited members
def save(self, update_fields=None):
from ..services import CreateFolder, UpdateFolder
+
if self.id is None:
# New folder
if update_fields:
@@ -1309,7 +1469,7 @@ Inherited members
# These cannot be changed
continue
if (f.is_required or f.is_required_after_save) and (
- getattr(self, f.name) is None or (f.is_list and not getattr(self, f.name))
+ getattr(self, f.name) is None or (f.is_list and not getattr(self, f.name))
):
# These are required and cannot be deleted
continue
@@ -1317,7 +1477,7 @@ Inherited members
res = UpdateFolder(account=self.account).get(folders=[(self, update_fields)])
folder_id, changekey = res.id, res.changekey
if self.id != folder_id:
- raise ValueError('ID mismatch')
+ raise ValueError("ID mismatch")
# Don't check changekey value. It may not change on no-op updates
self.changekey = changekey
self.root.update_folder(self) # Update the folder in the cache
@@ -1325,10 +1485,11 @@ Inherited members
def move(self, to_folder):
from ..services import MoveFolder
+
res = MoveFolder(account=self.account).get(folders=[self], to_folder=to_folder)
folder_id, changekey = res.id, res.changekey
if self.id != folder_id:
- raise ValueError('ID mismatch')
+ raise ValueError("ID mismatch")
# Don't check changekey value. It may not change on no-op moves
self.changekey = changekey
self.parent_folder_id = ParentFolderId(id=to_folder.id, changekey=to_folder.changekey)
@@ -1336,12 +1497,14 @@ Inherited members
def delete(self, delete_type=HARD_DELETE):
from ..services import DeleteFolder
+
DeleteFolder(account=self.account).get(folders=[self], delete_type=delete_type)
self.root.remove_folder(self) # Remove the updated folder from the cache
self._id = None
def empty(self, delete_type=HARD_DELETE, delete_sub_folders=False):
from ..services import EmptyFolder
+
EmptyFolder(account=self.account).get(
folders=[self], delete_type=delete_type, delete_sub_folders=delete_sub_folders
)
@@ -1354,11 +1517,11 @@ Inherited members
# distinguished folders from being deleted. Use with caution!
_seen = _seen or set()
if self.id in _seen:
- raise RecursionError(f'We already tried to wipe {self}')
+ raise RecursionError(f"We already tried to wipe {self}")
if _level > 16:
- raise RecursionError(f'Max recursion level reached: {_level}')
+ raise RecursionError(f"Max recursion level reached: {_level}")
_seen.add(self.id)
- log.warning('Wiping %s', self)
+ log.warning("Wiping %s", self)
has_distinguished_subfolders = any(f.is_distinguished for f in self.children)
try:
if has_distinguished_subfolders:
@@ -1371,26 +1534,26 @@ Inherited members
raise # We already tried this
self.empty(delete_sub_folders=False)
except (ErrorAccessDenied, ErrorCannotEmptyFolder, ErrorItemNotFound):
- log.warning('Not allowed to empty %s. Trying to delete items instead', self)
+ log.warning("Not allowed to empty %s. Trying to delete items instead", self)
kwargs = {}
if page_size is not None:
- kwargs['page_size'] = page_size
+ kwargs["page_size"] = page_size
if chunk_size is not None:
- kwargs['chunk_size'] = chunk_size
+ kwargs["chunk_size"] = chunk_size
try:
self.all().delete(**kwargs)
except (ErrorAccessDenied, ErrorCannotDeleteObject, ErrorItemNotFound):
- log.warning('Not allowed to delete items in %s', self)
+ log.warning("Not allowed to delete items in %s", self)
_level += 1
for f in self.children:
f.wipe(page_size=page_size, chunk_size=chunk_size, _seen=_seen, _level=_level)
# Remove non-distinguished children that are empty and have no subfolders
if f.is_deletable and not f.children:
- log.warning('Deleting folder %s', f)
+ log.warning("Deleting folder %s", f)
try:
f.delete()
except ErrorDeleteDistinguishedFolder:
- log.warning('Tried to delete a distinguished folder (%s)', f)
+ log.warning("Tried to delete a distinguished folder (%s)", f)
def test_access(self):
"""Does a simple FindItem to test (read) access to the folder. Maybe the account doesn't exist, maybe the
@@ -1402,12 +1565,12 @@ Inherited members
@classmethod
def _kwargs_from_elem(cls, elem, account):
# Check for 'DisplayName' element before collecting kwargs because because that clears the elements
- has_name_elem = elem.find(cls.get_field_by_fieldname('name').response_tag()) is not None
+ has_name_elem = elem.find(cls.get_field_by_fieldname("name").response_tag()) is not None
kwargs = {f.name: f.from_xml(elem=elem, account=account) for f in cls.FIELDS}
- if has_name_elem and not kwargs['name']:
+ if has_name_elem and not kwargs["name"]:
# When we request the 'DisplayName' property, some folders may still be returned with an empty value.
# Assign a default name to these folders.
- kwargs['name'] = cls.DISTINGUISHED_FOLDER_ID
+ kwargs["name"] = cls.DISTINGUISHED_FOLDER_ID
return kwargs
def to_id(self):
@@ -1416,22 +1579,21 @@ Inherited members
# the folder content since we fetched the changekey.
if self.account:
return DistinguishedFolderId(
- id=self.DISTINGUISHED_FOLDER_ID,
- mailbox=Mailbox(email_address=self.account.primary_smtp_address)
+ id=self.DISTINGUISHED_FOLDER_ID, mailbox=Mailbox(email_address=self.account.primary_smtp_address)
)
return DistinguishedFolderId(id=self.DISTINGUISHED_FOLDER_ID)
if self.id:
return FolderId(id=self.id, changekey=self.changekey)
- raise ValueError('Must be a distinguished folder or have an ID')
+ raise ValueError("Must be a distinguished folder or have an ID")
@classmethod
def resolve(cls, account, folder):
# Resolve a single folder
folders = list(FolderCollection(account=account, folders=[folder]).resolve())
if not folders:
- raise ErrorFolderNotFound(f'Could not find folder {folder!r}')
+ raise ErrorFolderNotFound(f"Could not find folder {folder!r}")
if len(folders) != 1:
- raise ValueError(f'Expected result length 1, but got {folders}')
+ raise ValueError(f"Expected result length 1, but got {folders}")
f = folders[0]
if isinstance(f, Exception):
raise f
@@ -1443,7 +1605,7 @@ Inherited members
def refresh(self):
fresh_folder = self.resolve(account=self.account, folder=self)
if self.id != fresh_folder.id:
- raise ValueError('ID mismatch')
+ raise ValueError("ID mismatch")
# Apparently, the changekey may get updated
for f in self.FIELDS:
setattr(self, f.name, getattr(fresh_folder, f.name))
@@ -1453,6 +1615,7 @@ Inherited members
def get_user_configuration(self, name, properties=None):
from ..services import GetUserConfiguration
from ..services.get_user_configuration import ALL
+
if properties is None:
properties = ALL
return GetUserConfiguration(account=self.account).get(
@@ -1463,6 +1626,7 @@ Inherited members
@require_id
def create_user_configuration(self, name, dictionary=None, xml_data=None, binary_data=None):
from ..services import CreateUserConfiguration
+
user_configuration = UserConfiguration(
user_configuration_name=UserConfigurationName(name=name, folder=self),
dictionary=dictionary,
@@ -1474,6 +1638,7 @@ Inherited members
@require_id
def update_user_configuration(self, name, dictionary=None, xml_data=None, binary_data=None):
from ..services import UpdateUserConfiguration
+
user_configuration = UserConfiguration(
user_configuration_name=UserConfigurationName(name=name, folder=self),
dictionary=dictionary,
@@ -1485,6 +1650,7 @@ Inherited members
@require_id
def delete_user_configuration(self, name):
from ..services import DeleteUserConfiguration
+
return DeleteUserConfiguration(account=self.account).get(
user_configuration_name=UserConfigurationNameMNS(name=name, folder=self)
)
@@ -1500,10 +1666,13 @@ Inherited members
:return: The subscription ID and a watermark
"""
from ..services import SubscribeToPull
+
if event_types is None:
event_types = SubscribeToPull.EVENT_TYPES
return FolderCollection(account=self.account, folders=[self]).subscribe_to_pull(
- event_types=event_types, watermark=watermark, timeout=timeout,
+ event_types=event_types,
+ watermark=watermark,
+ timeout=timeout,
)
@require_id
@@ -1517,10 +1686,14 @@ Inherited members
:return: The subscription ID and a watermark
"""
from ..services import SubscribeToPush
+
if event_types is None:
event_types = SubscribeToPush.EVENT_TYPES
return FolderCollection(account=self.account, folders=[self]).subscribe_to_push(
- event_types=event_types, watermark=watermark, status_frequency=status_frequency, callback_url=callback_url,
+ event_types=event_types,
+ watermark=watermark,
+ status_frequency=status_frequency,
+ callback_url=callback_url,
)
@require_id
@@ -1531,6 +1704,7 @@ Inherited members
:return: The subscription ID
"""
from ..services import SubscribeToStreaming
+
if event_types is None:
event_types = SubscribeToStreaming.EVENT_TYPES
return FolderCollection(account=self.account, folders=[self]).subscribe_to_streaming(event_types=event_types)
@@ -1557,6 +1731,7 @@ Inherited members
sync methods.
"""
from ..services import Unsubscribe
+
return Unsubscribe(account=self.account).get(subscription_id=subscription_id)
def sync_items(self, sync_state=None, only_fields=None, ignore=None, max_changes_returned=None, sync_scope=None):
@@ -1616,6 +1791,7 @@ Inherited members
sync methods.
"""
from ..services import GetEvents
+
svc = GetEvents(account=self.account)
while True:
notification = svc.get(subscription_id=subscription_id, watermark=watermark)
@@ -1637,12 +1813,15 @@ Inherited members
sync methods.
"""
from ..services import GetStreamingEvents
+
svc = GetStreamingEvents(account=self.account)
- subscription_ids = subscription_id_or_ids if is_iterable(subscription_id_or_ids, generators_allowed=True) \
+ subscription_ids = (
+ subscription_id_or_ids
+ if is_iterable(subscription_id_or_ids, generators_allowed=True)
else [subscription_id_or_ids]
+ )
for i, notification in enumerate(
- svc.call(subscription_ids=subscription_ids, connection_timeout=connection_timeout),
- start=1
+ svc.call(subscription_ids=subscription_ids, connection_timeout=connection_timeout), start=1
):
yield notification
if max_notifications_returned and i >= max_notifications_returned:
@@ -1659,10 +1838,10 @@ Inherited members
:param other:
:return:
"""
- if other == '..':
- raise ValueError('Cannot get parent without a folder cache')
+ if other == "..":
+ raise ValueError("Cannot get parent without a folder cache")
- if other == '.':
+ if other == ".":
return self
# Assume an exact match on the folder name in a shallow search will only return at most one folder
@@ -1673,11 +1852,11 @@ Inherited members
def __truediv__(self, other):
"""Support the some_folder / 'child_folder' / 'child_of_child_folder' navigation syntax."""
- if other == '..':
+ if other == "..":
if not self.parent:
- raise ValueError('Already at top')
+ raise ValueError("Already at top")
return self.parent
- if other == '.':
+ if other == ".":
return self
for c in self.children:
if c.name == other:
@@ -1685,12 +1864,21 @@ Inherited members
raise ErrorFolderNotFound(f"No subfolder with name {other!r}")
def __repr__(self):
- return self.__class__.__name__ + \
- repr((self.root, self.name, self.total_count, self.unread_count, self.child_folder_count,
- self.folder_class, self.id, self.changekey))
+ return self.__class__.__name__ + repr(
+ (
+ self.root,
+ self.name,
+ self.total_count,
+ self.unread_count,
+ self.child_folder_count,
+ self.folder_class,
+ self.id,
+ self.changekey,
+ )
+ )
def __str__(self):
- return f'{self.__class__.__name__} ({self.name})'
+ return f"{self.__class__.__name__} ({self.name})"
Ancestors
@@ -1803,11 +1991,29 @@ Static methods
:param container_class:
:return:
"""
- from .known_folders import Messages, Tasks, Calendar, ConversationSettings, Contacts, GALContacts, Reminders, \
- RecipientCache, RSSFeeds
+ from .known_folders import (
+ Calendar,
+ Contacts,
+ ConversationSettings,
+ GALContacts,
+ Messages,
+ RecipientCache,
+ Reminders,
+ RSSFeeds,
+ Tasks,
+ )
+
for folder_cls in (
- Messages, Tasks, Calendar, ConversationSettings, Contacts, GALContacts, Reminders, RecipientCache,
- RSSFeeds):
+ Messages,
+ Tasks,
+ Calendar,
+ ConversationSettings,
+ Contacts,
+ GALContacts,
+ Reminders,
+ RecipientCache,
+ RSSFeeds,
+ ):
if folder_cls.CONTAINER_CLASS == container_class:
return folder_cls
raise KeyError()
@@ -1846,7 +2052,7 @@ Static methods
try:
return cls.ITEM_MODEL_MAP[tag]
except KeyError:
- raise ValueError(f'Item type {tag} was unexpected in a {cls.__name__} folder')
+ raise ValueError(f"Item type {tag} was unexpected in a {cls.__name__} folder")
@@ -1879,9 +2085,9 @@ Static methods
# Resolve a single folder
folders = list(FolderCollection(account=account, folders=[folder]).resolve())
if not folders:
- raise ErrorFolderNotFound(f'Could not find folder {folder!r}')
+ raise ErrorFolderNotFound(f"Could not find folder {folder!r}")
if len(folders) != 1:
- raise ValueError(f'Expected result length 1, but got {folders}')
+ raise ValueError(f"Expected result length 1, but got {folders}")
f = folders[0]
if isinstance(f, Exception):
raise f
@@ -1919,7 +2125,7 @@ Instance variables
@property
def absolute(self):
- return ''.join(f'/{p.name}' for p in self.parts)
+ return "".join(f"/{p.name}" for p in self.parts)
var account
@@ -2096,6 +2302,7 @@ Methods
@require_id
def create_user_configuration(self, name, dictionary=None, xml_data=None, binary_data=None):
from ..services import CreateUserConfiguration
+
user_configuration = UserConfiguration(
user_configuration_name=UserConfigurationName(name=name, folder=self),
dictionary=dictionary,
@@ -2116,6 +2323,7 @@ Methods
def delete(self, delete_type=HARD_DELETE):
from ..services import DeleteFolder
+
DeleteFolder(account=self.account).get(folders=[self], delete_type=delete_type)
self.root.remove_folder(self) # Remove the updated folder from the cache
self._id = None
@@ -2133,6 +2341,7 @@ Methods
@require_id
def delete_user_configuration(self, name):
from ..services import DeleteUserConfiguration
+
return DeleteUserConfiguration(account=self.account).get(
user_configuration_name=UserConfigurationNameMNS(name=name, folder=self)
)
@@ -2149,6 +2358,7 @@ Methods
def empty(self, delete_type=HARD_DELETE, delete_sub_folders=False):
from ..services import EmptyFolder
+
EmptyFolder(account=self.account).get(
folders=[self], delete_type=delete_type, delete_sub_folders=delete_sub_folders
)
@@ -2182,6 +2392,7 @@ Methods
sync methods.
"""
from ..services import GetEvents
+
svc = GetEvents(account=self.account)
while True:
notification = svc.get(subscription_id=subscription_id, watermark=watermark)
@@ -2221,12 +2432,15 @@ Methods
sync methods.
"""
from ..services import GetStreamingEvents
+
svc = GetStreamingEvents(account=self.account)
- subscription_ids = subscription_id_or_ids if is_iterable(subscription_id_or_ids, generators_allowed=True) \
+ subscription_ids = (
+ subscription_id_or_ids
+ if is_iterable(subscription_id_or_ids, generators_allowed=True)
else [subscription_id_or_ids]
+ )
for i, notification in enumerate(
- svc.call(subscription_ids=subscription_ids, connection_timeout=connection_timeout),
- start=1
+ svc.call(subscription_ids=subscription_ids, connection_timeout=connection_timeout), start=1
):
yield notification
if max_notifications_returned and i >= max_notifications_returned:
@@ -2247,6 +2461,7 @@ Methods
def get_user_configuration(self, name, properties=None):
from ..services import GetUserConfiguration
from ..services.get_user_configuration import ALL
+
if properties is None:
properties = ALL
return GetUserConfiguration(account=self.account).get(
@@ -2279,10 +2494,11 @@ Methods
def move(self, to_folder):
from ..services import MoveFolder
+
res = MoveFolder(account=self.account).get(folders=[self], to_folder=to_folder)
folder_id, changekey = res.id, res.changekey
if self.id != folder_id:
- raise ValueError('ID mismatch')
+ raise ValueError("ID mismatch")
# Don't check changekey value. It may not change on no-op moves
self.changekey = changekey
self.parent_folder_id = ParentFolderId(id=to_folder.id, changekey=to_folder.changekey)
@@ -2311,9 +2527,9 @@ Methods
elif isinstance(field_path, Field):
field_path = FieldPath(field=field_path)
fields[i] = field_path
- if field_path.field.name == 'start':
+ if field_path.field.name == "start":
has_start = True
- elif field_path.field.name == 'end':
+ elif field_path.field.name == "end":
has_end = True
# For CalendarItem items, we want to inject internal timezone fields. See also CalendarItem.clean()
@@ -2371,7 +2587,7 @@ Methods
def refresh(self):
fresh_folder = self.resolve(account=self.account, folder=self)
if self.id != fresh_folder.id:
- raise ValueError('ID mismatch')
+ raise ValueError("ID mismatch")
# Apparently, the changekey may get updated
for f in self.FIELDS:
setattr(self, f.name, getattr(fresh_folder, f.name))
@@ -2389,6 +2605,7 @@ Methods
def save(self, update_fields=None):
from ..services import CreateFolder, UpdateFolder
+
if self.id is None:
# New folder
if update_fields:
@@ -2407,7 +2624,7 @@ Methods
# These cannot be changed
continue
if (f.is_required or f.is_required_after_save) and (
- getattr(self, f.name) is None or (f.is_list and not getattr(self, f.name))
+ getattr(self, f.name) is None or (f.is_list and not getattr(self, f.name))
):
# These are required and cannot be deleted
continue
@@ -2415,7 +2632,7 @@ Methods
res = UpdateFolder(account=self.account).get(folders=[(self, update_fields)])
folder_id, changekey = res.id, res.changekey
if self.id != folder_id:
- raise ValueError('ID mismatch')
+ raise ValueError("ID mismatch")
# Don't check changekey value. It may not change on no-op updates
self.changekey = changekey
self.root.update_folder(self) # Update the folder in the cache
@@ -2461,10 +2678,13 @@ Methods
:return: The subscription ID and a watermark
"""
from ..services import SubscribeToPull
+
if event_types is None:
event_types = SubscribeToPull.EVENT_TYPES
return FolderCollection(account=self.account, folders=[self]).subscribe_to_pull(
- event_types=event_types, watermark=watermark, timeout=timeout,
+ event_types=event_types,
+ watermark=watermark,
+ timeout=timeout,
)
@@ -2493,10 +2713,14 @@ Methods
:return: The subscription ID and a watermark
"""
from ..services import SubscribeToPush
+
if event_types is None:
event_types = SubscribeToPush.EVENT_TYPES
return FolderCollection(account=self.account, folders=[self]).subscribe_to_push(
- event_types=event_types, watermark=watermark, status_frequency=status_frequency, callback_url=callback_url,
+ event_types=event_types,
+ watermark=watermark,
+ status_frequency=status_frequency,
+ callback_url=callback_url,
)
@@ -2519,6 +2743,7 @@ Methods
:return: The subscription ID
"""
from ..services import SubscribeToStreaming
+
if event_types is None:
event_types = SubscribeToStreaming.EVENT_TYPES
return FolderCollection(account=self.account, folders=[self]).subscribe_to_streaming(event_types=event_types)
@@ -2636,13 +2861,12 @@ Methods
# the folder content since we fetched the changekey.
if self.account:
return DistinguishedFolderId(
- id=self.DISTINGUISHED_FOLDER_ID,
- mailbox=Mailbox(email_address=self.account.primary_smtp_address)
+ id=self.DISTINGUISHED_FOLDER_ID, mailbox=Mailbox(email_address=self.account.primary_smtp_address)
)
return DistinguishedFolderId(id=self.DISTINGUISHED_FOLDER_ID)
if self.id:
return FolderId(id=self.id, changekey=self.changekey)
- raise ValueError('Must be a distinguished folder or have an ID')
+ raise ValueError("Must be a distinguished folder or have an ID")
@@ -2673,22 +2897,22 @@ Methods
├── exchangelib issues
└── Mom
"""
- tree = f'{self.name}\n'
+ tree = f"{self.name}\n"
children = list(self.children)
- for i, c in enumerate(sorted(children, key=attrgetter('name')), start=1):
- nodes = c.tree().split('\n')
+ for i, c in enumerate(sorted(children, key=attrgetter("name")), start=1):
+ nodes = c.tree().split("\n")
for j, node in enumerate(nodes, start=1):
if i != len(children) and j == 1:
# Not the last child, but the first node, which is the name of the child
- tree += f'├── {node}\n'
+ tree += f"├── {node}\n"
elif i != len(children) and j > 1:
# Not the last child, and not name of child
- tree += f'│ {node}\n'
+ tree += f"│ {node}\n"
elif i == len(children) and j == 1:
# Not the last child, but the first node, which is the name of the child
- tree += f'└── {node}\n'
+ tree += f"└── {node}\n"
else: # Last child, and not name of child
- tree += f' {node}\n'
+ tree += f" {node}\n"
return tree.strip()
@@ -2715,6 +2939,7 @@ @require_id
def update_user_configuration(self, name, dictionary=None, xml_data=None, binary_data=None):
from ..services import UpdateUserConfiguration
+
user_configuration = UserConfiguration(
user_configuration_name=UserConfigurationName(name=name, folder=self),
dictionary=dictionary,
@@ -2779,11 +3005,11 @@ Methods
# distinguished folders from being deleted. Use with caution!
_seen = _seen or set()
if self.id in _seen:
- raise RecursionError(f'We already tried to wipe {self}')
+ raise RecursionError(f"We already tried to wipe {self}")
if _level > 16:
- raise RecursionError(f'Max recursion level reached: {_level}')
+ raise RecursionError(f"Max recursion level reached: {_level}")
_seen.add(self.id)
- log.warning('Wiping %s', self)
+ log.warning("Wiping %s", self)
has_distinguished_subfolders = any(f.is_distinguished for f in self.children)
try:
if has_distinguished_subfolders:
@@ -2796,26 +3022,26 @@ Methods
raise # We already tried this
self.empty(delete_sub_folders=False)
except (ErrorAccessDenied, ErrorCannotEmptyFolder, ErrorItemNotFound):
- log.warning('Not allowed to empty %s. Trying to delete items instead', self)
+ log.warning("Not allowed to empty %s. Trying to delete items instead", self)
kwargs = {}
if page_size is not None:
- kwargs['page_size'] = page_size
+ kwargs["page_size"] = page_size
if chunk_size is not None:
- kwargs['chunk_size'] = chunk_size
+ kwargs["chunk_size"] = chunk_size
try:
self.all().delete(**kwargs)
except (ErrorAccessDenied, ErrorCannotDeleteObject, ErrorItemNotFound):
- log.warning('Not allowed to delete items in %s', self)
+ log.warning("Not allowed to delete items in %s", self)
_level += 1
for f in self.children:
f.wipe(page_size=page_size, chunk_size=chunk_size, _seen=_seen, _level=_level)
# Remove non-distinguished children that are empty and have no subfolders
if f.is_deletable and not f.children:
- log.warning('Deleting folder %s', f)
+ log.warning("Deleting folder %s", f)
try:
f.delete()
except ErrorDeleteDistinguishedFolder:
- log.warning('Tried to delete a distinguished folder (%s)', f)
+ log.warning("Tried to delete a distinguished folder (%s)", f)
@@ -2856,20 +3082,20 @@ class Calendar(Folder):
"""An interface for the Exchange calendar."""
- DISTINGUISHED_FOLDER_ID = 'calendar'
- CONTAINER_CLASS = 'IPF.Appointment'
+ DISTINGUISHED_FOLDER_ID = "calendar"
+ CONTAINER_CLASS = "IPF.Appointment"
supported_item_models = (CalendarItem,)
LOCALIZED_NAMES = {
- 'da_DK': ('Kalender',),
- 'de_DE': ('Kalender',),
- 'en_US': ('Calendar',),
- 'es_ES': ('Calendario',),
- 'fr_CA': ('Calendrier',),
- 'nl_NL': ('Agenda',),
- 'ru_RU': ('Календарь',),
- 'sv_SE': ('Kalender',),
- 'zh_CN': ('日历',),
+ "da_DK": ("Kalender",),
+ "de_DE": ("Kalender",),
+ "en_US": ("Calendar",),
+ "es_ES": ("Calendario",),
+ "fr_CA": ("Calendrier",),
+ "nl_NL": ("Agenda",),
+ "ru_RU": ("Календарь",),
+ "sv_SE": ("Kalender",),
+ "zh_CN": ("日历",),
}
def view(self, *args, **kwargs):
@@ -2970,7 +3196,7 @@ Inherited members
class CalendarLogging(NonDeletableFolderMixin, Folder):
LOCALIZED_NAMES = {
- None: ('Calendar Logging',),
+ None: ("Calendar Logging",),
}
Ancestors
@@ -3042,7 +3268,7 @@ Inherited members
class CommonViews(NonDeletableFolderMixin, Folder):
DEFAULT_ITEM_TRAVERSAL_DEPTH = ASSOCIATED
LOCALIZED_NAMES = {
- None: ('Common Views',),
+ None: ("Common Views",),
}
Ancestors
@@ -3117,9 +3343,9 @@ Inherited members
class Companies(NonDeletableFolderMixin, Contacts):
DISTINGUISHED_FOLDER_ID = None
- CONTAINTER_CLASS = 'IPF.Contact.Company'
+ CONTAINTER_CLASS = "IPF.Contact.Company"
LOCALIZED_NAMES = {
- None: ('Companies',),
+ None: ("Companies",),
}
Ancestors
@@ -3198,7 +3424,7 @@ Inherited members
Expand source code
class Conflicts(WellknownFolder):
- DISTINGUISHED_FOLDER_ID = 'conflicts'
+ DISTINGUISHED_FOLDER_ID = "conflicts"
supported_from = EXCHANGE_2013
Ancestors
@@ -3272,20 +3498,20 @@ Inherited members
Expand source code
class Contacts(Folder):
- DISTINGUISHED_FOLDER_ID = 'contacts'
- CONTAINER_CLASS = 'IPF.Contact'
+ DISTINGUISHED_FOLDER_ID = "contacts"
+ CONTAINER_CLASS = "IPF.Contact"
supported_item_models = (Contact, DistributionList)
LOCALIZED_NAMES = {
- 'da_DK': ('Kontaktpersoner',),
- 'de_DE': ('Kontakte',),
- 'en_US': ('Contacts',),
- 'es_ES': ('Contactos',),
- 'fr_CA': ('Contacts',),
- 'nl_NL': ('Contactpersonen',),
- 'ru_RU': ('Контакты',),
- 'sv_SE': ('Kontakter',),
- 'zh_CN': ('联系人',),
+ "da_DK": ("Kontaktpersoner",),
+ "de_DE": ("Kontakte",),
+ "en_US": ("Contacts",),
+ "es_ES": ("Contactos",),
+ "fr_CA": ("Contacts",),
+ "nl_NL": ("Contactpersonen",),
+ "ru_RU": ("Контакты",),
+ "sv_SE": ("Kontakter",),
+ "zh_CN": ("联系人",),
}
Ancestors
@@ -3377,7 +3603,7 @@ Inherited members
Expand source code
class ConversationHistory(WellknownFolder):
- DISTINGUISHED_FOLDER_ID = 'conversationhistory'
+ DISTINGUISHED_FOLDER_ID = "conversationhistory"
supported_from = EXCHANGE_2013
Ancestors
@@ -3451,9 +3677,9 @@ Inherited members
Expand source code
class ConversationSettings(NonDeletableFolderMixin, Folder):
- CONTAINER_CLASS = 'IPF.Configuration'
+ CONTAINER_CLASS = "IPF.Configuration"
LOCALIZED_NAMES = {
- 'da_DK': ('Indstillinger for samtalehandlinger',),
+ "da_DK": ("Indstillinger for samtalehandlinger",),
}
Ancestors
@@ -3527,9 +3753,9 @@ Inherited members
Expand source code
class DefaultFoldersChangeHistory(NonDeletableFolderMixin, Folder):
- CONTAINER_CLASS = 'IPM.DefaultFolderHistoryItem'
+ CONTAINER_CLASS = "IPM.DefaultFolderHistoryItem"
LOCALIZED_NAMES = {
- None: ('DefaultFoldersChangeHistory',),
+ None: ("DefaultFoldersChangeHistory",),
}
Ancestors
@@ -3604,7 +3830,7 @@ Inherited members
class DeferredAction(NonDeletableFolderMixin, Folder):
LOCALIZED_NAMES = {
- None: ('Deferred Action',),
+ None: ("Deferred Action",),
}
Ancestors
@@ -3674,20 +3900,20 @@ Inherited members
Expand source code
class DeletedItems(Folder):
- DISTINGUISHED_FOLDER_ID = 'deleteditems'
- CONTAINER_CLASS = 'IPF.Note'
+ DISTINGUISHED_FOLDER_ID = "deleteditems"
+ CONTAINER_CLASS = "IPF.Note"
supported_item_models = ITEM_CLASSES
LOCALIZED_NAMES = {
- 'da_DK': ('Slettet post',),
- 'de_DE': ('Gelöschte Elemente',),
- 'en_US': ('Deleted Items',),
- 'es_ES': ('Elementos eliminados',),
- 'fr_CA': ('Éléments supprimés',),
- 'nl_NL': ('Verwijderde items',),
- 'ru_RU': ('Удаленные',),
- 'sv_SE': ('Borttaget',),
- 'zh_CN': ('已删除邮件',),
+ "da_DK": ("Slettet post",),
+ "de_DE": ("Gelöschte Elemente",),
+ "en_US": ("Deleted Items",),
+ "es_ES": ("Elementos eliminados",),
+ "fr_CA": ("Éléments supprimés",),
+ "nl_NL": ("Verwijderde items",),
+ "ru_RU": ("Удаленные",),
+ "sv_SE": ("Borttaget",),
+ "zh_CN": ("已删除邮件",),
}
Ancestors
@@ -3768,7 +3994,7 @@ Inherited members
Expand source code
class Directory(WellknownFolder):
- DISTINGUISHED_FOLDER_ID = 'directory'
+ DISTINGUISHED_FOLDER_ID = "directory"
supported_from = EXCHANGE_2013_SP1
Ancestors
@@ -3844,12 +4070,13 @@ Inherited members
class DistinguishedFolderId(FolderId):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/distinguishedfolderid"""
- ELEMENT_NAME = 'DistinguishedFolderId'
+ ELEMENT_NAME = "DistinguishedFolderId"
mailbox = MailboxField()
def clean(self, version=None):
from .folders import PublicFoldersRoot
+
super().clean(version=version)
if self.id == PublicFoldersRoot.DISTINGUISHED_FOLDER_ID:
# Avoid "ErrorInvalidOperation: It is not valid to specify a mailbox with the public folder root" from EWS
@@ -3893,6 +4120,7 @@ Methods
def clean(self, version=None):
from .folders import PublicFoldersRoot
+
super().clean(version=version)
if self.id == PublicFoldersRoot.DISTINGUISHED_FOLDER_ID:
# Avoid "ErrorInvalidOperation: It is not valid to specify a mailbox with the public folder root" from EWS
@@ -3923,18 +4151,18 @@ Inherited members
Expand source code
class Drafts(Messages):
- DISTINGUISHED_FOLDER_ID = 'drafts'
+ DISTINGUISHED_FOLDER_ID = "drafts"
LOCALIZED_NAMES = {
- 'da_DK': ('Kladder',),
- 'de_DE': ('Entwürfe',),
- 'en_US': ('Drafts',),
- 'es_ES': ('Borradores',),
- 'fr_CA': ('Brouillons',),
- 'nl_NL': ('Concepten',),
- 'ru_RU': ('Черновики',),
- 'sv_SE': ('Utkast',),
- 'zh_CN': ('草稿',),
+ "da_DK": ("Kladder",),
+ "de_DE": ("Entwürfe",),
+ "en_US": ("Drafts",),
+ "es_ES": ("Borradores",),
+ "fr_CA": ("Brouillons",),
+ "nl_NL": ("Concepten",),
+ "ru_RU": ("Черновики",),
+ "sv_SE": ("Utkast",),
+ "zh_CN": ("草稿",),
}
Ancestors
@@ -4009,7 +4237,7 @@ Inherited members
class ExchangeSyncData(NonDeletableFolderMixin, Folder):
LOCALIZED_NAMES = {
- None: ('ExchangeSyncData',),
+ None: ("ExchangeSyncData",),
}
Ancestors
@@ -4079,8 +4307,8 @@ Inherited members
Expand source code
class Favorites(WellknownFolder):
- CONTAINER_CLASS = 'IPF.Note'
- DISTINGUISHED_FOLDER_ID = 'favorites'
+ CONTAINER_CLASS = "IPF.Note"
+ DISTINGUISHED_FOLDER_ID = "favorites"
supported_from = EXCHANGE_2013
Ancestors
@@ -4158,10 +4386,10 @@ Inherited members
Expand source code
class Files(NonDeletableFolderMixin, Folder):
- CONTAINER_CLASS = 'IPF.Files'
+ CONTAINER_CLASS = "IPF.Files"
LOCALIZED_NAMES = {
- 'da_DK': ('Filer',),
+ "da_DK": ("Filer",),
}
Ancestors
@@ -4237,24 +4465,25 @@ Inherited members
class Folder(BaseFolder):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/folder"""
- permission_set = PermissionSetField(field_uri='folder:PermissionSet', supported_from=EXCHANGE_2007_SP1)
- effective_rights = EffectiveRightsField(field_uri='folder:EffectiveRights', is_read_only=True,
- supported_from=EXCHANGE_2007_SP1)
+ permission_set = PermissionSetField(field_uri="folder:PermissionSet", supported_from=EXCHANGE_2007_SP1)
+ effective_rights = EffectiveRightsField(
+ field_uri="folder:EffectiveRights", is_read_only=True, supported_from=EXCHANGE_2007_SP1
+ )
- __slots__ = '_root',
+ __slots__ = ("_root",)
def __init__(self, **kwargs):
- self._root = kwargs.pop('root', None) # This is a pointer to the root of the folder hierarchy
- parent = kwargs.pop('parent', None)
+ self._root = kwargs.pop("root", None) # This is a pointer to the root of the folder hierarchy
+ parent = kwargs.pop("parent", None)
if parent:
if self.root:
if parent.root != self.root:
raise ValueError("'parent.root' must match 'root'")
else:
self.root = parent.root
- if 'parent_folder_id' in kwargs and parent.id != kwargs['parent_folder_id']:
+ if "parent_folder_id" in kwargs and parent.id != kwargs["parent_folder_id"]:
raise ValueError("'parent_folder_id' must match 'parent' ID")
- kwargs['parent_folder_id'] = ParentFolderId(id=parent.id, changekey=parent.changekey)
+ kwargs["parent_folder_id"] = ParentFolderId(id=parent.id, changekey=parent.changekey)
super().__init__(**kwargs)
@property
@@ -4274,13 +4503,13 @@ Inherited members
@classmethod
def register(cls, *args, **kwargs):
if cls is not Folder:
- raise TypeError('For folders, custom fields must be registered on the Folder class')
+ raise TypeError("For folders, custom fields must be registered on the Folder class")
return super().register(*args, **kwargs)
@classmethod
def deregister(cls, *args, **kwargs):
if cls is not Folder:
- raise TypeError('For folders, custom fields must be registered on the Folder class')
+ raise TypeError("For folders, custom fields must be registered on the Folder class")
return super().deregister(*args, **kwargs)
@classmethod
@@ -4292,11 +4521,10 @@ Inherited members
"""
try:
return cls.resolve(
- account=root.account,
- folder=cls(root=root, name=cls.DISTINGUISHED_FOLDER_ID, is_distinguished=True)
+ account=root.account, folder=cls(root=root, name=cls.DISTINGUISHED_FOLDER_ID, is_distinguished=True)
)
except MISSING_FOLDER_ERRORS:
- raise ErrorFolderNotFound(f'Could not find distinguished folder {cls.DISTINGUISHED_FOLDER_ID!r}')
+ raise ErrorFolderNotFound(f"Could not find distinguished folder {cls.DISTINGUISHED_FOLDER_ID!r}")
@property
def parent(self):
@@ -4313,15 +4541,16 @@ Inherited members
self.parent_folder_id = None
else:
if not isinstance(value, BaseFolder):
- raise InvalidTypeError('value', value, BaseFolder)
+ raise InvalidTypeError("value", value, BaseFolder)
self.root = value.root
self.parent_folder_id = ParentFolderId(id=value.id, changekey=value.changekey)
def clean(self, version=None):
from .roots import RootOfHierarchy
+
super().clean(version=version)
if self.root and not isinstance(self.root, RootOfHierarchy):
- raise InvalidTypeError('root', self.root, RootOfHierarchy)
+ raise InvalidTypeError("root", self.root, RootOfHierarchy)
@classmethod
def from_xml_with_root(cls, elem, root):
@@ -4347,20 +4576,20 @@ Inherited members
if folder.name:
try:
# TODO: fld_class.LOCALIZED_NAMES is most definitely neither complete nor authoritative
- folder_cls = root.folder_cls_from_folder_name(folder_name=folder.name,
- locale=root.account.locale)
- log.debug('Folder class %s matches localized folder name %s', folder_cls, folder.name)
+ folder_cls = root.folder_cls_from_folder_name(folder_name=folder.name, locale=root.account.locale)
+ log.debug("Folder class %s matches localized folder name %s", folder_cls, folder.name)
except KeyError:
pass
if folder.folder_class and folder_cls == Folder:
try:
folder_cls = cls.folder_cls_from_container_class(container_class=folder.folder_class)
- log.debug('Folder class %s matches container class %s (%s)', folder_cls, folder.folder_class,
- folder.name)
+ log.debug(
+ "Folder class %s matches container class %s (%s)", folder_cls, folder.folder_class, folder.name
+ )
except KeyError:
pass
if folder_cls == Folder:
- log.debug('Fallback to class Folder (folder_class %s, name %s)', folder.folder_class, folder.name)
+ log.debug("Fallback to class Folder (folder_class %s, name %s)", folder.folder_class, folder.name)
return folder_cls(root=root, **{f.name: getattr(folder, f.name) for f in folder.FIELDS})
Ancestors
@@ -4451,20 +4680,20 @@ Static methods
if folder.name:
try:
# TODO: fld_class.LOCALIZED_NAMES is most definitely neither complete nor authoritative
- folder_cls = root.folder_cls_from_folder_name(folder_name=folder.name,
- locale=root.account.locale)
- log.debug('Folder class %s matches localized folder name %s', folder_cls, folder.name)
+ folder_cls = root.folder_cls_from_folder_name(folder_name=folder.name, locale=root.account.locale)
+ log.debug("Folder class %s matches localized folder name %s", folder_cls, folder.name)
except KeyError:
pass
if folder.folder_class and folder_cls == Folder:
try:
folder_cls = cls.folder_cls_from_container_class(container_class=folder.folder_class)
- log.debug('Folder class %s matches container class %s (%s)', folder_cls, folder.folder_class,
- folder.name)
+ log.debug(
+ "Folder class %s matches container class %s (%s)", folder_cls, folder.folder_class, folder.name
+ )
except KeyError:
pass
if folder_cls == Folder:
- log.debug('Fallback to class Folder (folder_class %s, name %s)', folder.folder_class, folder.name)
+ log.debug("Fallback to class Folder (folder_class %s, name %s)", folder.folder_class, folder.name)
return folder_cls(root=root, **{f.name: getattr(folder, f.name) for f in folder.FIELDS})
@@ -4488,11 +4717,10 @@ Static methods
"""
try:
return cls.resolve(
- account=root.account,
- folder=cls(root=root, name=cls.DISTINGUISHED_FOLDER_ID, is_distinguished=True)
+ account=root.account, folder=cls(root=root, name=cls.DISTINGUISHED_FOLDER_ID, is_distinguished=True)
)
except MISSING_FOLDER_ERRORS:
- raise ErrorFolderNotFound(f'Could not find distinguished folder {cls.DISTINGUISHED_FOLDER_ID!r}')
+ raise ErrorFolderNotFound(f"Could not find distinguished folder {cls.DISTINGUISHED_FOLDER_ID!r}")
@@ -4520,9 +4748,10 @@ def clean(self, version=None):
from .roots import RootOfHierarchy
+
super().clean(version=version)
if self.root and not isinstance(self.root, RootOfHierarchy):
- raise InvalidTypeError('root', self.root, RootOfHierarchy)
+ raise InvalidTypeError("root", self.root, RootOfHierarchy)
@@ -4581,7 +4810,7 @@ @require_account
-def find_folders(self, q=None, shape=ID_ONLY, depth=None, additional_fields=None, page_size=None, max_items=None,
- offset=0):
+def find_folders(
+ self, q=None, shape=ID_ONLY, depth=None, additional_fields=None, page_size=None, max_items=None, offset=0
+):
from ..services import FindFolder
+
# 'depth' controls whether to return direct children or recurse into sub-folders
from .base import BaseFolder, Folder
+
if q is None:
q = Q()
if not self.folders:
- log.debug('Folder list is empty')
+ log.debug("Folder list is empty")
return
if q.is_never():
- log.debug('Query will never return results')
+ log.debug("Query will never return results")
return
if q.is_empty():
restriction = None
@@ -5219,13 +5490,13 @@ Examples
)
yield from FindFolder(account=self.account, page_size=page_size).call(
- folders=self.folders,
- additional_fields=additional_fields,
- restriction=restriction,
- shape=shape,
- depth=depth,
- max_items=max_items,
- offset=offset,
+ folders=self.folders,
+ additional_fields=additional_fields,
+ restriction=restriction,
+ shape=shape,
+ depth=depth,
+ max_items=max_items,
+ offset=offset,
)
@@ -5250,8 +5521,18 @@ def find_items(self, q, shape=ID_ONLY, depth=None, additional_fields=None, order_fields=None,
- calendar_view=None, page_size=None, max_items=None, offset=0):
+def find_items(
+ self,
+ q,
+ shape=ID_ONLY,
+ depth=None,
+ additional_fields=None,
+ order_fields=None,
+ calendar_view=None,
+ page_size=None,
+ max_items=None,
+ offset=0,
+):
"""Private method to call the FindItem service.
:param q: a Q instance containing any restrictions
@@ -5269,21 +5550,21 @@ Examples
:return: a generator for the returned item IDs or items
"""
from ..services import FindItem
+
if not self.folders:
- log.debug('Folder list is empty')
+ log.debug("Folder list is empty")
return
if q.is_never():
- log.debug('Query will never return results')
+ log.debug("Query will never return results")
return
depth, restriction, query_string = self._rinse_args(
- q=q, depth=depth, additional_fields=additional_fields,
- field_validator=self.validate_item_field
+ q=q, depth=depth, additional_fields=additional_fields, field_validator=self.validate_item_field
)
if calendar_view is not None and not isinstance(calendar_view, CalendarView):
- raise InvalidTypeError('calendar_view', calendar_view, CalendarView)
+ raise InvalidTypeError("calendar_view", calendar_view, CalendarView)
log.debug(
- 'Finding %s items in folders %s (shape: %s, depth: %s, additional_fields: %s, restriction: %s)',
+ "Finding %s items in folders %s (shape: %s, depth: %s, additional_fields: %s, restriction: %s)",
self.account,
self.folders,
shape,
@@ -5324,8 +5605,17 @@ Examples
Expand source code
-def find_people(self, q, shape=ID_ONLY, depth=None, additional_fields=None, order_fields=None,
- page_size=None, max_items=None, offset=0):
+def find_people(
+ self,
+ q,
+ shape=ID_ONLY,
+ depth=None,
+ additional_fields=None,
+ order_fields=None,
+ page_size=None,
+ max_items=None,
+ offset=0,
+):
"""Private method to call the FindPeople service.
:param q: a Q instance containing any restrictions
@@ -5341,25 +5631,25 @@ Examples
:return: a generator for the returned personas
"""
from ..services import FindPeople
+
folder = self._get_single_folder()
if q.is_never():
- log.debug('Query will never return results')
+ log.debug("Query will never return results")
return
depth, restriction, query_string = self._rinse_args(
- q=q, depth=depth, additional_fields=additional_fields,
- field_validator=Persona.validate_field
+ q=q, depth=depth, additional_fields=additional_fields, field_validator=Persona.validate_field
)
yield from FindPeople(account=self.account, page_size=page_size).call(
- folder=folder,
- additional_fields=additional_fields,
- restriction=restriction,
- order_fields=order_fields,
- shape=shape,
- query_string=query_string,
- depth=depth,
- max_items=max_items,
- offset=offset,
+ folder=folder,
+ additional_fields=additional_fields,
+ restriction=restriction,
+ order_fields=order_fields,
+ shape=shape,
+ query_string=query_string,
+ depth=depth,
+ max_items=max_items,
+ offset=offset,
)
@@ -5374,7 +5664,8 @@ Examples
def get_folder_fields(self, target_cls, is_complex=None):
return {
- FieldPath(field=f) for f in target_cls.supported_fields(version=self.account.version)
+ FieldPath(field=f)
+ for f in target_cls.supported_fields(version=self.account.version)
if is_complex is None or f.is_complex is is_complex
}
@@ -5390,10 +5681,12 @@ Examples
def get_folders(self, additional_fields=None):
from ..services import GetFolder
+
# Expand folders with their full set of properties
from .base import BaseFolder
+
if not self.folders:
- log.debug('Folder list is empty')
+ log.debug("Folder list is empty")
return
if additional_fields is None:
# Default to all complex properties
@@ -5405,9 +5698,9 @@ Examples
)
yield from GetFolder(account=self.account).call(
- folders=self.folders,
- additional_fields=additional_fields,
- shape=ID_ONLY,
+ folders=self.folders,
+ additional_fields=additional_fields,
+ shape=ID_ONLY,
)
@@ -5449,17 +5742,18 @@ Examples
def resolve(self):
# Looks up the folders or folder IDs in the collection and returns full Folder instances with all fields set.
from .base import BaseFolder
+
resolveable_folders = []
for f in self.folders:
if isinstance(f, BaseFolder) and not f.get_folder_allowed:
- log.debug('GetFolder not allowed on folder %s. Non-complex fields must be fetched with FindFolder', f)
+ log.debug("GetFolder not allowed on folder %s. Non-complex fields must be fetched with FindFolder", f)
yield f
else:
resolveable_folders.append(f)
# Fetch all properties for the remaining folders of folder IDs
additional_fields = self.get_folder_fields(target_cls=self._get_target_cls(), is_complex=None)
yield from self.__class__(account=self.account, folders=resolveable_folders).get_folders(
- additional_fields=additional_fields
+ additional_fields=additional_fields
)
@@ -5487,13 +5781,17 @@ Examples
def subscribe_to_pull(self, event_types=None, watermark=None, timeout=60):
from ..services import SubscribeToPull
+
if not self.folders:
- log.debug('Folder list is empty')
+ log.debug("Folder list is empty")
return None
if event_types is None:
event_types = SubscribeToPull.EVENT_TYPES
return SubscribeToPull(account=self.account).get(
- folders=self.folders, event_types=event_types, watermark=watermark, timeout=timeout,
+ folders=self.folders,
+ event_types=event_types,
+ watermark=watermark,
+ timeout=timeout,
)
@@ -5508,13 +5806,17 @@ Examples
def subscribe_to_push(self, callback_url, event_types=None, watermark=None, status_frequency=1):
from ..services import SubscribeToPush
+
if not self.folders:
- log.debug('Folder list is empty')
+ log.debug("Folder list is empty")
return None
if event_types is None:
event_types = SubscribeToPush.EVENT_TYPES
return SubscribeToPush(account=self.account).get(
- folders=self.folders, event_types=event_types, watermark=watermark, status_frequency=status_frequency,
+ folders=self.folders,
+ event_types=event_types,
+ watermark=watermark,
+ status_frequency=status_frequency,
url=callback_url,
)
@@ -5530,8 +5832,9 @@ Examples
def subscribe_to_streaming(self, event_types=None):
from ..services import SubscribeToStreaming
+
if not self.folders:
- log.debug('Folder list is empty')
+ log.debug("Folder list is empty")
return None
if event_types is None:
event_types = SubscribeToStreaming.EVENT_TYPES
@@ -5549,6 +5852,7 @@ Examples
def sync_hierarchy(self, sync_state=None, only_fields=None):
from ..services import SyncFolderHierarchy
+
folder = self._get_single_folder()
if only_fields is None:
# We didn't restrict list of field paths. Get all fields from the server, including extended properties.
@@ -5595,6 +5899,7 @@ Examples
def sync_items(self, sync_state=None, only_fields=None, ignore=None, max_changes_returned=None, sync_scope=None):
from ..services import SyncFolderItems
+
folder = self._get_single_folder()
if only_fields is None:
# We didn't restrict list of field paths. Get all fields from the server, including extended properties.
@@ -5648,6 +5953,7 @@ Examples
sync methods.
"""
from ..services import Unsubscribe
+
return Unsubscribe(account=self.account).get(subscription_id=subscription_id)
@@ -5744,7 +6050,7 @@ Inherited members
class FolderId(ItemId):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/folderid"""
- ELEMENT_NAME = 'FolderId'
+ ELEMENT_NAME = "FolderId"
Ancestors
@@ -5790,8 +6096,9 @@ Inherited members
def __init__(self, folder_collection):
from .collections import FolderCollection
+
if not isinstance(folder_collection, FolderCollection):
- raise InvalidTypeError('folder_collection', folder_collection, FolderCollection)
+ raise InvalidTypeError("folder_collection", folder_collection, FolderCollection)
self.folder_collection = folder_collection
self.q = Q() # Default to no restrictions
self.only_fields = None
@@ -5811,6 +6118,7 @@ Inherited members
def only(self, *args):
"""Restrict the fields returned. 'name' and 'folder_class' are always returned."""
from .base import Folder
+
# Subfolders will always be of class Folder
all_fields = self.folder_collection.get_folder_fields(target_cls=Folder, is_complex=None)
all_fields.update(Folder.attribute_fields())
@@ -5840,18 +6148,19 @@ Inherited members
MultipleObjectsReturned if there are multiple results.
"""
from .collections import FolderCollection
- if not args and set(kwargs) in ({'id'}, {'id', 'changekey'}):
- folders = list(FolderCollection(
- account=self.folder_collection.account, folders=[FolderId(**kwargs)]
- ).resolve())
+
+ if not args and set(kwargs) in ({"id"}, {"id", "changekey"}):
+ folders = list(
+ FolderCollection(account=self.folder_collection.account, folders=[FolderId(**kwargs)]).resolve()
+ )
elif args or kwargs:
folders = list(self.filter(*args, **kwargs))
else:
folders = list(self.all())
if not folders:
- raise DoesNotExist('Could not find a child folder matching the query')
+ raise DoesNotExist("Could not find a child folder matching the query")
if len(folders) != 1:
- raise MultipleObjectsReturned(f'Expected result length 1, but got {folders}')
+ raise MultipleObjectsReturned(f"Expected result length 1, but got {folders}")
f = folders[0]
if isinstance(f, Exception):
raise f
@@ -5875,6 +6184,7 @@ Inherited members
def _query(self):
from .base import Folder
from .collections import FolderCollection
+
if self.only_fields is None:
# Subfolders will always be of class Folder
non_complex_fields = self.folder_collection.get_folder_fields(target_cls=Folder, is_complex=False)
@@ -5897,7 +6207,7 @@ Inherited members
yield f
continue
if not f.get_folder_allowed:
- log.debug('GetFolder not allowed on folder %s. Non-complex fields must be fetched with FindFolder', f)
+ log.debug("GetFolder not allowed on folder %s. Non-complex fields must be fetched with FindFolder", f)
yield f
else:
resolveable_folders.append(f)
@@ -5915,7 +6225,7 @@ Inherited members
continue
# Add the extra field values to the folders we fetched with find_folders()
if f.__class__ != complex_f.__class__:
- raise ValueError(f'Type mismatch: {f} vs {complex_f}')
+ raise ValueError(f"Type mismatch: {f} vs {complex_f}")
for complex_field in complex_fields:
field_name = complex_field.field.name
setattr(f, field_name, getattr(complex_f, field_name))
@@ -5994,18 +6304,19 @@ Methods
MultipleObjectsReturned if there are multiple results.
"""
from .collections import FolderCollection
- if not args and set(kwargs) in ({'id'}, {'id', 'changekey'}):
- folders = list(FolderCollection(
- account=self.folder_collection.account, folders=[FolderId(**kwargs)]
- ).resolve())
+
+ if not args and set(kwargs) in ({"id"}, {"id", "changekey"}):
+ folders = list(
+ FolderCollection(account=self.folder_collection.account, folders=[FolderId(**kwargs)]).resolve()
+ )
elif args or kwargs:
folders = list(self.filter(*args, **kwargs))
else:
folders = list(self.all())
if not folders:
- raise DoesNotExist('Could not find a child folder matching the query')
+ raise DoesNotExist("Could not find a child folder matching the query")
if len(folders) != 1:
- raise MultipleObjectsReturned(f'Expected result length 1, but got {folders}')
+ raise MultipleObjectsReturned(f"Expected result length 1, but got {folders}")
f = folders[0]
if isinstance(f, Exception):
raise f
@@ -6024,6 +6335,7 @@ Methods
def only(self, *args):
"""Restrict the fields returned. 'name' and 'folder_class' are always returned."""
from .base import Folder
+
# Subfolders will always be of class Folder
all_fields = self.folder_collection.get_folder_fields(target_cls=Folder, is_complex=None)
all_fields.update(Folder.attribute_fields())
@@ -6054,7 +6366,7 @@ Methods
class FreebusyData(NonDeletableFolderMixin, Folder):
LOCALIZED_NAMES = {
- None: ('Freebusy Data',),
+ None: ("Freebusy Data",),
}
Ancestors
@@ -6124,10 +6436,10 @@ Inherited members
Expand source code
class Friends(NonDeletableFolderMixin, Contacts):
- CONTAINER_CLASS = 'IPF.Note'
+ CONTAINER_CLASS = "IPF.Note"
LOCALIZED_NAMES = {
- 'de_DE': ('Bekannte',),
+ "de_DE": ("Bekannte",),
}
Ancestors
@@ -6203,10 +6515,10 @@ Inherited members
class GALContacts(NonDeletableFolderMixin, Contacts):
DISTINGUISHED_FOLDER_ID = None
- CONTAINER_CLASS = 'IPF.Contact.GalContacts'
+ CONTAINER_CLASS = "IPF.Contact.GalContacts"
LOCALIZED_NAMES = {
- None: ('GAL Contacts',),
+ None: ("GAL Contacts",),
}
Ancestors
@@ -6285,9 +6597,9 @@ Inherited members
Expand source code
class GraphAnalytics(NonDeletableFolderMixin, Folder):
- CONTAINER_CLASS = 'IPF.StoreItem.GraphAnalytics'
+ CONTAINER_CLASS = "IPF.StoreItem.GraphAnalytics"
LOCALIZED_NAMES = {
- None: ('GraphAnalytics',),
+ None: ("GraphAnalytics",),
}
Ancestors
@@ -6361,8 +6673,8 @@ Inherited members
Expand source code
class IMContactList(WellknownFolder):
- CONTAINER_CLASS = 'IPF.Contact.MOC.ImContactList'
- DISTINGUISHED_FOLDER_ID = 'imcontactlist'
+ CONTAINER_CLASS = "IPF.Contact.MOC.ImContactList"
+ DISTINGUISHED_FOLDER_ID = "imcontactlist"
supported_from = EXCHANGE_2013
Ancestors
@@ -6440,18 +6752,18 @@ Inherited members
Expand source code
class Inbox(Messages):
- DISTINGUISHED_FOLDER_ID = 'inbox'
+ DISTINGUISHED_FOLDER_ID = "inbox"
LOCALIZED_NAMES = {
- 'da_DK': ('Indbakke',),
- 'de_DE': ('Posteingang',),
- 'en_US': ('Inbox',),
- 'es_ES': ('Bandeja de entrada',),
- 'fr_CA': ('Boîte de réception',),
- 'nl_NL': ('Postvak IN',),
- 'ru_RU': ('Входящие',),
- 'sv_SE': ('Inkorgen',),
- 'zh_CN': ('收件箱',),
+ "da_DK": ("Indbakke",),
+ "de_DE": ("Posteingang",),
+ "en_US": ("Inbox",),
+ "es_ES": ("Bandeja de entrada",),
+ "fr_CA": ("Boîte de réception",),
+ "nl_NL": ("Postvak IN",),
+ "ru_RU": ("Входящие",),
+ "sv_SE": ("Inkorgen",),
+ "zh_CN": ("收件箱",),
}
Ancestors
@@ -6525,8 +6837,8 @@ Inherited members
Expand source code
class Journal(WellknownFolder):
- CONTAINER_CLASS = 'IPF.Journal'
- DISTINGUISHED_FOLDER_ID = 'journal'
+ CONTAINER_CLASS = "IPF.Journal"
+ DISTINGUISHED_FOLDER_ID = "journal"
Ancestors
@@ -6599,18 +6911,18 @@ Inherited members
Expand source code
class JunkEmail(Messages):
- DISTINGUISHED_FOLDER_ID = 'junkemail'
+ DISTINGUISHED_FOLDER_ID = "junkemail"
LOCALIZED_NAMES = {
- 'da_DK': ('Uønsket e-mail',),
- 'de_DE': ('Junk-E-Mail',),
- 'en_US': ('Junk E-mail',),
- 'es_ES': ('Correo no deseado',),
- 'fr_CA': ('Courrier indésirables',),
- 'nl_NL': ('Ongewenste e-mail',),
- 'ru_RU': ('Нежелательная почта',),
- 'sv_SE': ('Skräppost',),
- 'zh_CN': ('垃圾邮件',),
+ "da_DK": ("Uønsket e-mail",),
+ "de_DE": ("Junk-E-Mail",),
+ "en_US": ("Junk E-mail",),
+ "es_ES": ("Correo no deseado",),
+ "fr_CA": ("Courrier indésirables",),
+ "nl_NL": ("Ongewenste e-mail",),
+ "ru_RU": ("Нежелательная почта",),
+ "sv_SE": ("Skräppost",),
+ "zh_CN": ("垃圾邮件",),
}
Ancestors
@@ -6684,7 +6996,7 @@ Inherited members
Expand source code
class LocalFailures(WellknownFolder):
- DISTINGUISHED_FOLDER_ID = 'localfailures'
+ DISTINGUISHED_FOLDER_ID = "localfailures"
supported_from = EXCHANGE_2013
Ancestors
@@ -6759,7 +7071,7 @@ Inherited members
class Location(NonDeletableFolderMixin, Folder):
LOCALIZED_NAMES = {
- None: ('Location',),
+ None: ("Location",),
}
Ancestors
@@ -6830,7 +7142,7 @@ Inherited members
class MailboxAssociations(NonDeletableFolderMixin, Folder):
LOCALIZED_NAMES = {
- None: ('MailboxAssociations',),
+ None: ("MailboxAssociations",),
}
Ancestors
@@ -6900,7 +7212,7 @@ Inherited members
Expand source code
class Messages(Folder):
- CONTAINER_CLASS = 'IPF.Note'
+ CONTAINER_CLASS = "IPF.Note"
supported_item_models = (Message, MeetingRequest, MeetingResponse, MeetingCancellation)
Ancestors
@@ -6983,9 +7295,9 @@ Inherited members
class MsgFolderRoot(WellknownFolder):
"""Also known as the 'Top of Information Store' folder."""
- DISTINGUISHED_FOLDER_ID = 'msgfolderroot'
+ DISTINGUISHED_FOLDER_ID = "msgfolderroot"
LOCALIZED_NAMES = {
- 'zh_CN': ('信息存储顶部',),
+ "zh_CN": ("信息存储顶部",),
}
Ancestors
@@ -7059,8 +7371,8 @@ Inherited members
Expand source code
class MyContacts(WellknownFolder):
- CONTAINER_CLASS = 'IPF.Note'
- DISTINGUISHED_FOLDER_ID = 'mycontacts'
+ CONTAINER_CLASS = "IPF.Note"
+ DISTINGUISHED_FOLDER_ID = "mycontacts"
supported_from = EXCHANGE_2013
Ancestors
@@ -7138,9 +7450,9 @@ Inherited members
Expand source code
class MyContactsExtended(NonDeletableFolderMixin, Contacts):
- CONTAINER_CLASS = 'IPF.Note'
+ CONTAINER_CLASS = "IPF.Note"
LOCALIZED_NAMES = {
- None: ('MyContactsExtended',),
+ None: ("MyContactsExtended",),
}
Ancestors
@@ -7286,10 +7598,10 @@ Instance variables
Expand source code
class Notes(WellknownFolder):
- CONTAINER_CLASS = 'IPF.StickyNote'
- DISTINGUISHED_FOLDER_ID = 'notes'
+ CONTAINER_CLASS = "IPF.StickyNote"
+ DISTINGUISHED_FOLDER_ID = "notes"
LOCALIZED_NAMES = {
- 'da_DK': ('Noter',),
+ "da_DK": ("Noter",),
}
Ancestors
@@ -7368,9 +7680,9 @@ Inherited members
class OrganizationalContacts(NonDeletableFolderMixin, Contacts):
DISTINGUISHED_FOLDER_ID = None
- CONTAINTER_CLASS = 'IPF.Contact.OrganizationalContacts'
+ CONTAINTER_CLASS = "IPF.Contact.OrganizationalContacts"
LOCALIZED_NAMES = {
- None: ('Organizational Contacts',),
+ None: ("Organizational Contacts",),
}
Ancestors
@@ -7449,18 +7761,18 @@ Inherited members
Expand source code
class Outbox(Messages):
- DISTINGUISHED_FOLDER_ID = 'outbox'
+ DISTINGUISHED_FOLDER_ID = "outbox"
LOCALIZED_NAMES = {
- 'da_DK': ('Udbakke',),
- 'de_DE': ('Postausgang',),
- 'en_US': ('Outbox',),
- 'es_ES': ('Bandeja de salida',),
- 'fr_CA': (u"Boîte d'envoi",),
- 'nl_NL': ('Postvak UIT',),
- 'ru_RU': ('Исходящие',),
- 'sv_SE': ('Utkorgen',),
- 'zh_CN': ('发件箱',),
+ "da_DK": ("Udbakke",),
+ "de_DE": ("Postausgang",),
+ "en_US": ("Outbox",),
+ "es_ES": ("Bandeja de salida",),
+ "fr_CA": (u"Boîte d'envoi",),
+ "nl_NL": ("Postvak UIT",),
+ "ru_RU": ("Исходящие",),
+ "sv_SE": ("Utkorgen",),
+ "zh_CN": ("发件箱",),
}
Ancestors
@@ -7536,7 +7848,7 @@ Inherited members
class ParkedMessages(NonDeletableFolderMixin, Folder):
CONTAINER_CLASS = None
LOCALIZED_NAMES = {
- None: ('ParkedMessages',),
+ None: ("ParkedMessages",),
}
Ancestors
@@ -7610,9 +7922,9 @@ Inherited members
Expand source code
class PassThroughSearchResults(NonDeletableFolderMixin, Folder):
- CONTAINER_CLASS = 'IPF.StoreItem.PassThroughSearchResults'
+ CONTAINER_CLASS = "IPF.StoreItem.PassThroughSearchResults"
LOCALIZED_NAMES = {
- None: ('Pass-Through Search Results',),
+ None: ("Pass-Through Search Results",),
}
Ancestors
@@ -7686,9 +7998,9 @@ Inherited members
Expand source code
class PdpProfileV2Secured(NonDeletableFolderMixin, Folder):
- CONTAINER_CLASS = 'IPF.StoreItem.PdpProfileSecured'
+ CONTAINER_CLASS = "IPF.StoreItem.PdpProfileSecured"
LOCALIZED_NAMES = {
- None: ('PdpProfileV2Secured',),
+ None: ("PdpProfileV2Secured",),
}
Ancestors
@@ -7763,9 +8075,9 @@ Inherited members
class PeopleCentricConversationBuddies(NonDeletableFolderMixin, Contacts):
DISTINGUISHED_FOLDER_ID = None
- CONTAINTER_CLASS = 'IPF.Contact.PeopleCentricConversationBuddies'
+ CONTAINTER_CLASS = "IPF.Contact.PeopleCentricConversationBuddies"
LOCALIZED_NAMES = {
- None: ('PeopleCentricConversation Buddies',),
+ None: ("PeopleCentricConversation Buddies",),
}
Ancestors
@@ -7844,7 +8156,7 @@ Inherited members
Expand source code
class PeopleConnect(WellknownFolder):
- DISTINGUISHED_FOLDER_ID = 'peopleconnect'
+ DISTINGUISHED_FOLDER_ID = "peopleconnect"
supported_from = EXCHANGE_2013
Ancestors
@@ -7920,7 +8232,7 @@ Inherited members
class PublicFoldersRoot(RootOfHierarchy):
"""The root of the public folders hierarchy. Not available on all mailboxes."""
- DISTINGUISHED_FOLDER_ID = 'publicfoldersroot'
+ DISTINGUISHED_FOLDER_ID = "publicfoldersroot"
DEFAULT_FOLDER_TRAVERSAL_DEPTH = SHALLOW
supported_from = EXCHANGE_2007_SP1
@@ -7941,9 +8253,11 @@ Inherited members
children_map = {}
try:
- for f in SingleFolderQuerySet(account=self.account, folder=folder).depth(
- self.DEFAULT_FOLDER_TRAVERSAL_DEPTH
- ).all():
+ for f in (
+ SingleFolderQuerySet(account=self.account, folder=folder)
+ .depth(self.DEFAULT_FOLDER_TRAVERSAL_DEPTH)
+ .all()
+ ):
if isinstance(f, MISSING_FOLDER_ERRORS):
# We were unlucky. The folder disappeared between the FindFolder and the GetFolder calls
continue
@@ -8013,9 +8327,11 @@ Methods
children_map = {}
try:
- for f in SingleFolderQuerySet(account=self.account, folder=folder).depth(
- self.DEFAULT_FOLDER_TRAVERSAL_DEPTH
- ).all():
+ for f in (
+ SingleFolderQuerySet(account=self.account, folder=folder)
+ .depth(self.DEFAULT_FOLDER_TRAVERSAL_DEPTH)
+ .all()
+ ):
if isinstance(f, MISSING_FOLDER_ERRORS):
# We were unlucky. The folder disappeared between the FindFolder and the GetFolder calls
continue
@@ -8087,8 +8403,8 @@ Inherited members
Expand source code
class QuickContacts(WellknownFolder):
- CONTAINER_CLASS = 'IPF.Contact.MOC.QuickContacts'
- DISTINGUISHED_FOLDER_ID = 'quickcontacts'
+ CONTAINER_CLASS = "IPF.Contact.MOC.QuickContacts"
+ DISTINGUISHED_FOLDER_ID = "quickcontacts"
supported_from = EXCHANGE_2013
Ancestors
@@ -8166,9 +8482,9 @@ Inherited members
Expand source code
class RSSFeeds(NonDeletableFolderMixin, Folder):
- CONTAINER_CLASS = 'IPF.Note.OutlookHomepage'
+ CONTAINER_CLASS = "IPF.Note.OutlookHomepage"
LOCALIZED_NAMES = {
- None: ('RSS Feeds',),
+ None: ("RSS Feeds",),
}
Ancestors
@@ -8242,8 +8558,8 @@ Inherited members
Expand source code
class RecipientCache(Contacts):
- DISTINGUISHED_FOLDER_ID = 'recipientcache'
- CONTAINER_CLASS = 'IPF.Contact.RecipientCache'
+ DISTINGUISHED_FOLDER_ID = "recipientcache"
+ CONTAINER_CLASS = "IPF.Contact.RecipientCache"
supported_from = EXCHANGE_2013
LOCALIZED_NAMES = {}
@@ -8327,7 +8643,7 @@ Inherited members
Expand source code
class RecoverableItemsDeletions(WellknownFolder):
- DISTINGUISHED_FOLDER_ID = 'recoverableitemsdeletions'
+ DISTINGUISHED_FOLDER_ID = "recoverableitemsdeletions"
supported_from = EXCHANGE_2010_SP1
Ancestors
@@ -8401,7 +8717,7 @@ Inherited members
Expand source code
class RecoverableItemsPurges(WellknownFolder):
- DISTINGUISHED_FOLDER_ID = 'recoverableitemspurges'
+ DISTINGUISHED_FOLDER_ID = "recoverableitemspurges"
supported_from = EXCHANGE_2010_SP1
Ancestors
@@ -8475,7 +8791,7 @@ Inherited members
Expand source code
class RecoverableItemsRoot(WellknownFolder):
- DISTINGUISHED_FOLDER_ID = 'recoverableitemsroot'
+ DISTINGUISHED_FOLDER_ID = "recoverableitemsroot"
supported_from = EXCHANGE_2010_SP1
Ancestors
@@ -8549,7 +8865,7 @@ Inherited members
Expand source code
class RecoverableItemsVersions(WellknownFolder):
- DISTINGUISHED_FOLDER_ID = 'recoverableitemsversions'
+ DISTINGUISHED_FOLDER_ID = "recoverableitemsversions"
supported_from = EXCHANGE_2010_SP1
Ancestors
@@ -8623,9 +8939,9 @@ Inherited members
Expand source code
class Reminders(NonDeletableFolderMixin, Folder):
- CONTAINER_CLASS = 'Outlook.Reminder'
+ CONTAINER_CLASS = "Outlook.Reminder"
LOCALIZED_NAMES = {
- 'da_DK': ('Påmindelser',),
+ "da_DK": ("Påmindelser",),
}
Ancestors
@@ -8701,7 +9017,7 @@ Inherited members
class Root(RootOfHierarchy):
"""The root of the standard folder hierarchy."""
- DISTINGUISHED_FOLDER_ID = 'root'
+ DISTINGUISHED_FOLDER_ID = "root"
WELLKNOWN_FOLDERS = WELLKNOWN_FOLDERS_IN_ROOT
@property
@@ -8722,12 +9038,12 @@ Inherited members
# 3. Searching TOIS for a direct child folder of the same type that has a localized name
# 4. Searching root for a direct child folder of the same type that is marked as distinguished
# 5. Searching root for a direct child folder of the same type that has a localized name
- log.debug('Searching default %s folder in full folder list', folder_cls)
+ log.debug("Searching default %s folder in full folder list", folder_cls)
for f in self._folders_map.values():
# Require exact type, to avoid matching with subclasses (e.g. RecipientCache and Contacts)
if f.__class__ == folder_cls and f.has_distinguished_name:
- log.debug('Found cached %s folder with default distinguished name', folder_cls)
+ log.debug("Found cached %s folder with default distinguished name", folder_cls)
return f
# Try direct children of TOIS first, unless we're trying to get the TOIS folder
@@ -8750,14 +9066,14 @@ Inherited members
else:
candidates = [f for f in same_type if f.name.lower() in folder_cls.localized_names(self.account.locale)]
if not candidates:
- raise ErrorFolderNotFound(f'No usable default {folder_cls} folders')
+ raise ErrorFolderNotFound(f"No usable default {folder_cls} folders")
if len(candidates) > 1:
- raise ValueError(f'Multiple possible default {folder_cls} folders: {[f.name for f in candidates]}')
+ raise ValueError(f"Multiple possible default {folder_cls} folders: {[f.name for f in candidates]}")
candidate = candidates[0]
if candidate.is_distinguished:
- log.debug('Found distinguished %s folder', folder_cls)
+ log.debug("Found distinguished %s folder", folder_cls)
else:
- log.debug('Found %s folder with localized name %s', folder_cls, candidate.name)
+ log.debug("Found %s folder with localized name %s", folder_cls, candidate.name)
return candidate
Ancestors
@@ -8862,14 +9178,15 @@ Inherited members
# This folder type also has 'folder:PermissionSet' on some server versions, but requesting it sometimes causes
# 'ErrorAccessDenied', as reported by some users. Ignore it entirely for root folders - it's usefulness is
# deemed minimal at best.
- effective_rights = EffectiveRightsField(field_uri='folder:EffectiveRights', is_read_only=True,
- supported_from=EXCHANGE_2007_SP1)
+ effective_rights = EffectiveRightsField(
+ field_uri="folder:EffectiveRights", is_read_only=True, supported_from=EXCHANGE_2007_SP1
+ )
- __slots__ = '_account', '_subfolders'
+ __slots__ = "_account", "_subfolders"
# A special folder that acts as the top of a folder hierarchy. Finds and caches subfolders at arbitrary depth.
def __init__(self, **kwargs):
- self._account = kwargs.pop('account', None) # A pointer back to the account holding the folder hierarchy
+ self._account = kwargs.pop("account", None) # A pointer back to the account holding the folder hierarchy
super().__init__(**kwargs)
self._subfolders = None # See self._folders_map()
@@ -8888,13 +9205,13 @@ Inherited members
@classmethod
def register(cls, *args, **kwargs):
if cls is not RootOfHierarchy:
- raise TypeError('For folder roots, custom fields must be registered on the RootOfHierarchy class')
+ raise TypeError("For folder roots, custom fields must be registered on the RootOfHierarchy class")
return super().register(*args, **kwargs)
@classmethod
def deregister(cls, *args, **kwargs):
if cls is not RootOfHierarchy:
- raise TypeError('For folder roots, custom fields must be registered on the RootOfHierarchy class')
+ raise TypeError("For folder roots, custom fields must be registered on the RootOfHierarchy class")
return super().deregister(*args, **kwargs)
def get_folder(self, folder):
@@ -8938,14 +9255,13 @@ Inherited members
:param account:
"""
if not cls.DISTINGUISHED_FOLDER_ID:
- raise ValueError(f'Class {cls} must have a DISTINGUISHED_FOLDER_ID value')
+ raise ValueError(f"Class {cls} must have a DISTINGUISHED_FOLDER_ID value")
try:
return cls.resolve(
- account=account,
- folder=cls(account=account, name=cls.DISTINGUISHED_FOLDER_ID, is_distinguished=True)
+ account=account, folder=cls(account=account, name=cls.DISTINGUISHED_FOLDER_ID, is_distinguished=True)
)
except MISSING_FOLDER_ERRORS:
- raise ErrorFolderNotFound(f'Could not find distinguished folder {cls.DISTINGUISHED_FOLDER_ID}')
+ raise ErrorFolderNotFound(f"Could not find distinguished folder {cls.DISTINGUISHED_FOLDER_ID}")
def get_default_folder(self, folder_cls):
"""Return the distinguished folder instance of type folder_cls belonging to this account. If no distinguished
@@ -8959,21 +9275,21 @@ Inherited members
for f in self._folders_map.values():
# Require exact class, to not match subclasses, e.g. RecipientCache instead of Contacts
if f.__class__ == folder_cls and f.is_distinguished:
- log.debug('Found cached distinguished %s folder', folder_cls)
+ log.debug("Found cached distinguished %s folder", folder_cls)
return f
try:
- log.debug('Requesting distinguished %s folder explicitly', folder_cls)
+ log.debug("Requesting distinguished %s folder explicitly", folder_cls)
return folder_cls.get_distinguished(root=self)
except ErrorAccessDenied:
# Maybe we just don't have GetFolder access? Try FindItems instead
- log.debug('Testing default %s folder with FindItem', folder_cls)
+ log.debug("Testing default %s folder with FindItem", folder_cls)
fld = folder_cls(root=self, name=folder_cls.DISTINGUISHED_FOLDER_ID, is_distinguished=True)
fld.test_access()
return self._folders_map.get(fld.id, fld) # Use cached instance if available
except MISSING_FOLDER_ERRORS:
# The Exchange server does not return a distinguished folder of this type
pass
- raise ErrorFolderNotFound(f'No usable default {folder_cls} folders')
+ raise ErrorFolderNotFound(f"No usable default {folder_cls} folders")
@property
def _folders_map(self):
@@ -9004,9 +9320,9 @@ Inherited members
if isinstance(f, Exception):
raise f
folders_map[f.id] = f
- for f in SingleFolderQuerySet(account=self.account, folder=self).depth(
- self.DEFAULT_FOLDER_TRAVERSAL_DEPTH
- ).all():
+ for f in (
+ SingleFolderQuerySet(account=self.account, folder=self).depth(self.DEFAULT_FOLDER_TRAVERSAL_DEPTH).all()
+ ):
if isinstance(f, ErrorAccessDenied):
# We may not have FindFolder access, or GetFolder access, either to this folder or at all
continue
@@ -9042,9 +9358,19 @@ Inherited members
def __repr__(self):
# Let's not create an infinite loop when printing self.root
- return self.__class__.__name__ + \
- repr((self.account, '[self]', self.name, self.total_count, self.unread_count, self.child_folder_count,
- self.folder_class, self.id, self.changekey))
+ return self.__class__.__name__ + repr(
+ (
+ self.account,
+ "[self]",
+ self.name,
+ self.total_count,
+ self.unread_count,
+ self.child_folder_count,
+ self.folder_class,
+ self.id,
+ self.changekey,
+ )
+ )
Ancestors
@@ -9130,14 +9456,13 @@ Static methods
:param account:
"""
if not cls.DISTINGUISHED_FOLDER_ID:
- raise ValueError(f'Class {cls} must have a DISTINGUISHED_FOLDER_ID value')
+ raise ValueError(f"Class {cls} must have a DISTINGUISHED_FOLDER_ID value")
try:
return cls.resolve(
- account=account,
- folder=cls(account=account, name=cls.DISTINGUISHED_FOLDER_ID, is_distinguished=True)
+ account=account, folder=cls(account=account, name=cls.DISTINGUISHED_FOLDER_ID, is_distinguished=True)
)
except MISSING_FOLDER_ERRORS:
- raise ErrorFolderNotFound(f'Could not find distinguished folder {cls.DISTINGUISHED_FOLDER_ID}')
+ raise ErrorFolderNotFound(f"Could not find distinguished folder {cls.DISTINGUISHED_FOLDER_ID}")
@@ -9218,21 +9543,21 @@ Methods
for f in self._folders_map.values():
# Require exact class, to not match subclasses, e.g. RecipientCache instead of Contacts
if f.__class__ == folder_cls and f.is_distinguished:
- log.debug('Found cached distinguished %s folder', folder_cls)
+ log.debug("Found cached distinguished %s folder", folder_cls)
return f
try:
- log.debug('Requesting distinguished %s folder explicitly', folder_cls)
+ log.debug("Requesting distinguished %s folder explicitly", folder_cls)
return folder_cls.get_distinguished(root=self)
except ErrorAccessDenied:
# Maybe we just don't have GetFolder access? Try FindItems instead
- log.debug('Testing default %s folder with FindItem', folder_cls)
+ log.debug("Testing default %s folder with FindItem", folder_cls)
fld = folder_cls(root=self, name=folder_cls.DISTINGUISHED_FOLDER_ID, is_distinguished=True)
fld.test_access()
return self._folders_map.get(fld.id, fld) # Use cached instance if available
except MISSING_FOLDER_ERRORS:
# The Exchange server does not return a distinguished folder of this type
pass
- raise ErrorFolderNotFound(f'No usable default {folder_cls} folders')
+ raise ErrorFolderNotFound(f"No usable default {folder_cls} folders")
@@ -9334,7 +9659,7 @@ Inherited members
class Schedule(NonDeletableFolderMixin, Folder):
LOCALIZED_NAMES = {
- None: ('Schedule',),
+ None: ("Schedule",),
}
Ancestors
@@ -9404,7 +9729,7 @@ Inherited members
Expand source code
class SearchFolders(WellknownFolder):
- DISTINGUISHED_FOLDER_ID = 'searchfolders'
+ DISTINGUISHED_FOLDER_ID = "searchfolders"
class SentItems(Messages):
- DISTINGUISHED_FOLDER_ID = 'sentitems'
+ DISTINGUISHED_FOLDER_ID = "sentitems"
LOCALIZED_NAMES = {
- 'da_DK': ('Sendt post',),
- 'de_DE': ('Gesendete Elemente',),
- 'en_US': ('Sent Items',),
- 'es_ES': ('Elementos enviados',),
- 'fr_CA': ('Éléments envoyés',),
- 'nl_NL': ('Verzonden items',),
- 'ru_RU': ('Отправленные',),
- 'sv_SE': ('Skickat',),
- 'zh_CN': ('已发送邮件',),
+ "da_DK": ("Sendt post",),
+ "de_DE": ("Gesendete Elemente",),
+ "en_US": ("Sent Items",),
+ "es_ES": ("Elementos enviados",),
+ "fr_CA": ("Éléments envoyés",),
+ "nl_NL": ("Verzonden items",),
+ "ru_RU": ("Отправленные",),
+ "sv_SE": ("Skickat",),
+ "zh_CN": ("已发送邮件",),
}
class ServerFailures(WellknownFolder):
- DISTINGUISHED_FOLDER_ID = 'serverfailures'
+ DISTINGUISHED_FOLDER_ID = "serverfailures"
supported_from = EXCHANGE_2013
class Sharing(NonDeletableFolderMixin, Folder):
- CONTAINER_CLASS = 'IPF.Note'
+ CONTAINER_CLASS = "IPF.Note"
LOCALIZED_NAMES = {
- None: ('Sharing',),
+ None: ("Sharing",),
}
class Shortcuts(NonDeletableFolderMixin, Folder):
LOCALIZED_NAMES = {
- None: ('Shortcuts',),
+ None: ("Shortcuts",),
}
class Signal(NonDeletableFolderMixin, Folder):
- CONTAINER_CLASS = 'IPF.StoreItem.Signal'
+ CONTAINER_CLASS = "IPF.StoreItem.Signal"
LOCALIZED_NAMES = {
- None: ('Signal',),
+ None: ("Signal",),
}
class SmsAndChatsSync(NonDeletableFolderMixin, Folder):
- CONTAINER_CLASS = 'IPF.SmsAndChatsSync'
+ CONTAINER_CLASS = "IPF.SmsAndChatsSync"
LOCALIZED_NAMES = {
- None: ('SmsAndChatsSync',),
+ None: ("SmsAndChatsSync",),
}
class SpoolerQueue(NonDeletableFolderMixin, Folder):
LOCALIZED_NAMES = {
- None: ('Spooler Queue',),
+ None: ("Spooler Queue",),
}
class SyncIssues(WellknownFolder):
- CONTAINER_CLASS = 'IPF.Note'
- DISTINGUISHED_FOLDER_ID = 'syncissues'
+ CONTAINER_CLASS = "IPF.Note"
+ DISTINGUISHED_FOLDER_ID = "syncissues"
supported_from = EXCHANGE_2013
class System(NonDeletableFolderMixin, Folder):
LOCALIZED_NAMES = {
- None: ('System',),
+ None: ("System",),
}
get_folder_allowed = False
@@ -10213,20 +10539,20 @@ class Tasks(Folder):
- DISTINGUISHED_FOLDER_ID = 'tasks'
- CONTAINER_CLASS = 'IPF.Task'
+ DISTINGUISHED_FOLDER_ID = "tasks"
+ CONTAINER_CLASS = "IPF.Task"
supported_item_models = (Task,)
LOCALIZED_NAMES = {
- 'da_DK': ('Opgaver',),
- 'de_DE': ('Aufgaben',),
- 'en_US': ('Tasks',),
- 'es_ES': ('Tareas',),
- 'fr_CA': ('Tâches',),
- 'nl_NL': ('Taken',),
- 'ru_RU': ('Задачи',),
- 'sv_SE': ('Uppgifter',),
- 'zh_CN': ('任务',),
+ "da_DK": ("Opgaver",),
+ "de_DE": ("Aufgaben",),
+ "en_US": ("Tasks",),
+ "es_ES": ("Tareas",),
+ "fr_CA": ("Tâches",),
+ "nl_NL": ("Taken",),
+ "ru_RU": ("Задачи",),
+ "sv_SE": ("Uppgifter",),
+ "zh_CN": ("任务",),
}
class TemporarySaves(NonDeletableFolderMixin, Folder):
LOCALIZED_NAMES = {
- None: ('TemporarySaves',),
+ None: ("TemporarySaves",),
}
class ToDoSearch(WellknownFolder):
- CONTAINER_CLASS = 'IPF.Task'
- DISTINGUISHED_FOLDER_ID = 'todosearch'
+ CONTAINER_CLASS = "IPF.Task"
+ DISTINGUISHED_FOLDER_ID = "todosearch"
supported_from = EXCHANGE_2013
LOCALIZED_NAMES = {
- None: ('To-Do Search',),
+ None: ("To-Do Search",),
}
class Views(NonDeletableFolderMixin, Folder):
LOCALIZED_NAMES = {
- None: ('Views',),
+ None: ("Views",),
}
class VoiceMail(WellknownFolder):
- DISTINGUISHED_FOLDER_ID = 'voicemail'
- CONTAINER_CLASS = 'IPF.Note.Microsoft.Voicemail'
+ DISTINGUISHED_FOLDER_ID = "voicemail"
+ CONTAINER_CLASS = "IPF.Note.Microsoft.Voicemail"
LOCALIZED_NAMES = {
- None: ('Voice Mail',),
+ None: ("Voice Mail",),
}
class WorkingSet(NonDeletableFolderMixin, Folder):
LOCALIZED_NAMES = {
- None: ('Working Set',),
+ None: ("Working Set",),
}
exchangelib.folders.known_folders
from .base import Folder
-from .collections import FolderCollection
-from ..items import CalendarItem, Contact, Message, Task, DistributionList, MeetingRequest, MeetingResponse, \
- MeetingCancellation, ITEM_CLASSES, ASSOCIATED
+from ..items import (
+ ASSOCIATED,
+ ITEM_CLASSES,
+ CalendarItem,
+ Contact,
+ DistributionList,
+ MeetingCancellation,
+ MeetingRequest,
+ MeetingResponse,
+ Message,
+ Task,
+)
from ..properties import EWSMeta
from ..version import EXCHANGE_2010_SP1, EXCHANGE_2013, EXCHANGE_2013_SP1
+from .base import Folder
+from .collections import FolderCollection
class Calendar(Folder):
"""An interface for the Exchange calendar."""
- DISTINGUISHED_FOLDER_ID = 'calendar'
- CONTAINER_CLASS = 'IPF.Appointment'
+ DISTINGUISHED_FOLDER_ID = "calendar"
+ CONTAINER_CLASS = "IPF.Appointment"
supported_item_models = (CalendarItem,)
LOCALIZED_NAMES = {
- 'da_DK': ('Kalender',),
- 'de_DE': ('Kalender',),
- 'en_US': ('Calendar',),
- 'es_ES': ('Calendario',),
- 'fr_CA': ('Calendrier',),
- 'nl_NL': ('Agenda',),
- 'ru_RU': ('Календарь',),
- 'sv_SE': ('Kalender',),
- 'zh_CN': ('日历',),
+ "da_DK": ("Kalender",),
+ "de_DE": ("Kalender",),
+ "en_US": ("Calendar",),
+ "es_ES": ("Calendario",),
+ "fr_CA": ("Calendrier",),
+ "nl_NL": ("Agenda",),
+ "ru_RU": ("Календарь",),
+ "sv_SE": ("Kalender",),
+ "zh_CN": ("日历",),
}
def view(self, *args, **kwargs):
@@ -58,141 +68,141 @@ Module exchangelib.folders.known_folders
class DeletedItems(Folder):
- DISTINGUISHED_FOLDER_ID = 'deleteditems'
- CONTAINER_CLASS = 'IPF.Note'
+ DISTINGUISHED_FOLDER_ID = "deleteditems"
+ CONTAINER_CLASS = "IPF.Note"
supported_item_models = ITEM_CLASSES
LOCALIZED_NAMES = {
- 'da_DK': ('Slettet post',),
- 'de_DE': ('Gelöschte Elemente',),
- 'en_US': ('Deleted Items',),
- 'es_ES': ('Elementos eliminados',),
- 'fr_CA': ('Éléments supprimés',),
- 'nl_NL': ('Verwijderde items',),
- 'ru_RU': ('Удаленные',),
- 'sv_SE': ('Borttaget',),
- 'zh_CN': ('已删除邮件',),
+ "da_DK": ("Slettet post",),
+ "de_DE": ("Gelöschte Elemente",),
+ "en_US": ("Deleted Items",),
+ "es_ES": ("Elementos eliminados",),
+ "fr_CA": ("Éléments supprimés",),
+ "nl_NL": ("Verwijderde items",),
+ "ru_RU": ("Удаленные",),
+ "sv_SE": ("Borttaget",),
+ "zh_CN": ("已删除邮件",),
}
class Messages(Folder):
- CONTAINER_CLASS = 'IPF.Note'
+ CONTAINER_CLASS = "IPF.Note"
supported_item_models = (Message, MeetingRequest, MeetingResponse, MeetingCancellation)
class Drafts(Messages):
- DISTINGUISHED_FOLDER_ID = 'drafts'
+ DISTINGUISHED_FOLDER_ID = "drafts"
LOCALIZED_NAMES = {
- 'da_DK': ('Kladder',),
- 'de_DE': ('Entwürfe',),
- 'en_US': ('Drafts',),
- 'es_ES': ('Borradores',),
- 'fr_CA': ('Brouillons',),
- 'nl_NL': ('Concepten',),
- 'ru_RU': ('Черновики',),
- 'sv_SE': ('Utkast',),
- 'zh_CN': ('草稿',),
+ "da_DK": ("Kladder",),
+ "de_DE": ("Entwürfe",),
+ "en_US": ("Drafts",),
+ "es_ES": ("Borradores",),
+ "fr_CA": ("Brouillons",),
+ "nl_NL": ("Concepten",),
+ "ru_RU": ("Черновики",),
+ "sv_SE": ("Utkast",),
+ "zh_CN": ("草稿",),
}
class Inbox(Messages):
- DISTINGUISHED_FOLDER_ID = 'inbox'
+ DISTINGUISHED_FOLDER_ID = "inbox"
LOCALIZED_NAMES = {
- 'da_DK': ('Indbakke',),
- 'de_DE': ('Posteingang',),
- 'en_US': ('Inbox',),
- 'es_ES': ('Bandeja de entrada',),
- 'fr_CA': ('Boîte de réception',),
- 'nl_NL': ('Postvak IN',),
- 'ru_RU': ('Входящие',),
- 'sv_SE': ('Inkorgen',),
- 'zh_CN': ('收件箱',),
+ "da_DK": ("Indbakke",),
+ "de_DE": ("Posteingang",),
+ "en_US": ("Inbox",),
+ "es_ES": ("Bandeja de entrada",),
+ "fr_CA": ("Boîte de réception",),
+ "nl_NL": ("Postvak IN",),
+ "ru_RU": ("Входящие",),
+ "sv_SE": ("Inkorgen",),
+ "zh_CN": ("收件箱",),
}
class Outbox(Messages):
- DISTINGUISHED_FOLDER_ID = 'outbox'
+ DISTINGUISHED_FOLDER_ID = "outbox"
LOCALIZED_NAMES = {
- 'da_DK': ('Udbakke',),
- 'de_DE': ('Postausgang',),
- 'en_US': ('Outbox',),
- 'es_ES': ('Bandeja de salida',),
- 'fr_CA': (u"Boîte d'envoi",),
- 'nl_NL': ('Postvak UIT',),
- 'ru_RU': ('Исходящие',),
- 'sv_SE': ('Utkorgen',),
- 'zh_CN': ('发件箱',),
+ "da_DK": ("Udbakke",),
+ "de_DE": ("Postausgang",),
+ "en_US": ("Outbox",),
+ "es_ES": ("Bandeja de salida",),
+ "fr_CA": (u"Boîte d'envoi",),
+ "nl_NL": ("Postvak UIT",),
+ "ru_RU": ("Исходящие",),
+ "sv_SE": ("Utkorgen",),
+ "zh_CN": ("发件箱",),
}
class SentItems(Messages):
- DISTINGUISHED_FOLDER_ID = 'sentitems'
+ DISTINGUISHED_FOLDER_ID = "sentitems"
LOCALIZED_NAMES = {
- 'da_DK': ('Sendt post',),
- 'de_DE': ('Gesendete Elemente',),
- 'en_US': ('Sent Items',),
- 'es_ES': ('Elementos enviados',),
- 'fr_CA': ('Éléments envoyés',),
- 'nl_NL': ('Verzonden items',),
- 'ru_RU': ('Отправленные',),
- 'sv_SE': ('Skickat',),
- 'zh_CN': ('已发送邮件',),
+ "da_DK": ("Sendt post",),
+ "de_DE": ("Gesendete Elemente",),
+ "en_US": ("Sent Items",),
+ "es_ES": ("Elementos enviados",),
+ "fr_CA": ("Éléments envoyés",),
+ "nl_NL": ("Verzonden items",),
+ "ru_RU": ("Отправленные",),
+ "sv_SE": ("Skickat",),
+ "zh_CN": ("已发送邮件",),
}
class JunkEmail(Messages):
- DISTINGUISHED_FOLDER_ID = 'junkemail'
+ DISTINGUISHED_FOLDER_ID = "junkemail"
LOCALIZED_NAMES = {
- 'da_DK': ('Uønsket e-mail',),
- 'de_DE': ('Junk-E-Mail',),
- 'en_US': ('Junk E-mail',),
- 'es_ES': ('Correo no deseado',),
- 'fr_CA': ('Courrier indésirables',),
- 'nl_NL': ('Ongewenste e-mail',),
- 'ru_RU': ('Нежелательная почта',),
- 'sv_SE': ('Skräppost',),
- 'zh_CN': ('垃圾邮件',),
+ "da_DK": ("Uønsket e-mail",),
+ "de_DE": ("Junk-E-Mail",),
+ "en_US": ("Junk E-mail",),
+ "es_ES": ("Correo no deseado",),
+ "fr_CA": ("Courrier indésirables",),
+ "nl_NL": ("Ongewenste e-mail",),
+ "ru_RU": ("Нежелательная почта",),
+ "sv_SE": ("Skräppost",),
+ "zh_CN": ("垃圾邮件",),
}
class Tasks(Folder):
- DISTINGUISHED_FOLDER_ID = 'tasks'
- CONTAINER_CLASS = 'IPF.Task'
+ DISTINGUISHED_FOLDER_ID = "tasks"
+ CONTAINER_CLASS = "IPF.Task"
supported_item_models = (Task,)
LOCALIZED_NAMES = {
- 'da_DK': ('Opgaver',),
- 'de_DE': ('Aufgaben',),
- 'en_US': ('Tasks',),
- 'es_ES': ('Tareas',),
- 'fr_CA': ('Tâches',),
- 'nl_NL': ('Taken',),
- 'ru_RU': ('Задачи',),
- 'sv_SE': ('Uppgifter',),
- 'zh_CN': ('任务',),
+ "da_DK": ("Opgaver",),
+ "de_DE": ("Aufgaben",),
+ "en_US": ("Tasks",),
+ "es_ES": ("Tareas",),
+ "fr_CA": ("Tâches",),
+ "nl_NL": ("Taken",),
+ "ru_RU": ("Задачи",),
+ "sv_SE": ("Uppgifter",),
+ "zh_CN": ("任务",),
}
class Contacts(Folder):
- DISTINGUISHED_FOLDER_ID = 'contacts'
- CONTAINER_CLASS = 'IPF.Contact'
+ DISTINGUISHED_FOLDER_ID = "contacts"
+ CONTAINER_CLASS = "IPF.Contact"
supported_item_models = (Contact, DistributionList)
LOCALIZED_NAMES = {
- 'da_DK': ('Kontaktpersoner',),
- 'de_DE': ('Kontakte',),
- 'en_US': ('Contacts',),
- 'es_ES': ('Contactos',),
- 'fr_CA': ('Contacts',),
- 'nl_NL': ('Contactpersonen',),
- 'ru_RU': ('Контакты',),
- 'sv_SE': ('Kontakter',),
- 'zh_CN': ('联系人',),
+ "da_DK": ("Kontaktpersoner",),
+ "de_DE": ("Kontakte",),
+ "en_US": ("Contacts",),
+ "es_ES": ("Contactos",),
+ "fr_CA": ("Contacts",),
+ "nl_NL": ("Contactpersonen",),
+ "ru_RU": ("Контакты",),
+ "sv_SE": ("Kontakter",),
+ "zh_CN": ("联系人",),
}
@@ -203,175 +213,175 @@ Module exchangelib.folders.known_folders
class AdminAuditLogs(WellknownFolder):
- DISTINGUISHED_FOLDER_ID = 'adminauditlogs'
+ DISTINGUISHED_FOLDER_ID = "adminauditlogs"
supported_from = EXCHANGE_2013
get_folder_allowed = False
class ArchiveDeletedItems(WellknownFolder):
- DISTINGUISHED_FOLDER_ID = 'archivedeleteditems'
+ DISTINGUISHED_FOLDER_ID = "archivedeleteditems"
supported_from = EXCHANGE_2010_SP1
class ArchiveInbox(WellknownFolder):
- DISTINGUISHED_FOLDER_ID = 'archiveinbox'
+ DISTINGUISHED_FOLDER_ID = "archiveinbox"
supported_from = EXCHANGE_2013_SP1
class ArchiveMsgFolderRoot(WellknownFolder):
- DISTINGUISHED_FOLDER_ID = 'archivemsgfolderroot'
+ DISTINGUISHED_FOLDER_ID = "archivemsgfolderroot"
supported_from = EXCHANGE_2010_SP1
class ArchiveRecoverableItemsDeletions(WellknownFolder):
- DISTINGUISHED_FOLDER_ID = 'archiverecoverableitemsdeletions'
+ DISTINGUISHED_FOLDER_ID = "archiverecoverableitemsdeletions"
supported_from = EXCHANGE_2010_SP1
class ArchiveRecoverableItemsPurges(WellknownFolder):
- DISTINGUISHED_FOLDER_ID = 'archiverecoverableitemspurges'
+ DISTINGUISHED_FOLDER_ID = "archiverecoverableitemspurges"
supported_from = EXCHANGE_2010_SP1
class ArchiveRecoverableItemsRoot(WellknownFolder):
- DISTINGUISHED_FOLDER_ID = 'archiverecoverableitemsroot'
+ DISTINGUISHED_FOLDER_ID = "archiverecoverableitemsroot"
supported_from = EXCHANGE_2010_SP1
class ArchiveRecoverableItemsVersions(WellknownFolder):
- DISTINGUISHED_FOLDER_ID = 'archiverecoverableitemsversions'
+ DISTINGUISHED_FOLDER_ID = "archiverecoverableitemsversions"
supported_from = EXCHANGE_2010_SP1
class Conflicts(WellknownFolder):
- DISTINGUISHED_FOLDER_ID = 'conflicts'
+ DISTINGUISHED_FOLDER_ID = "conflicts"
supported_from = EXCHANGE_2013
class ConversationHistory(WellknownFolder):
- DISTINGUISHED_FOLDER_ID = 'conversationhistory'
+ DISTINGUISHED_FOLDER_ID = "conversationhistory"
supported_from = EXCHANGE_2013
class Directory(WellknownFolder):
- DISTINGUISHED_FOLDER_ID = 'directory'
+ DISTINGUISHED_FOLDER_ID = "directory"
supported_from = EXCHANGE_2013_SP1
class Favorites(WellknownFolder):
- CONTAINER_CLASS = 'IPF.Note'
- DISTINGUISHED_FOLDER_ID = 'favorites'
+ CONTAINER_CLASS = "IPF.Note"
+ DISTINGUISHED_FOLDER_ID = "favorites"
supported_from = EXCHANGE_2013
class IMContactList(WellknownFolder):
- CONTAINER_CLASS = 'IPF.Contact.MOC.ImContactList'
- DISTINGUISHED_FOLDER_ID = 'imcontactlist'
+ CONTAINER_CLASS = "IPF.Contact.MOC.ImContactList"
+ DISTINGUISHED_FOLDER_ID = "imcontactlist"
supported_from = EXCHANGE_2013
class Journal(WellknownFolder):
- CONTAINER_CLASS = 'IPF.Journal'
- DISTINGUISHED_FOLDER_ID = 'journal'
+ CONTAINER_CLASS = "IPF.Journal"
+ DISTINGUISHED_FOLDER_ID = "journal"
class LocalFailures(WellknownFolder):
- DISTINGUISHED_FOLDER_ID = 'localfailures'
+ DISTINGUISHED_FOLDER_ID = "localfailures"
supported_from = EXCHANGE_2013
class MsgFolderRoot(WellknownFolder):
"""Also known as the 'Top of Information Store' folder."""
- DISTINGUISHED_FOLDER_ID = 'msgfolderroot'
+ DISTINGUISHED_FOLDER_ID = "msgfolderroot"
LOCALIZED_NAMES = {
- 'zh_CN': ('信息存储顶部',),
+ "zh_CN": ("信息存储顶部",),
}
class MyContacts(WellknownFolder):
- CONTAINER_CLASS = 'IPF.Note'
- DISTINGUISHED_FOLDER_ID = 'mycontacts'
+ CONTAINER_CLASS = "IPF.Note"
+ DISTINGUISHED_FOLDER_ID = "mycontacts"
supported_from = EXCHANGE_2013
class Notes(WellknownFolder):
- CONTAINER_CLASS = 'IPF.StickyNote'
- DISTINGUISHED_FOLDER_ID = 'notes'
+ CONTAINER_CLASS = "IPF.StickyNote"
+ DISTINGUISHED_FOLDER_ID = "notes"
LOCALIZED_NAMES = {
- 'da_DK': ('Noter',),
+ "da_DK": ("Noter",),
}
class PeopleConnect(WellknownFolder):
- DISTINGUISHED_FOLDER_ID = 'peopleconnect'
+ DISTINGUISHED_FOLDER_ID = "peopleconnect"
supported_from = EXCHANGE_2013
class QuickContacts(WellknownFolder):
- CONTAINER_CLASS = 'IPF.Contact.MOC.QuickContacts'
- DISTINGUISHED_FOLDER_ID = 'quickcontacts'
+ CONTAINER_CLASS = "IPF.Contact.MOC.QuickContacts"
+ DISTINGUISHED_FOLDER_ID = "quickcontacts"
supported_from = EXCHANGE_2013
class RecipientCache(Contacts):
- DISTINGUISHED_FOLDER_ID = 'recipientcache'
- CONTAINER_CLASS = 'IPF.Contact.RecipientCache'
+ DISTINGUISHED_FOLDER_ID = "recipientcache"
+ CONTAINER_CLASS = "IPF.Contact.RecipientCache"
supported_from = EXCHANGE_2013
LOCALIZED_NAMES = {}
class RecoverableItemsDeletions(WellknownFolder):
- DISTINGUISHED_FOLDER_ID = 'recoverableitemsdeletions'
+ DISTINGUISHED_FOLDER_ID = "recoverableitemsdeletions"
supported_from = EXCHANGE_2010_SP1
class RecoverableItemsPurges(WellknownFolder):
- DISTINGUISHED_FOLDER_ID = 'recoverableitemspurges'
+ DISTINGUISHED_FOLDER_ID = "recoverableitemspurges"
supported_from = EXCHANGE_2010_SP1
class RecoverableItemsRoot(WellknownFolder):
- DISTINGUISHED_FOLDER_ID = 'recoverableitemsroot'
+ DISTINGUISHED_FOLDER_ID = "recoverableitemsroot"
supported_from = EXCHANGE_2010_SP1
class RecoverableItemsVersions(WellknownFolder):
- DISTINGUISHED_FOLDER_ID = 'recoverableitemsversions'
+ DISTINGUISHED_FOLDER_ID = "recoverableitemsversions"
supported_from = EXCHANGE_2010_SP1
class SearchFolders(WellknownFolder):
- DISTINGUISHED_FOLDER_ID = 'searchfolders'
+ DISTINGUISHED_FOLDER_ID = "searchfolders"
class ServerFailures(WellknownFolder):
- DISTINGUISHED_FOLDER_ID = 'serverfailures'
+ DISTINGUISHED_FOLDER_ID = "serverfailures"
supported_from = EXCHANGE_2013
class SyncIssues(WellknownFolder):
- CONTAINER_CLASS = 'IPF.Note'
- DISTINGUISHED_FOLDER_ID = 'syncissues'
+ CONTAINER_CLASS = "IPF.Note"
+ DISTINGUISHED_FOLDER_ID = "syncissues"
supported_from = EXCHANGE_2013
class ToDoSearch(WellknownFolder):
- CONTAINER_CLASS = 'IPF.Task'
- DISTINGUISHED_FOLDER_ID = 'todosearch'
+ CONTAINER_CLASS = "IPF.Task"
+ DISTINGUISHED_FOLDER_ID = "todosearch"
supported_from = EXCHANGE_2013
LOCALIZED_NAMES = {
- None: ('To-Do Search',),
+ None: ("To-Do Search",),
}
class VoiceMail(WellknownFolder):
- DISTINGUISHED_FOLDER_ID = 'voicemail'
- CONTAINER_CLASS = 'IPF.Note.Microsoft.Voicemail'
+ DISTINGUISHED_FOLDER_ID = "voicemail"
+ CONTAINER_CLASS = "IPF.Note.Microsoft.Voicemail"
LOCALIZED_NAMES = {
- None: ('Voice Mail',),
+ None: ("Voice Mail",),
}
@@ -384,251 +394,251 @@ Module exchangelib.folders.known_folders
class AllContacts(NonDeletableFolderMixin, Contacts):
- CONTAINER_CLASS = 'IPF.Note'
+ CONTAINER_CLASS = "IPF.Note"
LOCALIZED_NAMES = {
- None: ('AllContacts',),
+ None: ("AllContacts",),
}
class AllItems(NonDeletableFolderMixin, Folder):
- CONTAINER_CLASS = 'IPF'
+ CONTAINER_CLASS = "IPF"
LOCALIZED_NAMES = {
- None: ('AllItems',),
+ None: ("AllItems",),
}
class Audits(NonDeletableFolderMixin, Folder):
LOCALIZED_NAMES = {
- None: ('Audits',),
+ None: ("Audits",),
}
get_folder_allowed = False
class CalendarLogging(NonDeletableFolderMixin, Folder):
LOCALIZED_NAMES = {
- None: ('Calendar Logging',),
+ None: ("Calendar Logging",),
}
class CommonViews(NonDeletableFolderMixin, Folder):
DEFAULT_ITEM_TRAVERSAL_DEPTH = ASSOCIATED
LOCALIZED_NAMES = {
- None: ('Common Views',),
+ None: ("Common Views",),
}
class Companies(NonDeletableFolderMixin, Contacts):
DISTINGUISHED_FOLDER_ID = None
- CONTAINTER_CLASS = 'IPF.Contact.Company'
+ CONTAINTER_CLASS = "IPF.Contact.Company"
LOCALIZED_NAMES = {
- None: ('Companies',),
+ None: ("Companies",),
}
class ConversationSettings(NonDeletableFolderMixin, Folder):
- CONTAINER_CLASS = 'IPF.Configuration'
+ CONTAINER_CLASS = "IPF.Configuration"
LOCALIZED_NAMES = {
- 'da_DK': ('Indstillinger for samtalehandlinger',),
+ "da_DK": ("Indstillinger for samtalehandlinger",),
}
class DefaultFoldersChangeHistory(NonDeletableFolderMixin, Folder):
- CONTAINER_CLASS = 'IPM.DefaultFolderHistoryItem'
+ CONTAINER_CLASS = "IPM.DefaultFolderHistoryItem"
LOCALIZED_NAMES = {
- None: ('DefaultFoldersChangeHistory',),
+ None: ("DefaultFoldersChangeHistory",),
}
class DeferredAction(NonDeletableFolderMixin, Folder):
LOCALIZED_NAMES = {
- None: ('Deferred Action',),
+ None: ("Deferred Action",),
}
class ExchangeSyncData(NonDeletableFolderMixin, Folder):
LOCALIZED_NAMES = {
- None: ('ExchangeSyncData',),
+ None: ("ExchangeSyncData",),
}
class Files(NonDeletableFolderMixin, Folder):
- CONTAINER_CLASS = 'IPF.Files'
+ CONTAINER_CLASS = "IPF.Files"
LOCALIZED_NAMES = {
- 'da_DK': ('Filer',),
+ "da_DK": ("Filer",),
}
class FreebusyData(NonDeletableFolderMixin, Folder):
LOCALIZED_NAMES = {
- None: ('Freebusy Data',),
+ None: ("Freebusy Data",),
}
class Friends(NonDeletableFolderMixin, Contacts):
- CONTAINER_CLASS = 'IPF.Note'
+ CONTAINER_CLASS = "IPF.Note"
LOCALIZED_NAMES = {
- 'de_DE': ('Bekannte',),
+ "de_DE": ("Bekannte",),
}
class GALContacts(NonDeletableFolderMixin, Contacts):
DISTINGUISHED_FOLDER_ID = None
- CONTAINER_CLASS = 'IPF.Contact.GalContacts'
+ CONTAINER_CLASS = "IPF.Contact.GalContacts"
LOCALIZED_NAMES = {
- None: ('GAL Contacts',),
+ None: ("GAL Contacts",),
}
class GraphAnalytics(NonDeletableFolderMixin, Folder):
- CONTAINER_CLASS = 'IPF.StoreItem.GraphAnalytics'
+ CONTAINER_CLASS = "IPF.StoreItem.GraphAnalytics"
LOCALIZED_NAMES = {
- None: ('GraphAnalytics',),
+ None: ("GraphAnalytics",),
}
class Location(NonDeletableFolderMixin, Folder):
LOCALIZED_NAMES = {
- None: ('Location',),
+ None: ("Location",),
}
class MailboxAssociations(NonDeletableFolderMixin, Folder):
LOCALIZED_NAMES = {
- None: ('MailboxAssociations',),
+ None: ("MailboxAssociations",),
}
class MyContactsExtended(NonDeletableFolderMixin, Contacts):
- CONTAINER_CLASS = 'IPF.Note'
+ CONTAINER_CLASS = "IPF.Note"
LOCALIZED_NAMES = {
- None: ('MyContactsExtended',),
+ None: ("MyContactsExtended",),
}
class OrganizationalContacts(NonDeletableFolderMixin, Contacts):
DISTINGUISHED_FOLDER_ID = None
- CONTAINTER_CLASS = 'IPF.Contact.OrganizationalContacts'
+ CONTAINTER_CLASS = "IPF.Contact.OrganizationalContacts"
LOCALIZED_NAMES = {
- None: ('Organizational Contacts',),
+ None: ("Organizational Contacts",),
}
class ParkedMessages(NonDeletableFolderMixin, Folder):
CONTAINER_CLASS = None
LOCALIZED_NAMES = {
- None: ('ParkedMessages',),
+ None: ("ParkedMessages",),
}
class PassThroughSearchResults(NonDeletableFolderMixin, Folder):
- CONTAINER_CLASS = 'IPF.StoreItem.PassThroughSearchResults'
+ CONTAINER_CLASS = "IPF.StoreItem.PassThroughSearchResults"
LOCALIZED_NAMES = {
- None: ('Pass-Through Search Results',),
+ None: ("Pass-Through Search Results",),
}
class PeopleCentricConversationBuddies(NonDeletableFolderMixin, Contacts):
DISTINGUISHED_FOLDER_ID = None
- CONTAINTER_CLASS = 'IPF.Contact.PeopleCentricConversationBuddies'
+ CONTAINTER_CLASS = "IPF.Contact.PeopleCentricConversationBuddies"
LOCALIZED_NAMES = {
- None: ('PeopleCentricConversation Buddies',),
+ None: ("PeopleCentricConversation Buddies",),
}
class PdpProfileV2Secured(NonDeletableFolderMixin, Folder):
- CONTAINER_CLASS = 'IPF.StoreItem.PdpProfileSecured'
+ CONTAINER_CLASS = "IPF.StoreItem.PdpProfileSecured"
LOCALIZED_NAMES = {
- None: ('PdpProfileV2Secured',),
+ None: ("PdpProfileV2Secured",),
}
class Reminders(NonDeletableFolderMixin, Folder):
- CONTAINER_CLASS = 'Outlook.Reminder'
+ CONTAINER_CLASS = "Outlook.Reminder"
LOCALIZED_NAMES = {
- 'da_DK': ('Påmindelser',),
+ "da_DK": ("Påmindelser",),
}
class RSSFeeds(NonDeletableFolderMixin, Folder):
- CONTAINER_CLASS = 'IPF.Note.OutlookHomepage'
+ CONTAINER_CLASS = "IPF.Note.OutlookHomepage"
LOCALIZED_NAMES = {
- None: ('RSS Feeds',),
+ None: ("RSS Feeds",),
}
class Schedule(NonDeletableFolderMixin, Folder):
LOCALIZED_NAMES = {
- None: ('Schedule',),
+ None: ("Schedule",),
}
class Sharing(NonDeletableFolderMixin, Folder):
- CONTAINER_CLASS = 'IPF.Note'
+ CONTAINER_CLASS = "IPF.Note"
LOCALIZED_NAMES = {
- None: ('Sharing',),
+ None: ("Sharing",),
}
class Shortcuts(NonDeletableFolderMixin, Folder):
LOCALIZED_NAMES = {
- None: ('Shortcuts',),
+ None: ("Shortcuts",),
}
class Signal(NonDeletableFolderMixin, Folder):
- CONTAINER_CLASS = 'IPF.StoreItem.Signal'
+ CONTAINER_CLASS = "IPF.StoreItem.Signal"
LOCALIZED_NAMES = {
- None: ('Signal',),
+ None: ("Signal",),
}
class SmsAndChatsSync(NonDeletableFolderMixin, Folder):
- CONTAINER_CLASS = 'IPF.SmsAndChatsSync'
+ CONTAINER_CLASS = "IPF.SmsAndChatsSync"
LOCALIZED_NAMES = {
- None: ('SmsAndChatsSync',),
+ None: ("SmsAndChatsSync",),
}
class SpoolerQueue(NonDeletableFolderMixin, Folder):
LOCALIZED_NAMES = {
- None: ('Spooler Queue',),
+ None: ("Spooler Queue",),
}
class System(NonDeletableFolderMixin, Folder):
LOCALIZED_NAMES = {
- None: ('System',),
+ None: ("System",),
}
get_folder_allowed = False
class System1(NonDeletableFolderMixin, Folder):
LOCALIZED_NAMES = {
- None: ('System1',),
+ None: ("System1",),
}
get_folder_allowed = False
class TemporarySaves(NonDeletableFolderMixin, Folder):
LOCALIZED_NAMES = {
- None: ('TemporarySaves',),
+ None: ("TemporarySaves",),
}
class Views(NonDeletableFolderMixin, Folder):
LOCALIZED_NAMES = {
- None: ('Views',),
+ None: ("Views",),
}
class WorkingSet(NonDeletableFolderMixin, Folder):
LOCALIZED_NAMES = {
- None: ('Working Set',),
+ None: ("Working Set",),
}
@@ -739,7 +749,7 @@ Classes
Expand source code
class AdminAuditLogs(WellknownFolder):
- DISTINGUISHED_FOLDER_ID = 'adminauditlogs'
+ DISTINGUISHED_FOLDER_ID = "adminauditlogs"
supported_from = EXCHANGE_2013
get_folder_allowed = False
@@ -818,10 +828,10 @@ Inherited members
Expand source code
class AllContacts(NonDeletableFolderMixin, Contacts):
- CONTAINER_CLASS = 'IPF.Note'
+ CONTAINER_CLASS = "IPF.Note"
LOCALIZED_NAMES = {
- None: ('AllContacts',),
+ None: ("AllContacts",),
}
Ancestors
@@ -896,10 +906,10 @@ Inherited members
Expand source code
class AllItems(NonDeletableFolderMixin, Folder):
- CONTAINER_CLASS = 'IPF'
+ CONTAINER_CLASS = "IPF"
LOCALIZED_NAMES = {
- None: ('AllItems',),
+ None: ("AllItems",),
}
Ancestors
@@ -973,7 +983,7 @@ Inherited members
Expand source code
class ArchiveDeletedItems(WellknownFolder):
- DISTINGUISHED_FOLDER_ID = 'archivedeleteditems'
+ DISTINGUISHED_FOLDER_ID = "archivedeleteditems"
supported_from = EXCHANGE_2010_SP1
Ancestors
@@ -1047,7 +1057,7 @@ Inherited members
Expand source code
class ArchiveInbox(WellknownFolder):
- DISTINGUISHED_FOLDER_ID = 'archiveinbox'
+ DISTINGUISHED_FOLDER_ID = "archiveinbox"
supported_from = EXCHANGE_2013_SP1
Ancestors
@@ -1121,7 +1131,7 @@ Inherited members
Expand source code
class ArchiveMsgFolderRoot(WellknownFolder):
- DISTINGUISHED_FOLDER_ID = 'archivemsgfolderroot'
+ DISTINGUISHED_FOLDER_ID = "archivemsgfolderroot"
supported_from = EXCHANGE_2010_SP1
Ancestors
@@ -1195,7 +1205,7 @@ Inherited members
Expand source code
class ArchiveRecoverableItemsDeletions(WellknownFolder):
- DISTINGUISHED_FOLDER_ID = 'archiverecoverableitemsdeletions'
+ DISTINGUISHED_FOLDER_ID = "archiverecoverableitemsdeletions"
supported_from = EXCHANGE_2010_SP1
Ancestors
@@ -1269,7 +1279,7 @@ Inherited members
Expand source code
class ArchiveRecoverableItemsPurges(WellknownFolder):
- DISTINGUISHED_FOLDER_ID = 'archiverecoverableitemspurges'
+ DISTINGUISHED_FOLDER_ID = "archiverecoverableitemspurges"
supported_from = EXCHANGE_2010_SP1
Ancestors
@@ -1343,7 +1353,7 @@ Inherited members
Expand source code
class ArchiveRecoverableItemsRoot(WellknownFolder):
- DISTINGUISHED_FOLDER_ID = 'archiverecoverableitemsroot'
+ DISTINGUISHED_FOLDER_ID = "archiverecoverableitemsroot"
supported_from = EXCHANGE_2010_SP1
Ancestors
@@ -1417,7 +1427,7 @@ Inherited members
Expand source code
class ArchiveRecoverableItemsVersions(WellknownFolder):
- DISTINGUISHED_FOLDER_ID = 'archiverecoverableitemsversions'
+ DISTINGUISHED_FOLDER_ID = "archiverecoverableitemsversions"
supported_from = EXCHANGE_2010_SP1
Ancestors
@@ -1492,7 +1502,7 @@ Inherited members
class Audits(NonDeletableFolderMixin, Folder):
LOCALIZED_NAMES = {
- None: ('Audits',),
+ None: ("Audits",),
}
get_folder_allowed = False
@@ -1569,20 +1579,20 @@ Inherited members
class Calendar(Folder):
"""An interface for the Exchange calendar."""
- DISTINGUISHED_FOLDER_ID = 'calendar'
- CONTAINER_CLASS = 'IPF.Appointment'
+ DISTINGUISHED_FOLDER_ID = "calendar"
+ CONTAINER_CLASS = "IPF.Appointment"
supported_item_models = (CalendarItem,)
LOCALIZED_NAMES = {
- 'da_DK': ('Kalender',),
- 'de_DE': ('Kalender',),
- 'en_US': ('Calendar',),
- 'es_ES': ('Calendario',),
- 'fr_CA': ('Calendrier',),
- 'nl_NL': ('Agenda',),
- 'ru_RU': ('Календарь',),
- 'sv_SE': ('Kalender',),
- 'zh_CN': ('日历',),
+ "da_DK": ("Kalender",),
+ "de_DE": ("Kalender",),
+ "en_US": ("Calendar",),
+ "es_ES": ("Calendario",),
+ "fr_CA": ("Calendrier",),
+ "nl_NL": ("Agenda",),
+ "ru_RU": ("Календарь",),
+ "sv_SE": ("Kalender",),
+ "zh_CN": ("日历",),
}
def view(self, *args, **kwargs):
@@ -1683,7 +1693,7 @@ Inherited members
class CalendarLogging(NonDeletableFolderMixin, Folder):
LOCALIZED_NAMES = {
- None: ('Calendar Logging',),
+ None: ("Calendar Logging",),
}
Ancestors
@@ -1755,7 +1765,7 @@ Inherited members
class CommonViews(NonDeletableFolderMixin, Folder):
DEFAULT_ITEM_TRAVERSAL_DEPTH = ASSOCIATED
LOCALIZED_NAMES = {
- None: ('Common Views',),
+ None: ("Common Views",),
}
Ancestors
@@ -1830,9 +1840,9 @@ Inherited members
class Companies(NonDeletableFolderMixin, Contacts):
DISTINGUISHED_FOLDER_ID = None
- CONTAINTER_CLASS = 'IPF.Contact.Company'
+ CONTAINTER_CLASS = "IPF.Contact.Company"
LOCALIZED_NAMES = {
- None: ('Companies',),
+ None: ("Companies",),
}
Ancestors
@@ -1911,7 +1921,7 @@ Inherited members
Expand source code
class Conflicts(WellknownFolder):
- DISTINGUISHED_FOLDER_ID = 'conflicts'
+ DISTINGUISHED_FOLDER_ID = "conflicts"
supported_from = EXCHANGE_2013
Ancestors
@@ -1985,20 +1995,20 @@ Inherited members
Expand source code
class Contacts(Folder):
- DISTINGUISHED_FOLDER_ID = 'contacts'
- CONTAINER_CLASS = 'IPF.Contact'
+ DISTINGUISHED_FOLDER_ID = "contacts"
+ CONTAINER_CLASS = "IPF.Contact"
supported_item_models = (Contact, DistributionList)
LOCALIZED_NAMES = {
- 'da_DK': ('Kontaktpersoner',),
- 'de_DE': ('Kontakte',),
- 'en_US': ('Contacts',),
- 'es_ES': ('Contactos',),
- 'fr_CA': ('Contacts',),
- 'nl_NL': ('Contactpersonen',),
- 'ru_RU': ('Контакты',),
- 'sv_SE': ('Kontakter',),
- 'zh_CN': ('联系人',),
+ "da_DK": ("Kontaktpersoner",),
+ "de_DE": ("Kontakte",),
+ "en_US": ("Contacts",),
+ "es_ES": ("Contactos",),
+ "fr_CA": ("Contacts",),
+ "nl_NL": ("Contactpersonen",),
+ "ru_RU": ("Контакты",),
+ "sv_SE": ("Kontakter",),
+ "zh_CN": ("联系人",),
}
Ancestors
@@ -2090,7 +2100,7 @@ Inherited members
Expand source code
class ConversationHistory(WellknownFolder):
- DISTINGUISHED_FOLDER_ID = 'conversationhistory'
+ DISTINGUISHED_FOLDER_ID = "conversationhistory"
supported_from = EXCHANGE_2013
Ancestors
@@ -2164,9 +2174,9 @@ Inherited members
Expand source code
class ConversationSettings(NonDeletableFolderMixin, Folder):
- CONTAINER_CLASS = 'IPF.Configuration'
+ CONTAINER_CLASS = "IPF.Configuration"
LOCALIZED_NAMES = {
- 'da_DK': ('Indstillinger for samtalehandlinger',),
+ "da_DK": ("Indstillinger for samtalehandlinger",),
}
Ancestors
@@ -2240,9 +2250,9 @@ Inherited members
Expand source code
class DefaultFoldersChangeHistory(NonDeletableFolderMixin, Folder):
- CONTAINER_CLASS = 'IPM.DefaultFolderHistoryItem'
+ CONTAINER_CLASS = "IPM.DefaultFolderHistoryItem"
LOCALIZED_NAMES = {
- None: ('DefaultFoldersChangeHistory',),
+ None: ("DefaultFoldersChangeHistory",),
}
Ancestors
@@ -2317,7 +2327,7 @@ Inherited members
class DeferredAction(NonDeletableFolderMixin, Folder):
LOCALIZED_NAMES = {
- None: ('Deferred Action',),
+ None: ("Deferred Action",),
}
Ancestors
@@ -2387,20 +2397,20 @@ Inherited members
Expand source code
class DeletedItems(Folder):
- DISTINGUISHED_FOLDER_ID = 'deleteditems'
- CONTAINER_CLASS = 'IPF.Note'
+ DISTINGUISHED_FOLDER_ID = "deleteditems"
+ CONTAINER_CLASS = "IPF.Note"
supported_item_models = ITEM_CLASSES
LOCALIZED_NAMES = {
- 'da_DK': ('Slettet post',),
- 'de_DE': ('Gelöschte Elemente',),
- 'en_US': ('Deleted Items',),
- 'es_ES': ('Elementos eliminados',),
- 'fr_CA': ('Éléments supprimés',),
- 'nl_NL': ('Verwijderde items',),
- 'ru_RU': ('Удаленные',),
- 'sv_SE': ('Borttaget',),
- 'zh_CN': ('已删除邮件',),
+ "da_DK": ("Slettet post",),
+ "de_DE": ("Gelöschte Elemente",),
+ "en_US": ("Deleted Items",),
+ "es_ES": ("Elementos eliminados",),
+ "fr_CA": ("Éléments supprimés",),
+ "nl_NL": ("Verwijderde items",),
+ "ru_RU": ("Удаленные",),
+ "sv_SE": ("Borttaget",),
+ "zh_CN": ("已删除邮件",),
}
Ancestors
@@ -2481,7 +2491,7 @@ Inherited members
Expand source code
class Directory(WellknownFolder):
- DISTINGUISHED_FOLDER_ID = 'directory'
+ DISTINGUISHED_FOLDER_ID = "directory"
supported_from = EXCHANGE_2013_SP1
Ancestors
@@ -2555,18 +2565,18 @@ Inherited members
Expand source code
class Drafts(Messages):
- DISTINGUISHED_FOLDER_ID = 'drafts'
+ DISTINGUISHED_FOLDER_ID = "drafts"
LOCALIZED_NAMES = {
- 'da_DK': ('Kladder',),
- 'de_DE': ('Entwürfe',),
- 'en_US': ('Drafts',),
- 'es_ES': ('Borradores',),
- 'fr_CA': ('Brouillons',),
- 'nl_NL': ('Concepten',),
- 'ru_RU': ('Черновики',),
- 'sv_SE': ('Utkast',),
- 'zh_CN': ('草稿',),
+ "da_DK": ("Kladder",),
+ "de_DE": ("Entwürfe",),
+ "en_US": ("Drafts",),
+ "es_ES": ("Borradores",),
+ "fr_CA": ("Brouillons",),
+ "nl_NL": ("Concepten",),
+ "ru_RU": ("Черновики",),
+ "sv_SE": ("Utkast",),
+ "zh_CN": ("草稿",),
}
Ancestors
@@ -2641,7 +2651,7 @@ Inherited members
class ExchangeSyncData(NonDeletableFolderMixin, Folder):
LOCALIZED_NAMES = {
- None: ('ExchangeSyncData',),
+ None: ("ExchangeSyncData",),
}
Ancestors
@@ -2711,8 +2721,8 @@ Inherited members
Expand source code
class Favorites(WellknownFolder):
- CONTAINER_CLASS = 'IPF.Note'
- DISTINGUISHED_FOLDER_ID = 'favorites'
+ CONTAINER_CLASS = "IPF.Note"
+ DISTINGUISHED_FOLDER_ID = "favorites"
supported_from = EXCHANGE_2013
Ancestors
@@ -2790,10 +2800,10 @@ Inherited members
Expand source code
class Files(NonDeletableFolderMixin, Folder):
- CONTAINER_CLASS = 'IPF.Files'
+ CONTAINER_CLASS = "IPF.Files"
LOCALIZED_NAMES = {
- 'da_DK': ('Filer',),
+ "da_DK": ("Filer",),
}
Ancestors
@@ -2868,7 +2878,7 @@ Inherited members
class FreebusyData(NonDeletableFolderMixin, Folder):
LOCALIZED_NAMES = {
- None: ('Freebusy Data',),
+ None: ("Freebusy Data",),
}
Ancestors
@@ -2938,10 +2948,10 @@ Inherited members
Expand source code
class Friends(NonDeletableFolderMixin, Contacts):
- CONTAINER_CLASS = 'IPF.Note'
+ CONTAINER_CLASS = "IPF.Note"
LOCALIZED_NAMES = {
- 'de_DE': ('Bekannte',),
+ "de_DE": ("Bekannte",),
}
Ancestors
@@ -3017,10 +3027,10 @@ Inherited members
class GALContacts(NonDeletableFolderMixin, Contacts):
DISTINGUISHED_FOLDER_ID = None
- CONTAINER_CLASS = 'IPF.Contact.GalContacts'
+ CONTAINER_CLASS = "IPF.Contact.GalContacts"
LOCALIZED_NAMES = {
- None: ('GAL Contacts',),
+ None: ("GAL Contacts",),
}
Ancestors
@@ -3099,9 +3109,9 @@ Inherited members
Expand source code
class GraphAnalytics(NonDeletableFolderMixin, Folder):
- CONTAINER_CLASS = 'IPF.StoreItem.GraphAnalytics'
+ CONTAINER_CLASS = "IPF.StoreItem.GraphAnalytics"
LOCALIZED_NAMES = {
- None: ('GraphAnalytics',),
+ None: ("GraphAnalytics",),
}
Ancestors
@@ -3175,8 +3185,8 @@ Inherited members
Expand source code
class IMContactList(WellknownFolder):
- CONTAINER_CLASS = 'IPF.Contact.MOC.ImContactList'
- DISTINGUISHED_FOLDER_ID = 'imcontactlist'
+ CONTAINER_CLASS = "IPF.Contact.MOC.ImContactList"
+ DISTINGUISHED_FOLDER_ID = "imcontactlist"
supported_from = EXCHANGE_2013
Ancestors
@@ -3254,18 +3264,18 @@ Inherited members
Expand source code
class Inbox(Messages):
- DISTINGUISHED_FOLDER_ID = 'inbox'
+ DISTINGUISHED_FOLDER_ID = "inbox"
LOCALIZED_NAMES = {
- 'da_DK': ('Indbakke',),
- 'de_DE': ('Posteingang',),
- 'en_US': ('Inbox',),
- 'es_ES': ('Bandeja de entrada',),
- 'fr_CA': ('Boîte de réception',),
- 'nl_NL': ('Postvak IN',),
- 'ru_RU': ('Входящие',),
- 'sv_SE': ('Inkorgen',),
- 'zh_CN': ('收件箱',),
+ "da_DK": ("Indbakke",),
+ "de_DE": ("Posteingang",),
+ "en_US": ("Inbox",),
+ "es_ES": ("Bandeja de entrada",),
+ "fr_CA": ("Boîte de réception",),
+ "nl_NL": ("Postvak IN",),
+ "ru_RU": ("Входящие",),
+ "sv_SE": ("Inkorgen",),
+ "zh_CN": ("收件箱",),
}
Ancestors
@@ -3339,8 +3349,8 @@ Inherited members
Expand source code
class Journal(WellknownFolder):
- CONTAINER_CLASS = 'IPF.Journal'
- DISTINGUISHED_FOLDER_ID = 'journal'
+ CONTAINER_CLASS = "IPF.Journal"
+ DISTINGUISHED_FOLDER_ID = "journal"
Ancestors
@@ -3413,18 +3423,18 @@ Inherited members
Expand source code
class JunkEmail(Messages):
- DISTINGUISHED_FOLDER_ID = 'junkemail'
+ DISTINGUISHED_FOLDER_ID = "junkemail"
LOCALIZED_NAMES = {
- 'da_DK': ('Uønsket e-mail',),
- 'de_DE': ('Junk-E-Mail',),
- 'en_US': ('Junk E-mail',),
- 'es_ES': ('Correo no deseado',),
- 'fr_CA': ('Courrier indésirables',),
- 'nl_NL': ('Ongewenste e-mail',),
- 'ru_RU': ('Нежелательная почта',),
- 'sv_SE': ('Skräppost',),
- 'zh_CN': ('垃圾邮件',),
+ "da_DK": ("Uønsket e-mail",),
+ "de_DE": ("Junk-E-Mail",),
+ "en_US": ("Junk E-mail",),
+ "es_ES": ("Correo no deseado",),
+ "fr_CA": ("Courrier indésirables",),
+ "nl_NL": ("Ongewenste e-mail",),
+ "ru_RU": ("Нежелательная почта",),
+ "sv_SE": ("Skräppost",),
+ "zh_CN": ("垃圾邮件",),
}
Ancestors
@@ -3498,7 +3508,7 @@ Inherited members
Expand source code
class LocalFailures(WellknownFolder):
- DISTINGUISHED_FOLDER_ID = 'localfailures'
+ DISTINGUISHED_FOLDER_ID = "localfailures"
supported_from = EXCHANGE_2013
Ancestors
@@ -3573,7 +3583,7 @@ Inherited members
class Location(NonDeletableFolderMixin, Folder):
LOCALIZED_NAMES = {
- None: ('Location',),
+ None: ("Location",),
}
Ancestors
@@ -3644,7 +3654,7 @@ Inherited members
class MailboxAssociations(NonDeletableFolderMixin, Folder):
LOCALIZED_NAMES = {
- None: ('MailboxAssociations',),
+ None: ("MailboxAssociations",),
}
Ancestors
@@ -3714,7 +3724,7 @@ Inherited members
Expand source code
class Messages(Folder):
- CONTAINER_CLASS = 'IPF.Note'
+ CONTAINER_CLASS = "IPF.Note"
supported_item_models = (Message, MeetingRequest, MeetingResponse, MeetingCancellation)
Ancestors
@@ -3797,9 +3807,9 @@ Inherited members
class MsgFolderRoot(WellknownFolder):
"""Also known as the 'Top of Information Store' folder."""
- DISTINGUISHED_FOLDER_ID = 'msgfolderroot'
+ DISTINGUISHED_FOLDER_ID = "msgfolderroot"
LOCALIZED_NAMES = {
- 'zh_CN': ('信息存储顶部',),
+ "zh_CN": ("信息存储顶部",),
}
Ancestors
@@ -3873,8 +3883,8 @@ Inherited members
Expand source code
class MyContacts(WellknownFolder):
- CONTAINER_CLASS = 'IPF.Note'
- DISTINGUISHED_FOLDER_ID = 'mycontacts'
+ CONTAINER_CLASS = "IPF.Note"
+ DISTINGUISHED_FOLDER_ID = "mycontacts"
supported_from = EXCHANGE_2013
Ancestors
@@ -3952,9 +3962,9 @@ Inherited members
Expand source code
class MyContactsExtended(NonDeletableFolderMixin, Contacts):
- CONTAINER_CLASS = 'IPF.Note'
+ CONTAINER_CLASS = "IPF.Note"
LOCALIZED_NAMES = {
- None: ('MyContactsExtended',),
+ None: ("MyContactsExtended",),
}
Ancestors
@@ -4100,10 +4110,10 @@ Instance variables
Expand source code
class Notes(WellknownFolder):
- CONTAINER_CLASS = 'IPF.StickyNote'
- DISTINGUISHED_FOLDER_ID = 'notes'
+ CONTAINER_CLASS = "IPF.StickyNote"
+ DISTINGUISHED_FOLDER_ID = "notes"
LOCALIZED_NAMES = {
- 'da_DK': ('Noter',),
+ "da_DK": ("Noter",),
}
Ancestors
@@ -4182,9 +4192,9 @@ Inherited members
class OrganizationalContacts(NonDeletableFolderMixin, Contacts):
DISTINGUISHED_FOLDER_ID = None
- CONTAINTER_CLASS = 'IPF.Contact.OrganizationalContacts'
+ CONTAINTER_CLASS = "IPF.Contact.OrganizationalContacts"
LOCALIZED_NAMES = {
- None: ('Organizational Contacts',),
+ None: ("Organizational Contacts",),
}
Ancestors
@@ -4263,18 +4273,18 @@ Inherited members
Expand source code
class Outbox(Messages):
- DISTINGUISHED_FOLDER_ID = 'outbox'
+ DISTINGUISHED_FOLDER_ID = "outbox"
LOCALIZED_NAMES = {
- 'da_DK': ('Udbakke',),
- 'de_DE': ('Postausgang',),
- 'en_US': ('Outbox',),
- 'es_ES': ('Bandeja de salida',),
- 'fr_CA': (u"Boîte d'envoi",),
- 'nl_NL': ('Postvak UIT',),
- 'ru_RU': ('Исходящие',),
- 'sv_SE': ('Utkorgen',),
- 'zh_CN': ('发件箱',),
+ "da_DK": ("Udbakke",),
+ "de_DE": ("Postausgang",),
+ "en_US": ("Outbox",),
+ "es_ES": ("Bandeja de salida",),
+ "fr_CA": (u"Boîte d'envoi",),
+ "nl_NL": ("Postvak UIT",),
+ "ru_RU": ("Исходящие",),
+ "sv_SE": ("Utkorgen",),
+ "zh_CN": ("发件箱",),
}
Ancestors
@@ -4350,7 +4360,7 @@ Inherited members
class ParkedMessages(NonDeletableFolderMixin, Folder):
CONTAINER_CLASS = None
LOCALIZED_NAMES = {
- None: ('ParkedMessages',),
+ None: ("ParkedMessages",),
}
Ancestors
@@ -4424,9 +4434,9 @@ Inherited members
Expand source code
class PassThroughSearchResults(NonDeletableFolderMixin, Folder):
- CONTAINER_CLASS = 'IPF.StoreItem.PassThroughSearchResults'
+ CONTAINER_CLASS = "IPF.StoreItem.PassThroughSearchResults"
LOCALIZED_NAMES = {
- None: ('Pass-Through Search Results',),
+ None: ("Pass-Through Search Results",),
}
Ancestors
@@ -4500,9 +4510,9 @@ Inherited members
Expand source code
class PdpProfileV2Secured(NonDeletableFolderMixin, Folder):
- CONTAINER_CLASS = 'IPF.StoreItem.PdpProfileSecured'
+ CONTAINER_CLASS = "IPF.StoreItem.PdpProfileSecured"
LOCALIZED_NAMES = {
- None: ('PdpProfileV2Secured',),
+ None: ("PdpProfileV2Secured",),
}
Ancestors
@@ -4577,9 +4587,9 @@ Inherited members
class PeopleCentricConversationBuddies(NonDeletableFolderMixin, Contacts):
DISTINGUISHED_FOLDER_ID = None
- CONTAINTER_CLASS = 'IPF.Contact.PeopleCentricConversationBuddies'
+ CONTAINTER_CLASS = "IPF.Contact.PeopleCentricConversationBuddies"
LOCALIZED_NAMES = {
- None: ('PeopleCentricConversation Buddies',),
+ None: ("PeopleCentricConversation Buddies",),
}
Ancestors
@@ -4658,7 +4668,7 @@ Inherited members
Expand source code
class PeopleConnect(WellknownFolder):
- DISTINGUISHED_FOLDER_ID = 'peopleconnect'
+ DISTINGUISHED_FOLDER_ID = "peopleconnect"
supported_from = EXCHANGE_2013
Ancestors
@@ -4732,8 +4742,8 @@ Inherited members
Expand source code
class QuickContacts(WellknownFolder):
- CONTAINER_CLASS = 'IPF.Contact.MOC.QuickContacts'
- DISTINGUISHED_FOLDER_ID = 'quickcontacts'
+ CONTAINER_CLASS = "IPF.Contact.MOC.QuickContacts"
+ DISTINGUISHED_FOLDER_ID = "quickcontacts"
supported_from = EXCHANGE_2013
Ancestors
@@ -4811,9 +4821,9 @@ Inherited members
Expand source code
class RSSFeeds(NonDeletableFolderMixin, Folder):
- CONTAINER_CLASS = 'IPF.Note.OutlookHomepage'
+ CONTAINER_CLASS = "IPF.Note.OutlookHomepage"
LOCALIZED_NAMES = {
- None: ('RSS Feeds',),
+ None: ("RSS Feeds",),
}
Ancestors
@@ -4887,8 +4897,8 @@ Inherited members
Expand source code
class RecipientCache(Contacts):
- DISTINGUISHED_FOLDER_ID = 'recipientcache'
- CONTAINER_CLASS = 'IPF.Contact.RecipientCache'
+ DISTINGUISHED_FOLDER_ID = "recipientcache"
+ CONTAINER_CLASS = "IPF.Contact.RecipientCache"
supported_from = EXCHANGE_2013
LOCALIZED_NAMES = {}
@@ -4972,7 +4982,7 @@ Inherited members
Expand source code
class RecoverableItemsDeletions(WellknownFolder):
- DISTINGUISHED_FOLDER_ID = 'recoverableitemsdeletions'
+ DISTINGUISHED_FOLDER_ID = "recoverableitemsdeletions"
supported_from = EXCHANGE_2010_SP1
Ancestors
@@ -5046,7 +5056,7 @@ Inherited members
Expand source code
class RecoverableItemsPurges(WellknownFolder):
- DISTINGUISHED_FOLDER_ID = 'recoverableitemspurges'
+ DISTINGUISHED_FOLDER_ID = "recoverableitemspurges"
supported_from = EXCHANGE_2010_SP1
Ancestors
@@ -5120,7 +5130,7 @@ Inherited members
Expand source code
class RecoverableItemsRoot(WellknownFolder):
- DISTINGUISHED_FOLDER_ID = 'recoverableitemsroot'
+ DISTINGUISHED_FOLDER_ID = "recoverableitemsroot"
supported_from = EXCHANGE_2010_SP1
Ancestors
@@ -5194,7 +5204,7 @@ Inherited members
Expand source code
class RecoverableItemsVersions(WellknownFolder):
- DISTINGUISHED_FOLDER_ID = 'recoverableitemsversions'
+ DISTINGUISHED_FOLDER_ID = "recoverableitemsversions"
supported_from = EXCHANGE_2010_SP1
Ancestors
@@ -5268,9 +5278,9 @@ Inherited members
Expand source code
class Reminders(NonDeletableFolderMixin, Folder):
- CONTAINER_CLASS = 'Outlook.Reminder'
+ CONTAINER_CLASS = "Outlook.Reminder"
LOCALIZED_NAMES = {
- 'da_DK': ('Påmindelser',),
+ "da_DK": ("Påmindelser",),
}
Ancestors
@@ -5345,7 +5355,7 @@ Inherited members
class Schedule(NonDeletableFolderMixin, Folder):
LOCALIZED_NAMES = {
- None: ('Schedule',),
+ None: ("Schedule",),
}
Ancestors
@@ -5415,7 +5425,7 @@ Inherited members
Expand source code
class SearchFolders(WellknownFolder):
- DISTINGUISHED_FOLDER_ID = 'searchfolders'
+ DISTINGUISHED_FOLDER_ID = "searchfolders"
Ancestors
@@ -5484,18 +5494,18 @@ Inherited members
Expand source code
class SentItems(Messages):
- DISTINGUISHED_FOLDER_ID = 'sentitems'
+ DISTINGUISHED_FOLDER_ID = "sentitems"
LOCALIZED_NAMES = {
- 'da_DK': ('Sendt post',),
- 'de_DE': ('Gesendete Elemente',),
- 'en_US': ('Sent Items',),
- 'es_ES': ('Elementos enviados',),
- 'fr_CA': ('Éléments envoyés',),
- 'nl_NL': ('Verzonden items',),
- 'ru_RU': ('Отправленные',),
- 'sv_SE': ('Skickat',),
- 'zh_CN': ('已发送邮件',),
+ "da_DK": ("Sendt post",),
+ "de_DE": ("Gesendete Elemente",),
+ "en_US": ("Sent Items",),
+ "es_ES": ("Elementos enviados",),
+ "fr_CA": ("Éléments envoyés",),
+ "nl_NL": ("Verzonden items",),
+ "ru_RU": ("Отправленные",),
+ "sv_SE": ("Skickat",),
+ "zh_CN": ("已发送邮件",),
}
Ancestors
@@ -5569,7 +5579,7 @@ Inherited members
Expand source code
class ServerFailures(WellknownFolder):
- DISTINGUISHED_FOLDER_ID = 'serverfailures'
+ DISTINGUISHED_FOLDER_ID = "serverfailures"
supported_from = EXCHANGE_2013
Ancestors
@@ -5643,9 +5653,9 @@ Inherited members
Expand source code
class Sharing(NonDeletableFolderMixin, Folder):
- CONTAINER_CLASS = 'IPF.Note'
+ CONTAINER_CLASS = "IPF.Note"
LOCALIZED_NAMES = {
- None: ('Sharing',),
+ None: ("Sharing",),
}
Ancestors
@@ -5720,7 +5730,7 @@ Inherited members
class Shortcuts(NonDeletableFolderMixin, Folder):
LOCALIZED_NAMES = {
- None: ('Shortcuts',),
+ None: ("Shortcuts",),
}
Ancestors
@@ -5790,9 +5800,9 @@ Inherited members
Expand source code
class Signal(NonDeletableFolderMixin, Folder):
- CONTAINER_CLASS = 'IPF.StoreItem.Signal'
+ CONTAINER_CLASS = "IPF.StoreItem.Signal"
LOCALIZED_NAMES = {
- None: ('Signal',),
+ None: ("Signal",),
}
Ancestors
@@ -5866,9 +5876,9 @@ Inherited members
Expand source code
class SmsAndChatsSync(NonDeletableFolderMixin, Folder):
- CONTAINER_CLASS = 'IPF.SmsAndChatsSync'
+ CONTAINER_CLASS = "IPF.SmsAndChatsSync"
LOCALIZED_NAMES = {
- None: ('SmsAndChatsSync',),
+ None: ("SmsAndChatsSync",),
}
Ancestors
@@ -5943,7 +5953,7 @@ Inherited members
class SpoolerQueue(NonDeletableFolderMixin, Folder):
LOCALIZED_NAMES = {
- None: ('Spooler Queue',),
+ None: ("Spooler Queue",),
}
Ancestors
@@ -6013,8 +6023,8 @@ Inherited members
Expand source code
class SyncIssues(WellknownFolder):
- CONTAINER_CLASS = 'IPF.Note'
- DISTINGUISHED_FOLDER_ID = 'syncissues'
+ CONTAINER_CLASS = "IPF.Note"
+ DISTINGUISHED_FOLDER_ID = "syncissues"
supported_from = EXCHANGE_2013
Ancestors
@@ -6093,7 +6103,7 @@ Inherited members
class System(NonDeletableFolderMixin, Folder):
LOCALIZED_NAMES = {
- None: ('System',),
+ None: ("System",),
}
get_folder_allowed = False
@@ -6169,7 +6179,7 @@ Inherited members
class System1(NonDeletableFolderMixin, Folder):
LOCALIZED_NAMES = {
- None: ('System1',),
+ None: ("System1",),
}
get_folder_allowed = False
@@ -6244,20 +6254,20 @@ Inherited members
Expand source code
class Tasks(Folder):
- DISTINGUISHED_FOLDER_ID = 'tasks'
- CONTAINER_CLASS = 'IPF.Task'
+ DISTINGUISHED_FOLDER_ID = "tasks"
+ CONTAINER_CLASS = "IPF.Task"
supported_item_models = (Task,)
LOCALIZED_NAMES = {
- 'da_DK': ('Opgaver',),
- 'de_DE': ('Aufgaben',),
- 'en_US': ('Tasks',),
- 'es_ES': ('Tareas',),
- 'fr_CA': ('Tâches',),
- 'nl_NL': ('Taken',),
- 'ru_RU': ('Задачи',),
- 'sv_SE': ('Uppgifter',),
- 'zh_CN': ('任务',),
+ "da_DK": ("Opgaver",),
+ "de_DE": ("Aufgaben",),
+ "en_US": ("Tasks",),
+ "es_ES": ("Tareas",),
+ "fr_CA": ("Tâches",),
+ "nl_NL": ("Taken",),
+ "ru_RU": ("Задачи",),
+ "sv_SE": ("Uppgifter",),
+ "zh_CN": ("任务",),
}
Ancestors
@@ -6339,7 +6349,7 @@ Inherited members
class TemporarySaves(NonDeletableFolderMixin, Folder):
LOCALIZED_NAMES = {
- None: ('TemporarySaves',),
+ None: ("TemporarySaves",),
}
Ancestors
@@ -6409,12 +6419,12 @@ Inherited members
Expand source code
class ToDoSearch(WellknownFolder):
- CONTAINER_CLASS = 'IPF.Task'
- DISTINGUISHED_FOLDER_ID = 'todosearch'
+ CONTAINER_CLASS = "IPF.Task"
+ DISTINGUISHED_FOLDER_ID = "todosearch"
supported_from = EXCHANGE_2013
LOCALIZED_NAMES = {
- None: ('To-Do Search',),
+ None: ("To-Do Search",),
}
Ancestors
@@ -6497,7 +6507,7 @@ Inherited members
class Views(NonDeletableFolderMixin, Folder):
LOCALIZED_NAMES = {
- None: ('Views',),
+ None: ("Views",),
}
Ancestors
@@ -6567,10 +6577,10 @@ Inherited members
Expand source code
class VoiceMail(WellknownFolder):
- DISTINGUISHED_FOLDER_ID = 'voicemail'
- CONTAINER_CLASS = 'IPF.Note.Microsoft.Voicemail'
+ DISTINGUISHED_FOLDER_ID = "voicemail"
+ CONTAINER_CLASS = "IPF.Note.Microsoft.Voicemail"
LOCALIZED_NAMES = {
- None: ('Voice Mail',),
+ None: ("Voice Mail",),
}
Ancestors
@@ -6751,7 +6761,7 @@ Inherited members
class WorkingSet(NonDeletableFolderMixin, Folder):
LOCALIZED_NAMES = {
- None: ('Working Set',),
+ None: ("Working Set",),
}
Ancestors
diff --git a/docs/exchangelib/folders/queryset.html b/docs/exchangelib/folders/queryset.html
index 2db1a571..b2b11337 100644
--- a/docs/exchangelib/folders/queryset.html
+++ b/docs/exchangelib/folders/queryset.html
@@ -29,15 +29,15 @@ Module exchangelib.folders.queryset
import logging
from copy import deepcopy
-from ..errors import ErrorFolderNotFound, ErrorNoPublicFolderReplicaAvailable, ErrorItemNotFound, InvalidTypeError
-from ..properties import InvalidField, FolderId
+from ..errors import ErrorFolderNotFound, ErrorItemNotFound, ErrorNoPublicFolderReplicaAvailable, InvalidTypeError
+from ..properties import FolderId, InvalidField
from ..queryset import DoesNotExist, MultipleObjectsReturned
from ..restriction import Q
# Traversal enums
-SHALLOW = 'Shallow'
-SOFT_DELETED = 'SoftDeleted'
-DEEP = 'Deep'
+SHALLOW = "Shallow"
+SOFT_DELETED = "SoftDeleted"
+DEEP = "Deep"
FOLDER_TRAVERSAL_CHOICES = (SHALLOW, DEEP, SOFT_DELETED)
MISSING_FOLDER_ERRORS = (ErrorFolderNotFound, ErrorItemNotFound, ErrorNoPublicFolderReplicaAvailable)
@@ -51,8 +51,9 @@ Module exchangelib.folders.queryset
def __init__(self, folder_collection):
from .collections import FolderCollection
+
if not isinstance(folder_collection, FolderCollection):
- raise InvalidTypeError('folder_collection', folder_collection, FolderCollection)
+ raise InvalidTypeError("folder_collection", folder_collection, FolderCollection)
self.folder_collection = folder_collection
self.q = Q() # Default to no restrictions
self.only_fields = None
@@ -72,6 +73,7 @@ Module exchangelib.folders.queryset
def only(self, *args):
"""Restrict the fields returned. 'name' and 'folder_class' are always returned."""
from .base import Folder
+
# Subfolders will always be of class Folder
all_fields = self.folder_collection.get_folder_fields(target_cls=Folder, is_complex=None)
all_fields.update(Folder.attribute_fields())
@@ -101,18 +103,19 @@ Module exchangelib.folders.queryset
MultipleObjectsReturned if there are multiple results.
"""
from .collections import FolderCollection
- if not args and set(kwargs) in ({'id'}, {'id', 'changekey'}):
- folders = list(FolderCollection(
- account=self.folder_collection.account, folders=[FolderId(**kwargs)]
- ).resolve())
+
+ if not args and set(kwargs) in ({"id"}, {"id", "changekey"}):
+ folders = list(
+ FolderCollection(account=self.folder_collection.account, folders=[FolderId(**kwargs)]).resolve()
+ )
elif args or kwargs:
folders = list(self.filter(*args, **kwargs))
else:
folders = list(self.all())
if not folders:
- raise DoesNotExist('Could not find a child folder matching the query')
+ raise DoesNotExist("Could not find a child folder matching the query")
if len(folders) != 1:
- raise MultipleObjectsReturned(f'Expected result length 1, but got {folders}')
+ raise MultipleObjectsReturned(f"Expected result length 1, but got {folders}")
f = folders[0]
if isinstance(f, Exception):
raise f
@@ -136,6 +139,7 @@ Module exchangelib.folders.queryset
def _query(self):
from .base import Folder
from .collections import FolderCollection
+
if self.only_fields is None:
# Subfolders will always be of class Folder
non_complex_fields = self.folder_collection.get_folder_fields(target_cls=Folder, is_complex=False)
@@ -158,7 +162,7 @@ Module exchangelib.folders.queryset
yield f
continue
if not f.get_folder_allowed:
- log.debug('GetFolder not allowed on folder %s. Non-complex fields must be fetched with FindFolder', f)
+ log.debug("GetFolder not allowed on folder %s. Non-complex fields must be fetched with FindFolder", f)
yield f
else:
resolveable_folders.append(f)
@@ -176,7 +180,7 @@ Module exchangelib.folders.queryset
continue
# Add the extra field values to the folders we fetched with find_folders()
if f.__class__ != complex_f.__class__:
- raise ValueError(f'Type mismatch: {f} vs {complex_f}')
+ raise ValueError(f"Type mismatch: {f} vs {complex_f}")
for complex_field in complex_fields:
field_name = complex_field.field.name
setattr(f, field_name, getattr(complex_f, field_name))
@@ -188,6 +192,7 @@ Module exchangelib.folders.queryset
def __init__(self, account, folder):
from .collections import FolderCollection
+
folder_collection = FolderCollection(account=account, folders=[folder])
super().__init__(folder_collection=folder_collection)
@@ -222,8 +227,9 @@ Classes
def __init__(self, folder_collection):
from .collections import FolderCollection
+
if not isinstance(folder_collection, FolderCollection):
- raise InvalidTypeError('folder_collection', folder_collection, FolderCollection)
+ raise InvalidTypeError("folder_collection", folder_collection, FolderCollection)
self.folder_collection = folder_collection
self.q = Q() # Default to no restrictions
self.only_fields = None
@@ -243,6 +249,7 @@ Classes
def only(self, *args):
"""Restrict the fields returned. 'name' and 'folder_class' are always returned."""
from .base import Folder
+
# Subfolders will always be of class Folder
all_fields = self.folder_collection.get_folder_fields(target_cls=Folder, is_complex=None)
all_fields.update(Folder.attribute_fields())
@@ -272,18 +279,19 @@ Classes
MultipleObjectsReturned if there are multiple results.
"""
from .collections import FolderCollection
- if not args and set(kwargs) in ({'id'}, {'id', 'changekey'}):
- folders = list(FolderCollection(
- account=self.folder_collection.account, folders=[FolderId(**kwargs)]
- ).resolve())
+
+ if not args and set(kwargs) in ({"id"}, {"id", "changekey"}):
+ folders = list(
+ FolderCollection(account=self.folder_collection.account, folders=[FolderId(**kwargs)]).resolve()
+ )
elif args or kwargs:
folders = list(self.filter(*args, **kwargs))
else:
folders = list(self.all())
if not folders:
- raise DoesNotExist('Could not find a child folder matching the query')
+ raise DoesNotExist("Could not find a child folder matching the query")
if len(folders) != 1:
- raise MultipleObjectsReturned(f'Expected result length 1, but got {folders}')
+ raise MultipleObjectsReturned(f"Expected result length 1, but got {folders}")
f = folders[0]
if isinstance(f, Exception):
raise f
@@ -307,6 +315,7 @@ Classes
def _query(self):
from .base import Folder
from .collections import FolderCollection
+
if self.only_fields is None:
# Subfolders will always be of class Folder
non_complex_fields = self.folder_collection.get_folder_fields(target_cls=Folder, is_complex=False)
@@ -329,7 +338,7 @@ Classes
yield f
continue
if not f.get_folder_allowed:
- log.debug('GetFolder not allowed on folder %s. Non-complex fields must be fetched with FindFolder', f)
+ log.debug("GetFolder not allowed on folder %s. Non-complex fields must be fetched with FindFolder", f)
yield f
else:
resolveable_folders.append(f)
@@ -347,7 +356,7 @@ Classes
continue
# Add the extra field values to the folders we fetched with find_folders()
if f.__class__ != complex_f.__class__:
- raise ValueError(f'Type mismatch: {f} vs {complex_f}')
+ raise ValueError(f"Type mismatch: {f} vs {complex_f}")
for complex_field in complex_fields:
field_name = complex_field.field.name
setattr(f, field_name, getattr(complex_f, field_name))
@@ -426,18 +435,19 @@ Methods
MultipleObjectsReturned if there are multiple results.
"""
from .collections import FolderCollection
- if not args and set(kwargs) in ({'id'}, {'id', 'changekey'}):
- folders = list(FolderCollection(
- account=self.folder_collection.account, folders=[FolderId(**kwargs)]
- ).resolve())
+
+ if not args and set(kwargs) in ({"id"}, {"id", "changekey"}):
+ folders = list(
+ FolderCollection(account=self.folder_collection.account, folders=[FolderId(**kwargs)]).resolve()
+ )
elif args or kwargs:
folders = list(self.filter(*args, **kwargs))
else:
folders = list(self.all())
if not folders:
- raise DoesNotExist('Could not find a child folder matching the query')
+ raise DoesNotExist("Could not find a child folder matching the query")
if len(folders) != 1:
- raise MultipleObjectsReturned(f'Expected result length 1, but got {folders}')
+ raise MultipleObjectsReturned(f"Expected result length 1, but got {folders}")
f = folders[0]
if isinstance(f, Exception):
raise f
@@ -456,6 +466,7 @@ Methods
def only(self, *args):
"""Restrict the fields returned. 'name' and 'folder_class' are always returned."""
from .base import Folder
+
# Subfolders will always be of class Folder
all_fields = self.folder_collection.get_folder_fields(target_cls=Folder, is_complex=None)
all_fields.update(Folder.attribute_fields())
@@ -489,6 +500,7 @@ Methods
def __init__(self, account, folder):
from .collections import FolderCollection
+
folder_collection = FolderCollection(account=account, folders=[folder])
super().__init__(folder_collection=folder_collection)
diff --git a/docs/exchangelib/folders/roots.html b/docs/exchangelib/folders/roots.html
index 90c38f46..557f7715 100644
--- a/docs/exchangelib/folders/roots.html
+++ b/docs/exchangelib/folders/roots.html
@@ -29,15 +29,19 @@ Module exchangelib.folders.roots
import logging
from threading import Lock
-from .base import BaseFolder
-from .collections import FolderCollection
-from .known_folders import MsgFolderRoot, NON_DELETABLE_FOLDERS, WELLKNOWN_FOLDERS_IN_ROOT, \
- WELLKNOWN_FOLDERS_IN_ARCHIVE_ROOT
-from .queryset import SingleFolderQuerySet, SHALLOW, MISSING_FOLDER_ERRORS
from ..errors import ErrorAccessDenied, ErrorFolderNotFound, ErrorInvalidOperation
from ..fields import EffectiveRightsField
from ..properties import EWSMeta
from ..version import EXCHANGE_2007_SP1, EXCHANGE_2010_SP1
+from .base import BaseFolder
+from .collections import FolderCollection
+from .known_folders import (
+ NON_DELETABLE_FOLDERS,
+ WELLKNOWN_FOLDERS_IN_ARCHIVE_ROOT,
+ WELLKNOWN_FOLDERS_IN_ROOT,
+ MsgFolderRoot,
+)
+from .queryset import MISSING_FOLDER_ERRORS, SHALLOW, SingleFolderQuerySet
log = logging.getLogger(__name__)
@@ -56,14 +60,15 @@ Module exchangelib.folders.roots
# This folder type also has 'folder:PermissionSet' on some server versions, but requesting it sometimes causes
# 'ErrorAccessDenied', as reported by some users. Ignore it entirely for root folders - it's usefulness is
# deemed minimal at best.
- effective_rights = EffectiveRightsField(field_uri='folder:EffectiveRights', is_read_only=True,
- supported_from=EXCHANGE_2007_SP1)
+ effective_rights = EffectiveRightsField(
+ field_uri="folder:EffectiveRights", is_read_only=True, supported_from=EXCHANGE_2007_SP1
+ )
- __slots__ = '_account', '_subfolders'
+ __slots__ = "_account", "_subfolders"
# A special folder that acts as the top of a folder hierarchy. Finds and caches subfolders at arbitrary depth.
def __init__(self, **kwargs):
- self._account = kwargs.pop('account', None) # A pointer back to the account holding the folder hierarchy
+ self._account = kwargs.pop("account", None) # A pointer back to the account holding the folder hierarchy
super().__init__(**kwargs)
self._subfolders = None # See self._folders_map()
@@ -82,13 +87,13 @@ Module exchangelib.folders.roots
@classmethod
def register(cls, *args, **kwargs):
if cls is not RootOfHierarchy:
- raise TypeError('For folder roots, custom fields must be registered on the RootOfHierarchy class')
+ raise TypeError("For folder roots, custom fields must be registered on the RootOfHierarchy class")
return super().register(*args, **kwargs)
@classmethod
def deregister(cls, *args, **kwargs):
if cls is not RootOfHierarchy:
- raise TypeError('For folder roots, custom fields must be registered on the RootOfHierarchy class')
+ raise TypeError("For folder roots, custom fields must be registered on the RootOfHierarchy class")
return super().deregister(*args, **kwargs)
def get_folder(self, folder):
@@ -132,14 +137,13 @@ Module exchangelib.folders.roots
:param account:
"""
if not cls.DISTINGUISHED_FOLDER_ID:
- raise ValueError(f'Class {cls} must have a DISTINGUISHED_FOLDER_ID value')
+ raise ValueError(f"Class {cls} must have a DISTINGUISHED_FOLDER_ID value")
try:
return cls.resolve(
- account=account,
- folder=cls(account=account, name=cls.DISTINGUISHED_FOLDER_ID, is_distinguished=True)
+ account=account, folder=cls(account=account, name=cls.DISTINGUISHED_FOLDER_ID, is_distinguished=True)
)
except MISSING_FOLDER_ERRORS:
- raise ErrorFolderNotFound(f'Could not find distinguished folder {cls.DISTINGUISHED_FOLDER_ID}')
+ raise ErrorFolderNotFound(f"Could not find distinguished folder {cls.DISTINGUISHED_FOLDER_ID}")
def get_default_folder(self, folder_cls):
"""Return the distinguished folder instance of type folder_cls belonging to this account. If no distinguished
@@ -153,21 +157,21 @@ Module exchangelib.folders.roots
for f in self._folders_map.values():
# Require exact class, to not match subclasses, e.g. RecipientCache instead of Contacts
if f.__class__ == folder_cls and f.is_distinguished:
- log.debug('Found cached distinguished %s folder', folder_cls)
+ log.debug("Found cached distinguished %s folder", folder_cls)
return f
try:
- log.debug('Requesting distinguished %s folder explicitly', folder_cls)
+ log.debug("Requesting distinguished %s folder explicitly", folder_cls)
return folder_cls.get_distinguished(root=self)
except ErrorAccessDenied:
# Maybe we just don't have GetFolder access? Try FindItems instead
- log.debug('Testing default %s folder with FindItem', folder_cls)
+ log.debug("Testing default %s folder with FindItem", folder_cls)
fld = folder_cls(root=self, name=folder_cls.DISTINGUISHED_FOLDER_ID, is_distinguished=True)
fld.test_access()
return self._folders_map.get(fld.id, fld) # Use cached instance if available
except MISSING_FOLDER_ERRORS:
# The Exchange server does not return a distinguished folder of this type
pass
- raise ErrorFolderNotFound(f'No usable default {folder_cls} folders')
+ raise ErrorFolderNotFound(f"No usable default {folder_cls} folders")
@property
def _folders_map(self):
@@ -198,9 +202,9 @@ Module exchangelib.folders.roots
if isinstance(f, Exception):
raise f
folders_map[f.id] = f
- for f in SingleFolderQuerySet(account=self.account, folder=self).depth(
- self.DEFAULT_FOLDER_TRAVERSAL_DEPTH
- ).all():
+ for f in (
+ SingleFolderQuerySet(account=self.account, folder=self).depth(self.DEFAULT_FOLDER_TRAVERSAL_DEPTH).all()
+ ):
if isinstance(f, ErrorAccessDenied):
# We may not have FindFolder access, or GetFolder access, either to this folder or at all
continue
@@ -236,15 +240,25 @@ Module exchangelib.folders.roots
def __repr__(self):
# Let's not create an infinite loop when printing self.root
- return self.__class__.__name__ + \
- repr((self.account, '[self]', self.name, self.total_count, self.unread_count, self.child_folder_count,
- self.folder_class, self.id, self.changekey))
+ return self.__class__.__name__ + repr(
+ (
+ self.account,
+ "[self]",
+ self.name,
+ self.total_count,
+ self.unread_count,
+ self.child_folder_count,
+ self.folder_class,
+ self.id,
+ self.changekey,
+ )
+ )
class Root(RootOfHierarchy):
"""The root of the standard folder hierarchy."""
- DISTINGUISHED_FOLDER_ID = 'root'
+ DISTINGUISHED_FOLDER_ID = "root"
WELLKNOWN_FOLDERS = WELLKNOWN_FOLDERS_IN_ROOT
@property
@@ -265,12 +279,12 @@ Module exchangelib.folders.roots
# 3. Searching TOIS for a direct child folder of the same type that has a localized name
# 4. Searching root for a direct child folder of the same type that is marked as distinguished
# 5. Searching root for a direct child folder of the same type that has a localized name
- log.debug('Searching default %s folder in full folder list', folder_cls)
+ log.debug("Searching default %s folder in full folder list", folder_cls)
for f in self._folders_map.values():
# Require exact type, to avoid matching with subclasses (e.g. RecipientCache and Contacts)
if f.__class__ == folder_cls and f.has_distinguished_name:
- log.debug('Found cached %s folder with default distinguished name', folder_cls)
+ log.debug("Found cached %s folder with default distinguished name", folder_cls)
return f
# Try direct children of TOIS first, unless we're trying to get the TOIS folder
@@ -293,21 +307,21 @@ Module exchangelib.folders.roots
else:
candidates = [f for f in same_type if f.name.lower() in folder_cls.localized_names(self.account.locale)]
if not candidates:
- raise ErrorFolderNotFound(f'No usable default {folder_cls} folders')
+ raise ErrorFolderNotFound(f"No usable default {folder_cls} folders")
if len(candidates) > 1:
- raise ValueError(f'Multiple possible default {folder_cls} folders: {[f.name for f in candidates]}')
+ raise ValueError(f"Multiple possible default {folder_cls} folders: {[f.name for f in candidates]}")
candidate = candidates[0]
if candidate.is_distinguished:
- log.debug('Found distinguished %s folder', folder_cls)
+ log.debug("Found distinguished %s folder", folder_cls)
else:
- log.debug('Found %s folder with localized name %s', folder_cls, candidate.name)
+ log.debug("Found %s folder with localized name %s", folder_cls, candidate.name)
return candidate
class PublicFoldersRoot(RootOfHierarchy):
"""The root of the public folders hierarchy. Not available on all mailboxes."""
- DISTINGUISHED_FOLDER_ID = 'publicfoldersroot'
+ DISTINGUISHED_FOLDER_ID = "publicfoldersroot"
DEFAULT_FOLDER_TRAVERSAL_DEPTH = SHALLOW
supported_from = EXCHANGE_2007_SP1
@@ -328,9 +342,11 @@ Module exchangelib.folders.roots
children_map = {}
try:
- for f in SingleFolderQuerySet(account=self.account, folder=folder).depth(
- self.DEFAULT_FOLDER_TRAVERSAL_DEPTH
- ).all():
+ for f in (
+ SingleFolderQuerySet(account=self.account, folder=folder)
+ .depth(self.DEFAULT_FOLDER_TRAVERSAL_DEPTH)
+ .all()
+ ):
if isinstance(f, MISSING_FOLDER_ERRORS):
# We were unlucky. The folder disappeared between the FindFolder and the GetFolder calls
continue
@@ -352,7 +368,7 @@ Module exchangelib.folders.roots
class ArchiveRoot(RootOfHierarchy):
"""The root of the archive folders hierarchy. Not available on all mailboxes."""
- DISTINGUISHED_FOLDER_ID = 'archiveroot'
+ DISTINGUISHED_FOLDER_ID = "archiveroot"
supported_from = EXCHANGE_2010_SP1
WELLKNOWN_FOLDERS = WELLKNOWN_FOLDERS_IN_ARCHIVE_ROOT
@@ -379,7 +395,7 @@ Classes
class ArchiveRoot(RootOfHierarchy):
"""The root of the archive folders hierarchy. Not available on all mailboxes."""
- DISTINGUISHED_FOLDER_ID = 'archiveroot'
+ DISTINGUISHED_FOLDER_ID = "archiveroot"
supported_from = EXCHANGE_2010_SP1
WELLKNOWN_FOLDERS = WELLKNOWN_FOLDERS_IN_ARCHIVE_ROOT
@@ -461,7 +477,7 @@ Inherited members
class PublicFoldersRoot(RootOfHierarchy):
"""The root of the public folders hierarchy. Not available on all mailboxes."""
- DISTINGUISHED_FOLDER_ID = 'publicfoldersroot'
+ DISTINGUISHED_FOLDER_ID = "publicfoldersroot"
DEFAULT_FOLDER_TRAVERSAL_DEPTH = SHALLOW
supported_from = EXCHANGE_2007_SP1
@@ -482,9 +498,11 @@ Inherited members
children_map = {}
try:
- for f in SingleFolderQuerySet(account=self.account, folder=folder).depth(
- self.DEFAULT_FOLDER_TRAVERSAL_DEPTH
- ).all():
+ for f in (
+ SingleFolderQuerySet(account=self.account, folder=folder)
+ .depth(self.DEFAULT_FOLDER_TRAVERSAL_DEPTH)
+ .all()
+ ):
if isinstance(f, MISSING_FOLDER_ERRORS):
# We were unlucky. The folder disappeared between the FindFolder and the GetFolder calls
continue
@@ -554,9 +572,11 @@ Methods
children_map = {}
try:
- for f in SingleFolderQuerySet(account=self.account, folder=folder).depth(
- self.DEFAULT_FOLDER_TRAVERSAL_DEPTH
- ).all():
+ for f in (
+ SingleFolderQuerySet(account=self.account, folder=folder)
+ .depth(self.DEFAULT_FOLDER_TRAVERSAL_DEPTH)
+ .all()
+ ):
if isinstance(f, MISSING_FOLDER_ERRORS):
# We were unlucky. The folder disappeared between the FindFolder and the GetFolder calls
continue
@@ -630,7 +650,7 @@ Inherited members
class Root(RootOfHierarchy):
"""The root of the standard folder hierarchy."""
- DISTINGUISHED_FOLDER_ID = 'root'
+ DISTINGUISHED_FOLDER_ID = "root"
WELLKNOWN_FOLDERS = WELLKNOWN_FOLDERS_IN_ROOT
@property
@@ -651,12 +671,12 @@ Inherited members
# 3. Searching TOIS for a direct child folder of the same type that has a localized name
# 4. Searching root for a direct child folder of the same type that is marked as distinguished
# 5. Searching root for a direct child folder of the same type that has a localized name
- log.debug('Searching default %s folder in full folder list', folder_cls)
+ log.debug("Searching default %s folder in full folder list", folder_cls)
for f in self._folders_map.values():
# Require exact type, to avoid matching with subclasses (e.g. RecipientCache and Contacts)
if f.__class__ == folder_cls and f.has_distinguished_name:
- log.debug('Found cached %s folder with default distinguished name', folder_cls)
+ log.debug("Found cached %s folder with default distinguished name", folder_cls)
return f
# Try direct children of TOIS first, unless we're trying to get the TOIS folder
@@ -679,14 +699,14 @@ Inherited members
else:
candidates = [f for f in same_type if f.name.lower() in folder_cls.localized_names(self.account.locale)]
if not candidates:
- raise ErrorFolderNotFound(f'No usable default {folder_cls} folders')
+ raise ErrorFolderNotFound(f"No usable default {folder_cls} folders")
if len(candidates) > 1:
- raise ValueError(f'Multiple possible default {folder_cls} folders: {[f.name for f in candidates]}')
+ raise ValueError(f"Multiple possible default {folder_cls} folders: {[f.name for f in candidates]}")
candidate = candidates[0]
if candidate.is_distinguished:
- log.debug('Found distinguished %s folder', folder_cls)
+ log.debug("Found distinguished %s folder", folder_cls)
else:
- log.debug('Found %s folder with localized name %s', folder_cls, candidate.name)
+ log.debug("Found %s folder with localized name %s", folder_cls, candidate.name)
return candidate
Ancestors
@@ -791,14 +811,15 @@ Inherited members
# This folder type also has 'folder:PermissionSet' on some server versions, but requesting it sometimes causes
# 'ErrorAccessDenied', as reported by some users. Ignore it entirely for root folders - it's usefulness is
# deemed minimal at best.
- effective_rights = EffectiveRightsField(field_uri='folder:EffectiveRights', is_read_only=True,
- supported_from=EXCHANGE_2007_SP1)
+ effective_rights = EffectiveRightsField(
+ field_uri="folder:EffectiveRights", is_read_only=True, supported_from=EXCHANGE_2007_SP1
+ )
- __slots__ = '_account', '_subfolders'
+ __slots__ = "_account", "_subfolders"
# A special folder that acts as the top of a folder hierarchy. Finds and caches subfolders at arbitrary depth.
def __init__(self, **kwargs):
- self._account = kwargs.pop('account', None) # A pointer back to the account holding the folder hierarchy
+ self._account = kwargs.pop("account", None) # A pointer back to the account holding the folder hierarchy
super().__init__(**kwargs)
self._subfolders = None # See self._folders_map()
@@ -817,13 +838,13 @@ Inherited members
@classmethod
def register(cls, *args, **kwargs):
if cls is not RootOfHierarchy:
- raise TypeError('For folder roots, custom fields must be registered on the RootOfHierarchy class')
+ raise TypeError("For folder roots, custom fields must be registered on the RootOfHierarchy class")
return super().register(*args, **kwargs)
@classmethod
def deregister(cls, *args, **kwargs):
if cls is not RootOfHierarchy:
- raise TypeError('For folder roots, custom fields must be registered on the RootOfHierarchy class')
+ raise TypeError("For folder roots, custom fields must be registered on the RootOfHierarchy class")
return super().deregister(*args, **kwargs)
def get_folder(self, folder):
@@ -867,14 +888,13 @@ Inherited members
:param account:
"""
if not cls.DISTINGUISHED_FOLDER_ID:
- raise ValueError(f'Class {cls} must have a DISTINGUISHED_FOLDER_ID value')
+ raise ValueError(f"Class {cls} must have a DISTINGUISHED_FOLDER_ID value")
try:
return cls.resolve(
- account=account,
- folder=cls(account=account, name=cls.DISTINGUISHED_FOLDER_ID, is_distinguished=True)
+ account=account, folder=cls(account=account, name=cls.DISTINGUISHED_FOLDER_ID, is_distinguished=True)
)
except MISSING_FOLDER_ERRORS:
- raise ErrorFolderNotFound(f'Could not find distinguished folder {cls.DISTINGUISHED_FOLDER_ID}')
+ raise ErrorFolderNotFound(f"Could not find distinguished folder {cls.DISTINGUISHED_FOLDER_ID}")
def get_default_folder(self, folder_cls):
"""Return the distinguished folder instance of type folder_cls belonging to this account. If no distinguished
@@ -888,21 +908,21 @@ Inherited members
for f in self._folders_map.values():
# Require exact class, to not match subclasses, e.g. RecipientCache instead of Contacts
if f.__class__ == folder_cls and f.is_distinguished:
- log.debug('Found cached distinguished %s folder', folder_cls)
+ log.debug("Found cached distinguished %s folder", folder_cls)
return f
try:
- log.debug('Requesting distinguished %s folder explicitly', folder_cls)
+ log.debug("Requesting distinguished %s folder explicitly", folder_cls)
return folder_cls.get_distinguished(root=self)
except ErrorAccessDenied:
# Maybe we just don't have GetFolder access? Try FindItems instead
- log.debug('Testing default %s folder with FindItem', folder_cls)
+ log.debug("Testing default %s folder with FindItem", folder_cls)
fld = folder_cls(root=self, name=folder_cls.DISTINGUISHED_FOLDER_ID, is_distinguished=True)
fld.test_access()
return self._folders_map.get(fld.id, fld) # Use cached instance if available
except MISSING_FOLDER_ERRORS:
# The Exchange server does not return a distinguished folder of this type
pass
- raise ErrorFolderNotFound(f'No usable default {folder_cls} folders')
+ raise ErrorFolderNotFound(f"No usable default {folder_cls} folders")
@property
def _folders_map(self):
@@ -933,9 +953,9 @@ Inherited members
if isinstance(f, Exception):
raise f
folders_map[f.id] = f
- for f in SingleFolderQuerySet(account=self.account, folder=self).depth(
- self.DEFAULT_FOLDER_TRAVERSAL_DEPTH
- ).all():
+ for f in (
+ SingleFolderQuerySet(account=self.account, folder=self).depth(self.DEFAULT_FOLDER_TRAVERSAL_DEPTH).all()
+ ):
if isinstance(f, ErrorAccessDenied):
# We may not have FindFolder access, or GetFolder access, either to this folder or at all
continue
@@ -971,9 +991,19 @@ Inherited members
def __repr__(self):
# Let's not create an infinite loop when printing self.root
- return self.__class__.__name__ + \
- repr((self.account, '[self]', self.name, self.total_count, self.unread_count, self.child_folder_count,
- self.folder_class, self.id, self.changekey))
+ return self.__class__.__name__ + repr(
+ (
+ self.account,
+ "[self]",
+ self.name,
+ self.total_count,
+ self.unread_count,
+ self.child_folder_count,
+ self.folder_class,
+ self.id,
+ self.changekey,
+ )
+ )
Ancestors
@@ -1059,14 +1089,13 @@ Static methods
:param account:
"""
if not cls.DISTINGUISHED_FOLDER_ID:
- raise ValueError(f'Class {cls} must have a DISTINGUISHED_FOLDER_ID value')
+ raise ValueError(f"Class {cls} must have a DISTINGUISHED_FOLDER_ID value")
try:
return cls.resolve(
- account=account,
- folder=cls(account=account, name=cls.DISTINGUISHED_FOLDER_ID, is_distinguished=True)
+ account=account, folder=cls(account=account, name=cls.DISTINGUISHED_FOLDER_ID, is_distinguished=True)
)
except MISSING_FOLDER_ERRORS:
- raise ErrorFolderNotFound(f'Could not find distinguished folder {cls.DISTINGUISHED_FOLDER_ID}')
+ raise ErrorFolderNotFound(f"Could not find distinguished folder {cls.DISTINGUISHED_FOLDER_ID}")
@@ -1147,21 +1176,21 @@
diff --git a/docs/exchangelib/index.html b/docs/exchangelib/index.html
index 7613db4b..53a8450a 100644
--- a/docs/exchangelib/index.html
+++ b/docs/exchangelib/index.html
@@ -30,51 +30,109 @@ Package exchangelib
from .attachments import FileAttachment, ItemAttachment
from .autodiscover import discover
from .configuration import Configuration
-from .credentials import DELEGATE, IMPERSONATION, Credentials, OAuth2Credentials, \
- OAuth2AuthorizationCodeCredentials
-from .ewsdatetime import EWSDate, EWSDateTime, EWSTimeZone, UTC, UTC_NOW
+from .credentials import DELEGATE, IMPERSONATION, Credentials, OAuth2AuthorizationCodeCredentials, OAuth2Credentials
+from .ewsdatetime import UTC, UTC_NOW, EWSDate, EWSDateTime, EWSTimeZone
from .extended_properties import ExtendedProperty
-from .folders import Folder, RootOfHierarchy, FolderCollection, SHALLOW, DEEP
-from .items import AcceptItem, TentativelyAcceptItem, DeclineItem, CalendarItem, CancelCalendarItem, Contact, \
- DistributionList, Message, PostItem, Task, ForwardItem, ReplyToItem, ReplyAllToItem
-from .properties import Body, HTMLBody, ItemId, Mailbox, Attendee, Room, RoomList, UID, DLMailbox
-from .protocol import FaultTolerance, FailFast, BaseProtocol, NoVerifyHTTPAdapter, TLSClientAuth
+from .folders import DEEP, SHALLOW, Folder, FolderCollection, RootOfHierarchy
+from .items import (
+ AcceptItem,
+ CalendarItem,
+ CancelCalendarItem,
+ Contact,
+ DeclineItem,
+ DistributionList,
+ ForwardItem,
+ Message,
+ PostItem,
+ ReplyAllToItem,
+ ReplyToItem,
+ Task,
+ TentativelyAcceptItem,
+)
+from .properties import UID, Attendee, Body, DLMailbox, HTMLBody, ItemId, Mailbox, Room, RoomList
+from .protocol import BaseProtocol, FailFast, FaultTolerance, NoVerifyHTTPAdapter, TLSClientAuth
from .restriction import Q
from .settings import OofSettings
-from .transport import BASIC, DIGEST, NTLM, GSSAPI, SSPI, OAUTH2, CBA
+from .transport import BASIC, CBA, DIGEST, GSSAPI, NTLM, OAUTH2, SSPI
from .version import Build, Version
-__version__ = '4.7.1'
+__version__ = "4.7.2"
__all__ = [
- '__version__',
- 'Account', 'Identity',
- 'FileAttachment', 'ItemAttachment',
- 'discover',
- 'Configuration',
- 'DELEGATE', 'IMPERSONATION', 'Credentials', 'OAuth2AuthorizationCodeCredentials', 'OAuth2Credentials',
- 'EWSDate', 'EWSDateTime', 'EWSTimeZone', 'UTC', 'UTC_NOW',
- 'ExtendedProperty',
- 'Folder', 'RootOfHierarchy', 'FolderCollection', 'SHALLOW', 'DEEP',
- 'AcceptItem', 'TentativelyAcceptItem', 'DeclineItem', 'CalendarItem', 'CancelCalendarItem', 'Contact',
- 'DistributionList', 'Message', 'PostItem', 'Task', 'ForwardItem', 'ReplyToItem', 'ReplyAllToItem',
- 'ItemId', 'Mailbox', 'DLMailbox', 'Attendee', 'Room', 'RoomList', 'Body', 'HTMLBody', 'UID',
- 'FailFast', 'FaultTolerance', 'BaseProtocol', 'NoVerifyHTTPAdapter', 'TLSClientAuth',
- 'OofSettings',
- 'Q',
- 'BASIC', 'DIGEST', 'NTLM', 'GSSAPI', 'SSPI', 'OAUTH2', 'CBA',
- 'Build', 'Version',
- 'close_connections',
+ "__version__",
+ "Account",
+ "Identity",
+ "FileAttachment",
+ "ItemAttachment",
+ "discover",
+ "Configuration",
+ "DELEGATE",
+ "IMPERSONATION",
+ "Credentials",
+ "OAuth2AuthorizationCodeCredentials",
+ "OAuth2Credentials",
+ "EWSDate",
+ "EWSDateTime",
+ "EWSTimeZone",
+ "UTC",
+ "UTC_NOW",
+ "ExtendedProperty",
+ "Folder",
+ "RootOfHierarchy",
+ "FolderCollection",
+ "SHALLOW",
+ "DEEP",
+ "AcceptItem",
+ "TentativelyAcceptItem",
+ "DeclineItem",
+ "CalendarItem",
+ "CancelCalendarItem",
+ "Contact",
+ "DistributionList",
+ "Message",
+ "PostItem",
+ "Task",
+ "ForwardItem",
+ "ReplyToItem",
+ "ReplyAllToItem",
+ "ItemId",
+ "Mailbox",
+ "DLMailbox",
+ "Attendee",
+ "Room",
+ "RoomList",
+ "Body",
+ "HTMLBody",
+ "UID",
+ "FailFast",
+ "FaultTolerance",
+ "BaseProtocol",
+ "NoVerifyHTTPAdapter",
+ "TLSClientAuth",
+ "OofSettings",
+ "Q",
+ "BASIC",
+ "DIGEST",
+ "NTLM",
+ "GSSAPI",
+ "SSPI",
+ "OAUTH2",
+ "CBA",
+ "Build",
+ "Version",
+ "close_connections",
]
# Set a default user agent, e.g. "exchangelib/3.1.1 (python-requests/2.22.0)"
import requests.utils
+
BaseProtocol.USERAGENT = f"{__name__}/{__version__} ({requests.utils.default_user_agent()})"
def close_connections():
from .autodiscover import close_connections as close_autodiscover_connections
from .protocol import close_connections as close_protocol_connections
+
close_autodiscover_connections()
close_protocol_connections()
@@ -206,6 +264,7 @@ def close_connections():
from .autodiscover import close_connections as close_autodiscover_connections
from .protocol import close_connections as close_protocol_connections
+
close_autodiscover_connections()
close_protocol_connections()
@@ -220,9 +279,7 @@ def discover(email, credentials=None, auth_type=None, retry_policy=None):
- ad_response, protocol = Autodiscovery(
- email=email, credentials=credentials
- ).discover()
+ ad_response, protocol = Autodiscovery(email=email, credentials=credentials).discover()
protocol.config.auth_typ = auth_type
protocol.config.retry_policy = retry_policy
return ad_response, protocol
@@ -251,7 +308,7 @@ class AcceptItem(BaseMeetingReplyItem):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/acceptitem"""
- ELEMENT_NAME = 'AcceptItem'
+ ELEMENT_NAME = "AcceptItem"
class Account:
"""Models an Exchange server user account."""
- def __init__(self, primary_smtp_address, fullname=None, access_type=None, autodiscover=False, credentials=None,
- config=None, locale=None, default_timezone=None):
+ def __init__(
+ self,
+ primary_smtp_address,
+ fullname=None,
+ access_type=None,
+ autodiscover=False,
+ credentials=None,
+ config=None,
+ locale=None,
+ default_timezone=None,
+ ):
"""
:param primary_smtp_address: The primary email address associated with the account on the Exchange server
@@ -329,37 +395,37 @@ Inherited members
assume values to be in the provided timezone. Defaults to the timezone of the host.
:return:
"""
- if '@' not in primary_smtp_address:
+ if "@" not in primary_smtp_address:
raise ValueError(f"primary_smtp_address {primary_smtp_address!r} is not an email address")
self.fullname = fullname
# Assume delegate access if individual credentials are provided. Else, assume service user with impersonation
self.access_type = access_type or (DELEGATE if credentials else IMPERSONATION)
if self.access_type not in ACCESS_TYPES:
- raise InvalidEnumValue('access_type', self.access_type, ACCESS_TYPES)
+ raise InvalidEnumValue("access_type", self.access_type, ACCESS_TYPES)
try:
# get_locale() might not be able to determine the locale
self.locale = locale or stdlib_locale.getlocale()[0] or None
except ValueError as e:
# getlocale() may throw ValueError if it fails to parse the system locale
- log.warning('Failed to get locale (%s)', e)
+ log.warning("Failed to get locale (%s)", e)
self.locale = None
if not isinstance(self.locale, (type(None), str)):
- raise InvalidTypeError('locale', self.locale, str)
+ raise InvalidTypeError("locale", self.locale, str)
if default_timezone:
try:
self.default_timezone = EWSTimeZone.from_timezone(default_timezone)
except TypeError:
- raise InvalidTypeError('default_timezone', default_timezone, EWSTimeZone)
+ raise InvalidTypeError("default_timezone", default_timezone, EWSTimeZone)
else:
try:
self.default_timezone = EWSTimeZone.localzone()
except (ValueError, UnknownTimeZone) as e:
# There is no translation from local timezone name to Windows timezone name, or e failed to find the
# local timezone.
- log.warning('%s. Fallback to UTC', e.args[0])
+ log.warning("%s. Fallback to UTC", e.args[0])
self.default_timezone = UTC
if not isinstance(config, (Configuration, type(None))):
- raise InvalidTypeError('config', config, Configuration)
+ raise InvalidTypeError("config", config, Configuration)
if autodiscover:
if config:
auth_type, retry_policy, version = config.auth_type, config.retry_policy, config.version
@@ -379,7 +445,7 @@ Inherited members
primary_smtp_address = self.ad_response.autodiscover_smtp_address
else:
if not config:
- raise AttributeError('non-autodiscover requires a config')
+ raise AttributeError("non-autodiscover requires a config")
self.ad_response = None
self.protocol = Protocol(config=config)
@@ -393,7 +459,7 @@ Inherited members
# server version up-front but delegate account requests to an older backend server. Create a new instance to
# avoid changing the protocol version.
self.version = self.protocol.version.copy()
- log.debug('Added account: %s', self)
+ log.debug("Added account: %s", self)
@property
def primary_smtp_address(self):
@@ -601,7 +667,7 @@ Inherited members
# We accept generators, so it's not always convenient for caller to know up-front if 'ids' is empty. Allow
# empty 'ids' and return early.
return
- kwargs['items'] = items
+ kwargs["items"] = items
yield from service_cls(account=self, chunk_size=chunk_size).call(**kwargs)
def export(self, items, chunk_size=None):
@@ -612,9 +678,7 @@ Inherited members
:return: A list of strings, the exported representation of the object
"""
- return list(
- self._consume_item_service(service_cls=ExportItems, items=items, chunk_size=chunk_size, kwargs={})
- )
+ return list(self._consume_item_service(service_cls=ExportItems, items=items, chunk_size=chunk_size, kwargs={}))
def upload(self, data, chunk_size=None):
"""Upload objects retrieved from an export to the given folders.
@@ -636,12 +700,11 @@ Inherited members
-> [("idA", "changekey"), ("idB", "changekey"), ("idC", "changekey")]
"""
items = ((f, (None, False, d) if isinstance(d, str) else d) for f, d in data)
- return list(
- self._consume_item_service(service_cls=UploadItems, items=items, chunk_size=chunk_size, kwargs={})
- )
+ return list(self._consume_item_service(service_cls=UploadItems, items=items, chunk_size=chunk_size, kwargs={}))
- def bulk_create(self, folder, items, message_disposition=SAVE_ONLY, send_meeting_invitations=SEND_TO_NONE,
- chunk_size=None):
+ def bulk_create(
+ self, folder, items, message_disposition=SAVE_ONLY, send_meeting_invitations=SEND_TO_NONE, chunk_size=None
+ ):
"""Create new items in 'folder'.
:param folder: the folder to create the items in
@@ -658,23 +721,36 @@ Inherited members
"""
if isinstance(items, QuerySet):
# bulk_create() on a queryset does not make sense because it returns items that have already been created
- raise ValueError('Cannot bulk create items from a QuerySet')
+ raise ValueError("Cannot bulk create items from a QuerySet")
log.debug(
- 'Adding items for %s (folder %s, message_disposition: %s, send_meeting_invitations: %s)',
+ "Adding items for %s (folder %s, message_disposition: %s, send_meeting_invitations: %s)",
self,
folder,
message_disposition,
send_meeting_invitations,
)
- return list(self._consume_item_service(service_cls=CreateItem, items=items, chunk_size=chunk_size, kwargs=dict(
- folder=folder,
- message_disposition=message_disposition,
- send_meeting_invitations=send_meeting_invitations,
- )))
+ return list(
+ self._consume_item_service(
+ service_cls=CreateItem,
+ items=items,
+ chunk_size=chunk_size,
+ kwargs=dict(
+ folder=folder,
+ message_disposition=message_disposition,
+ send_meeting_invitations=send_meeting_invitations,
+ ),
+ )
+ )
- def bulk_update(self, items, conflict_resolution=AUTO_RESOLVE, message_disposition=SAVE_ONLY,
- send_meeting_invitations_or_cancellations=SEND_TO_NONE, suppress_read_receipts=True,
- chunk_size=None):
+ def bulk_update(
+ self,
+ items,
+ conflict_resolution=AUTO_RESOLVE,
+ message_disposition=SAVE_ONLY,
+ send_meeting_invitations_or_cancellations=SEND_TO_NONE,
+ suppress_read_receipts=True,
+ chunk_size=None,
+ ):
"""Bulk update existing items.
:param items: a list of (Item, fieldnames) tuples, where 'Item' is an Item object, and 'fieldnames' is a list
@@ -694,23 +770,37 @@ Inherited members
# fact, it could be dangerous if the queryset contains an '.only()'. This would wipe out certain fields
# entirely.
if isinstance(items, QuerySet):
- raise ValueError('Cannot bulk update on a queryset')
+ raise ValueError("Cannot bulk update on a queryset")
log.debug(
- 'Updating items for %s (conflict_resolution %s, message_disposition: %s, send_meeting_invitations: %s)',
+ "Updating items for %s (conflict_resolution %s, message_disposition: %s, send_meeting_invitations: %s)",
self,
conflict_resolution,
message_disposition,
send_meeting_invitations_or_cancellations,
)
- return list(self._consume_item_service(service_cls=UpdateItem, items=items, chunk_size=chunk_size, kwargs=dict(
- conflict_resolution=conflict_resolution,
- message_disposition=message_disposition,
- send_meeting_invitations_or_cancellations=send_meeting_invitations_or_cancellations,
- suppress_read_receipts=suppress_read_receipts,
- )))
+ return list(
+ self._consume_item_service(
+ service_cls=UpdateItem,
+ items=items,
+ chunk_size=chunk_size,
+ kwargs=dict(
+ conflict_resolution=conflict_resolution,
+ message_disposition=message_disposition,
+ send_meeting_invitations_or_cancellations=send_meeting_invitations_or_cancellations,
+ suppress_read_receipts=suppress_read_receipts,
+ ),
+ )
+ )
- def bulk_delete(self, ids, delete_type=HARD_DELETE, send_meeting_cancellations=SEND_TO_NONE,
- affected_task_occurrences=ALL_OCCURRENCES, suppress_read_receipts=True, chunk_size=None):
+ def bulk_delete(
+ self,
+ ids,
+ delete_type=HARD_DELETE,
+ send_meeting_cancellations=SEND_TO_NONE,
+ affected_task_occurrences=ALL_OCCURRENCES,
+ suppress_read_receipts=True,
+ chunk_size=None,
+ ):
"""Bulk delete items.
:param ids: an iterable of either (id, changekey) tuples or Item objects.
@@ -726,19 +816,24 @@ Inherited members
:return: a list of either True or exception instances, in the same order as the input
"""
log.debug(
- 'Deleting items for %s (delete_type: %s, send_meeting_invitations: %s, affected_task_occurrences: %s)',
+ "Deleting items for %s (delete_type: %s, send_meeting_invitations: %s, affected_task_occurrences: %s)",
self,
delete_type,
send_meeting_cancellations,
affected_task_occurrences,
)
return list(
- self._consume_item_service(service_cls=DeleteItem, items=ids, chunk_size=chunk_size, kwargs=dict(
- delete_type=delete_type,
- send_meeting_cancellations=send_meeting_cancellations,
- affected_task_occurrences=affected_task_occurrences,
- suppress_read_receipts=suppress_read_receipts,
- ))
+ self._consume_item_service(
+ service_cls=DeleteItem,
+ items=ids,
+ chunk_size=chunk_size,
+ kwargs=dict(
+ delete_type=delete_type,
+ send_meeting_cancellations=send_meeting_cancellations,
+ affected_task_occurrences=affected_task_occurrences,
+ suppress_read_receipts=suppress_read_receipts,
+ ),
+ )
)
def bulk_send(self, ids, save_copy=True, copy_to_folder=None, chunk_size=None):
@@ -756,9 +851,14 @@ Inherited members
if save_copy and not copy_to_folder:
copy_to_folder = self.sent # 'Sent' is default EWS behaviour
return list(
- self._consume_item_service(service_cls=SendItem, items=ids, chunk_size=chunk_size, kwargs=dict(
- saved_item_folder=copy_to_folder,
- ))
+ self._consume_item_service(
+ service_cls=SendItem,
+ items=ids,
+ chunk_size=chunk_size,
+ kwargs=dict(
+ saved_item_folder=copy_to_folder,
+ ),
+ )
)
def bulk_copy(self, ids, to_folder, chunk_size=None):
@@ -770,9 +870,16 @@ Inherited members
:return: Status for each send operation, in the same order as the input
"""
- return list(self._consume_item_service(service_cls=CopyItem, items=ids, chunk_size=chunk_size, kwargs=dict(
- to_folder=to_folder,
- )))
+ return list(
+ self._consume_item_service(
+ service_cls=CopyItem,
+ items=ids,
+ chunk_size=chunk_size,
+ kwargs=dict(
+ to_folder=to_folder,
+ ),
+ )
+ )
def bulk_move(self, ids, to_folder, chunk_size=None):
"""Move items to another folder.
@@ -784,9 +891,16 @@ Inherited members
:return: The new IDs of the moved items, in the same order as the input. If 'to_folder' is a public folder or a
folder in a different mailbox, an empty list is returned.
"""
- return list(self._consume_item_service(service_cls=MoveItem, items=ids, chunk_size=chunk_size, kwargs=dict(
- to_folder=to_folder,
- )))
+ return list(
+ self._consume_item_service(
+ service_cls=MoveItem,
+ items=ids,
+ chunk_size=chunk_size,
+ kwargs=dict(
+ to_folder=to_folder,
+ ),
+ )
+ )
def bulk_archive(self, ids, to_folder, chunk_size=None):
"""Archive items to a folder in the archive mailbox. An archive mailbox must be enabled in order for this
@@ -798,9 +912,15 @@ Inherited members
:return: A list containing True or an exception instance in stable order of the requested items
"""
- return list(self._consume_item_service(service_cls=ArchiveItem, items=ids, chunk_size=chunk_size, kwargs=dict(
- to_folder=to_folder,
- ))
+ return list(
+ self._consume_item_service(
+ service_cls=ArchiveItem,
+ items=ids,
+ chunk_size=chunk_size,
+ kwargs=dict(
+ to_folder=to_folder,
+ ),
+ )
)
def bulk_mark_as_junk(self, ids, is_junk, move_item, chunk_size=None):
@@ -814,10 +934,17 @@ Inherited members
:return: A list containing the new IDs of the moved items, if items were moved, or True, or an exception
instance, in stable order of the requested items.
"""
- return list(self._consume_item_service(service_cls=MarkAsJunk, items=ids, chunk_size=chunk_size, kwargs=dict(
- is_junk=is_junk,
- move_item=move_item,
- )))
+ return list(
+ self._consume_item_service(
+ service_cls=MarkAsJunk,
+ items=ids,
+ chunk_size=chunk_size,
+ kwargs=dict(
+ is_junk=is_junk,
+ move_item=move_item,
+ ),
+ )
+ )
def fetch(self, ids, folder=None, only_fields=None, chunk_size=None):
"""Fetch items by ID.
@@ -842,13 +969,19 @@ Inherited members
for field in only_fields:
validation_folder.validate_item_field(field=field, version=self.version)
# Remove ItemId and ChangeKey. We get them unconditionally
- additional_fields = {f for f in validation_folder.normalize_fields(fields=only_fields)
- if not f.field.is_attribute}
+ additional_fields = {
+ f for f in validation_folder.normalize_fields(fields=only_fields) if not f.field.is_attribute
+ }
# Always use IdOnly here, because AllProperties doesn't actually get *all* properties
- yield from self._consume_item_service(service_cls=GetItem, items=ids, chunk_size=chunk_size, kwargs=dict(
+ yield from self._consume_item_service(
+ service_cls=GetItem,
+ items=ids,
+ chunk_size=chunk_size,
+ kwargs=dict(
additional_fields=additional_fields,
shape=ID_ONLY,
- ))
+ ),
+ )
def fetch_personas(self, ids):
"""Fetch personas by ID.
@@ -872,7 +1005,7 @@ Inherited members
return GetMailTips(protocol=self.protocol).get(
sending_as=SendingAs(email_address=self.primary_smtp_address),
recipients=[Mailbox(email_address=self.primary_smtp_address)],
- mail_tips_requested='All',
+ mail_tips_requested="All",
)
@property
@@ -882,7 +1015,7 @@ Inherited members
def __str__(self):
if self.fullname:
- return f'{self.primary_smtp_address} ({self.fullname})'
+ return f"{self.primary_smtp_address} ({self.fullname})"
return self.primary_smtp_address
@@ -2004,8 +2150,9 @@ Methods
Expand source code
-def bulk_create(self, folder, items, message_disposition=SAVE_ONLY, send_meeting_invitations=SEND_TO_NONE,
- chunk_size=None):
+def bulk_create(
+ self, folder, items, message_disposition=SAVE_ONLY, send_meeting_invitations=SEND_TO_NONE, chunk_size=None
+):
"""Create new items in 'folder'.
:param folder: the folder to create the items in
@@ -2022,19 +2169,26 @@ Methods
"""
if isinstance(items, QuerySet):
# bulk_create() on a queryset does not make sense because it returns items that have already been created
- raise ValueError('Cannot bulk create items from a QuerySet')
+ raise ValueError("Cannot bulk create items from a QuerySet")
log.debug(
- 'Adding items for %s (folder %s, message_disposition: %s, send_meeting_invitations: %s)',
+ "Adding items for %s (folder %s, message_disposition: %s, send_meeting_invitations: %s)",
self,
folder,
message_disposition,
send_meeting_invitations,
)
- return list(self._consume_item_service(service_cls=CreateItem, items=items, chunk_size=chunk_size, kwargs=dict(
- folder=folder,
- message_disposition=message_disposition,
- send_meeting_invitations=send_meeting_invitations,
- )))
+ return list(
+ self._consume_item_service(
+ service_cls=CreateItem,
+ items=items,
+ chunk_size=chunk_size,
+ kwargs=dict(
+ folder=folder,
+ message_disposition=message_disposition,
+ send_meeting_invitations=send_meeting_invitations,
+ ),
+ )
+ )
@@ -2056,8 +2210,15 @@ Methods
Expand source code
-def bulk_delete(self, ids, delete_type=HARD_DELETE, send_meeting_cancellations=SEND_TO_NONE,
- affected_task_occurrences=ALL_OCCURRENCES, suppress_read_receipts=True, chunk_size=None):
+def bulk_delete(
+ self,
+ ids,
+ delete_type=HARD_DELETE,
+ send_meeting_cancellations=SEND_TO_NONE,
+ affected_task_occurrences=ALL_OCCURRENCES,
+ suppress_read_receipts=True,
+ chunk_size=None,
+):
"""Bulk delete items.
:param ids: an iterable of either (id, changekey) tuples or Item objects.
@@ -2073,19 +2234,24 @@ Methods
:return: a list of either True or exception instances, in the same order as the input
"""
log.debug(
- 'Deleting items for %s (delete_type: %s, send_meeting_invitations: %s, affected_task_occurrences: %s)',
+ "Deleting items for %s (delete_type: %s, send_meeting_invitations: %s, affected_task_occurrences: %s)",
self,
delete_type,
send_meeting_cancellations,
affected_task_occurrences,
)
return list(
- self._consume_item_service(service_cls=DeleteItem, items=ids, chunk_size=chunk_size, kwargs=dict(
- delete_type=delete_type,
- send_meeting_cancellations=send_meeting_cancellations,
- affected_task_occurrences=affected_task_occurrences,
- suppress_read_receipts=suppress_read_receipts,
- ))
+ self._consume_item_service(
+ service_cls=DeleteItem,
+ items=ids,
+ chunk_size=chunk_size,
+ kwargs=dict(
+ delete_type=delete_type,
+ send_meeting_cancellations=send_meeting_cancellations,
+ affected_task_occurrences=affected_task_occurrences,
+ suppress_read_receipts=suppress_read_receipts,
+ ),
+ )
)
@@ -2115,10 +2281,17 @@ Methods
:return: A list containing the new IDs of the moved items, if items were moved, or True, or an exception
instance, in stable order of the requested items.
"""
- return list(self._consume_item_service(service_cls=MarkAsJunk, items=ids, chunk_size=chunk_size, kwargs=dict(
- is_junk=is_junk,
- move_item=move_item,
- )))
+ return list(
+ self._consume_item_service(
+ service_cls=MarkAsJunk,
+ items=ids,
+ chunk_size=chunk_size,
+ kwargs=dict(
+ is_junk=is_junk,
+ move_item=move_item,
+ ),
+ )
+ )
@@ -2145,9 +2318,16 @@ Methods
:return: The new IDs of the moved items, in the same order as the input. If 'to_folder' is a public folder or a
folder in a different mailbox, an empty list is returned.
"""
- return list(self._consume_item_service(service_cls=MoveItem, items=ids, chunk_size=chunk_size, kwargs=dict(
- to_folder=to_folder,
- )))
+ return list(
+ self._consume_item_service(
+ service_cls=MoveItem,
+ items=ids,
+ chunk_size=chunk_size,
+ kwargs=dict(
+ to_folder=to_folder,
+ ),
+ )
+ )
@@ -2179,9 +2359,14 @@ Methods
if save_copy and not copy_to_folder:
copy_to_folder = self.sent # 'Sent' is default EWS behaviour
return list(
- self._consume_item_service(service_cls=SendItem, items=ids, chunk_size=chunk_size, kwargs=dict(
- saved_item_folder=copy_to_folder,
- ))
+ self._consume_item_service(
+ service_cls=SendItem,
+ items=ids,
+ chunk_size=chunk_size,
+ kwargs=dict(
+ saved_item_folder=copy_to_folder,
+ ),
+ )
)
@@ -2205,9 +2390,15 @@ def bulk_update(self, items, conflict_resolution=AUTO_RESOLVE, message_disposition=SAVE_ONLY,
- send_meeting_invitations_or_cancellations=SEND_TO_NONE, suppress_read_receipts=True,
- chunk_size=None):
+def bulk_update(
+ self,
+ items,
+ conflict_resolution=AUTO_RESOLVE,
+ message_disposition=SAVE_ONLY,
+ send_meeting_invitations_or_cancellations=SEND_TO_NONE,
+ suppress_read_receipts=True,
+ chunk_size=None,
+):
"""Bulk update existing items.
:param items: a list of (Item, fieldnames) tuples, where 'Item' is an Item object, and 'fieldnames' is a list
@@ -2227,20 +2418,27 @@ Methods
# fact, it could be dangerous if the queryset contains an '.only()'. This would wipe out certain fields
# entirely.
if isinstance(items, QuerySet):
- raise ValueError('Cannot bulk update on a queryset')
+ raise ValueError("Cannot bulk update on a queryset")
log.debug(
- 'Updating items for %s (conflict_resolution %s, message_disposition: %s, send_meeting_invitations: %s)',
+ "Updating items for %s (conflict_resolution %s, message_disposition: %s, send_meeting_invitations: %s)",
self,
conflict_resolution,
message_disposition,
send_meeting_invitations_or_cancellations,
)
- return list(self._consume_item_service(service_cls=UpdateItem, items=items, chunk_size=chunk_size, kwargs=dict(
- conflict_resolution=conflict_resolution,
- message_disposition=message_disposition,
- send_meeting_invitations_or_cancellations=send_meeting_invitations_or_cancellations,
- suppress_read_receipts=suppress_read_receipts,
- )))
+ return list(
+ self._consume_item_service(
+ service_cls=UpdateItem,
+ items=items,
+ chunk_size=chunk_size,
+ kwargs=dict(
+ conflict_resolution=conflict_resolution,
+ message_disposition=message_disposition,
+ send_meeting_invitations_or_cancellations=send_meeting_invitations_or_cancellations,
+ suppress_read_receipts=suppress_read_receipts,
+ ),
+ )
+ )
@@ -2263,9 +2461,7 @@ Methods
:return: A list of strings, the exported representation of the object
"""
- return list(
- self._consume_item_service(service_cls=ExportItems, items=items, chunk_size=chunk_size, kwargs={})
- )
+ return list(self._consume_item_service(service_cls=ExportItems, items=items, chunk_size=chunk_size, kwargs={}))
@@ -2305,13 +2501,19 @@ Methods
for field in only_fields:
validation_folder.validate_item_field(field=field, version=self.version)
# Remove ItemId and ChangeKey. We get them unconditionally
- additional_fields = {f for f in validation_folder.normalize_fields(fields=only_fields)
- if not f.field.is_attribute}
+ additional_fields = {
+ f for f in validation_folder.normalize_fields(fields=only_fields) if not f.field.is_attribute
+ }
# Always use IdOnly here, because AllProperties doesn't actually get *all* properties
- yield from self._consume_item_service(service_cls=GetItem, items=ids, chunk_size=chunk_size, kwargs=dict(
+ yield from self._consume_item_service(
+ service_cls=GetItem,
+ items=ids,
+ chunk_size=chunk_size,
+ kwargs=dict(
additional_fields=additional_fields,
shape=ID_ONLY,
- ))
+ ),
+ )
@@ -2384,9 +2586,7 @@ Methods
-> [("idA", "changekey"), ("idB", "changekey"), ("idC", "changekey")]
"""
items = ((f, (None, False, d) if isinstance(d, str) else d) for f, d in data)
- return list(
- self._consume_item_service(service_cls=UploadItems, items=items, chunk_size=chunk_size, kwargs={})
- )
+ return list(self._consume_item_service(service_cls=UploadItems, items=items, chunk_size=chunk_size, kwargs={}))
@@ -2404,13 +2604,14 @@ class Attendee(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/attendee"""
- ELEMENT_NAME = 'Attendee'
- RESPONSE_TYPES = {'Unknown', 'Organizer', 'Tentative', 'Accept', 'Decline', 'NoResponseReceived'}
+ ELEMENT_NAME = "Attendee"
+ RESPONSE_TYPES = {"Unknown", "Organizer", "Tentative", "Accept", "Decline", "NoResponseReceived"}
mailbox = MailboxField(is_required=True)
- response_type = ChoiceField(field_uri='ResponseType', choices={Choice(c) for c in RESPONSE_TYPES},
- default='Unknown')
- last_response_time = DateTimeField(field_uri='LastResponseTime')
+ response_type = ChoiceField(
+ field_uri="ResponseType", choices={Choice(c) for c in RESPONSE_TYPES}, default="Unknown"
+ )
+ last_response_time = DateTimeField(field_uri="LastResponseTime")
def __hash__(self):
return hash(self.mailbox)
@@ -2542,7 +2743,7 @@ def close(self):
- log.debug('Server %s: Closing sessions', self.server)
+ log.debug("Server %s: Closing sessions", self.server)
while True:
try:
session = self._session_pool.get(block=False)
@@ -3022,27 +3238,27 @@ Methods
def create_oauth2_session(self):
has_token = False
- scope = ['https://outlook.office365.com/.default']
+ scope = ["https://outlook.office365.com/.default"]
session_params = {}
token_params = {}
if isinstance(self.credentials, OAuth2AuthorizationCodeCredentials):
# Ask for a refresh token
- scope.append('offline_access')
+ scope.append("offline_access")
# We don't know (or need) the Microsoft tenant ID. Use
# common/ to let Microsoft select the appropriate tenant
# for the provided authorization code or refresh token.
#
# Suppress looks-like-password warning from Bandit.
- token_url = 'https://login.microsoftonline.com/common/oauth2/v2.0/token' # nosec
+ token_url = "https://login.microsoftonline.com/common/oauth2/v2.0/token" # nosec
client_params = {}
has_token = self.credentials.access_token is not None
if has_token:
- session_params['token'] = self.credentials.access_token
+ session_params["token"] = self.credentials.access_token
elif self.credentials.authorization_code is not None:
- token_params['code'] = self.credentials.authorization_code
+ token_params["code"] = self.credentials.authorization_code
self.credentials.authorization_code = None
if self.credentials.client_id is not None and self.credentials.client_secret is not None:
@@ -3053,25 +3269,32 @@ Methods
# covers cases where the caller doesn't have access to
# the client secret but is working with a service that
# can provide it refreshed tokens on a limited basis).
- session_params.update({
- 'auto_refresh_kwargs': {
- 'client_id': self.credentials.client_id,
- 'client_secret': self.credentials.client_secret,
- },
- 'auto_refresh_url': token_url,
- 'token_updater': self.credentials.on_token_auto_refreshed,
- })
+ session_params.update(
+ {
+ "auto_refresh_kwargs": {
+ "client_id": self.credentials.client_id,
+ "client_secret": self.credentials.client_secret,
+ },
+ "auto_refresh_url": token_url,
+ "token_updater": self.credentials.on_token_auto_refreshed,
+ }
+ )
client = WebApplicationClient(self.credentials.client_id, **client_params)
else:
- token_url = f'https://login.microsoftonline.com/{self.credentials.tenant_id}/oauth2/v2.0/token'
+ token_url = f"https://login.microsoftonline.com/{self.credentials.tenant_id}/oauth2/v2.0/token"
client = BackendApplicationClient(client_id=self.credentials.client_id)
session = self.raw_session(self.service_endpoint, oauth2_client=client, oauth2_session_params=session_params)
if not has_token:
# Fetch the token explicitly -- it doesn't occur implicitly
- token = session.fetch_token(token_url=token_url, client_id=self.credentials.client_id,
- client_secret=self.credentials.client_secret, scope=scope,
- timeout=self.TIMEOUT, **token_params)
+ token = session.fetch_token(
+ token_url=token_url,
+ client_id=self.credentials.client_id,
+ client_secret=self.credentials.client_secret,
+ scope=scope,
+ timeout=self.TIMEOUT,
+ **token_params,
+ )
# Allow the credentials object to update its copy of the new
# token, and give the application an opportunity to cache it
self.credentials.on_token_auto_refreshed(token)
@@ -3092,7 +3315,7 @@ Methods
def create_session(self):
if self.credentials is None:
if self.auth_type in CREDENTIALS_REQUIRED:
- raise ValueError(f'Auth type {self.auth_type!r} requires credentials')
+ raise ValueError(f"Auth type {self.auth_type!r} requires credentials")
session = self.raw_session(self.service_endpoint)
session.auth = get_auth_instance(auth_type=self.auth_type)
else:
@@ -3107,18 +3330,18 @@ Methods
session.credentials_sig = self.credentials.sig()
else:
if self.auth_type == NTLM and self.credentials.type == self.credentials.EMAIL:
- username = '\\' + self.credentials.username
+ username = "\\" + self.credentials.username
else:
username = self.credentials.username
session = self.raw_session(self.service_endpoint)
- session.auth = get_auth_instance(auth_type=self.auth_type, username=username,
- password=self.credentials.password)
+ session.auth = get_auth_instance(
+ auth_type=self.auth_type, username=username, password=self.credentials.password
+ )
# Add some extra info
- session.session_id = sum(map(ord, str(os.urandom(100)))) # Used for debugging messages in services
+ session.session_id = random.randint(10000, 99999) # Used for debugging messages in services
session.usage_count = 0
- session.protocol = self
- log.debug('Server %s: Created session %s', self.server, session.session_id)
+ log.debug("Server %s: Created session %s", self.server, session.session_id)
return session
@@ -3139,13 +3362,17 @@ Methods
# Take a single session from the pool and discard it. We need to protect this with a lock while we are changing
# the pool size variable, to avoid race conditions. We must keep at least one session in the pool.
if self._session_pool_size <= 1:
- raise SessionPoolMinSizeReached('Session pool size cannot be decreased further')
+ raise SessionPoolMinSizeReached("Session pool size cannot be decreased further")
with self._session_pool_lock:
if self._session_pool_size <= 1:
- log.debug('Session pool size was decreased in another thread')
+ log.debug("Session pool size was decreased in another thread")
return
- log.warning('Server %s: Decreasing session pool size from %s to %s', self.server, self._session_pool_size,
- self._session_pool_size - 1)
+ log.warning(
+ "Server %s: Decreasing session pool size from %s to %s",
+ self.server,
+ self._session_pool_size,
+ self._session_pool_size - 1,
+ )
session = self.get_session()
self.close_session(session)
self._session_pool_size -= 1
@@ -3162,7 +3389,7 @@ Methods
def get_auth_type(self):
# Autodetect authentication type. We also set version hint here.
- name = str(self.credentials) if self.credentials and str(self.credentials) else 'DUMMY'
+ name = str(self.credentials) if self.credentials and str(self.credentials) else "DUMMY"
auth_type, api_version_hint = get_service_authtype(
service_endpoint=self.service_endpoint, retry_policy=self.retry_policy, api_versions=API_VERSIONS, name=name
)
@@ -3185,7 +3412,7 @@ Methods
_timeout = 60 # Rate-limit messages about session starvation
try:
session = self._session_pool.get(block=False)
- log.debug('Server %s: Got session immediately', self.server)
+ log.debug("Server %s: Got session immediately", self.server)
except Empty:
try:
self.increase_poolsize()
@@ -3193,13 +3420,13 @@ Methods
pass
while True:
try:
- log.debug('Server %s: Waiting for session', self.server)
+ log.debug("Server %s: Waiting for session", self.server)
session = self._session_pool.get(timeout=_timeout)
break
except Empty:
# This is normal when we have many worker threads starving for available sessions
- log.debug('Server %s: No sessions available for %s seconds', self.server, _timeout)
- log.debug('Server %s: Got session %s', self.server, session.session_id)
+ log.debug("Server %s: No sessions available for %s seconds", self.server, _timeout)
+ log.debug("Server %s: Got session %s", self.server, session.session_id)
session.usage_count += 1
return session
@@ -3218,13 +3445,17 @@ Methods
# Create a single session and insert it into the pool. We need to protect this with a lock while we are changing
# the pool size variable, to avoid race conditions. We must not exceed the pool size limit.
if self._session_pool_size >= self._session_pool_maxsize:
- raise SessionPoolMaxSizeReached('Session pool size cannot be increased further')
+ raise SessionPoolMaxSizeReached("Session pool size cannot be increased further")
with self._session_pool_lock:
if self._session_pool_size >= self._session_pool_maxsize:
- log.debug('Session pool size was increased in another thread')
+ log.debug("Session pool size was increased in another thread")
return
- log.debug('Server %s: Increasing session pool size from %s to %s', self.server, self._session_pool_size,
- self._session_pool_size + 1)
+ log.debug(
+ "Server %s: Increasing session pool size from %s to %s",
+ self.server,
+ self._session_pool_size,
+ self._session_pool_size + 1,
+ )
self._session_pool.put(self.create_session(), block=False)
self._session_pool_size += 1
@@ -3264,9 +3495,9 @@ def release_session(self, session):
# This should never fail, as we don't have more sessions than the queue contains
- log.debug('Server %s: Releasing session %s', self.server, session.session_id)
+ log.debug("Server %s: Releasing session %s", self.server, session.session_id)
if self.MAX_SESSION_USAGE_COUNT and session.usage_count >= self.MAX_SESSION_USAGE_COUNT:
- log.debug('Server %s: session %s usage exceeded limit. Discarding', self.server, session.session_id)
+ log.debug("Server %s: session %s usage exceeded limit. Discarding", self.server, session.session_id)
session = self.renew_session(session)
self._session_pool.put(session, block=False)
@@ -3282,7 +3513,7 @@ def renew_session(self, session):
# The session is useless. Close it completely and place a fresh session in the pool
- log.debug('Server %s: Renewing session %s', self.server, session.session_id)
+ log.debug("Server %s: Renewing session %s", self.server, session.session_id)
self.close_session(session)
return self.create_session()
@@ -3298,7 +3529,7 @@ def retire_session(self, session):
# The session is useless. Close it completely and place a fresh session in the pool
- log.debug('Server %s: Retiring session %s', self.server, session.session_id)
+ log.debug("Server %s: Retiring session %s", self.server, session.session_id)
self.close_session(session)
self.release_session(self.create_session())
@@ -3322,7 +3553,7 @@ @classmethod
def from_xml(cls, elem):
xml_elems_map = {
- 'major_version': 'MajorVersion',
- 'minor_version': 'MinorVersion',
- 'major_build': 'MajorBuildNumber',
- 'minor_build': 'MinorBuildNumber',
+ "major_version": "MajorVersion",
+ "minor_version": "MinorVersion",
+ "major_build": "MajorBuildNumber",
+ "minor_build": "MinorBuildNumber",
}
kwargs = {}
for k, xml_elem in xml_elems_map.items():
@@ -3618,11 +3850,11 @@ Methods
def api_version(self):
if EXCHANGE_2013_SP1 <= self < EXCHANGE_2016:
- return 'Exchange2013_SP1'
+ return "Exchange2013_SP1"
try:
return self.API_VERSION_MAP[self.major_version][self.minor_version]
except KeyError:
- raise ValueError(f'API version for build {self} is unknown')
+ raise ValueError(f"API version for build {self} is unknown")
@@ -3658,66 +3890,75 @@ Methods
class CalendarItem(Item, AcceptDeclineMixIn):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/calendaritem"""
- ELEMENT_NAME = 'CalendarItem'
-
- uid = TextField(field_uri='calendar:UID', is_required_after_save=True, is_searchable=False)
- recurrence_id = DateTimeField(field_uri='calendar:RecurrenceId', is_read_only=True)
- start = DateOrDateTimeField(field_uri='calendar:Start', is_required=True)
- end = DateOrDateTimeField(field_uri='calendar:End', is_required=True)
- original_start = DateTimeField(field_uri='calendar:OriginalStart', is_read_only=True)
- is_all_day = BooleanField(field_uri='calendar:IsAllDayEvent', is_required=True, default=False)
- legacy_free_busy_status = FreeBusyStatusField(field_uri='calendar:LegacyFreeBusyStatus', is_required=True,
- default='Busy')
- location = TextField(field_uri='calendar:Location')
- when = TextField(field_uri='calendar:When')
- is_meeting = BooleanField(field_uri='calendar:IsMeeting', is_read_only=True)
- is_cancelled = BooleanField(field_uri='calendar:IsCancelled', is_read_only=True)
- is_recurring = BooleanField(field_uri='calendar:IsRecurring', is_read_only=True)
- meeting_request_was_sent = BooleanField(field_uri='calendar:MeetingRequestWasSent', is_read_only=True)
- is_response_requested = BooleanField(field_uri='calendar:IsResponseRequested', default=None,
- is_required_after_save=True, is_searchable=False)
- type = ChoiceField(field_uri='calendar:CalendarItemType', choices={Choice(c) for c in CALENDAR_ITEM_CHOICES},
- is_read_only=True)
- my_response_type = ChoiceField(field_uri='calendar:MyResponseType', choices={
- Choice(c) for c in Attendee.RESPONSE_TYPES
- }, is_read_only=True)
- organizer = MailboxField(field_uri='calendar:Organizer', is_read_only=True)
- required_attendees = AttendeesField(field_uri='calendar:RequiredAttendees', is_searchable=False)
- optional_attendees = AttendeesField(field_uri='calendar:OptionalAttendees', is_searchable=False)
- resources = AttendeesField(field_uri='calendar:Resources', is_searchable=False)
- conflicting_meeting_count = IntegerField(field_uri='calendar:ConflictingMeetingCount', is_read_only=True)
- adjacent_meeting_count = IntegerField(field_uri='calendar:AdjacentMeetingCount', is_read_only=True)
- conflicting_meetings = EWSElementListField(field_uri='calendar:ConflictingMeetings', value_cls='CalendarItem',
- namespace=Item.NAMESPACE, is_read_only=True)
- adjacent_meetings = EWSElementListField(field_uri='calendar:AdjacentMeetings', value_cls='CalendarItem',
- namespace=Item.NAMESPACE, is_read_only=True)
- duration = CharField(field_uri='calendar:Duration', is_read_only=True)
- appointment_reply_time = DateTimeField(field_uri='calendar:AppointmentReplyTime', is_read_only=True)
- appointment_sequence_number = IntegerField(field_uri='calendar:AppointmentSequenceNumber', is_read_only=True)
- appointment_state = AppointmentStateField(field_uri='calendar:AppointmentState', is_read_only=True)
- recurrence = RecurrenceField(field_uri='calendar:Recurrence', is_searchable=False)
- first_occurrence = OccurrenceField(field_uri='calendar:FirstOccurrence', value_cls=FirstOccurrence,
- is_read_only=True)
- last_occurrence = OccurrenceField(field_uri='calendar:LastOccurrence', value_cls=LastOccurrence,
- is_read_only=True)
- modified_occurrences = OccurrenceListField(field_uri='calendar:ModifiedOccurrences', value_cls=Occurrence,
- is_read_only=True)
- deleted_occurrences = OccurrenceListField(field_uri='calendar:DeletedOccurrences', value_cls=DeletedOccurrence,
- is_read_only=True)
- _meeting_timezone = TimeZoneField(field_uri='calendar:MeetingTimeZone', deprecated_from=EXCHANGE_2010,
- is_searchable=False)
- _start_timezone = TimeZoneField(field_uri='calendar:StartTimeZone', supported_from=EXCHANGE_2010,
- is_searchable=False)
- _end_timezone = TimeZoneField(field_uri='calendar:EndTimeZone', supported_from=EXCHANGE_2010,
- is_searchable=False)
- conference_type = EnumAsIntField(field_uri='calendar:ConferenceType', enum=CONFERENCE_TYPES, min=0,
- default=None, is_required_after_save=True)
- allow_new_time_proposal = BooleanField(field_uri='calendar:AllowNewTimeProposal', default=None,
- is_required_after_save=True, is_searchable=False)
- is_online_meeting = BooleanField(field_uri='calendar:IsOnlineMeeting', default=None,
- is_read_only=True)
- meeting_workspace_url = URIField(field_uri='calendar:MeetingWorkspaceUrl')
- net_show_url = URIField(field_uri='calendar:NetShowUrl')
+ ELEMENT_NAME = "CalendarItem"
+
+ uid = TextField(field_uri="calendar:UID", is_required_after_save=True, is_searchable=False)
+ recurrence_id = DateTimeField(field_uri="calendar:RecurrenceId", is_read_only=True)
+ start = DateOrDateTimeField(field_uri="calendar:Start", is_required=True)
+ end = DateOrDateTimeField(field_uri="calendar:End", is_required=True)
+ original_start = DateTimeField(field_uri="calendar:OriginalStart", is_read_only=True)
+ is_all_day = BooleanField(field_uri="calendar:IsAllDayEvent", is_required=True, default=False)
+ legacy_free_busy_status = FreeBusyStatusField(
+ field_uri="calendar:LegacyFreeBusyStatus", is_required=True, default="Busy"
+ )
+ location = TextField(field_uri="calendar:Location")
+ when = TextField(field_uri="calendar:When")
+ is_meeting = BooleanField(field_uri="calendar:IsMeeting", is_read_only=True)
+ is_cancelled = BooleanField(field_uri="calendar:IsCancelled", is_read_only=True)
+ is_recurring = BooleanField(field_uri="calendar:IsRecurring", is_read_only=True)
+ meeting_request_was_sent = BooleanField(field_uri="calendar:MeetingRequestWasSent", is_read_only=True)
+ is_response_requested = BooleanField(
+ field_uri="calendar:IsResponseRequested", default=None, is_required_after_save=True, is_searchable=False
+ )
+ type = ChoiceField(
+ field_uri="calendar:CalendarItemType", choices={Choice(c) for c in CALENDAR_ITEM_CHOICES}, is_read_only=True
+ )
+ my_response_type = ChoiceField(
+ field_uri="calendar:MyResponseType", choices={Choice(c) for c in Attendee.RESPONSE_TYPES}, is_read_only=True
+ )
+ organizer = MailboxField(field_uri="calendar:Organizer", is_read_only=True)
+ required_attendees = AttendeesField(field_uri="calendar:RequiredAttendees", is_searchable=False)
+ optional_attendees = AttendeesField(field_uri="calendar:OptionalAttendees", is_searchable=False)
+ resources = AttendeesField(field_uri="calendar:Resources", is_searchable=False)
+ conflicting_meeting_count = IntegerField(field_uri="calendar:ConflictingMeetingCount", is_read_only=True)
+ adjacent_meeting_count = IntegerField(field_uri="calendar:AdjacentMeetingCount", is_read_only=True)
+ conflicting_meetings = EWSElementListField(
+ field_uri="calendar:ConflictingMeetings", value_cls="CalendarItem", namespace=Item.NAMESPACE, is_read_only=True
+ )
+ adjacent_meetings = EWSElementListField(
+ field_uri="calendar:AdjacentMeetings", value_cls="CalendarItem", namespace=Item.NAMESPACE, is_read_only=True
+ )
+ duration = CharField(field_uri="calendar:Duration", is_read_only=True)
+ appointment_reply_time = DateTimeField(field_uri="calendar:AppointmentReplyTime", is_read_only=True)
+ appointment_sequence_number = IntegerField(field_uri="calendar:AppointmentSequenceNumber", is_read_only=True)
+ appointment_state = AppointmentStateField(field_uri="calendar:AppointmentState", is_read_only=True)
+ recurrence = RecurrenceField(field_uri="calendar:Recurrence", is_searchable=False)
+ first_occurrence = OccurrenceField(
+ field_uri="calendar:FirstOccurrence", value_cls=FirstOccurrence, is_read_only=True
+ )
+ last_occurrence = OccurrenceField(field_uri="calendar:LastOccurrence", value_cls=LastOccurrence, is_read_only=True)
+ modified_occurrences = OccurrenceListField(
+ field_uri="calendar:ModifiedOccurrences", value_cls=Occurrence, is_read_only=True
+ )
+ deleted_occurrences = OccurrenceListField(
+ field_uri="calendar:DeletedOccurrences", value_cls=DeletedOccurrence, is_read_only=True
+ )
+ _meeting_timezone = TimeZoneField(
+ field_uri="calendar:MeetingTimeZone", deprecated_from=EXCHANGE_2010, is_searchable=False
+ )
+ _start_timezone = TimeZoneField(
+ field_uri="calendar:StartTimeZone", supported_from=EXCHANGE_2010, is_searchable=False
+ )
+ _end_timezone = TimeZoneField(field_uri="calendar:EndTimeZone", supported_from=EXCHANGE_2010, is_searchable=False)
+ conference_type = EnumAsIntField(
+ field_uri="calendar:ConferenceType", enum=CONFERENCE_TYPES, min=0, default=None, is_required_after_save=True
+ )
+ allow_new_time_proposal = BooleanField(
+ field_uri="calendar:AllowNewTimeProposal", default=None, is_required_after_save=True, is_searchable=False
+ )
+ is_online_meeting = BooleanField(field_uri="calendar:IsOnlineMeeting", default=None, is_read_only=True)
+ meeting_workspace_url = URIField(field_uri="calendar:MeetingWorkspaceUrl")
+ net_show_url = URIField(field_uri="calendar:NetShowUrl")
def occurrence(self, index):
"""Get an occurrence of a recurring master by index. No query is sent to the server to actually fetch the item.
@@ -3788,9 +4029,7 @@ Methods
def cancel(self, **kwargs):
return CancelCalendarItem(
- account=self.account,
- reference_item_id=ReferenceItemId(id=self.id, changekey=self.changekey),
- **kwargs
+ account=self.account, reference_item_id=ReferenceItemId(id=self.id, changekey=self.changekey), **kwargs
).send()
def _update_fieldnames(self):
@@ -3798,8 +4037,8 @@ Methods
if self.type == OCCURRENCE:
# Some CalendarItem fields cannot be updated when the item is an occurrence. The values are empty when we
# receive them so would have been updated because they are set to None.
- update_fields.remove('recurrence')
- update_fields.remove('uid')
+ update_fields.remove("recurrence")
+ update_fields.remove("uid")
return update_fields
@classmethod
@@ -3809,15 +4048,15 @@ Methods
# applicable.
if not item.is_all_day:
return item
- for field_name in ('start', 'end'):
+ for field_name in ("start", "end"):
val = getattr(item, field_name)
if val is None:
continue
# Return just the date part of the value. Subtract 1 day from the date if this is the end field. This is
# the inverse of what we do in .to_xml(). Convert to the local timezone before getting the date.
- if field_name == 'end':
+ if field_name == "end":
val -= datetime.timedelta(days=1)
- tz = getattr(item, f'_{field_name}_timezone')
+ tz = getattr(item, f"_{field_name}_timezone")
setattr(item, field_name, val.astimezone(tz).date())
return item
@@ -3825,11 +4064,11 @@ Methods
meeting_tz_field, start_tz_field, end_tz_field = CalendarItem.timezone_fields()
if self.account.version.build < EXCHANGE_2010:
return meeting_tz_field
- if field_name == 'start':
+ if field_name == "start":
return start_tz_field
- if field_name == 'end':
+ if field_name == "end":
return end_tz_field
- raise ValueError('Unsupported field_name')
+ raise ValueError("Unsupported field_name")
def date_to_datetime(self, field_name):
# EWS always expects a datetime. If we have a date value, then convert it to datetime in the local
@@ -3838,7 +4077,7 @@ Methods
value = getattr(self, field_name)
tz = getattr(self, self.tz_field_for_field_name(field_name).name)
value = EWSDateTime.combine(value, datetime.time(0, 0)).replace(tzinfo=tz)
- if field_name == 'end':
+ if field_name == "end":
value += datetime.timedelta(days=1)
return value
@@ -3852,7 +4091,7 @@ Methods
elem = super().to_xml(version=version)
if not self.is_all_day:
return elem
- for field_name in ('start', 'end'):
+ for field_name in ("start", "end"):
value = getattr(self, field_name)
if value is None:
continue
@@ -3903,15 +4142,15 @@ Static methods
# applicable.
if not item.is_all_day:
return item
- for field_name in ('start', 'end'):
+ for field_name in ("start", "end"):
val = getattr(item, field_name)
if val is None:
continue
# Return just the date part of the value. Subtract 1 day from the date if this is the end field. This is
# the inverse of what we do in .to_xml(). Convert to the local timezone before getting the date.
- if field_name == 'end':
+ if field_name == "end":
val -= datetime.timedelta(days=1)
- tz = getattr(item, f'_{field_name}_timezone')
+ tz = getattr(item, f"_{field_name}_timezone")
setattr(item, field_name, val.astimezone(tz).date())
return item
@@ -4099,9 +4338,7 @@ Methods
def cancel(self, **kwargs):
return CancelCalendarItem(
- account=self.account,
- reference_item_id=ReferenceItemId(id=self.id, changekey=self.changekey),
- **kwargs
+ account=self.account, reference_item_id=ReferenceItemId(id=self.id, changekey=self.changekey), **kwargs
).send()
@@ -4174,7 +4411,7 @@ Methods
value = getattr(self, field_name)
tz = getattr(self, self.tz_field_for_field_name(field_name).name)
value = EWSDateTime.combine(value, datetime.time(0, 0)).replace(tzinfo=tz)
- if field_name == 'end':
+ if field_name == "end":
value += datetime.timedelta(days=1)
return value
@@ -4255,7 +4492,7 @@ class CancelCalendarItem(BaseReplyItem):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/cancelcalendaritem"""
- ELEMENT_NAME = 'CancelCalendarItem'
- author_idx = BaseReplyItem.FIELDS.index_by_name('author')
- FIELDS = BaseReplyItem.FIELDS[:author_idx] + BaseReplyItem.FIELDS[author_idx + 1:]
+ ELEMENT_NAME = "CancelCalendarItem"
+ author_idx = BaseReplyItem.FIELDS.index_by_name("author")
+ FIELDS = BaseReplyItem.FIELDS[:author_idx] + BaseReplyItem.FIELDS[author_idx + 1 :]
class Contact(Item):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/contact"""
- ELEMENT_NAME = 'Contact'
-
- file_as = TextField(field_uri='contacts:FileAs')
- file_as_mapping = ChoiceField(field_uri='contacts:FileAsMapping', choices={
- Choice('None'), Choice('LastCommaFirst'), Choice('FirstSpaceLast'), Choice('Company'),
- Choice('LastCommaFirstCompany'), Choice('CompanyLastFirst'), Choice('LastFirst'),
- Choice('LastFirstCompany'), Choice('CompanyLastCommaFirst'), Choice('LastFirstSuffix'),
- Choice('LastSpaceFirstCompany'), Choice('CompanyLastSpaceFirst'), Choice('LastSpaceFirst'),
- Choice('DisplayName'), Choice('FirstName'), Choice('LastFirstMiddleSuffix'), Choice('LastName'),
- Choice('Empty'),
- })
- display_name = TextField(field_uri='contacts:DisplayName', is_required=True)
- given_name = CharField(field_uri='contacts:GivenName')
- initials = TextField(field_uri='contacts:Initials')
- middle_name = CharField(field_uri='contacts:MiddleName')
- nickname = TextField(field_uri='contacts:Nickname')
- complete_name = EWSElementField(field_uri='contacts:CompleteName', value_cls=CompleteName, is_read_only=True)
- company_name = TextField(field_uri='contacts:CompanyName')
- email_addresses = EmailAddressesField(field_uri='contacts:EmailAddress')
- physical_addresses = PhysicalAddressField(field_uri='contacts:PhysicalAddress')
- phone_numbers = PhoneNumberField(field_uri='contacts:PhoneNumber')
- assistant_name = TextField(field_uri='contacts:AssistantName')
- birthday = DateTimeBackedDateField(field_uri='contacts:Birthday', default_time=datetime.time(11, 59))
- business_homepage = URIField(field_uri='contacts:BusinessHomePage')
- children = TextListField(field_uri='contacts:Children')
- companies = TextListField(field_uri='contacts:Companies', is_searchable=False)
- contact_source = ChoiceField(field_uri='contacts:ContactSource', choices={
- Choice('Store'), Choice('ActiveDirectory')
- }, is_read_only=True)
- department = TextField(field_uri='contacts:Department')
- generation = TextField(field_uri='contacts:Generation')
- im_addresses = CharField(field_uri='contacts:ImAddresses', is_read_only=True)
- job_title = TextField(field_uri='contacts:JobTitle')
- manager = TextField(field_uri='contacts:Manager')
- mileage = TextField(field_uri='contacts:Mileage')
- office = TextField(field_uri='contacts:OfficeLocation')
- postal_address_index = ChoiceField(field_uri='contacts:PostalAddressIndex', choices={
- Choice('Business'), Choice('Home'), Choice('Other'), Choice('None')
- }, default='None', is_required_after_save=True)
- profession = TextField(field_uri='contacts:Profession')
- spouse_name = TextField(field_uri='contacts:SpouseName')
- surname = CharField(field_uri='contacts:Surname')
- wedding_anniversary = DateTimeBackedDateField(field_uri='contacts:WeddingAnniversary',
- default_time=datetime.time(11, 59))
- has_picture = BooleanField(field_uri='contacts:HasPicture', supported_from=EXCHANGE_2010, is_read_only=True)
- phonetic_full_name = TextField(field_uri='contacts:PhoneticFullName', supported_from=EXCHANGE_2010_SP2,
- is_read_only=True)
- phonetic_first_name = TextField(field_uri='contacts:PhoneticFirstName', supported_from=EXCHANGE_2010_SP2,
- is_read_only=True)
- phonetic_last_name = TextField(field_uri='contacts:PhoneticLastName', supported_from=EXCHANGE_2010_SP2,
- is_read_only=True)
- email_alias = EmailAddressField(field_uri='contacts:Alias', is_read_only=True,
- supported_from=EXCHANGE_2010_SP2)
+ ELEMENT_NAME = "Contact"
+
+ file_as = TextField(field_uri="contacts:FileAs")
+ file_as_mapping = ChoiceField(
+ field_uri="contacts:FileAsMapping",
+ choices={
+ Choice("None"),
+ Choice("LastCommaFirst"),
+ Choice("FirstSpaceLast"),
+ Choice("Company"),
+ Choice("LastCommaFirstCompany"),
+ Choice("CompanyLastFirst"),
+ Choice("LastFirst"),
+ Choice("LastFirstCompany"),
+ Choice("CompanyLastCommaFirst"),
+ Choice("LastFirstSuffix"),
+ Choice("LastSpaceFirstCompany"),
+ Choice("CompanyLastSpaceFirst"),
+ Choice("LastSpaceFirst"),
+ Choice("DisplayName"),
+ Choice("FirstName"),
+ Choice("LastFirstMiddleSuffix"),
+ Choice("LastName"),
+ Choice("Empty"),
+ },
+ )
+ display_name = TextField(field_uri="contacts:DisplayName", is_required=True)
+ given_name = CharField(field_uri="contacts:GivenName")
+ initials = TextField(field_uri="contacts:Initials")
+ middle_name = CharField(field_uri="contacts:MiddleName")
+ nickname = TextField(field_uri="contacts:Nickname")
+ complete_name = EWSElementField(field_uri="contacts:CompleteName", value_cls=CompleteName, is_read_only=True)
+ company_name = TextField(field_uri="contacts:CompanyName")
+ email_addresses = EmailAddressesField(field_uri="contacts:EmailAddress")
+ physical_addresses = PhysicalAddressField(field_uri="contacts:PhysicalAddress")
+ phone_numbers = PhoneNumberField(field_uri="contacts:PhoneNumber")
+ assistant_name = TextField(field_uri="contacts:AssistantName")
+ birthday = DateTimeBackedDateField(field_uri="contacts:Birthday", default_time=datetime.time(11, 59))
+ business_homepage = URIField(field_uri="contacts:BusinessHomePage")
+ children = TextListField(field_uri="contacts:Children")
+ companies = TextListField(field_uri="contacts:Companies", is_searchable=False)
+ contact_source = ChoiceField(
+ field_uri="contacts:ContactSource", choices={Choice("Store"), Choice("ActiveDirectory")}, is_read_only=True
+ )
+ department = TextField(field_uri="contacts:Department")
+ generation = TextField(field_uri="contacts:Generation")
+ im_addresses = CharField(field_uri="contacts:ImAddresses", is_read_only=True)
+ job_title = TextField(field_uri="contacts:JobTitle")
+ manager = TextField(field_uri="contacts:Manager")
+ mileage = TextField(field_uri="contacts:Mileage")
+ office = TextField(field_uri="contacts:OfficeLocation")
+ postal_address_index = ChoiceField(
+ field_uri="contacts:PostalAddressIndex",
+ choices={Choice("Business"), Choice("Home"), Choice("Other"), Choice("None")},
+ default="None",
+ is_required_after_save=True,
+ )
+ profession = TextField(field_uri="contacts:Profession")
+ spouse_name = TextField(field_uri="contacts:SpouseName")
+ surname = CharField(field_uri="contacts:Surname")
+ wedding_anniversary = DateTimeBackedDateField(
+ field_uri="contacts:WeddingAnniversary", default_time=datetime.time(11, 59)
+ )
+ has_picture = BooleanField(field_uri="contacts:HasPicture", supported_from=EXCHANGE_2010, is_read_only=True)
+ phonetic_full_name = TextField(
+ field_uri="contacts:PhoneticFullName", supported_from=EXCHANGE_2010_SP2, is_read_only=True
+ )
+ phonetic_first_name = TextField(
+ field_uri="contacts:PhoneticFirstName", supported_from=EXCHANGE_2010_SP2, is_read_only=True
+ )
+ phonetic_last_name = TextField(
+ field_uri="contacts:PhoneticLastName", supported_from=EXCHANGE_2010_SP2, is_read_only=True
+ )
+ email_alias = EmailAddressField(field_uri="contacts:Alias", is_read_only=True, supported_from=EXCHANGE_2010_SP2)
# 'notes' is documented in MSDN but apparently unused. Writing to it raises ErrorInvalidPropertyRequest. OWA
# put entries into the 'notes' form field into the 'body' field.
- notes = CharField(field_uri='contacts:Notes', supported_from=EXCHANGE_2010_SP2, is_read_only=True)
+ notes = CharField(field_uri="contacts:Notes", supported_from=EXCHANGE_2010_SP2, is_read_only=True)
# 'photo' is documented in MSDN but apparently unused. Writing to it raises ErrorInvalidPropertyRequest. OWA
# adds photos as FileAttachments on the contact item (with 'is_contact_photo=True'), which automatically flips
# the 'has_picture' field.
- photo = Base64Field(field_uri='contacts:Photo', supported_from=EXCHANGE_2010_SP2, is_read_only=True)
- user_smime_certificate = Base64Field(field_uri='contacts:UserSMIMECertificate', supported_from=EXCHANGE_2010_SP2,
- is_read_only=True)
- ms_exchange_certificate = Base64Field(field_uri='contacts:MSExchangeCertificate', supported_from=EXCHANGE_2010_SP2,
- is_read_only=True)
- directory_id = TextField(field_uri='contacts:DirectoryId', supported_from=EXCHANGE_2010_SP2, is_read_only=True)
- manager_mailbox = MailboxField(field_uri='contacts:ManagerMailbox', supported_from=EXCHANGE_2010_SP2,
- is_read_only=True)
- direct_reports = MailboxListField(field_uri='contacts:DirectReports', supported_from=EXCHANGE_2010_SP2,
- is_read_only=True)
+ photo = Base64Field(field_uri="contacts:Photo", supported_from=EXCHANGE_2010_SP2, is_read_only=True)
+ user_smime_certificate = Base64Field(
+ field_uri="contacts:UserSMIMECertificate", supported_from=EXCHANGE_2010_SP2, is_read_only=True
+ )
+ ms_exchange_certificate = Base64Field(
+ field_uri="contacts:MSExchangeCertificate", supported_from=EXCHANGE_2010_SP2, is_read_only=True
+ )
+ directory_id = TextField(field_uri="contacts:DirectoryId", supported_from=EXCHANGE_2010_SP2, is_read_only=True)
+ manager_mailbox = MailboxField(
+ field_uri="contacts:ManagerMailbox", supported_from=EXCHANGE_2010_SP2, is_read_only=True
+ )
+ direct_reports = MailboxListField(
+ field_uri="contacts:DirectReports", supported_from=EXCHANGE_2010_SP2, is_read_only=True
+ )
class DeclineItem(BaseMeetingReplyItem):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/declineitem"""
- ELEMENT_NAME = 'DeclineItem'
+ ELEMENT_NAME = "DeclineItem"
class DistributionList(Item):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/distributionlist"""
- ELEMENT_NAME = 'DistributionList'
+ ELEMENT_NAME = "DistributionList"
- display_name = CharField(field_uri='contacts:DisplayName', is_required=True)
- file_as = CharField(field_uri='contacts:FileAs', is_read_only=True)
- contact_source = ChoiceField(field_uri='contacts:ContactSource', choices={
- Choice('Store'), Choice('ActiveDirectory')
- }, is_read_only=True)
- members = MemberListField(field_uri='distributionlist:Members')
+ display_name = CharField(field_uri="contacts:DisplayName", is_required=True)
+ file_as = CharField(field_uri="contacts:FileAs", is_read_only=True)
+ contact_source = ChoiceField(
+ field_uri="contacts:ContactSource", choices={Choice("Store"), Choice("ActiveDirectory")}, is_read_only=True
+ )
+ members = MemberListField(field_uri="distributionlist:Members")
class EWSDate(datetime.date):
"""Extends the normal date implementation to satisfy EWS."""
- __slots__ = '_year', '_month', '_day', '_hashcode'
+ __slots__ = "_year", "_month", "_day", "_hashcode"
def ewsformat(self):
"""ISO 8601 format to satisfy xs:date as interpreted by EWS. Example: 2009-01-15."""
@@ -5102,21 +5373,21 @@ Inherited members
@classmethod
def from_date(cls, d):
if type(d) is not datetime.date:
- raise InvalidTypeError('d', d, datetime.date)
+ raise InvalidTypeError("d", d, datetime.date)
return cls(d.year, d.month, d.day)
@classmethod
def from_string(cls, date_string):
# Sometimes, we'll receive a date string with timezone information. Not very useful.
- if date_string.endswith('Z'):
- date_fmt = '%Y-%m-%dZ'
- elif ':' in date_string:
- if '+' in date_string:
- date_fmt = '%Y-%m-%d+%H:%M'
+ if date_string.endswith("Z"):
+ date_fmt = "%Y-%m-%dZ"
+ elif ":" in date_string:
+ if "+" in date_string:
+ date_fmt = "%Y-%m-%d+%H:%M"
else:
- date_fmt = '%Y-%m-%d-%H:%M'
+ date_fmt = "%Y-%m-%d-%H:%M"
else:
- date_fmt = '%Y-%m-%d'
+ date_fmt = "%Y-%m-%d"
d = datetime.datetime.strptime(date_string, date_fmt).date()
if isinstance(d, cls):
return d
@@ -5140,7 +5411,7 @@ Static methods
@classmethod
def from_date(cls, d):
if type(d) is not datetime.date:
- raise InvalidTypeError('d', d, datetime.date)
+ raise InvalidTypeError("d", d, datetime.date)
return cls(d.year, d.month, d.day)
@@ -5156,15 +5427,15 @@ Static methods
@classmethod
def from_string(cls, date_string):
# Sometimes, we'll receive a date string with timezone information. Not very useful.
- if date_string.endswith('Z'):
- date_fmt = '%Y-%m-%dZ'
- elif ':' in date_string:
- if '+' in date_string:
- date_fmt = '%Y-%m-%d+%H:%M'
+ if date_string.endswith("Z"):
+ date_fmt = "%Y-%m-%dZ"
+ elif ":" in date_string:
+ if "+" in date_string:
+ date_fmt = "%Y-%m-%d+%H:%M"
else:
- date_fmt = '%Y-%m-%d-%H:%M'
+ date_fmt = "%Y-%m-%d-%H:%M"
else:
- date_fmt = '%Y-%m-%d'
+ date_fmt = "%Y-%m-%d"
d = datetime.datetime.strptime(date_string, date_fmt).date()
if isinstance(d, cls):
return d
@@ -5220,7 +5491,7 @@ Methods
class EWSDateTime(datetime.datetime):
"""Extends the normal datetime implementation to satisfy EWS."""
- __slots__ = '_year', '_month', '_day', '_hour', '_minute', '_second', '_microsecond', '_tzinfo', '_hashcode'
+ __slots__ = "_year", "_month", "_day", "_hour", "_minute", "_second", "_microsecond", "_tzinfo", "_hashcode"
def __new__(cls, *args, **kwargs):
# pylint: disable=arguments-differ
@@ -5228,16 +5499,16 @@ Methods
if len(args) == 8:
tzinfo = args[7]
else:
- tzinfo = kwargs.get('tzinfo')
+ tzinfo = kwargs.get("tzinfo")
if isinstance(tzinfo, zoneinfo.ZoneInfo):
# Don't allow pytz or dateutil timezones here. They are not safe to use as direct input for datetime()
tzinfo = EWSTimeZone.from_timezone(tzinfo)
if not isinstance(tzinfo, (EWSTimeZone, type(None))):
- raise InvalidTypeError('tzinfo', tzinfo, EWSTimeZone)
+ raise InvalidTypeError("tzinfo", tzinfo, EWSTimeZone)
if len(args) == 8:
args = args[:7] + (tzinfo,)
else:
- kwargs['tzinfo'] = tzinfo
+ kwargs["tzinfo"] = tzinfo
return super().__new__(cls, *args, **kwargs)
def ewsformat(self):
@@ -5246,17 +5517,17 @@ Methods
* 2009-01-15T13:45:56+01:00
"""
if not self.tzinfo:
- raise ValueError(f'{self!r} must be timezone-aware')
- if self.tzinfo.key == 'UTC':
+ raise ValueError(f"{self!r} must be timezone-aware")
+ if self.tzinfo.key == "UTC":
if self.microsecond:
- return self.strftime('%Y-%m-%dT%H:%M:%S.%fZ')
- return self.strftime('%Y-%m-%dT%H:%M:%SZ')
+ return self.strftime("%Y-%m-%dT%H:%M:%S.%fZ")
+ return self.strftime("%Y-%m-%dT%H:%M:%SZ")
return self.isoformat()
@classmethod
def from_datetime(cls, d):
if type(d) is not datetime.datetime:
- raise InvalidTypeError('d', d, datetime.datetime)
+ raise InvalidTypeError("d", d, datetime.datetime)
if d.tzinfo is None:
tz = None
elif isinstance(d.tzinfo, EWSTimeZone):
@@ -5296,12 +5567,12 @@ Methods
@classmethod
def from_string(cls, date_string):
# Parses several common datetime formats and returns timezone-aware EWSDateTime objects
- if date_string.endswith('Z'):
+ if date_string.endswith("Z"):
# UTC datetime
- return super().strptime(date_string, '%Y-%m-%dT%H:%M:%SZ').replace(tzinfo=UTC)
+ return super().strptime(date_string, "%Y-%m-%dT%H:%M:%SZ").replace(tzinfo=UTC)
if len(date_string) == 19:
# This is probably a naive datetime. Don't allow this, but signal caller with an appropriate error
- local_dt = super().strptime(date_string, '%Y-%m-%dT%H:%M:%S')
+ local_dt = super().strptime(date_string, "%Y-%m-%dT%H:%M:%S")
raise NaiveDateTimeNotAllowed(local_dt)
# This is probably a datetime value with timezone information. This comes in the form '+/-HH:MM'.
aware_dt = datetime.datetime.fromisoformat(date_string).astimezone(UTC).replace(tzinfo=UTC)
@@ -5362,7 +5633,7 @@ Static methods
@classmethod
def from_datetime(cls, d):
if type(d) is not datetime.datetime:
- raise InvalidTypeError('d', d, datetime.datetime)
+ raise InvalidTypeError("d", d, datetime.datetime)
if d.tzinfo is None:
tz = None
elif isinstance(d.tzinfo, EWSTimeZone):
@@ -5384,12 +5655,12 @@ Static methods
@classmethod
def from_string(cls, date_string):
# Parses several common datetime formats and returns timezone-aware EWSDateTime objects
- if date_string.endswith('Z'):
+ if date_string.endswith("Z"):
# UTC datetime
- return super().strptime(date_string, '%Y-%m-%dT%H:%M:%SZ').replace(tzinfo=UTC)
+ return super().strptime(date_string, "%Y-%m-%dT%H:%M:%SZ").replace(tzinfo=UTC)
if len(date_string) == 19:
# This is probably a naive datetime. Don't allow this, but signal caller with an appropriate error
- local_dt = super().strptime(date_string, '%Y-%m-%dT%H:%M:%S')
+ local_dt = super().strptime(date_string, "%Y-%m-%dT%H:%M:%S")
raise NaiveDateTimeNotAllowed(local_dt)
# This is probably a datetime value with timezone information. This comes in the form '+/-HH:MM'.
aware_dt = datetime.datetime.fromisoformat(date_string).astimezone(UTC).replace(tzinfo=UTC)
@@ -5523,11 +5794,11 @@ Methods
* 2009-01-15T13:45:56+01:00
"""
if not self.tzinfo:
- raise ValueError(f'{self!r} must be timezone-aware')
- if self.tzinfo.key == 'UTC':
+ raise ValueError(f"{self!r} must be timezone-aware")
+ if self.tzinfo.key == "UTC":
if self.microsecond:
- return self.strftime('%Y-%m-%dT%H:%M:%S.%fZ')
- return self.strftime('%Y-%m-%dT%H:%M:%SZ')
+ return self.strftime("%Y-%m-%dT%H:%M:%S.%fZ")
+ return self.strftime("%Y-%m-%dT%H:%M:%SZ")
return self.isoformat()
@@ -5560,12 +5831,12 @@ Methods
try:
instance.ms_id = cls.IANA_TO_MS_MAP[instance.key][0]
except KeyError:
- raise UnknownTimeZone(f'No Windows timezone name found for timezone {instance.key!r}')
+ raise UnknownTimeZone(f"No Windows timezone name found for timezone {instance.key!r}")
# We don't need the Windows long-format timezone name in long format. It's used in timezone XML elements, but
# EWS happily accepts empty strings. For a full list of timezones supported by the target server, including
# long-format names, see output of services.GetServerTimeZones(account.protocol).call()
- instance.ms_name = ''
+ instance.ms_name = ""
return instance
def __eq__(self, other):
@@ -5583,11 +5854,11 @@ Methods
try:
return cls(cls.MS_TO_IANA_MAP[ms_id])
except KeyError:
- if '/' in ms_id:
+ if "/" in ms_id:
# EWS sometimes returns an ID that has a region/location format, e.g. 'Europe/Copenhagen'. Try the
# string unaltered.
return cls(ms_id)
- raise UnknownTimeZone(f'Windows timezone ID {ms_id!r} is unknown by CLDR')
+ raise UnknownTimeZone(f"Windows timezone ID {ms_id!r} is unknown by CLDR")
@classmethod
def from_pytz(cls, tz):
@@ -5602,8 +5873,8 @@ Methods
def from_dateutil(cls, tz):
# Objects returned by dateutil.tz.tzlocal() and dateutil.tz.gettz() are not supported. They
# don't contain enough information to reliably match them with a CLDR timezone.
- if hasattr(tz, '_filename'):
- key = '/'.join(tz._filename.split('/')[-2:])
+ if hasattr(tz, "_filename"):
+ key = "/".join(tz._filename.split("/")[-2:])
return cls(key)
return cls(tz.tzname(datetime.datetime.now()))
@@ -5615,19 +5886,19 @@ Methods
def from_timezone(cls, tz):
# Support multiple tzinfo implementations. We could use isinstance(), but then we'd have to have pytz
# and dateutil as dependencies for this package.
- tz_module = tz.__class__.__module__.split('.')[0]
+ tz_module = tz.__class__.__module__.split(".")[0]
try:
return {
- cls.__module__.split('.')[0]: lambda z: z,
- 'backports': cls.from_zoneinfo,
- 'datetime': cls.from_datetime,
- 'dateutil': cls.from_dateutil,
- 'pytz': cls.from_pytz,
- 'zoneinfo': cls.from_zoneinfo,
- 'pytz_deprecation_shim': lambda z: cls.from_timezone(z.unwrap_shim())
+ cls.__module__.split(".")[0]: lambda z: z,
+ "backports": cls.from_zoneinfo,
+ "datetime": cls.from_datetime,
+ "dateutil": cls.from_dateutil,
+ "pytz": cls.from_pytz,
+ "zoneinfo": cls.from_zoneinfo,
+ "pytz_deprecation_shim": lambda z: cls.from_timezone(z.unwrap_shim()),
}[tz_module](tz)
except KeyError:
- raise TypeError(f'Unsupported tzinfo type: {tz!r}')
+ raise TypeError(f"Unsupported tzinfo type: {tz!r}")
@classmethod
def localzone(cls):
@@ -5691,8 +5962,8 @@ Static methods
def from_dateutil(cls, tz):
# Objects returned by dateutil.tz.tzlocal() and dateutil.tz.gettz() are not supported. They
# don't contain enough information to reliably match them with a CLDR timezone.
- if hasattr(tz, '_filename'):
- key = '/'.join(tz._filename.split('/')[-2:])
+ if hasattr(tz, "_filename"):
+ key = "/".join(tz._filename.split("/")[-2:])
return cls(key)
return cls(tz.tzname(datetime.datetime.now()))
@@ -5713,11 +5984,11 @@ Static methods
try:
return cls(cls.MS_TO_IANA_MAP[ms_id])
except KeyError:
- if '/' in ms_id:
+ if "/" in ms_id:
# EWS sometimes returns an ID that has a region/location format, e.g. 'Europe/Copenhagen'. Try the
# string unaltered.
return cls(ms_id)
- raise UnknownTimeZone(f'Windows timezone ID {ms_id!r} is unknown by CLDR')
+ raise UnknownTimeZone(f"Windows timezone ID {ms_id!r} is unknown by CLDR")
@@ -5747,19 +6018,19 @@ Static methods
def from_timezone(cls, tz):
# Support multiple tzinfo implementations. We could use isinstance(), but then we'd have to have pytz
# and dateutil as dependencies for this package.
- tz_module = tz.__class__.__module__.split('.')[0]
+ tz_module = tz.__class__.__module__.split(".")[0]
try:
return {
- cls.__module__.split('.')[0]: lambda z: z,
- 'backports': cls.from_zoneinfo,
- 'datetime': cls.from_datetime,
- 'dateutil': cls.from_dateutil,
- 'pytz': cls.from_pytz,
- 'zoneinfo': cls.from_zoneinfo,
- 'pytz_deprecation_shim': lambda z: cls.from_timezone(z.unwrap_shim())
+ cls.__module__.split(".")[0]: lambda z: z,
+ "backports": cls.from_zoneinfo,
+ "datetime": cls.from_datetime,
+ "dateutil": cls.from_dateutil,
+ "pytz": cls.from_pytz,
+ "zoneinfo": cls.from_zoneinfo,
+ "pytz_deprecation_shim": lambda z: cls.from_timezone(z.unwrap_shim()),
}[tz_module](tz)
except KeyError:
- raise TypeError(f'Unsupported tzinfo type: {tz!r}')
+ raise TypeError(f"Unsupported tzinfo type: {tz!r}")
@@ -5830,72 +6101,73 @@ Methods
class ExtendedProperty(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/extendedproperty"""
- ELEMENT_NAME = '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',
+ "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
+ # The following types cannot be used for setting or getting (see docs) and are thus not very useful here:
+ # 'Error'
+ # 'Null'
+ # 'Object'
+ # 'ObjectArray'
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
+ "ApplicationTime",
+ "Binary",
+ "BinaryArray",
+ "Boolean",
+ "CLSID",
+ "CLSIDArray",
+ "Currency",
+ "CurrencyArray",
+ "Double",
+ "DoubleArray",
+ "Float",
+ "FloatArray",
+ "Integer",
+ "IntegerArray",
+ "Long",
+ "LongArray",
+ "Short",
+ "ShortArray",
+ "SystemTime",
+ "SystemTimeArray",
+ "String",
+ "StringArray",
+ }
# 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',
+ "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()}
@@ -5904,15 +6176,15 @@ Methods
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 = ''
+ property_type = ""
- __slots__ = 'value',
+ __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')
+ self.value = kwargs.pop("value")
super().__init__(**kwargs)
@classmethod
@@ -5938,7 +6210,7 @@ Methods
)
if cls.distinguished_property_set_id not in cls.DISTINGUISHED_SETS:
raise InvalidEnumValue(
- 'distinguished_property_set_id', cls.distinguished_property_set_id, cls.DISTINGUISHED_SETS
+ "distinguished_property_set_id", cls.distinguished_property_set_id, cls.DISTINGUISHED_SETS
)
@classmethod
@@ -5949,16 +6221,12 @@ Methods
"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"
- )
+ 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
- ]):
+ 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(
@@ -5988,7 +6256,7 @@ Methods
@classmethod
def _validate_property_type(cls):
if cls.property_type not in cls.PROPERTY_TYPES:
- raise InvalidEnumValue('property_type', cls.property_type, cls.PROPERTY_TYPES)
+ raise InvalidEnumValue("property_type", cls.property_type, cls.PROPERTY_TYPES)
def clean(self, version=None):
self.validate_cls()
@@ -6036,30 +6304,29 @@ Methods
# 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(f'{{{TNS}}}Values')
+ values = elem.find(f"{{{TNS}}}Values")
return [
- xml_text_to_value(value=val, value_type=python_type)
- for val in get_xml_attrs(values, f'{{{TNS}}}Value')
+ xml_text_to_value(value=val, value_type=python_type) for val in get_xml_attrs(values, f"{{{TNS}}}Value")
]
- extended_field_value = xml_text_to_value(value=get_xml_attr(elem, f'{{{TNS}}}Value'), value_type=python_type)
+ extended_field_value = xml_text_to_value(value=get_xml_attr(elem, f"{{{TNS}}}Value"), 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 ""
return extended_field_value
def to_xml(self, version):
if self.is_array_type():
- values = create_element('t:Values')
+ values = create_element("t:Values")
for v in self.value:
- add_xml_child(values, 't:Value', v)
+ add_xml_child(values, "t:Value", v)
return values
- return set_xml_value(create_element('t:Value'), self.value, version=version)
+ return set_xml_value(create_element("t:Value"), self.value, version=version)
@classmethod
def is_array_type(cls):
- return cls.property_type.endswith('Array')
+ return cls.property_type.endswith("Array")
@classmethod
def property_tag_as_int(cls):
@@ -6076,18 +6343,18 @@ Methods
# 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,
+ "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
@@ -6196,17 +6463,16 @@ Static methods
# 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(f'{{{TNS}}}Values')
+ values = elem.find(f"{{{TNS}}}Values")
return [
- xml_text_to_value(value=val, value_type=python_type)
- for val in get_xml_attrs(values, f'{{{TNS}}}Value')
+ xml_text_to_value(value=val, value_type=python_type) for val in get_xml_attrs(values, f"{{{TNS}}}Value")
]
- extended_field_value = xml_text_to_value(value=get_xml_attr(elem, f'{{{TNS}}}Value'), value_type=python_type)
+ extended_field_value = xml_text_to_value(value=get_xml_attr(elem, f"{{{TNS}}}Value"), 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 ""
return extended_field_value
@@ -6221,7 +6487,7 @@ Static methods
@classmethod
def is_array_type(cls):
- return cls.property_type.endswith('Array')
+ return cls.property_type.endswith("Array")
@@ -6295,18 +6561,18 @@ Static methods
# 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,
+ "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]
@@ -6374,11 +6640,11 @@ def to_xml(self, version):
if self.is_array_type():
- values = create_element('t:Values')
+ values = create_element("t:Values")
for v in self.value:
- add_xml_child(values, 't:Value', v)
+ add_xml_child(values, "t:Value", v)
return values
- return set_xml_value(create_element('t:Value'), self.value, version=version)
+ return set_xml_value(create_element("t:Value"), self.value, version=version)
class FileAttachment(Attachment):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/fileattachment"""
- ELEMENT_NAME = 'FileAttachment'
+ ELEMENT_NAME = "FileAttachment"
- is_contact_photo = BooleanField(field_uri='IsContactPhoto')
- _content = Base64Field(field_uri='Content')
+ is_contact_photo = BooleanField(field_uri="IsContactPhoto")
+ _content = Base64Field(field_uri="Content")
- __slots__ = '_fp',
+ __slots__ = ("_fp",)
def __init__(self, **kwargs):
- kwargs['_content'] = kwargs.pop('content', None)
+ kwargs["_content"] = kwargs.pop("content", None)
super().__init__(**kwargs)
self._fp = None
@@ -6614,7 +6884,7 @@ Inherited members
# Create a file-like object for the attachment content. We try hard to reduce memory consumption so we never
# store the full attachment content in-memory.
if not self.parent_item or not self.parent_item.account:
- raise ValueError(f'{self.__class__.__name__} must have an account')
+ raise ValueError(f"{self.__class__.__name__} must have an account")
self._fp = FileAttachmentIO(attachment=self)
@property
@@ -6635,13 +6905,13 @@ Inherited members
def content(self, value):
"""Replace the attachment content."""
if not isinstance(value, bytes):
- raise InvalidTypeError('value', value, bytes)
+ raise InvalidTypeError("value", value, bytes)
self._content = value
@classmethod
def from_xml(cls, elem, account):
kwargs = {f.name: f.from_xml(elem=elem, account=account) for f in cls.FIELDS}
- kwargs['content'] = kwargs.pop('_content')
+ kwargs["content"] = kwargs.pop("_content")
cls._clear(elem)
return cls(**kwargs)
@@ -6652,7 +6922,7 @@ Inherited members
def __getstate__(self):
# The fp does not need to be pickled
state = {k: getattr(self, k) for k in self._slots_keys}
- del state['_fp']
+ del state["_fp"]
return state
def __setstate__(self, state):
@@ -6691,7 +6961,7 @@ Static methods
@classmethod
def from_xml(cls, elem, account):
kwargs = {f.name: f.from_xml(elem=elem, account=account) for f in cls.FIELDS}
- kwargs['content'] = kwargs.pop('_content')
+ kwargs["content"] = kwargs.pop("_content")
cls._clear(elem)
return cls(**kwargs)
@@ -6785,24 +7055,25 @@ Inherited members
class Folder(BaseFolder):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/folder"""
- permission_set = PermissionSetField(field_uri='folder:PermissionSet', supported_from=EXCHANGE_2007_SP1)
- effective_rights = EffectiveRightsField(field_uri='folder:EffectiveRights', is_read_only=True,
- supported_from=EXCHANGE_2007_SP1)
+ permission_set = PermissionSetField(field_uri="folder:PermissionSet", supported_from=EXCHANGE_2007_SP1)
+ effective_rights = EffectiveRightsField(
+ field_uri="folder:EffectiveRights", is_read_only=True, supported_from=EXCHANGE_2007_SP1
+ )
- __slots__ = '_root',
+ __slots__ = ("_root",)
def __init__(self, **kwargs):
- self._root = kwargs.pop('root', None) # This is a pointer to the root of the folder hierarchy
- parent = kwargs.pop('parent', None)
+ self._root = kwargs.pop("root", None) # This is a pointer to the root of the folder hierarchy
+ parent = kwargs.pop("parent", None)
if parent:
if self.root:
if parent.root != self.root:
raise ValueError("'parent.root' must match 'root'")
else:
self.root = parent.root
- if 'parent_folder_id' in kwargs and parent.id != kwargs['parent_folder_id']:
+ if "parent_folder_id" in kwargs and parent.id != kwargs["parent_folder_id"]:
raise ValueError("'parent_folder_id' must match 'parent' ID")
- kwargs['parent_folder_id'] = ParentFolderId(id=parent.id, changekey=parent.changekey)
+ kwargs["parent_folder_id"] = ParentFolderId(id=parent.id, changekey=parent.changekey)
super().__init__(**kwargs)
@property
@@ -6822,13 +7093,13 @@ Inherited members
@classmethod
def register(cls, *args, **kwargs):
if cls is not Folder:
- raise TypeError('For folders, custom fields must be registered on the Folder class')
+ raise TypeError("For folders, custom fields must be registered on the Folder class")
return super().register(*args, **kwargs)
@classmethod
def deregister(cls, *args, **kwargs):
if cls is not Folder:
- raise TypeError('For folders, custom fields must be registered on the Folder class')
+ raise TypeError("For folders, custom fields must be registered on the Folder class")
return super().deregister(*args, **kwargs)
@classmethod
@@ -6840,11 +7111,10 @@ Inherited members
"""
try:
return cls.resolve(
- account=root.account,
- folder=cls(root=root, name=cls.DISTINGUISHED_FOLDER_ID, is_distinguished=True)
+ account=root.account, folder=cls(root=root, name=cls.DISTINGUISHED_FOLDER_ID, is_distinguished=True)
)
except MISSING_FOLDER_ERRORS:
- raise ErrorFolderNotFound(f'Could not find distinguished folder {cls.DISTINGUISHED_FOLDER_ID!r}')
+ raise ErrorFolderNotFound(f"Could not find distinguished folder {cls.DISTINGUISHED_FOLDER_ID!r}")
@property
def parent(self):
@@ -6861,15 +7131,16 @@ Inherited members
self.parent_folder_id = None
else:
if not isinstance(value, BaseFolder):
- raise InvalidTypeError('value', value, BaseFolder)
+ raise InvalidTypeError("value", value, BaseFolder)
self.root = value.root
self.parent_folder_id = ParentFolderId(id=value.id, changekey=value.changekey)
def clean(self, version=None):
from .roots import RootOfHierarchy
+
super().clean(version=version)
if self.root and not isinstance(self.root, RootOfHierarchy):
- raise InvalidTypeError('root', self.root, RootOfHierarchy)
+ raise InvalidTypeError("root", self.root, RootOfHierarchy)
@classmethod
def from_xml_with_root(cls, elem, root):
@@ -6895,20 +7166,20 @@ Inherited members
if folder.name:
try:
# TODO: fld_class.LOCALIZED_NAMES is most definitely neither complete nor authoritative
- folder_cls = root.folder_cls_from_folder_name(folder_name=folder.name,
- locale=root.account.locale)
- log.debug('Folder class %s matches localized folder name %s', folder_cls, folder.name)
+ folder_cls = root.folder_cls_from_folder_name(folder_name=folder.name, locale=root.account.locale)
+ log.debug("Folder class %s matches localized folder name %s", folder_cls, folder.name)
except KeyError:
pass
if folder.folder_class and folder_cls == Folder:
try:
folder_cls = cls.folder_cls_from_container_class(container_class=folder.folder_class)
- log.debug('Folder class %s matches container class %s (%s)', folder_cls, folder.folder_class,
- folder.name)
+ log.debug(
+ "Folder class %s matches container class %s (%s)", folder_cls, folder.folder_class, folder.name
+ )
except KeyError:
pass
if folder_cls == Folder:
- log.debug('Fallback to class Folder (folder_class %s, name %s)', folder.folder_class, folder.name)
+ log.debug("Fallback to class Folder (folder_class %s, name %s)", folder.folder_class, folder.name)
return folder_cls(root=root, **{f.name: getattr(folder, f.name) for f in folder.FIELDS})
Ancestors
@@ -6999,20 +7270,20 @@ Static methods
if folder.name:
try:
# TODO: fld_class.LOCALIZED_NAMES is most definitely neither complete nor authoritative
- folder_cls = root.folder_cls_from_folder_name(folder_name=folder.name,
- locale=root.account.locale)
- log.debug('Folder class %s matches localized folder name %s', folder_cls, folder.name)
+ folder_cls = root.folder_cls_from_folder_name(folder_name=folder.name, locale=root.account.locale)
+ log.debug("Folder class %s matches localized folder name %s", folder_cls, folder.name)
except KeyError:
pass
if folder.folder_class and folder_cls == Folder:
try:
folder_cls = cls.folder_cls_from_container_class(container_class=folder.folder_class)
- log.debug('Folder class %s matches container class %s (%s)', folder_cls, folder.folder_class,
- folder.name)
+ log.debug(
+ "Folder class %s matches container class %s (%s)", folder_cls, folder.folder_class, folder.name
+ )
except KeyError:
pass
if folder_cls == Folder:
- log.debug('Fallback to class Folder (folder_class %s, name %s)', folder.folder_class, folder.name)
+ log.debug("Fallback to class Folder (folder_class %s, name %s)", folder.folder_class, folder.name)
return folder_cls(root=root, **{f.name: getattr(folder, f.name) for f in folder.FIELDS})
@@ -7036,11 +7307,10 @@ def clean(self, version=None):
from .roots import RootOfHierarchy
+
super().clean(version=version)
if self.root and not isinstance(self.root, RootOfHierarchy):
- raise InvalidTypeError('root', self.root, RootOfHierarchy)
+ raise InvalidTypeError("root", self.root, RootOfHierarchy)
@@ -7129,7 +7400,7 @@ @require_account
-def find_folders(self, q=None, shape=ID_ONLY, depth=None, additional_fields=None, page_size=None, max_items=None,
- offset=0):
+def find_folders(
+ self, q=None, shape=ID_ONLY, depth=None, additional_fields=None, page_size=None, max_items=None, offset=0
+):
from ..services import FindFolder
+
# 'depth' controls whether to return direct children or recurse into sub-folders
from .base import BaseFolder, Folder
+
if q is None:
q = Q()
if not self.folders:
- log.debug('Folder list is empty')
+ log.debug("Folder list is empty")
return
if q.is_never():
- log.debug('Query will never return results')
+ log.debug("Query will never return results")
return
if q.is_empty():
restriction = None
@@ -7767,13 +8080,13 @@ Examples
)
yield from FindFolder(account=self.account, page_size=page_size).call(
- folders=self.folders,
- additional_fields=additional_fields,
- restriction=restriction,
- shape=shape,
- depth=depth,
- max_items=max_items,
- offset=offset,
+ folders=self.folders,
+ additional_fields=additional_fields,
+ restriction=restriction,
+ shape=shape,
+ depth=depth,
+ max_items=max_items,
+ offset=offset,
)
@@ -7798,8 +8111,18 @@ def find_items(self, q, shape=ID_ONLY, depth=None, additional_fields=None, order_fields=None,
- calendar_view=None, page_size=None, max_items=None, offset=0):
+def find_items(
+ self,
+ q,
+ shape=ID_ONLY,
+ depth=None,
+ additional_fields=None,
+ order_fields=None,
+ calendar_view=None,
+ page_size=None,
+ max_items=None,
+ offset=0,
+):
"""Private method to call the FindItem service.
:param q: a Q instance containing any restrictions
@@ -7817,21 +8140,21 @@ Examples
:return: a generator for the returned item IDs or items
"""
from ..services import FindItem
+
if not self.folders:
- log.debug('Folder list is empty')
+ log.debug("Folder list is empty")
return
if q.is_never():
- log.debug('Query will never return results')
+ log.debug("Query will never return results")
return
depth, restriction, query_string = self._rinse_args(
- q=q, depth=depth, additional_fields=additional_fields,
- field_validator=self.validate_item_field
+ q=q, depth=depth, additional_fields=additional_fields, field_validator=self.validate_item_field
)
if calendar_view is not None and not isinstance(calendar_view, CalendarView):
- raise InvalidTypeError('calendar_view', calendar_view, CalendarView)
+ raise InvalidTypeError("calendar_view", calendar_view, CalendarView)
log.debug(
- 'Finding %s items in folders %s (shape: %s, depth: %s, additional_fields: %s, restriction: %s)',
+ "Finding %s items in folders %s (shape: %s, depth: %s, additional_fields: %s, restriction: %s)",
self.account,
self.folders,
shape,
@@ -7872,8 +8195,17 @@ Examples
Expand source code
-def find_people(self, q, shape=ID_ONLY, depth=None, additional_fields=None, order_fields=None,
- page_size=None, max_items=None, offset=0):
+def find_people(
+ self,
+ q,
+ shape=ID_ONLY,
+ depth=None,
+ additional_fields=None,
+ order_fields=None,
+ page_size=None,
+ max_items=None,
+ offset=0,
+):
"""Private method to call the FindPeople service.
:param q: a Q instance containing any restrictions
@@ -7889,25 +8221,25 @@ Examples
:return: a generator for the returned personas
"""
from ..services import FindPeople
+
folder = self._get_single_folder()
if q.is_never():
- log.debug('Query will never return results')
+ log.debug("Query will never return results")
return
depth, restriction, query_string = self._rinse_args(
- q=q, depth=depth, additional_fields=additional_fields,
- field_validator=Persona.validate_field
+ q=q, depth=depth, additional_fields=additional_fields, field_validator=Persona.validate_field
)
yield from FindPeople(account=self.account, page_size=page_size).call(
- folder=folder,
- additional_fields=additional_fields,
- restriction=restriction,
- order_fields=order_fields,
- shape=shape,
- query_string=query_string,
- depth=depth,
- max_items=max_items,
- offset=offset,
+ folder=folder,
+ additional_fields=additional_fields,
+ restriction=restriction,
+ order_fields=order_fields,
+ shape=shape,
+ query_string=query_string,
+ depth=depth,
+ max_items=max_items,
+ offset=offset,
)
@@ -7922,7 +8254,8 @@ Examples
def get_folder_fields(self, target_cls, is_complex=None):
return {
- FieldPath(field=f) for f in target_cls.supported_fields(version=self.account.version)
+ FieldPath(field=f)
+ for f in target_cls.supported_fields(version=self.account.version)
if is_complex is None or f.is_complex is is_complex
}
@@ -7938,10 +8271,12 @@ Examples
def get_folders(self, additional_fields=None):
from ..services import GetFolder
+
# Expand folders with their full set of properties
from .base import BaseFolder
+
if not self.folders:
- log.debug('Folder list is empty')
+ log.debug("Folder list is empty")
return
if additional_fields is None:
# Default to all complex properties
@@ -7953,9 +8288,9 @@ Examples
)
yield from GetFolder(account=self.account).call(
- folders=self.folders,
- additional_fields=additional_fields,
- shape=ID_ONLY,
+ folders=self.folders,
+ additional_fields=additional_fields,
+ shape=ID_ONLY,
)
@@ -7997,17 +8332,18 @@ Examples
def resolve(self):
# Looks up the folders or folder IDs in the collection and returns full Folder instances with all fields set.
from .base import BaseFolder
+
resolveable_folders = []
for f in self.folders:
if isinstance(f, BaseFolder) and not f.get_folder_allowed:
- log.debug('GetFolder not allowed on folder %s. Non-complex fields must be fetched with FindFolder', f)
+ log.debug("GetFolder not allowed on folder %s. Non-complex fields must be fetched with FindFolder", f)
yield f
else:
resolveable_folders.append(f)
# Fetch all properties for the remaining folders of folder IDs
additional_fields = self.get_folder_fields(target_cls=self._get_target_cls(), is_complex=None)
yield from self.__class__(account=self.account, folders=resolveable_folders).get_folders(
- additional_fields=additional_fields
+ additional_fields=additional_fields
)
@@ -8035,13 +8371,17 @@ Examples
def subscribe_to_pull(self, event_types=None, watermark=None, timeout=60):
from ..services import SubscribeToPull
+
if not self.folders:
- log.debug('Folder list is empty')
+ log.debug("Folder list is empty")
return None
if event_types is None:
event_types = SubscribeToPull.EVENT_TYPES
return SubscribeToPull(account=self.account).get(
- folders=self.folders, event_types=event_types, watermark=watermark, timeout=timeout,
+ folders=self.folders,
+ event_types=event_types,
+ watermark=watermark,
+ timeout=timeout,
)
@@ -8056,13 +8396,17 @@ Examples
def subscribe_to_push(self, callback_url, event_types=None, watermark=None, status_frequency=1):
from ..services import SubscribeToPush
+
if not self.folders:
- log.debug('Folder list is empty')
+ log.debug("Folder list is empty")
return None
if event_types is None:
event_types = SubscribeToPush.EVENT_TYPES
return SubscribeToPush(account=self.account).get(
- folders=self.folders, event_types=event_types, watermark=watermark, status_frequency=status_frequency,
+ folders=self.folders,
+ event_types=event_types,
+ watermark=watermark,
+ status_frequency=status_frequency,
url=callback_url,
)
@@ -8078,8 +8422,9 @@ Examples
def subscribe_to_streaming(self, event_types=None):
from ..services import SubscribeToStreaming
+
if not self.folders:
- log.debug('Folder list is empty')
+ log.debug("Folder list is empty")
return None
if event_types is None:
event_types = SubscribeToStreaming.EVENT_TYPES
@@ -8097,6 +8442,7 @@ Examples
def sync_hierarchy(self, sync_state=None, only_fields=None):
from ..services import SyncFolderHierarchy
+
folder = self._get_single_folder()
if only_fields is None:
# We didn't restrict list of field paths. Get all fields from the server, including extended properties.
@@ -8143,6 +8489,7 @@ Examples
def sync_items(self, sync_state=None, only_fields=None, ignore=None, max_changes_returned=None, sync_scope=None):
from ..services import SyncFolderItems
+
folder = self._get_single_folder()
if only_fields is None:
# We didn't restrict list of field paths. Get all fields from the server, including extended properties.
@@ -8196,6 +8543,7 @@ Examples
sync methods.
"""
from ..services import Unsubscribe
+
return Unsubscribe(account=self.account).get(subscription_id=subscription_id)
@@ -8292,7 +8640,7 @@ Inherited members
class ForwardItem(BaseReplyItem):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/forwarditem"""
- ELEMENT_NAME = 'ForwardItem'
+ ELEMENT_NAME = "ForwardItem"
Ancestors
@@ -8337,7 +8685,7 @@ Inherited members
MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/body
"""
- body_type = 'HTML'
+ body_type = "HTML"
Ancestors
@@ -8415,30 +8763,34 @@ Inherited members
class ItemAttachment(Attachment):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/itemattachment"""
- ELEMENT_NAME = 'ItemAttachment'
+ ELEMENT_NAME = "ItemAttachment"
- _item = ItemField(field_uri='Item')
+ _item = ItemField(field_uri="Item")
def __init__(self, **kwargs):
- kwargs['_item'] = kwargs.pop('item', None)
+ kwargs["_item"] = kwargs.pop("item", None)
super().__init__(**kwargs)
@property
def item(self):
from .folders import BaseFolder
from .services import GetAttachment
+
if self.attachment_id is None:
return self._item
if self._item is not None:
return self._item
# We have an ID to the data but still haven't called GetAttachment to get the actual data. Do that now.
if not self.parent_item or not self.parent_item.account:
- raise ValueError(f'{self.__class__.__name__} must have an account')
+ raise ValueError(f"{self.__class__.__name__} must have an account")
additional_fields = {
FieldPath(field=f) for f in BaseFolder.allowed_item_fields(version=self.parent_item.account.version)
}
attachment = GetAttachment(account=self.parent_item.account).get(
- items=[self.attachment_id], include_mime_content=True, body_type=None, filter_html_content=None,
+ items=[self.attachment_id],
+ include_mime_content=True,
+ body_type=None,
+ filter_html_content=None,
additional_fields=additional_fields,
)
self._item = attachment.item
@@ -8447,14 +8799,15 @@ Inherited members
@item.setter
def item(self, value):
from .items import Item
+
if not isinstance(value, Item):
- raise InvalidTypeError('value', value, Item)
+ raise InvalidTypeError("value", value, Item)
self._item = value
@classmethod
def from_xml(cls, elem, account):
kwargs = {f.name: f.from_xml(elem=elem, account=account) for f in cls.FIELDS}
- kwargs['item'] = kwargs.pop('_item')
+ kwargs["item"] = kwargs.pop("_item")
cls._clear(elem)
return cls(**kwargs)
@@ -8488,7 +8841,7 @@ Static methods
@classmethod
def from_xml(cls, elem, account):
kwargs = {f.name: f.from_xml(elem=elem, account=account) for f in cls.FIELDS}
- kwargs['item'] = kwargs.pop('_item')
+ kwargs["item"] = kwargs.pop("_item")
cls._clear(elem)
return cls(**kwargs)
@@ -8507,18 +8860,22 @@ Instance variables
def item(self):
from .folders import BaseFolder
from .services import GetAttachment
+
if self.attachment_id is None:
return self._item
if self._item is not None:
return self._item
# We have an ID to the data but still haven't called GetAttachment to get the actual data. Do that now.
if not self.parent_item or not self.parent_item.account:
- raise ValueError(f'{self.__class__.__name__} must have an account')
+ raise ValueError(f"{self.__class__.__name__} must have an account")
additional_fields = {
FieldPath(field=f) for f in BaseFolder.allowed_item_fields(version=self.parent_item.account.version)
}
attachment = GetAttachment(account=self.parent_item.account).get(
- items=[self.attachment_id], include_mime_content=True, body_type=None, filter_html_content=None,
+ items=[self.attachment_id],
+ include_mime_content=True,
+ body_type=None,
+ filter_html_content=None,
additional_fields=additional_fields,
)
self._item = attachment.item
@@ -8556,9 +8913,9 @@ Inherited members
MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/itemid
"""
- ELEMENT_NAME = 'ItemId'
- ID_ATTR = 'Id'
- CHANGEKEY_ATTR = 'ChangeKey'
+ ELEMENT_NAME = "ItemId"
+ ID_ATTR = "Id"
+ CHANGEKEY_ATTR = "ChangeKey"
id = IdField(field_uri=ID_ATTR, is_required=True)
changekey = IdField(field_uri=CHANGEKEY_ATTR, is_required=False)
@@ -8635,20 +8992,26 @@ Inherited members
class Mailbox(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/mailbox"""
- ELEMENT_NAME = 'Mailbox'
- MAILBOX = 'Mailbox'
- ONE_OFF = 'OneOff'
+ ELEMENT_NAME = "Mailbox"
+ MAILBOX = "Mailbox"
+ ONE_OFF = "OneOff"
MAILBOX_TYPE_CHOICES = {
- Choice(MAILBOX), Choice('PublicDL'), Choice('PrivateDL'), Choice('Contact'), Choice('PublicFolder'),
- Choice('Unknown'), Choice(ONE_OFF), Choice('GroupMailbox', supported_from=EXCHANGE_2013)
- }
+ Choice(MAILBOX),
+ Choice("PublicDL"),
+ Choice("PrivateDL"),
+ Choice("Contact"),
+ Choice("PublicFolder"),
+ Choice("Unknown"),
+ Choice(ONE_OFF),
+ Choice("GroupMailbox", supported_from=EXCHANGE_2013),
+ }
- name = TextField(field_uri='Name')
- email_address = EmailAddressField(field_uri='EmailAddress')
+ name = TextField(field_uri="Name")
+ email_address = EmailAddressField(field_uri="EmailAddress")
# RoutingType values are not restricted:
# https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/routingtype-emailaddresstype
- routing_type = TextField(field_uri='RoutingType', default='SMTP')
- mailbox_type = ChoiceField(field_uri='MailboxType', choices=MAILBOX_TYPE_CHOICES, default=MAILBOX)
+ routing_type = TextField(field_uri="RoutingType", default="SMTP")
+ mailbox_type = ChoiceField(field_uri="MailboxType", choices=MAILBOX_TYPE_CHOICES, default=MAILBOX)
item_id = EWSElementField(value_cls=ItemId, is_read_only=True)
def clean(self, version=None):
@@ -8785,37 +9148,52 @@ Inherited members
https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/message-ex15websvcsotherref
"""
- ELEMENT_NAME = 'Message'
-
- sender = MailboxField(field_uri='message:Sender', is_read_only=True, is_read_only_after_send=True)
- to_recipients = MailboxListField(field_uri='message:ToRecipients', is_read_only_after_send=True,
- is_searchable=False)
- cc_recipients = MailboxListField(field_uri='message:CcRecipients', is_read_only_after_send=True,
- is_searchable=False)
- bcc_recipients = MailboxListField(field_uri='message:BccRecipients', is_read_only_after_send=True,
- is_searchable=False)
- is_read_receipt_requested = BooleanField(field_uri='message:IsReadReceiptRequested',
- is_required=True, default=False, is_read_only_after_send=True)
- is_delivery_receipt_requested = BooleanField(field_uri='message:IsDeliveryReceiptRequested', is_required=True,
- default=False, is_read_only_after_send=True)
- conversation_index = Base64Field(field_uri='message:ConversationIndex', is_read_only=True)
- conversation_topic = CharField(field_uri='message:ConversationTopic', is_read_only=True)
+ ELEMENT_NAME = "Message"
+
+ sender = MailboxField(field_uri="message:Sender", is_read_only=True, is_read_only_after_send=True)
+ to_recipients = MailboxListField(
+ field_uri="message:ToRecipients", is_read_only_after_send=True, is_searchable=False
+ )
+ cc_recipients = MailboxListField(
+ field_uri="message:CcRecipients", is_read_only_after_send=True, is_searchable=False
+ )
+ bcc_recipients = MailboxListField(
+ field_uri="message:BccRecipients", is_read_only_after_send=True, is_searchable=False
+ )
+ is_read_receipt_requested = BooleanField(
+ field_uri="message:IsReadReceiptRequested", is_required=True, default=False, is_read_only_after_send=True
+ )
+ is_delivery_receipt_requested = BooleanField(
+ field_uri="message:IsDeliveryReceiptRequested", is_required=True, default=False, is_read_only_after_send=True
+ )
+ conversation_index = Base64Field(field_uri="message:ConversationIndex", is_read_only=True)
+ conversation_topic = CharField(field_uri="message:ConversationTopic", is_read_only=True)
# Rename 'From' to 'author'. We can't use fieldname 'from' since it's a Python keyword.
- author = MailboxField(field_uri='message:From', is_read_only_after_send=True)
- message_id = CharField(field_uri='message:InternetMessageId', is_read_only_after_send=True)
- is_read = BooleanField(field_uri='message:IsRead', is_required=True, default=False)
- is_response_requested = BooleanField(field_uri='message:IsResponseRequested', default=False, is_required=True)
- references = TextField(field_uri='message:References')
- reply_to = MailboxListField(field_uri='message:ReplyTo', is_read_only_after_send=True, is_searchable=False)
- received_by = MailboxField(field_uri='message:ReceivedBy', is_read_only=True)
- received_representing = MailboxField(field_uri='message:ReceivedRepresenting', is_read_only=True)
- reminder_message_data = EWSElementField(field_uri='message:ReminderMessageData', value_cls=ReminderMessageData,
- supported_from=EXCHANGE_2013_SP1, is_read_only=True)
+ author = MailboxField(field_uri="message:From", is_read_only_after_send=True)
+ message_id = CharField(field_uri="message:InternetMessageId", is_read_only_after_send=True)
+ is_read = BooleanField(field_uri="message:IsRead", is_required=True, default=False)
+ is_response_requested = BooleanField(field_uri="message:IsResponseRequested", default=False, is_required=True)
+ references = TextField(field_uri="message:References")
+ reply_to = MailboxListField(field_uri="message:ReplyTo", is_read_only_after_send=True, is_searchable=False)
+ received_by = MailboxField(field_uri="message:ReceivedBy", is_read_only=True)
+ received_representing = MailboxField(field_uri="message:ReceivedRepresenting", is_read_only=True)
+ reminder_message_data = EWSElementField(
+ field_uri="message:ReminderMessageData",
+ value_cls=ReminderMessageData,
+ supported_from=EXCHANGE_2013_SP1,
+ is_read_only=True,
+ )
@require_account
- def send(self, save_copy=True, copy_to_folder=None, conflict_resolution=AUTO_RESOLVE,
- send_meeting_invitations=SEND_TO_NONE):
+ def send(
+ self,
+ save_copy=True,
+ copy_to_folder=None,
+ conflict_resolution=AUTO_RESOLVE,
+ send_meeting_invitations=SEND_TO_NONE,
+ ):
from ..services import SendItem
+
# Only sends a message. The message can either be an existing draft stored in EWS or a new message that does
# not yet exist in EWS.
if copy_to_folder and not save_copy:
@@ -8833,42 +9211,48 @@ Inherited members
if copy_to_folder:
# This would better be done via send_and_save() but lets just support it here
self.folder = copy_to_folder
- return self.send_and_save(conflict_resolution=conflict_resolution,
- send_meeting_invitations=send_meeting_invitations)
+ return self.send_and_save(
+ conflict_resolution=conflict_resolution, send_meeting_invitations=send_meeting_invitations
+ )
if self.account.version.build < EXCHANGE_2013 and self.attachments:
# At least some versions prior to Exchange 2013 can't send attachments immediately. You need to first save,
# then attach, then send. This is done in send_and_save(). send() will delete the item again.
- self.send_and_save(conflict_resolution=conflict_resolution,
- send_meeting_invitations=send_meeting_invitations)
+ self.send_and_save(
+ conflict_resolution=conflict_resolution, send_meeting_invitations=send_meeting_invitations
+ )
return None
self._create(message_disposition=SEND_ONLY, send_meeting_invitations=send_meeting_invitations)
return None
- def send_and_save(self, update_fields=None, conflict_resolution=AUTO_RESOLVE,
- send_meeting_invitations=SEND_TO_NONE):
+ def send_and_save(
+ self, update_fields=None, conflict_resolution=AUTO_RESOLVE, send_meeting_invitations=SEND_TO_NONE
+ ):
# Sends Message and saves a copy in the parent folder. Does not return an ItemId.
if self.id:
self._update(
update_fieldnames=update_fields,
message_disposition=SEND_AND_SAVE_COPY,
conflict_resolution=conflict_resolution,
- send_meeting_invitations=send_meeting_invitations
+ send_meeting_invitations=send_meeting_invitations,
)
else:
if self.account.version.build < EXCHANGE_2013 and self.attachments:
# At least some versions prior to Exchange 2013 can't send-and-save attachments immediately. You need
# to first save, then attach, then send. This is done in save().
- self.save(update_fields=update_fields, conflict_resolution=conflict_resolution,
- send_meeting_invitations=send_meeting_invitations)
- self.send(save_copy=False, conflict_resolution=conflict_resolution,
- send_meeting_invitations=send_meeting_invitations)
- else:
- self._create(
- message_disposition=SEND_AND_SAVE_COPY,
- send_meeting_invitations=send_meeting_invitations
+ self.save(
+ update_fields=update_fields,
+ conflict_resolution=conflict_resolution,
+ send_meeting_invitations=send_meeting_invitations,
+ )
+ self.send(
+ save_copy=False,
+ conflict_resolution=conflict_resolution,
+ send_meeting_invitations=send_meeting_invitations,
)
+ else:
+ self._create(message_disposition=SEND_AND_SAVE_COPY, send_meeting_invitations=send_meeting_invitations)
@require_id
def create_reply(self, subject, body, to_recipients=None, cc_recipients=None, bcc_recipients=None):
@@ -8887,13 +9271,7 @@ Inherited members
)
def reply(self, subject, body, to_recipients=None, cc_recipients=None, bcc_recipients=None):
- self.create_reply(
- subject,
- body,
- to_recipients,
- cc_recipients,
- bcc_recipients
- ).send()
+ self.create_reply(subject, body, to_recipients, cc_recipients, bcc_recipients).send()
@require_id
def create_reply_all(self, subject, body):
@@ -8922,6 +9300,7 @@ Inherited members
:return:
"""
from ..services import MarkAsJunk
+
res = MarkAsJunk(account=self.account).get(
items=[self], is_junk=is_junk, move_item=move_item, expect_result=move_item
)
@@ -9095,6 +9474,7 @@ Methods
:return:
"""
from ..services import MarkAsJunk
+
res = MarkAsJunk(account=self.account).get(
items=[self], is_junk=is_junk, move_item=move_item, expect_result=move_item
)
@@ -9114,13 +9494,7 @@ Methods
Expand source code
def reply(self, subject, body, to_recipients=None, cc_recipients=None, bcc_recipients=None):
- self.create_reply(
- subject,
- body,
- to_recipients,
- cc_recipients,
- bcc_recipients
- ).send()
+ self.create_reply(subject, body, to_recipients, cc_recipients, bcc_recipients).send()
@@ -9146,9 +9520,15 @@ Methods
Expand source code
@require_account
-def send(self, save_copy=True, copy_to_folder=None, conflict_resolution=AUTO_RESOLVE,
- send_meeting_invitations=SEND_TO_NONE):
+def send(
+ self,
+ save_copy=True,
+ copy_to_folder=None,
+ conflict_resolution=AUTO_RESOLVE,
+ send_meeting_invitations=SEND_TO_NONE,
+):
from ..services import SendItem
+
# Only sends a message. The message can either be an existing draft stored in EWS or a new message that does
# not yet exist in EWS.
if copy_to_folder and not save_copy:
@@ -9166,14 +9546,16 @@ Methods
if copy_to_folder:
# This would better be done via send_and_save() but lets just support it here
self.folder = copy_to_folder
- return self.send_and_save(conflict_resolution=conflict_resolution,
- send_meeting_invitations=send_meeting_invitations)
+ return self.send_and_save(
+ conflict_resolution=conflict_resolution, send_meeting_invitations=send_meeting_invitations
+ )
if self.account.version.build < EXCHANGE_2013 and self.attachments:
# At least some versions prior to Exchange 2013 can't send attachments immediately. You need to first save,
# then attach, then send. This is done in send_and_save(). send() will delete the item again.
- self.send_and_save(conflict_resolution=conflict_resolution,
- send_meeting_invitations=send_meeting_invitations)
+ self.send_and_save(
+ conflict_resolution=conflict_resolution, send_meeting_invitations=send_meeting_invitations
+ )
return None
self._create(message_disposition=SEND_ONLY, send_meeting_invitations=send_meeting_invitations)
@@ -9189,29 +9571,33 @@ Methods
Expand source code
-def send_and_save(self, update_fields=None, conflict_resolution=AUTO_RESOLVE,
- send_meeting_invitations=SEND_TO_NONE):
+def send_and_save(
+ self, update_fields=None, conflict_resolution=AUTO_RESOLVE, send_meeting_invitations=SEND_TO_NONE
+):
# Sends Message and saves a copy in the parent folder. Does not return an ItemId.
if self.id:
self._update(
update_fieldnames=update_fields,
message_disposition=SEND_AND_SAVE_COPY,
conflict_resolution=conflict_resolution,
- send_meeting_invitations=send_meeting_invitations
+ send_meeting_invitations=send_meeting_invitations,
)
else:
if self.account.version.build < EXCHANGE_2013 and self.attachments:
# At least some versions prior to Exchange 2013 can't send-and-save attachments immediately. You need
# to first save, then attach, then send. This is done in save().
- self.save(update_fields=update_fields, conflict_resolution=conflict_resolution,
- send_meeting_invitations=send_meeting_invitations)
- self.send(save_copy=False, conflict_resolution=conflict_resolution,
- send_meeting_invitations=send_meeting_invitations)
+ self.save(
+ update_fields=update_fields,
+ conflict_resolution=conflict_resolution,
+ send_meeting_invitations=send_meeting_invitations,
+ )
+ self.send(
+ save_copy=False,
+ conflict_resolution=conflict_resolution,
+ send_meeting_invitations=send_meeting_invitations,
+ )
else:
- self._create(
- message_disposition=SEND_AND_SAVE_COPY,
- send_meeting_invitations=send_meeting_invitations
- )
+ self._create(message_disposition=SEND_AND_SAVE_COPY, send_meeting_invitations=send_meeting_invitations)
@@ -9342,20 +9728,23 @@ Methods
super().__init__(**kwargs)
self.authorization_code = authorization_code
if access_token is not None and not isinstance(access_token, dict):
- raise InvalidTypeError('access_token', access_token, OAuth2Token)
+ raise InvalidTypeError("access_token", access_token, OAuth2Token)
self.access_token = access_token
def __repr__(self):
return self.__class__.__name__ + repr(
- (self.client_id, '[client_secret]', '[authorization_code]', '[access_token]')
+ (self.client_id, "[client_secret]", "[authorization_code]", "[access_token]")
)
def __str__(self):
client_id = self.client_id
- credential = '[access_token]' if self.access_token is not None else \
- ('[authorization_code]' if self.authorization_code is not None else None)
- description = ' '.join(filter(None, [client_id, credential]))
- return description or '[underspecified credentials]'
+ credential = (
+ "[access_token]"
+ if self.access_token is not None
+ else ("[authorization_code]" if self.authorization_code is not None else None)
+ )
+ description = " ".join(filter(None, [client_id, credential]))
+ return description or "[underspecified credentials]"
class OofSettings(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/oofsettings"""
- ELEMENT_NAME = 'OofSettings'
- REQUEST_ELEMENT_NAME = 'UserOofSettings'
+ ELEMENT_NAME = "OofSettings"
+ REQUEST_ELEMENT_NAME = "UserOofSettings"
- ENABLED = 'Enabled'
- SCHEDULED = 'Scheduled'
- DISABLED = 'Disabled'
+ ENABLED = "Enabled"
+ SCHEDULED = "Scheduled"
+ DISABLED = "Disabled"
STATE_CHOICES = (ENABLED, SCHEDULED, DISABLED)
- state = ChoiceField(field_uri='OofState', is_required=True, choices={Choice(c) for c in STATE_CHOICES})
- external_audience = ChoiceField(field_uri='ExternalAudience',
- choices={Choice('None'), Choice('Known'), Choice('All')}, default='All')
- start = DateTimeField(field_uri='StartTime')
- end = DateTimeField(field_uri='EndTime')
- internal_reply = MessageField(field_uri='InternalReply')
- external_reply = MessageField(field_uri='ExternalReply')
+ state = ChoiceField(field_uri="OofState", is_required=True, choices={Choice(c) for c in STATE_CHOICES})
+ external_audience = ChoiceField(
+ field_uri="ExternalAudience", choices={Choice("None"), Choice("Known"), Choice("All")}, default="All"
+ )
+ start = DateTimeField(field_uri="StartTime")
+ end = DateTimeField(field_uri="EndTime")
+ internal_reply = MessageField(field_uri="InternalReply")
+ external_reply = MessageField(field_uri="ExternalReply")
def clean(self, version=None):
super().clean(version=version)
@@ -9575,7 +9965,7 @@ Inherited members
@classmethod
def from_xml(cls, elem, account):
kwargs = {}
- for attr in ('state', 'external_audience', 'internal_reply', 'external_reply'):
+ for attr in ("state", "external_audience", "internal_reply", "external_reply"):
f = cls.get_field_by_fieldname(attr)
kwargs[attr] = f.from_xml(elem=elem, account=account)
kwargs.update(OutOfOffice.duration_to_start_end(elem=elem, account=account))
@@ -9584,24 +9974,24 @@ Inherited members
def to_xml(self, version):
self.clean(version=version)
- elem = create_element(f't:{self.REQUEST_ELEMENT_NAME}')
- for attr in ('state', 'external_audience'):
+ elem = create_element(f"t:{self.REQUEST_ELEMENT_NAME}")
+ for attr in ("state", "external_audience"):
value = getattr(self, attr)
f = self.get_field_by_fieldname(attr)
set_xml_value(elem, f.to_xml(value, version=version))
if self.start or self.end:
- duration = create_element('t:Duration')
+ duration = create_element("t:Duration")
if self.start:
- f = self.get_field_by_fieldname('start')
+ f = self.get_field_by_fieldname("start")
set_xml_value(duration, f.to_xml(self.start, version=version))
if self.end:
- f = self.get_field_by_fieldname('end')
+ f = self.get_field_by_fieldname("end")
set_xml_value(duration, f.to_xml(self.end, version=version))
elem.append(duration)
- for attr in ('internal_reply', 'external_reply'):
+ for attr in ("internal_reply", "external_reply"):
value = getattr(self, attr)
if value is None:
- value = '' # The value can be empty, but the XML element must always be present
+ value = "" # The value can be empty, but the XML element must always be present
f = self.get_field_by_fieldname(attr)
set_xml_value(elem, f.to_xml(value, version=version))
return elem
@@ -9610,10 +10000,10 @@ Inherited members
# Customize comparison
if self.state == self.DISABLED:
# All values except state are ignored by the server
- relevant_attrs = ('state',)
+ relevant_attrs = ("state",)
elif self.state != self.SCHEDULED:
# 'start' and 'end' values are ignored by the server, and the server always returns today's date
- relevant_attrs = tuple(f.name for f in self.FIELDS if f.name not in ('start', 'end'))
+ relevant_attrs = tuple(f.name for f in self.FIELDS if f.name not in ("start", "end"))
else:
relevant_attrs = tuple(f.name for f in self.FIELDS)
return hash(tuple(getattr(self, attr) for attr in relevant_attrs))
@@ -9667,7 +10057,7 @@ @classmethod
def from_xml(cls, elem, account):
kwargs = {}
- for attr in ('state', 'external_audience', 'internal_reply', 'external_reply'):
+ for attr in ("state", "external_audience", "internal_reply", "external_reply"):
f = cls.get_field_by_fieldname(attr)
kwargs[attr] = f.from_xml(elem=elem, account=account)
kwargs.update(OutOfOffice.duration_to_start_end(elem=elem, account=account))
@@ -9738,24 +10128,24 @@ Methods
def to_xml(self, version):
self.clean(version=version)
- elem = create_element(f't:{self.REQUEST_ELEMENT_NAME}')
- for attr in ('state', 'external_audience'):
+ elem = create_element(f"t:{self.REQUEST_ELEMENT_NAME}")
+ for attr in ("state", "external_audience"):
value = getattr(self, attr)
f = self.get_field_by_fieldname(attr)
set_xml_value(elem, f.to_xml(value, version=version))
if self.start or self.end:
- duration = create_element('t:Duration')
+ duration = create_element("t:Duration")
if self.start:
- f = self.get_field_by_fieldname('start')
+ f = self.get_field_by_fieldname("start")
set_xml_value(duration, f.to_xml(self.start, version=version))
if self.end:
- f = self.get_field_by_fieldname('end')
+ f = self.get_field_by_fieldname("end")
set_xml_value(duration, f.to_xml(self.end, version=version))
elem.append(duration)
- for attr in ('internal_reply', 'external_reply'):
+ for attr in ("internal_reply", "external_reply"):
value = getattr(self, attr)
if value is None:
- value = '' # The value can be empty, but the XML element must always be present
+ value = "" # The value can be empty, but the XML element must always be present
f = self.get_field_by_fieldname(attr)
set_xml_value(elem, f.to_xml(value, version=version))
return elem
@@ -9792,18 +10182,18 @@ Inherited members
class PostItem(Item):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/postitem"""
- ELEMENT_NAME = 'PostItem'
+ ELEMENT_NAME = "PostItem"
- conversation_index = Message.FIELDS['conversation_index']
- conversation_topic = Message.FIELDS['conversation_topic']
+ conversation_index = Message.FIELDS["conversation_index"]
+ conversation_topic = Message.FIELDS["conversation_topic"]
- author = Message.FIELDS['author']
- message_id = Message.FIELDS['message_id']
- is_read = Message.FIELDS['is_read']
+ author = Message.FIELDS["author"]
+ message_id = Message.FIELDS["message_id"]
+ is_read = Message.FIELDS["is_read"]
- posted_time = DateTimeField(field_uri='postitem:PostedTime', is_read_only=True)
- references = TextField(field_uri='message:References')
- sender = MailboxField(field_uri='message:Sender', is_read_only=True, is_read_only_after_send=True)
+ posted_time = DateTimeField(field_uri="postitem:PostedTime", is_read_only=True)
+ references = TextField(field_uri="message:References")
+ sender = MailboxField(field_uri="message:Sender", is_read_only=True, is_read_only_after_send=True)
class ReplyAllToItem(BaseReplyItem):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/replyalltoitem"""
- ELEMENT_NAME = 'ReplyAllToItem'
+ ELEMENT_NAME = "ReplyAllToItem"
class ReplyToItem(BaseReplyItem):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/replytoitem"""
- ELEMENT_NAME = 'ReplyToItem'
+ ELEMENT_NAME = "ReplyToItem"
class Room(Mailbox):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/room"""
- ELEMENT_NAME = 'Room'
+ ELEMENT_NAME = "Room"
@classmethod
def from_xml(cls, elem, account):
- id_elem = elem.find(f'{{{TNS}}}Id')
+ id_elem = elem.find(f"{{{TNS}}}Id")
item_id_elem = id_elem.find(ItemId.response_tag())
kwargs = dict(
- name=get_xml_attr(id_elem, f'{{{TNS}}}Name'),
- email_address=get_xml_attr(id_elem, f'{{{TNS}}}EmailAddress'),
- mailbox_type=get_xml_attr(id_elem, f'{{{TNS}}}MailboxType'),
+ name=get_xml_attr(id_elem, f"{{{TNS}}}Name"),
+ email_address=get_xml_attr(id_elem, f"{{{TNS}}}EmailAddress"),
+ mailbox_type=get_xml_attr(id_elem, f"{{{TNS}}}MailboxType"),
item_id=ItemId.from_xml(elem=item_id_elem, account=account) if item_id_elem else None,
)
cls._clear(elem)
@@ -10903,12 +11306,12 @@ Static methods
@classmethod
def from_xml(cls, elem, account):
- id_elem = elem.find(f'{{{TNS}}}Id')
+ id_elem = elem.find(f"{{{TNS}}}Id")
item_id_elem = id_elem.find(ItemId.response_tag())
kwargs = dict(
- name=get_xml_attr(id_elem, f'{{{TNS}}}Name'),
- email_address=get_xml_attr(id_elem, f'{{{TNS}}}EmailAddress'),
- mailbox_type=get_xml_attr(id_elem, f'{{{TNS}}}MailboxType'),
+ name=get_xml_attr(id_elem, f"{{{TNS}}}Name"),
+ email_address=get_xml_attr(id_elem, f"{{{TNS}}}EmailAddress"),
+ mailbox_type=get_xml_attr(id_elem, f"{{{TNS}}}MailboxType"),
item_id=ItemId.from_xml(elem=item_id_elem, account=account) if item_id_elem else None,
)
cls._clear(elem)
@@ -10941,14 +11344,14 @@ Inherited members
class RoomList(Mailbox):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/roomlist"""
- ELEMENT_NAME = 'RoomList'
+ ELEMENT_NAME = "RoomList"
NAMESPACE = MNS
@classmethod
def response_tag(cls):
# In a GetRoomLists response, room lists are delivered as Address elements. See
# https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/address-emailaddresstype
- return f'{{{TNS}}}Address'
+ return f"{{{TNS}}}Address"
Ancestors
@@ -10981,7 +11384,7 @@ Static methods
def response_tag(cls):
# In a GetRoomLists response, room lists are delivered as Address elements. See
# https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/address-emailaddresstype
- return f'{{{TNS}}}Address'
+ return f"{{{TNS}}}Address"
@@ -11021,14 +11424,15 @@
@@ -11497,7 +11909,7 @@ Inherited members
cert_file = None
def init_poolmanager(self, *args, **kwargs):
- kwargs['cert_file'] = self.cert_file
+ kwargs["cert_file"] = self.cert_file
return super().init_poolmanager(*args, **kwargs)
def init_poolmanager(self, *args, **kwargs):
- kwargs['cert_file'] = self.cert_file
+ kwargs["cert_file"] = self.cert_file
return super().init_poolmanager(*args, **kwargs)
@@ -11555,49 +11967,78 @@ class Task(Item):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/task"""
- ELEMENT_NAME = 'Task'
- NOT_STARTED = 'NotStarted'
- COMPLETED = 'Completed'
+ ELEMENT_NAME = "Task"
+ NOT_STARTED = "NotStarted"
+ COMPLETED = "Completed"
- actual_work = IntegerField(field_uri='task:ActualWork', min=0)
- assigned_time = DateTimeField(field_uri='task:AssignedTime', is_read_only=True)
- billing_information = TextField(field_uri='task:BillingInformation')
- change_count = IntegerField(field_uri='task:ChangeCount', is_read_only=True, min=0)
- companies = TextListField(field_uri='task:Companies')
+ actual_work = IntegerField(field_uri="task:ActualWork", min=0)
+ assigned_time = DateTimeField(field_uri="task:AssignedTime", is_read_only=True)
+ billing_information = TextField(field_uri="task:BillingInformation")
+ change_count = IntegerField(field_uri="task:ChangeCount", is_read_only=True, min=0)
+ companies = TextListField(field_uri="task:Companies")
# 'complete_date' can be set, but is ignored by the server, which sets it to now()
- complete_date = DateTimeField(field_uri='task:CompleteDate', is_read_only=True)
- contacts = TextListField(field_uri='task:Contacts')
- delegation_state = ChoiceField(field_uri='task:DelegationState', choices={
- Choice('NoMatch'), Choice('OwnNew'), Choice('Owned'), Choice('Accepted'), Choice('Declined'), Choice('Max')
- }, is_read_only=True)
- delegator = CharField(field_uri='task:Delegator', is_read_only=True)
- due_date = DateTimeBackedDateField(field_uri='task:DueDate')
- is_editable = BooleanField(field_uri='task:IsAssignmentEditable', is_read_only=True)
- is_complete = BooleanField(field_uri='task:IsComplete', is_read_only=True)
- is_recurring = BooleanField(field_uri='task:IsRecurring', is_read_only=True)
- is_team_task = BooleanField(field_uri='task:IsTeamTask', is_read_only=True)
- mileage = TextField(field_uri='task:Mileage')
- owner = CharField(field_uri='task:Owner', is_read_only=True)
- percent_complete = DecimalField(field_uri='task:PercentComplete', is_required=True, default=Decimal(0.0),
- min=Decimal(0), max=Decimal(100), is_searchable=False)
- recurrence = TaskRecurrenceField(field_uri='task:Recurrence', is_searchable=False)
- start_date = DateTimeBackedDateField(field_uri='task:StartDate')
- status = ChoiceField(field_uri='task:Status', choices={
- Choice(NOT_STARTED), Choice('InProgress'), Choice(COMPLETED), Choice('WaitingOnOthers'), Choice('Deferred')
- }, is_required=True, is_searchable=False, default=NOT_STARTED)
- status_description = CharField(field_uri='task:StatusDescription', is_read_only=True)
- total_work = IntegerField(field_uri='task:TotalWork', min=0)
+ complete_date = DateTimeField(field_uri="task:CompleteDate", is_read_only=True)
+ contacts = TextListField(field_uri="task:Contacts")
+ delegation_state = ChoiceField(
+ field_uri="task:DelegationState",
+ choices={
+ Choice("NoMatch"),
+ Choice("OwnNew"),
+ Choice("Owned"),
+ Choice("Accepted"),
+ Choice("Declined"),
+ Choice("Max"),
+ },
+ is_read_only=True,
+ )
+ delegator = CharField(field_uri="task:Delegator", is_read_only=True)
+ due_date = DateTimeBackedDateField(field_uri="task:DueDate")
+ is_editable = BooleanField(field_uri="task:IsAssignmentEditable", is_read_only=True)
+ is_complete = BooleanField(field_uri="task:IsComplete", is_read_only=True)
+ is_recurring = BooleanField(field_uri="task:IsRecurring", is_read_only=True)
+ is_team_task = BooleanField(field_uri="task:IsTeamTask", is_read_only=True)
+ mileage = TextField(field_uri="task:Mileage")
+ owner = CharField(field_uri="task:Owner", is_read_only=True)
+ percent_complete = DecimalField(
+ field_uri="task:PercentComplete",
+ is_required=True,
+ default=Decimal(0.0),
+ min=Decimal(0),
+ max=Decimal(100),
+ is_searchable=False,
+ )
+ recurrence = TaskRecurrenceField(field_uri="task:Recurrence", is_searchable=False)
+ start_date = DateTimeBackedDateField(field_uri="task:StartDate")
+ status = ChoiceField(
+ field_uri="task:Status",
+ choices={
+ Choice(NOT_STARTED),
+ Choice("InProgress"),
+ Choice(COMPLETED),
+ Choice("WaitingOnOthers"),
+ Choice("Deferred"),
+ },
+ is_required=True,
+ is_searchable=False,
+ default=NOT_STARTED,
+ )
+ status_description = CharField(field_uri="task:StatusDescription", is_read_only=True)
+ total_work = IntegerField(field_uri="task:TotalWork", min=0)
def clean(self, version=None):
super().clean(version=version)
if self.due_date and self.start_date and self.due_date < self.start_date:
- log.warning("'due_date' must be greater than 'start_date' (%s vs %s). Resetting 'due_date'",
- self.due_date, self.start_date)
+ log.warning(
+ "'due_date' must be greater than 'start_date' (%s vs %s). Resetting 'due_date'",
+ self.due_date,
+ self.start_date,
+ )
self.due_date = self.start_date
if self.complete_date:
if self.status != self.COMPLETED:
- log.warning("'status' must be '%s' when 'complete_date' is set (%s). Resetting",
- self.COMPLETED, self.status)
+ log.warning(
+ "'status' must be '%s' when 'complete_date' is set (%s). Resetting", self.COMPLETED, self.status
+ )
self.status = self.COMPLETED
now = datetime.datetime.now(tz=UTC)
if (self.complete_date - now).total_seconds() > 120:
@@ -11606,19 +12047,28 @@ Methods
log.warning("'complete_date' must be in the past (%s vs %s). Resetting", self.complete_date, now)
self.complete_date = now
if self.start_date and self.complete_date.date() < self.start_date:
- log.warning("'complete_date' must be greater than 'start_date' (%s vs %s). Resetting",
- self.complete_date, self.start_date)
+ log.warning(
+ "'complete_date' must be greater than 'start_date' (%s vs %s). Resetting",
+ self.complete_date,
+ self.start_date,
+ )
self.complete_date = EWSDateTime.combine(self.start_date, datetime.time(0, 0)).replace(tzinfo=UTC)
if self.percent_complete is not None:
if self.status == self.COMPLETED and self.percent_complete != Decimal(100):
# percent_complete must be 100% if task is complete
- log.warning("'percent_complete' must be 100 when 'status' is '%s' (%s). Resetting",
- self.COMPLETED, self.percent_complete)
+ log.warning(
+ "'percent_complete' must be 100 when 'status' is '%s' (%s). Resetting",
+ self.COMPLETED,
+ self.percent_complete,
+ )
self.percent_complete = Decimal(100)
elif self.status == self.NOT_STARTED and self.percent_complete != Decimal(0):
# percent_complete must be 0% if task is not started
- log.warning("'percent_complete' must be 0 when 'status' is '%s' (%s). Resetting",
- self.NOT_STARTED, self.percent_complete)
+ log.warning(
+ "'percent_complete' must be 0 when 'status' is '%s' (%s). Resetting",
+ self.NOT_STARTED,
+ self.percent_complete,
+ )
self.percent_complete = Decimal(0)
def complete(self):
@@ -11759,13 +12209,17 @@ Methods
def clean(self, version=None):
super().clean(version=version)
if self.due_date and self.start_date and self.due_date < self.start_date:
- log.warning("'due_date' must be greater than 'start_date' (%s vs %s). Resetting 'due_date'",
- self.due_date, self.start_date)
+ log.warning(
+ "'due_date' must be greater than 'start_date' (%s vs %s). Resetting 'due_date'",
+ self.due_date,
+ self.start_date,
+ )
self.due_date = self.start_date
if self.complete_date:
if self.status != self.COMPLETED:
- log.warning("'status' must be '%s' when 'complete_date' is set (%s). Resetting",
- self.COMPLETED, self.status)
+ log.warning(
+ "'status' must be '%s' when 'complete_date' is set (%s). Resetting", self.COMPLETED, self.status
+ )
self.status = self.COMPLETED
now = datetime.datetime.now(tz=UTC)
if (self.complete_date - now).total_seconds() > 120:
@@ -11774,19 +12228,28 @@ Methods
log.warning("'complete_date' must be in the past (%s vs %s). Resetting", self.complete_date, now)
self.complete_date = now
if self.start_date and self.complete_date.date() < self.start_date:
- log.warning("'complete_date' must be greater than 'start_date' (%s vs %s). Resetting",
- self.complete_date, self.start_date)
+ log.warning(
+ "'complete_date' must be greater than 'start_date' (%s vs %s). Resetting",
+ self.complete_date,
+ self.start_date,
+ )
self.complete_date = EWSDateTime.combine(self.start_date, datetime.time(0, 0)).replace(tzinfo=UTC)
if self.percent_complete is not None:
if self.status == self.COMPLETED and self.percent_complete != Decimal(100):
# percent_complete must be 100% if task is complete
- log.warning("'percent_complete' must be 100 when 'status' is '%s' (%s). Resetting",
- self.COMPLETED, self.percent_complete)
+ log.warning(
+ "'percent_complete' must be 100 when 'status' is '%s' (%s). Resetting",
+ self.COMPLETED,
+ self.percent_complete,
+ )
self.percent_complete = Decimal(100)
elif self.status == self.NOT_STARTED and self.percent_complete != Decimal(0):
# percent_complete must be 0% if task is not started
- log.warning("'percent_complete' must be 0 when 'status' is '%s' (%s). Resetting",
- self.NOT_STARTED, self.percent_complete)
+ log.warning(
+ "'percent_complete' must be 0 when 'status' is '%s' (%s). Resetting",
+ self.NOT_STARTED,
+ self.percent_complete,
+ )
self.percent_complete = Decimal(0)
@@ -11844,7 +12307,7 @@ Inherited members
class TentativelyAcceptItem(BaseMeetingReplyItem):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/tentativelyacceptitem"""
- ELEMENT_NAME = 'TentativelyAcceptItem'
+ ELEMENT_NAME = "TentativelyAcceptItem"
class Version:
"""Holds information about the server version."""
- __slots__ = 'build', 'api_version'
+ __slots__ = "build", "api_version"
def __init__(self, build, api_version=None):
if api_version is None:
if not isinstance(build, Build):
- raise InvalidTypeError('build', build, Build)
+ raise InvalidTypeError("build", build, Build)
self.api_version = build.api_version()
else:
if not isinstance(build, (Build, type(None))):
- raise InvalidTypeError('build', build, Build)
+ raise InvalidTypeError("build", build, Build)
if not isinstance(api_version, str):
- raise InvalidTypeError('api_version', api_version, str)
+ raise InvalidTypeError("api_version", api_version, str)
self.api_version = api_version
self.build = build
@@ -12009,53 +12465,62 @@ Static methods
:param api_version_hint: (Default value = None)
"""
from .services import ResolveNames
+
# The protocol doesn't have a version yet, so default to latest supported version if we don't have a hint.
api_version = api_version_hint or API_VERSIONS[0]
- log.debug('Asking server for version info using API version %s', api_version)
+ log.debug("Asking server for version info using API version %s", api_version)
# We don't know the build version yet. Hopefully, the server will report it in the SOAP header. Lots of
# places expect a version to have a build, so this is a bit dangerous, but passing a fake build around is also
# dangerous. Make sure the call to ResolveNames does not require a version build.
protocol.config.version = Version(build=None, api_version=api_version)
# Use ResolveNames as a minimal request to the server to test if the version is correct. If not, ResolveNames
# will try to guess the version automatically.
- name = str(protocol.credentials) if protocol.credentials and str(protocol.credentials) else 'DUMMY'
+ name = str(protocol.credentials) if protocol.credentials and str(protocol.credentials) else "DUMMY"
try:
list(ResolveNames(protocol=protocol).call(unresolved_entries=[name]))
except ResponseMessageError as e:
# We may have survived long enough to get a new version
if not protocol.config.version.build:
- raise TransportError(f'No valid version headers found in response ({e!r})')
+ raise TransportError(f"No valid version headers found in response ({e!r})")
if not protocol.config.version.build:
- raise TransportError('No valid version headers found in response')
+ raise TransportError("No valid version headers found in response")
return protocol.config.version
@staticmethod
def _is_invalid_version_string(version):
# Check if a version string is bogus, e.g. V2_, V2015_ or V2018_
- return re.match(r'V[0-9]{1,4}_.*', version)
+ return re.match(r"V[0-9]{1,4}_.*", version)
@classmethod
def from_soap_header(cls, requested_api_version, header):
- info = header.find(f'{{{TNS}}}ServerVersionInfo')
+ info = header.find(f"{{{TNS}}}ServerVersionInfo")
if info is None:
- raise TransportError(f'No ServerVersionInfo in header: {xml_to_str(header)!r}')
+ raise TransportError(f"No ServerVersionInfo in header: {xml_to_str(header)!r}")
try:
build = Build.from_xml(elem=info)
except ValueError:
- raise TransportError(f'Bad ServerVersionInfo in response: {xml_to_str(header)!r}')
+ raise TransportError(f"Bad ServerVersionInfo in response: {xml_to_str(header)!r}")
# Not all Exchange servers send the Version element
- api_version_from_server = info.get('Version') or build.api_version()
+ api_version_from_server = info.get("Version") or build.api_version()
if api_version_from_server != requested_api_version:
if cls._is_invalid_version_string(api_version_from_server):
# For unknown reasons, Office 365 may respond with an API version strings that is invalid in a request.
# Detect these so we can fallback to a valid version string.
- log.debug('API version "%s" worked but server reports version "%s". Using "%s"', requested_api_version,
- api_version_from_server, requested_api_version)
+ log.debug(
+ 'API version "%s" worked but server reports version "%s". Using "%s"',
+ requested_api_version,
+ api_version_from_server,
+ requested_api_version,
+ )
api_version_from_server = requested_api_version
else:
# Trust API version from server response
- log.debug('API version "%s" worked but server reports version "%s". Using "%s"', requested_api_version,
- api_version_from_server, api_version_from_server)
+ log.debug(
+ 'API version "%s" worked but server reports version "%s". Using "%s"',
+ requested_api_version,
+ api_version_from_server,
+ api_version_from_server,
+ )
return cls(build=build, api_version=api_version_from_server)
def copy(self):
@@ -12074,7 +12539,7 @@ Static methods
return self.__class__.__name__ + repr((self.build, self.api_version))
def __str__(self):
- return f'Build={self.build}, API={self.api_version}, Fullname={self.fullname}'
+ return f"Build={self.build}, API={self.api_version}, Fullname={self.fullname}"
@classmethod
def from_soap_header(cls, requested_api_version, header):
- info = header.find(f'{{{TNS}}}ServerVersionInfo')
+ info = header.find(f"{{{TNS}}}ServerVersionInfo")
if info is None:
- raise TransportError(f'No ServerVersionInfo in header: {xml_to_str(header)!r}')
+ raise TransportError(f"No ServerVersionInfo in header: {xml_to_str(header)!r}")
try:
build = Build.from_xml(elem=info)
except ValueError:
- raise TransportError(f'Bad ServerVersionInfo in response: {xml_to_str(header)!r}')
+ raise TransportError(f"Bad ServerVersionInfo in response: {xml_to_str(header)!r}")
# Not all Exchange servers send the Version element
- api_version_from_server = info.get('Version') or build.api_version()
+ api_version_from_server = info.get("Version") or build.api_version()
if api_version_from_server != requested_api_version:
if cls._is_invalid_version_string(api_version_from_server):
# For unknown reasons, Office 365 may respond with an API version strings that is invalid in a request.
# Detect these so we can fallback to a valid version string.
- log.debug('API version "%s" worked but server reports version "%s". Using "%s"', requested_api_version,
- api_version_from_server, requested_api_version)
+ log.debug(
+ 'API version "%s" worked but server reports version "%s". Using "%s"',
+ requested_api_version,
+ api_version_from_server,
+ requested_api_version,
+ )
api_version_from_server = requested_api_version
else:
# Trust API version from server response
- log.debug('API version "%s" worked but server reports version "%s". Using "%s"', requested_api_version,
- api_version_from_server, api_version_from_server)
+ log.debug(
+ 'API version "%s" worked but server reports version "%s". Using "%s"',
+ requested_api_version,
+ api_version_from_server,
+ api_version_from_server,
+ )
return cls(build=build, api_version=api_version_from_server)
@@ -12141,24 +12614,25 @@ exchangelib.indexed_properties
import logging
-from .fields import EmailSubField, LabelField, SubField, NamedSubField, Choice
+from .fields import Choice, EmailSubField, LabelField, NamedSubField, SubField
from .properties import EWSElement, EWSMeta
log = logging.getLogger(__name__)
@@ -47,31 +47,47 @@ Module exchangelib.indexed_properties
def value_field(cls, version):
fields = cls.supported_fields(version=version)
if len(fields) != 1:
- raise ValueError(f'Class {cls} must have only one value field (found {tuple(f.name for f in fields)})')
+ raise ValueError(f"Class {cls} must have only one value field (found {tuple(f.name for f in fields)})")
return fields[0]
class EmailAddress(SingleFieldIndexedElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/entry-emailaddress"""
- ELEMENT_NAME = 'Entry'
- LABEL_CHOICES = ('EmailAddress1', 'EmailAddress2', 'EmailAddress3')
+ ELEMENT_NAME = "Entry"
+ LABEL_CHOICES = ("EmailAddress1", "EmailAddress2", "EmailAddress3")
- label = LabelField(field_uri='Key', choices={Choice(c) for c in LABEL_CHOICES}, default=LABEL_CHOICES[0])
+ label = LabelField(field_uri="Key", choices={Choice(c) for c in LABEL_CHOICES}, default=LABEL_CHOICES[0])
email = EmailSubField(is_required=True)
class PhoneNumber(SingleFieldIndexedElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/entry-phonenumber"""
- ELEMENT_NAME = 'Entry'
+ ELEMENT_NAME = "Entry"
LABEL_CHOICES = (
- 'AssistantPhone', 'BusinessFax', 'BusinessPhone', 'BusinessPhone2', 'Callback', 'CarPhone', 'CompanyMainPhone',
- 'HomeFax', 'HomePhone', 'HomePhone2', 'Isdn', 'MobilePhone', 'OtherFax', 'OtherTelephone', 'Pager',
- 'PrimaryPhone', 'RadioPhone', 'Telex', 'TtyTddPhone'
+ "AssistantPhone",
+ "BusinessFax",
+ "BusinessPhone",
+ "BusinessPhone2",
+ "Callback",
+ "CarPhone",
+ "CompanyMainPhone",
+ "HomeFax",
+ "HomePhone",
+ "HomePhone2",
+ "Isdn",
+ "MobilePhone",
+ "OtherFax",
+ "OtherTelephone",
+ "Pager",
+ "PrimaryPhone",
+ "RadioPhone",
+ "Telex",
+ "TtyTddPhone",
)
- label = LabelField(field_uri='Key', choices={Choice(c) for c in LABEL_CHOICES}, default='PrimaryPhone')
+ label = LabelField(field_uri="Key", choices={Choice(c) for c in LABEL_CHOICES}, default="PrimaryPhone")
phone_number = SubField(is_required=True)
@@ -82,15 +98,15 @@ Module exchangelib.indexed_properties
class PhysicalAddress(MultiFieldIndexedElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/entry-physicaladdress"""
- ELEMENT_NAME = 'Entry'
- LABEL_CHOICES = ('Business', 'Home', 'Other')
+ ELEMENT_NAME = "Entry"
+ LABEL_CHOICES = ("Business", "Home", "Other")
- label = LabelField(field_uri='Key', choices={Choice(c) for c in LABEL_CHOICES}, default=LABEL_CHOICES[0])
- street = NamedSubField(field_uri='Street') # Street, house number, etc.
- city = NamedSubField(field_uri='City')
- state = NamedSubField(field_uri='State')
- country = NamedSubField(field_uri='CountryOrRegion')
- zipcode = NamedSubField(field_uri='PostalCode')
+ label = LabelField(field_uri="Key", choices={Choice(c) for c in LABEL_CHOICES}, default=LABEL_CHOICES[0])
+ street = NamedSubField(field_uri="Street") # Street, house number, etc.
+ city = NamedSubField(field_uri="City")
+ state = NamedSubField(field_uri="State")
+ country = NamedSubField(field_uri="CountryOrRegion")
+ zipcode = NamedSubField(field_uri="PostalCode")
def clean(self, version=None):
if isinstance(self.zipcode, int):
@@ -120,10 +136,10 @@ Classes
class EmailAddress(SingleFieldIndexedElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/entry-emailaddress"""
- ELEMENT_NAME = 'Entry'
- LABEL_CHOICES = ('EmailAddress1', 'EmailAddress2', 'EmailAddress3')
+ ELEMENT_NAME = "Entry"
+ LABEL_CHOICES = ("EmailAddress1", "EmailAddress2", "EmailAddress3")
- label = LabelField(field_uri='Key', choices={Choice(c) for c in LABEL_CHOICES}, default=LABEL_CHOICES[0])
+ label = LabelField(field_uri="Key", choices={Choice(c) for c in LABEL_CHOICES}, default=LABEL_CHOICES[0])
email = EmailSubField(is_required=True)
Ancestors
@@ -260,14 +276,30 @@ Inherited members
class PhoneNumber(SingleFieldIndexedElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/entry-phonenumber"""
- ELEMENT_NAME = 'Entry'
+ ELEMENT_NAME = "Entry"
LABEL_CHOICES = (
- 'AssistantPhone', 'BusinessFax', 'BusinessPhone', 'BusinessPhone2', 'Callback', 'CarPhone', 'CompanyMainPhone',
- 'HomeFax', 'HomePhone', 'HomePhone2', 'Isdn', 'MobilePhone', 'OtherFax', 'OtherTelephone', 'Pager',
- 'PrimaryPhone', 'RadioPhone', 'Telex', 'TtyTddPhone'
+ "AssistantPhone",
+ "BusinessFax",
+ "BusinessPhone",
+ "BusinessPhone2",
+ "Callback",
+ "CarPhone",
+ "CompanyMainPhone",
+ "HomeFax",
+ "HomePhone",
+ "HomePhone2",
+ "Isdn",
+ "MobilePhone",
+ "OtherFax",
+ "OtherTelephone",
+ "Pager",
+ "PrimaryPhone",
+ "RadioPhone",
+ "Telex",
+ "TtyTddPhone",
)
- label = LabelField(field_uri='Key', choices={Choice(c) for c in LABEL_CHOICES}, default='PrimaryPhone')
+ label = LabelField(field_uri="Key", choices={Choice(c) for c in LABEL_CHOICES}, default="PrimaryPhone")
phone_number = SubField(is_required=True)
Ancestors
@@ -327,15 +359,15 @@ Inherited members
class PhysicalAddress(MultiFieldIndexedElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/entry-physicaladdress"""
- ELEMENT_NAME = 'Entry'
- LABEL_CHOICES = ('Business', 'Home', 'Other')
+ ELEMENT_NAME = "Entry"
+ LABEL_CHOICES = ("Business", "Home", "Other")
- label = LabelField(field_uri='Key', choices={Choice(c) for c in LABEL_CHOICES}, default=LABEL_CHOICES[0])
- street = NamedSubField(field_uri='Street') # Street, house number, etc.
- city = NamedSubField(field_uri='City')
- state = NamedSubField(field_uri='State')
- country = NamedSubField(field_uri='CountryOrRegion')
- zipcode = NamedSubField(field_uri='PostalCode')
+ label = LabelField(field_uri="Key", choices={Choice(c) for c in LABEL_CHOICES}, default=LABEL_CHOICES[0])
+ street = NamedSubField(field_uri="Street") # Street, house number, etc.
+ city = NamedSubField(field_uri="City")
+ state = NamedSubField(field_uri="State")
+ country = NamedSubField(field_uri="CountryOrRegion")
+ zipcode = NamedSubField(field_uri="PostalCode")
def clean(self, version=None):
if isinstance(self.zipcode, int):
@@ -437,7 +469,7 @@ Inherited members
def value_field(cls, version):
fields = cls.supported_fields(version=version)
if len(fields) != 1:
- raise ValueError(f'Class {cls} must have only one value field (found {tuple(f.name for f in fields)})')
+ raise ValueError(f"Class {cls} must have only one value field (found {tuple(f.name for f in fields)})")
return fields[0]
Ancestors
@@ -465,7 +497,7 @@ Static methods
def value_field(cls, version):
fields = cls.supported_fields(version=version)
if len(fields) != 1:
- raise ValueError(f'Class {cls} must have only one value field (found {tuple(f.name for f in fields)})')
+ raise ValueError(f"Class {cls} must have only one value field (found {tuple(f.name for f in fields)})")
return fields[0]
diff --git a/docs/exchangelib/items/base.html b/docs/exchangelib/items/base.html
index 24bd2be7..8d516d51 100644
--- a/docs/exchangelib/items/base.html
+++ b/docs/exchangelib/items/base.html
@@ -30,27 +30,37 @@ exchangelib.items.base
exchangelib.items.base
exchangelib.items.base
exchangelib.items.base
exchangelib.items.base
exchangelib.items.base
exchangelib.items.base
exchangelib.items.base
exchangelib.items.base
class BaseReplyItem(EWSElement, metaclass=EWSMeta):
"""Base class for reply/forward elements that share the same fields."""
- subject = CharField(field_uri='Subject')
- body = BodyField(field_uri='Body') # Accepts and returns Body or HTMLBody instances
- to_recipients = MailboxListField(field_uri='ToRecipients')
- cc_recipients = MailboxListField(field_uri='CcRecipients')
- bcc_recipients = MailboxListField(field_uri='BccRecipients')
- is_read_receipt_requested = BooleanField(field_uri='IsReadReceiptRequested')
- is_delivery_receipt_requested = BooleanField(field_uri='IsDeliveryReceiptRequested')
- author = MailboxField(field_uri='From')
+ subject = CharField(field_uri="Subject")
+ body = BodyField(field_uri="Body") # Accepts and returns Body or HTMLBody instances
+ to_recipients = MailboxListField(field_uri="ToRecipients")
+ cc_recipients = MailboxListField(field_uri="CcRecipients")
+ bcc_recipients = MailboxListField(field_uri="BccRecipients")
+ is_read_receipt_requested = BooleanField(field_uri="IsReadReceiptRequested")
+ is_delivery_receipt_requested = BooleanField(field_uri="IsDeliveryReceiptRequested")
+ author = MailboxField(field_uri="From")
reference_item_id = EWSElementField(value_cls=ReferenceItemId)
- new_body = BodyField(field_uri='NewBodyContent') # Accepts and returns Body or HTMLBody instances
- received_by = MailboxField(field_uri='ReceivedBy', supported_from=EXCHANGE_2007_SP1)
- received_by_representing = MailboxField(field_uri='ReceivedRepresenting', supported_from=EXCHANGE_2007_SP1)
+ new_body = BodyField(field_uri="NewBodyContent") # Accepts and returns Body or HTMLBody instances
+ received_by = MailboxField(field_uri="ReceivedBy", supported_from=EXCHANGE_2007_SP1)
+ received_representing = MailboxField(field_uri="ReceivedRepresenting", supported_from=EXCHANGE_2007_SP1)
- __slots__ = 'account',
+ __slots__ = ("account",)
def __init__(self, **kwargs):
# 'account' is optional but allows calling 'send()' and 'save()'
from ..account import Account
- self.account = kwargs.pop('account', None)
+
+ self.account = kwargs.pop("account", None)
if self.account is not None and not isinstance(self.account, Account):
- raise InvalidTypeError('account', self.account, Account)
+ raise InvalidTypeError("account", self.account, Account)
super().__init__(**kwargs)
@require_account
def send(self, save_copy=True, copy_to_folder=None):
from ..services import CreateItem
+
if copy_to_folder and not save_copy:
raise AttributeError("'save_copy' must be True when 'copy_to_folder' is set")
message_disposition = SEND_AND_SAVE_COPY if save_copy else SEND_ONLY
@@ -438,6 +460,7 @@ Inherited members
:return:
"""
from ..services import CreateItem
+
return CreateItem(account=self.account).get(
items=[self],
folder=folder,
@@ -501,7 +524,7 @@ Instance variables
-
-var received_by_representing
+var received_representing
-
@@ -539,6 +562,7 @@ Methods
:return:
"""
from ..services import CreateItem
+
return CreateItem(account=self.account).get(
items=[self],
folder=folder,
@@ -559,6 +583,7 @@ Methods
@require_account
def send(self, save_copy=True, copy_to_folder=None):
from ..services import CreateItem
+
if copy_to_folder and not save_copy:
raise AttributeError("'save_copy' must be True when 'copy_to_folder' is set")
message_disposition = SEND_AND_SAVE_COPY if save_copy else SEND_ONLY
@@ -601,7 +626,7 @@ Inherited members
class BulkCreateResult(BaseItem):
"""A dummy class to store return values from a CreateItem service call."""
- attachments = AttachmentField(field_uri='item:Attachments') # ItemAttachment or FileAttachment
+ attachments = AttachmentField(field_uri="item:Attachments") # ItemAttachment or FileAttachment
def __init__(self, **kwargs):
super().__init__(**kwargs)
@@ -660,7 +685,7 @@ Inherited members
"""Base class for classes that can change their list of supported fields dynamically."""
# This class implements dynamic fields on an element class, so we need to include __dict__ in __slots__
- __slots__ = '__dict__',
+ __slots__ = ("__dict__",)
INSERT_AFTER_FIELD = None
@@ -673,7 +698,7 @@ Inherited members
:return:
"""
if not cls.INSERT_AFTER_FIELD:
- raise ValueError(f'Class {cls} is missing INSERT_AFTER_FIELD value')
+ raise ValueError(f"Class {cls} is missing INSERT_AFTER_FIELD value")
try:
cls.get_field_by_fieldname(attr_name)
except InvalidField:
@@ -776,7 +801,7 @@ Static methods
:return:
"""
if not cls.INSERT_AFTER_FIELD:
- raise ValueError(f'Class {cls} is missing INSERT_AFTER_FIELD value')
+ raise ValueError(f"Class {cls} is missing INSERT_AFTER_FIELD value")
try:
cls.get_field_by_fieldname(attr_name)
except InvalidField:
@@ -850,7 +875,7 @@ is_read_receipt_requested
new_body
received_by
-received_by_representing
+received_representing
reference_item_id
save
send
diff --git a/docs/exchangelib/items/calendar_item.html b/docs/exchangelib/items/calendar_item.html
index 92a2f9ec..e11ddafb 100644
--- a/docs/exchangelib/items/calendar_item.html
+++ b/docs/exchangelib/items/calendar_item.html
@@ -29,30 +29,52 @@ Module exchangelib.items.calendar_item
import datetime
import logging
-from .base import BaseItem, BaseReplyItem, SEND_AND_SAVE_COPY, SEND_TO_NONE
-from .item import Item
-from .message import Message
from ..ewsdatetime import EWSDate, EWSDateTime
-from ..fields import BooleanField, IntegerField, TextField, ChoiceField, URIField, BodyField, DateTimeField, \
- MessageHeaderField, AttachmentField, RecurrenceField, MailboxField, AttendeesField, Choice, OccurrenceField, \
- OccurrenceListField, TimeZoneField, CharField, EnumAsIntField, FreeBusyStatusField, ReferenceItemIdField, \
- AssociatedCalendarItemIdField, DateOrDateTimeField, EWSElementListField, AppointmentStateField
-from ..properties import Attendee, ReferenceItemId, OccurrenceItemId, RecurringMasterItemId, EWSMeta
-from ..recurrence import FirstOccurrence, LastOccurrence, Occurrence, DeletedOccurrence
-from ..util import set_xml_value, require_account
+from ..fields import (
+ AppointmentStateField,
+ AssociatedCalendarItemIdField,
+ AttachmentField,
+ AttendeesField,
+ BodyField,
+ BooleanField,
+ CharField,
+ Choice,
+ ChoiceField,
+ DateOrDateTimeField,
+ DateTimeField,
+ EnumAsIntField,
+ EWSElementListField,
+ FreeBusyStatusField,
+ IntegerField,
+ MailboxField,
+ MessageHeaderField,
+ OccurrenceField,
+ OccurrenceListField,
+ RecurrenceField,
+ ReferenceItemIdField,
+ TextField,
+ TimeZoneField,
+ URIField,
+)
+from ..properties import Attendee, EWSMeta, OccurrenceItemId, RecurringMasterItemId, ReferenceItemId
+from ..recurrence import DeletedOccurrence, FirstOccurrence, LastOccurrence, Occurrence
+from ..util import require_account, set_xml_value
from ..version import EXCHANGE_2010, EXCHANGE_2013
+from .base import SEND_AND_SAVE_COPY, SEND_TO_NONE, BaseItem, BaseReplyItem
+from .item import Item
+from .message import Message
log = logging.getLogger(__name__)
# Conference Type values. See
# https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/conferencetype
-CONFERENCE_TYPES = ('NetMeeting', 'NetShow', 'Chat')
+CONFERENCE_TYPES = ("NetMeeting", "NetShow", "Chat")
# CalendarItemType enums
-SINGLE = 'Single'
-OCCURRENCE = 'Occurrence'
-EXCEPTION = 'Exception'
-RECURRING_MASTER = 'RecurringMaster'
+SINGLE = "Single"
+OCCURRENCE = "Occurrence"
+EXCEPTION = "Exception"
+RECURRING_MASTER = "RecurringMaster"
CALENDAR_ITEM_CHOICES = (SINGLE, OCCURRENCE, EXCEPTION, RECURRING_MASTER)
@@ -61,89 +83,92 @@ Module exchangelib.items.calendar_item
def accept(self, message_disposition=SEND_AND_SAVE_COPY, **kwargs):
return AcceptItem(
- account=self.account,
- reference_item_id=ReferenceItemId(id=self.id, changekey=self.changekey),
- **kwargs
+ account=self.account, reference_item_id=ReferenceItemId(id=self.id, changekey=self.changekey), **kwargs
).send(message_disposition)
def decline(self, message_disposition=SEND_AND_SAVE_COPY, **kwargs):
return DeclineItem(
- account=self.account,
- reference_item_id=ReferenceItemId(id=self.id, changekey=self.changekey),
- **kwargs
+ account=self.account, reference_item_id=ReferenceItemId(id=self.id, changekey=self.changekey), **kwargs
).send(message_disposition)
def tentatively_accept(self, message_disposition=SEND_AND_SAVE_COPY, **kwargs):
return TentativelyAcceptItem(
- account=self.account,
- reference_item_id=ReferenceItemId(id=self.id, changekey=self.changekey),
- **kwargs
+ account=self.account, reference_item_id=ReferenceItemId(id=self.id, changekey=self.changekey), **kwargs
).send(message_disposition)
class CalendarItem(Item, AcceptDeclineMixIn):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/calendaritem"""
- ELEMENT_NAME = 'CalendarItem'
-
- uid = TextField(field_uri='calendar:UID', is_required_after_save=True, is_searchable=False)
- recurrence_id = DateTimeField(field_uri='calendar:RecurrenceId', is_read_only=True)
- start = DateOrDateTimeField(field_uri='calendar:Start', is_required=True)
- end = DateOrDateTimeField(field_uri='calendar:End', is_required=True)
- original_start = DateTimeField(field_uri='calendar:OriginalStart', is_read_only=True)
- is_all_day = BooleanField(field_uri='calendar:IsAllDayEvent', is_required=True, default=False)
- legacy_free_busy_status = FreeBusyStatusField(field_uri='calendar:LegacyFreeBusyStatus', is_required=True,
- default='Busy')
- location = TextField(field_uri='calendar:Location')
- when = TextField(field_uri='calendar:When')
- is_meeting = BooleanField(field_uri='calendar:IsMeeting', is_read_only=True)
- is_cancelled = BooleanField(field_uri='calendar:IsCancelled', is_read_only=True)
- is_recurring = BooleanField(field_uri='calendar:IsRecurring', is_read_only=True)
- meeting_request_was_sent = BooleanField(field_uri='calendar:MeetingRequestWasSent', is_read_only=True)
- is_response_requested = BooleanField(field_uri='calendar:IsResponseRequested', default=None,
- is_required_after_save=True, is_searchable=False)
- type = ChoiceField(field_uri='calendar:CalendarItemType', choices={Choice(c) for c in CALENDAR_ITEM_CHOICES},
- is_read_only=True)
- my_response_type = ChoiceField(field_uri='calendar:MyResponseType', choices={
- Choice(c) for c in Attendee.RESPONSE_TYPES
- }, is_read_only=True)
- organizer = MailboxField(field_uri='calendar:Organizer', is_read_only=True)
- required_attendees = AttendeesField(field_uri='calendar:RequiredAttendees', is_searchable=False)
- optional_attendees = AttendeesField(field_uri='calendar:OptionalAttendees', is_searchable=False)
- resources = AttendeesField(field_uri='calendar:Resources', is_searchable=False)
- conflicting_meeting_count = IntegerField(field_uri='calendar:ConflictingMeetingCount', is_read_only=True)
- adjacent_meeting_count = IntegerField(field_uri='calendar:AdjacentMeetingCount', is_read_only=True)
- conflicting_meetings = EWSElementListField(field_uri='calendar:ConflictingMeetings', value_cls='CalendarItem',
- namespace=Item.NAMESPACE, is_read_only=True)
- adjacent_meetings = EWSElementListField(field_uri='calendar:AdjacentMeetings', value_cls='CalendarItem',
- namespace=Item.NAMESPACE, is_read_only=True)
- duration = CharField(field_uri='calendar:Duration', is_read_only=True)
- appointment_reply_time = DateTimeField(field_uri='calendar:AppointmentReplyTime', is_read_only=True)
- appointment_sequence_number = IntegerField(field_uri='calendar:AppointmentSequenceNumber', is_read_only=True)
- appointment_state = AppointmentStateField(field_uri='calendar:AppointmentState', is_read_only=True)
- recurrence = RecurrenceField(field_uri='calendar:Recurrence', is_searchable=False)
- first_occurrence = OccurrenceField(field_uri='calendar:FirstOccurrence', value_cls=FirstOccurrence,
- is_read_only=True)
- last_occurrence = OccurrenceField(field_uri='calendar:LastOccurrence', value_cls=LastOccurrence,
- is_read_only=True)
- modified_occurrences = OccurrenceListField(field_uri='calendar:ModifiedOccurrences', value_cls=Occurrence,
- is_read_only=True)
- deleted_occurrences = OccurrenceListField(field_uri='calendar:DeletedOccurrences', value_cls=DeletedOccurrence,
- is_read_only=True)
- _meeting_timezone = TimeZoneField(field_uri='calendar:MeetingTimeZone', deprecated_from=EXCHANGE_2010,
- is_searchable=False)
- _start_timezone = TimeZoneField(field_uri='calendar:StartTimeZone', supported_from=EXCHANGE_2010,
- is_searchable=False)
- _end_timezone = TimeZoneField(field_uri='calendar:EndTimeZone', supported_from=EXCHANGE_2010,
- is_searchable=False)
- conference_type = EnumAsIntField(field_uri='calendar:ConferenceType', enum=CONFERENCE_TYPES, min=0,
- default=None, is_required_after_save=True)
- allow_new_time_proposal = BooleanField(field_uri='calendar:AllowNewTimeProposal', default=None,
- is_required_after_save=True, is_searchable=False)
- is_online_meeting = BooleanField(field_uri='calendar:IsOnlineMeeting', default=None,
- is_read_only=True)
- meeting_workspace_url = URIField(field_uri='calendar:MeetingWorkspaceUrl')
- net_show_url = URIField(field_uri='calendar:NetShowUrl')
+ ELEMENT_NAME = "CalendarItem"
+
+ uid = TextField(field_uri="calendar:UID", is_required_after_save=True, is_searchable=False)
+ recurrence_id = DateTimeField(field_uri="calendar:RecurrenceId", is_read_only=True)
+ start = DateOrDateTimeField(field_uri="calendar:Start", is_required=True)
+ end = DateOrDateTimeField(field_uri="calendar:End", is_required=True)
+ original_start = DateTimeField(field_uri="calendar:OriginalStart", is_read_only=True)
+ is_all_day = BooleanField(field_uri="calendar:IsAllDayEvent", is_required=True, default=False)
+ legacy_free_busy_status = FreeBusyStatusField(
+ field_uri="calendar:LegacyFreeBusyStatus", is_required=True, default="Busy"
+ )
+ location = TextField(field_uri="calendar:Location")
+ when = TextField(field_uri="calendar:When")
+ is_meeting = BooleanField(field_uri="calendar:IsMeeting", is_read_only=True)
+ is_cancelled = BooleanField(field_uri="calendar:IsCancelled", is_read_only=True)
+ is_recurring = BooleanField(field_uri="calendar:IsRecurring", is_read_only=True)
+ meeting_request_was_sent = BooleanField(field_uri="calendar:MeetingRequestWasSent", is_read_only=True)
+ is_response_requested = BooleanField(
+ field_uri="calendar:IsResponseRequested", default=None, is_required_after_save=True, is_searchable=False
+ )
+ type = ChoiceField(
+ field_uri="calendar:CalendarItemType", choices={Choice(c) for c in CALENDAR_ITEM_CHOICES}, is_read_only=True
+ )
+ my_response_type = ChoiceField(
+ field_uri="calendar:MyResponseType", choices={Choice(c) for c in Attendee.RESPONSE_TYPES}, is_read_only=True
+ )
+ organizer = MailboxField(field_uri="calendar:Organizer", is_read_only=True)
+ required_attendees = AttendeesField(field_uri="calendar:RequiredAttendees", is_searchable=False)
+ optional_attendees = AttendeesField(field_uri="calendar:OptionalAttendees", is_searchable=False)
+ resources = AttendeesField(field_uri="calendar:Resources", is_searchable=False)
+ conflicting_meeting_count = IntegerField(field_uri="calendar:ConflictingMeetingCount", is_read_only=True)
+ adjacent_meeting_count = IntegerField(field_uri="calendar:AdjacentMeetingCount", is_read_only=True)
+ conflicting_meetings = EWSElementListField(
+ field_uri="calendar:ConflictingMeetings", value_cls="CalendarItem", namespace=Item.NAMESPACE, is_read_only=True
+ )
+ adjacent_meetings = EWSElementListField(
+ field_uri="calendar:AdjacentMeetings", value_cls="CalendarItem", namespace=Item.NAMESPACE, is_read_only=True
+ )
+ duration = CharField(field_uri="calendar:Duration", is_read_only=True)
+ appointment_reply_time = DateTimeField(field_uri="calendar:AppointmentReplyTime", is_read_only=True)
+ appointment_sequence_number = IntegerField(field_uri="calendar:AppointmentSequenceNumber", is_read_only=True)
+ appointment_state = AppointmentStateField(field_uri="calendar:AppointmentState", is_read_only=True)
+ recurrence = RecurrenceField(field_uri="calendar:Recurrence", is_searchable=False)
+ first_occurrence = OccurrenceField(
+ field_uri="calendar:FirstOccurrence", value_cls=FirstOccurrence, is_read_only=True
+ )
+ last_occurrence = OccurrenceField(field_uri="calendar:LastOccurrence", value_cls=LastOccurrence, is_read_only=True)
+ modified_occurrences = OccurrenceListField(
+ field_uri="calendar:ModifiedOccurrences", value_cls=Occurrence, is_read_only=True
+ )
+ deleted_occurrences = OccurrenceListField(
+ field_uri="calendar:DeletedOccurrences", value_cls=DeletedOccurrence, is_read_only=True
+ )
+ _meeting_timezone = TimeZoneField(
+ field_uri="calendar:MeetingTimeZone", deprecated_from=EXCHANGE_2010, is_searchable=False
+ )
+ _start_timezone = TimeZoneField(
+ field_uri="calendar:StartTimeZone", supported_from=EXCHANGE_2010, is_searchable=False
+ )
+ _end_timezone = TimeZoneField(field_uri="calendar:EndTimeZone", supported_from=EXCHANGE_2010, is_searchable=False)
+ conference_type = EnumAsIntField(
+ field_uri="calendar:ConferenceType", enum=CONFERENCE_TYPES, min=0, default=None, is_required_after_save=True
+ )
+ allow_new_time_proposal = BooleanField(
+ field_uri="calendar:AllowNewTimeProposal", default=None, is_required_after_save=True, is_searchable=False
+ )
+ is_online_meeting = BooleanField(field_uri="calendar:IsOnlineMeeting", default=None, is_read_only=True)
+ meeting_workspace_url = URIField(field_uri="calendar:MeetingWorkspaceUrl")
+ net_show_url = URIField(field_uri="calendar:NetShowUrl")
def occurrence(self, index):
"""Get an occurrence of a recurring master by index. No query is sent to the server to actually fetch the item.
@@ -214,9 +239,7 @@ Module exchangelib.items.calendar_item
def cancel(self, **kwargs):
return CancelCalendarItem(
- account=self.account,
- reference_item_id=ReferenceItemId(id=self.id, changekey=self.changekey),
- **kwargs
+ account=self.account, reference_item_id=ReferenceItemId(id=self.id, changekey=self.changekey), **kwargs
).send()
def _update_fieldnames(self):
@@ -224,8 +247,8 @@ Module exchangelib.items.calendar_item
if self.type == OCCURRENCE:
# Some CalendarItem fields cannot be updated when the item is an occurrence. The values are empty when we
# receive them so would have been updated because they are set to None.
- update_fields.remove('recurrence')
- update_fields.remove('uid')
+ update_fields.remove("recurrence")
+ update_fields.remove("uid")
return update_fields
@classmethod
@@ -235,15 +258,15 @@ Module exchangelib.items.calendar_item
# applicable.
if not item.is_all_day:
return item
- for field_name in ('start', 'end'):
+ for field_name in ("start", "end"):
val = getattr(item, field_name)
if val is None:
continue
# Return just the date part of the value. Subtract 1 day from the date if this is the end field. This is
# the inverse of what we do in .to_xml(). Convert to the local timezone before getting the date.
- if field_name == 'end':
+ if field_name == "end":
val -= datetime.timedelta(days=1)
- tz = getattr(item, f'_{field_name}_timezone')
+ tz = getattr(item, f"_{field_name}_timezone")
setattr(item, field_name, val.astimezone(tz).date())
return item
@@ -251,11 +274,11 @@ Module exchangelib.items.calendar_item
meeting_tz_field, start_tz_field, end_tz_field = CalendarItem.timezone_fields()
if self.account.version.build < EXCHANGE_2010:
return meeting_tz_field
- if field_name == 'start':
+ if field_name == "start":
return start_tz_field
- if field_name == 'end':
+ if field_name == "end":
return end_tz_field
- raise ValueError('Unsupported field_name')
+ raise ValueError("Unsupported field_name")
def date_to_datetime(self, field_name):
# EWS always expects a datetime. If we have a date value, then convert it to datetime in the local
@@ -264,7 +287,7 @@ Module exchangelib.items.calendar_item
value = getattr(self, field_name)
tz = getattr(self, self.tz_field_for_field_name(field_name).name)
value = EWSDateTime.combine(value, datetime.time(0, 0)).replace(tzinfo=tz)
- if field_name == 'end':
+ if field_name == "end":
value += datetime.timedelta(days=1)
return value
@@ -278,7 +301,7 @@ Module exchangelib.items.calendar_item
elem = super().to_xml(version=version)
if not self.is_all_day:
return elem
- for field_name in ('start', 'end'):
+ for field_name in ("start", "end"):
value = getattr(self, field_name)
if value is None:
continue
@@ -302,96 +325,123 @@ Module exchangelib.items.calendar_item
Therefore BaseMeetingItem inherits from EWSElement has no save() or send() method
"""
- associated_calendar_item_id = AssociatedCalendarItemIdField(field_uri='meeting:AssociatedCalendarItemId')
- is_delegated = BooleanField(field_uri='meeting:IsDelegated', is_read_only=True, default=False)
- is_out_of_date = BooleanField(field_uri='meeting:IsOutOfDate', is_read_only=True, default=False)
- has_been_processed = BooleanField(field_uri='meeting:HasBeenProcessed', is_read_only=True, default=False)
- response_type = ChoiceField(field_uri='meeting:ResponseType', choices={
- Choice('Unknown'), Choice('Organizer'), Choice('Tentative'), Choice('Accept'), Choice('Decline'),
- Choice('NoResponseReceived')
- }, is_required=True, default='Unknown')
-
- effective_rights_idx = Item.FIELDS.index_by_name('effective_rights')
- sender_idx = Message.FIELDS.index_by_name('sender')
- reply_to_idx = Message.FIELDS.index_by_name('reply_to')
- FIELDS = Item.FIELDS[:effective_rights_idx] \
- + Message.FIELDS[sender_idx:reply_to_idx + 1] \
+ associated_calendar_item_id = AssociatedCalendarItemIdField(field_uri="meeting:AssociatedCalendarItemId")
+ is_delegated = BooleanField(field_uri="meeting:IsDelegated", is_read_only=True, default=False)
+ is_out_of_date = BooleanField(field_uri="meeting:IsOutOfDate", is_read_only=True, default=False)
+ has_been_processed = BooleanField(field_uri="meeting:HasBeenProcessed", is_read_only=True, default=False)
+ response_type = ChoiceField(
+ field_uri="meeting:ResponseType",
+ choices={
+ Choice("Unknown"),
+ Choice("Organizer"),
+ Choice("Tentative"),
+ Choice("Accept"),
+ Choice("Decline"),
+ Choice("NoResponseReceived"),
+ },
+ is_required=True,
+ default="Unknown",
+ )
+
+ effective_rights_idx = Item.FIELDS.index_by_name("effective_rights")
+ sender_idx = Message.FIELDS.index_by_name("sender")
+ received_representing_idx = Message.FIELDS.index_by_name("received_representing")
+ FIELDS = (
+ Item.FIELDS[:effective_rights_idx]
+ + Message.FIELDS[sender_idx : received_representing_idx + 1]
+ Item.FIELDS[effective_rights_idx:]
+ )
class MeetingRequest(BaseMeetingItem, AcceptDeclineMixIn):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/meetingrequest"""
- ELEMENT_NAME = 'MeetingRequest'
-
- meeting_request_type = ChoiceField(field_uri='meetingRequest:MeetingRequestType', choices={
- Choice('FullUpdate'), Choice('InformationalUpdate'), Choice('NewMeetingRequest'), Choice('None'),
- Choice('Outdated'), Choice('PrincipalWantsCopy'), Choice('SilentUpdate')
- }, default='None')
- intended_free_busy_status = ChoiceField(field_uri='meetingRequest:IntendedFreeBusyStatus', choices={
- Choice('Free'), Choice('Tentative'), Choice('Busy'), Choice('OOF'), Choice('NoData')
- }, is_required=True, default='Busy')
+ ELEMENT_NAME = "MeetingRequest"
+
+ meeting_request_type = ChoiceField(
+ field_uri="meetingRequest:MeetingRequestType",
+ choices={
+ Choice("FullUpdate"),
+ Choice("InformationalUpdate"),
+ Choice("NewMeetingRequest"),
+ Choice("None"),
+ Choice("Outdated"),
+ Choice("PrincipalWantsCopy"),
+ Choice("SilentUpdate"),
+ },
+ default="None",
+ )
+ intended_free_busy_status = ChoiceField(
+ field_uri="meetingRequest:IntendedFreeBusyStatus",
+ choices={Choice("Free"), Choice("Tentative"), Choice("Busy"), Choice("OOF"), Choice("NoData")},
+ is_required=True,
+ default="Busy",
+ )
# This element also has some fields from CalendarItem
- start_idx = CalendarItem.FIELDS.index_by_name('start')
- is_response_requested_idx = CalendarItem.FIELDS.index_by_name('is_response_requested')
- FIELDS = BaseMeetingItem.FIELDS \
- + CalendarItem.FIELDS[start_idx:is_response_requested_idx]\
- + CalendarItem.FIELDS[is_response_requested_idx + 1:]
+ start_idx = CalendarItem.FIELDS.index_by_name("start")
+ is_response_requested_idx = CalendarItem.FIELDS.index_by_name("is_response_requested")
+ FIELDS = (
+ BaseMeetingItem.FIELDS
+ + CalendarItem.FIELDS[start_idx:is_response_requested_idx]
+ + CalendarItem.FIELDS[is_response_requested_idx + 1 :]
+ )
class MeetingMessage(BaseMeetingItem):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/meetingmessage"""
- ELEMENT_NAME = 'MeetingMessage'
+ ELEMENT_NAME = "MeetingMessage"
class MeetingResponse(BaseMeetingItem):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/meetingresponse"""
- ELEMENT_NAME = 'MeetingResponse'
+ ELEMENT_NAME = "MeetingResponse"
- received_by = MailboxField(field_uri='message:ReceivedBy', is_read_only=True)
- received_representing = MailboxField(field_uri='message:ReceivedRepresenting', is_read_only=True)
- proposed_start = DateTimeField(field_uri='meeting:ProposedStart', supported_from=EXCHANGE_2013)
- proposed_end = DateTimeField(field_uri='meeting:ProposedEnd', supported_from=EXCHANGE_2013)
+ proposed_start = DateTimeField(field_uri="meeting:ProposedStart", supported_from=EXCHANGE_2013)
+ proposed_end = DateTimeField(field_uri="meeting:ProposedEnd", supported_from=EXCHANGE_2013)
class MeetingCancellation(BaseMeetingItem):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/meetingcancellation"""
- ELEMENT_NAME = 'MeetingCancellation'
+ ELEMENT_NAME = "MeetingCancellation"
class BaseMeetingReplyItem(BaseItem, metaclass=EWSMeta):
"""Base class for meeting request reply items that share the same fields (Accept, TentativelyAccept, Decline)."""
- item_class = CharField(field_uri='item:ItemClass', is_read_only=True)
- sensitivity = ChoiceField(field_uri='item:Sensitivity', choices={
- Choice('Normal'), Choice('Personal'), Choice('Private'), Choice('Confidential')
- }, is_required=True, default='Normal')
- body = BodyField(field_uri='item:Body') # Accepts and returns Body or HTMLBody instances
- attachments = AttachmentField(field_uri='item:Attachments') # ItemAttachment or FileAttachment
- headers = MessageHeaderField(field_uri='item:InternetMessageHeaders', is_read_only=True)
-
- sender = Message.FIELDS['sender']
- to_recipients = Message.FIELDS['to_recipients']
- cc_recipients = Message.FIELDS['cc_recipients']
- bcc_recipients = Message.FIELDS['bcc_recipients']
- is_read_receipt_requested = Message.FIELDS['is_read_receipt_requested']
- is_delivery_receipt_requested = Message.FIELDS['is_delivery_receipt_requested']
-
- reference_item_id = ReferenceItemIdField(field_uri='item:ReferenceItemId')
- received_by = MailboxField(field_uri='message:ReceivedBy', is_read_only=True)
- received_representing = MailboxField(field_uri='message:ReceivedRepresenting', is_read_only=True)
- proposed_start = DateTimeField(field_uri='meeting:ProposedStart', supported_from=EXCHANGE_2013)
- proposed_end = DateTimeField(field_uri='meeting:ProposedEnd', supported_from=EXCHANGE_2013)
+ item_class = CharField(field_uri="item:ItemClass", is_read_only=True)
+ sensitivity = ChoiceField(
+ field_uri="item:Sensitivity",
+ choices={Choice("Normal"), Choice("Personal"), Choice("Private"), Choice("Confidential")},
+ is_required=True,
+ default="Normal",
+ )
+ body = BodyField(field_uri="item:Body") # Accepts and returns Body or HTMLBody instances
+ attachments = AttachmentField(field_uri="item:Attachments") # ItemAttachment or FileAttachment
+ headers = MessageHeaderField(field_uri="item:InternetMessageHeaders", is_read_only=True)
+
+ sender = Message.FIELDS["sender"]
+ to_recipients = Message.FIELDS["to_recipients"]
+ cc_recipients = Message.FIELDS["cc_recipients"]
+ bcc_recipients = Message.FIELDS["bcc_recipients"]
+ is_read_receipt_requested = Message.FIELDS["is_read_receipt_requested"]
+ is_delivery_receipt_requested = Message.FIELDS["is_delivery_receipt_requested"]
+
+ reference_item_id = ReferenceItemIdField(field_uri="item:ReferenceItemId")
+ received_by = MailboxField(field_uri="message:ReceivedBy", is_read_only=True)
+ received_representing = MailboxField(field_uri="message:ReceivedRepresenting", is_read_only=True)
+ proposed_start = DateTimeField(field_uri="meeting:ProposedStart", supported_from=EXCHANGE_2013)
+ proposed_end = DateTimeField(field_uri="meeting:ProposedEnd", supported_from=EXCHANGE_2013)
@require_account
def send(self, message_disposition=SEND_AND_SAVE_COPY):
# Some responses contain multiple response IDs, e.g. MeetingRequest.accept(). Return either the single ID or
# the list of IDs.
from ..services import CreateItem
+
return CreateItem(account=self.account).get(
items=[self],
folder=self.folder,
@@ -403,27 +453,27 @@ Module exchangelib.items.calendar_item
class AcceptItem(BaseMeetingReplyItem):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/acceptitem"""
- ELEMENT_NAME = 'AcceptItem'
+ ELEMENT_NAME = "AcceptItem"
class TentativelyAcceptItem(BaseMeetingReplyItem):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/tentativelyacceptitem"""
- ELEMENT_NAME = 'TentativelyAcceptItem'
+ ELEMENT_NAME = "TentativelyAcceptItem"
class DeclineItem(BaseMeetingReplyItem):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/declineitem"""
- ELEMENT_NAME = 'DeclineItem'
+ ELEMENT_NAME = "DeclineItem"
class CancelCalendarItem(BaseReplyItem):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/cancelcalendaritem"""
- ELEMENT_NAME = 'CancelCalendarItem'
- author_idx = BaseReplyItem.FIELDS.index_by_name('author')
- FIELDS = BaseReplyItem.FIELDS[:author_idx] + BaseReplyItem.FIELDS[author_idx + 1:]
+ ELEMENT_NAME = "CancelCalendarItem"
+ author_idx = BaseReplyItem.FIELDS.index_by_name("author")
+ FIELDS = BaseReplyItem.FIELDS[:author_idx] + BaseReplyItem.FIELDS[author_idx + 1 :]
@@ -449,23 +499,17 @@ Classes
def accept(self, message_disposition=SEND_AND_SAVE_COPY, **kwargs):
return AcceptItem(
- account=self.account,
- reference_item_id=ReferenceItemId(id=self.id, changekey=self.changekey),
- **kwargs
+ account=self.account, reference_item_id=ReferenceItemId(id=self.id, changekey=self.changekey), **kwargs
).send(message_disposition)
def decline(self, message_disposition=SEND_AND_SAVE_COPY, **kwargs):
return DeclineItem(
- account=self.account,
- reference_item_id=ReferenceItemId(id=self.id, changekey=self.changekey),
- **kwargs
+ account=self.account, reference_item_id=ReferenceItemId(id=self.id, changekey=self.changekey), **kwargs
).send(message_disposition)
def tentatively_accept(self, message_disposition=SEND_AND_SAVE_COPY, **kwargs):
return TentativelyAcceptItem(
- account=self.account,
- reference_item_id=ReferenceItemId(id=self.id, changekey=self.changekey),
- **kwargs
+ account=self.account, reference_item_id=ReferenceItemId(id=self.id, changekey=self.changekey), **kwargs
).send(message_disposition)
Subclasses
@@ -486,9 +530,7 @@ Methods
def accept(self, message_disposition=SEND_AND_SAVE_COPY, **kwargs):
return AcceptItem(
- account=self.account,
- reference_item_id=ReferenceItemId(id=self.id, changekey=self.changekey),
- **kwargs
+ account=self.account, reference_item_id=ReferenceItemId(id=self.id, changekey=self.changekey), **kwargs
).send(message_disposition)
@@ -503,9 +545,7 @@ Methods
def decline(self, message_disposition=SEND_AND_SAVE_COPY, **kwargs):
return DeclineItem(
- account=self.account,
- reference_item_id=ReferenceItemId(id=self.id, changekey=self.changekey),
- **kwargs
+ account=self.account, reference_item_id=ReferenceItemId(id=self.id, changekey=self.changekey), **kwargs
).send(message_disposition)
@@ -520,9 +560,7 @@ Methods
def tentatively_accept(self, message_disposition=SEND_AND_SAVE_COPY, **kwargs):
return TentativelyAcceptItem(
- account=self.account,
- reference_item_id=ReferenceItemId(id=self.id, changekey=self.changekey),
- **kwargs
+ account=self.account, reference_item_id=ReferenceItemId(id=self.id, changekey=self.changekey), **kwargs
).send(message_disposition)
@@ -546,7 +584,7 @@ Methods
class AcceptItem(BaseMeetingReplyItem):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/acceptitem"""
- ELEMENT_NAME = 'AcceptItem'
+ ELEMENT_NAME = "AcceptItem"
var reply_to_idx
var received_representing_idx
var received_by
var received_representing
var references
class BaseMeetingReplyItem(BaseItem, metaclass=EWSMeta):
"""Base class for meeting request reply items that share the same fields (Accept, TentativelyAccept, Decline)."""
- item_class = CharField(field_uri='item:ItemClass', is_read_only=True)
- sensitivity = ChoiceField(field_uri='item:Sensitivity', choices={
- Choice('Normal'), Choice('Personal'), Choice('Private'), Choice('Confidential')
- }, is_required=True, default='Normal')
- body = BodyField(field_uri='item:Body') # Accepts and returns Body or HTMLBody instances
- attachments = AttachmentField(field_uri='item:Attachments') # ItemAttachment or FileAttachment
- headers = MessageHeaderField(field_uri='item:InternetMessageHeaders', is_read_only=True)
-
- sender = Message.FIELDS['sender']
- to_recipients = Message.FIELDS['to_recipients']
- cc_recipients = Message.FIELDS['cc_recipients']
- bcc_recipients = Message.FIELDS['bcc_recipients']
- is_read_receipt_requested = Message.FIELDS['is_read_receipt_requested']
- is_delivery_receipt_requested = Message.FIELDS['is_delivery_receipt_requested']
-
- reference_item_id = ReferenceItemIdField(field_uri='item:ReferenceItemId')
- received_by = MailboxField(field_uri='message:ReceivedBy', is_read_only=True)
- received_representing = MailboxField(field_uri='message:ReceivedRepresenting', is_read_only=True)
- proposed_start = DateTimeField(field_uri='meeting:ProposedStart', supported_from=EXCHANGE_2013)
- proposed_end = DateTimeField(field_uri='meeting:ProposedEnd', supported_from=EXCHANGE_2013)
+ item_class = CharField(field_uri="item:ItemClass", is_read_only=True)
+ sensitivity = ChoiceField(
+ field_uri="item:Sensitivity",
+ choices={Choice("Normal"), Choice("Personal"), Choice("Private"), Choice("Confidential")},
+ is_required=True,
+ default="Normal",
+ )
+ body = BodyField(field_uri="item:Body") # Accepts and returns Body or HTMLBody instances
+ attachments = AttachmentField(field_uri="item:Attachments") # ItemAttachment or FileAttachment
+ headers = MessageHeaderField(field_uri="item:InternetMessageHeaders", is_read_only=True)
+
+ sender = Message.FIELDS["sender"]
+ to_recipients = Message.FIELDS["to_recipients"]
+ cc_recipients = Message.FIELDS["cc_recipients"]
+ bcc_recipients = Message.FIELDS["bcc_recipients"]
+ is_read_receipt_requested = Message.FIELDS["is_read_receipt_requested"]
+ is_delivery_receipt_requested = Message.FIELDS["is_delivery_receipt_requested"]
+
+ reference_item_id = ReferenceItemIdField(field_uri="item:ReferenceItemId")
+ received_by = MailboxField(field_uri="message:ReceivedBy", is_read_only=True)
+ received_representing = MailboxField(field_uri="message:ReceivedRepresenting", is_read_only=True)
+ proposed_start = DateTimeField(field_uri="meeting:ProposedStart", supported_from=EXCHANGE_2013)
+ proposed_end = DateTimeField(field_uri="meeting:ProposedEnd", supported_from=EXCHANGE_2013)
@require_account
def send(self, message_disposition=SEND_AND_SAVE_COPY):
# Some responses contain multiple response IDs, e.g. MeetingRequest.accept(). Return either the single ID or
# the list of IDs.
from ..services import CreateItem
+
return CreateItem(account=self.account).get(
items=[self],
folder=self.folder,
@@ -912,6 +973,7 @@ Methods
# Some responses contain multiple response IDs, e.g. MeetingRequest.accept(). Return either the single ID or
# the list of IDs.
from ..services import CreateItem
+
return CreateItem(account=self.account).get(
items=[self],
folder=self.folder,
@@ -956,66 +1018,75 @@ Inherited members
class CalendarItem(Item, AcceptDeclineMixIn):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/calendaritem"""
- ELEMENT_NAME = 'CalendarItem'
-
- uid = TextField(field_uri='calendar:UID', is_required_after_save=True, is_searchable=False)
- recurrence_id = DateTimeField(field_uri='calendar:RecurrenceId', is_read_only=True)
- start = DateOrDateTimeField(field_uri='calendar:Start', is_required=True)
- end = DateOrDateTimeField(field_uri='calendar:End', is_required=True)
- original_start = DateTimeField(field_uri='calendar:OriginalStart', is_read_only=True)
- is_all_day = BooleanField(field_uri='calendar:IsAllDayEvent', is_required=True, default=False)
- legacy_free_busy_status = FreeBusyStatusField(field_uri='calendar:LegacyFreeBusyStatus', is_required=True,
- default='Busy')
- location = TextField(field_uri='calendar:Location')
- when = TextField(field_uri='calendar:When')
- is_meeting = BooleanField(field_uri='calendar:IsMeeting', is_read_only=True)
- is_cancelled = BooleanField(field_uri='calendar:IsCancelled', is_read_only=True)
- is_recurring = BooleanField(field_uri='calendar:IsRecurring', is_read_only=True)
- meeting_request_was_sent = BooleanField(field_uri='calendar:MeetingRequestWasSent', is_read_only=True)
- is_response_requested = BooleanField(field_uri='calendar:IsResponseRequested', default=None,
- is_required_after_save=True, is_searchable=False)
- type = ChoiceField(field_uri='calendar:CalendarItemType', choices={Choice(c) for c in CALENDAR_ITEM_CHOICES},
- is_read_only=True)
- my_response_type = ChoiceField(field_uri='calendar:MyResponseType', choices={
- Choice(c) for c in Attendee.RESPONSE_TYPES
- }, is_read_only=True)
- organizer = MailboxField(field_uri='calendar:Organizer', is_read_only=True)
- required_attendees = AttendeesField(field_uri='calendar:RequiredAttendees', is_searchable=False)
- optional_attendees = AttendeesField(field_uri='calendar:OptionalAttendees', is_searchable=False)
- resources = AttendeesField(field_uri='calendar:Resources', is_searchable=False)
- conflicting_meeting_count = IntegerField(field_uri='calendar:ConflictingMeetingCount', is_read_only=True)
- adjacent_meeting_count = IntegerField(field_uri='calendar:AdjacentMeetingCount', is_read_only=True)
- conflicting_meetings = EWSElementListField(field_uri='calendar:ConflictingMeetings', value_cls='CalendarItem',
- namespace=Item.NAMESPACE, is_read_only=True)
- adjacent_meetings = EWSElementListField(field_uri='calendar:AdjacentMeetings', value_cls='CalendarItem',
- namespace=Item.NAMESPACE, is_read_only=True)
- duration = CharField(field_uri='calendar:Duration', is_read_only=True)
- appointment_reply_time = DateTimeField(field_uri='calendar:AppointmentReplyTime', is_read_only=True)
- appointment_sequence_number = IntegerField(field_uri='calendar:AppointmentSequenceNumber', is_read_only=True)
- appointment_state = AppointmentStateField(field_uri='calendar:AppointmentState', is_read_only=True)
- recurrence = RecurrenceField(field_uri='calendar:Recurrence', is_searchable=False)
- first_occurrence = OccurrenceField(field_uri='calendar:FirstOccurrence', value_cls=FirstOccurrence,
- is_read_only=True)
- last_occurrence = OccurrenceField(field_uri='calendar:LastOccurrence', value_cls=LastOccurrence,
- is_read_only=True)
- modified_occurrences = OccurrenceListField(field_uri='calendar:ModifiedOccurrences', value_cls=Occurrence,
- is_read_only=True)
- deleted_occurrences = OccurrenceListField(field_uri='calendar:DeletedOccurrences', value_cls=DeletedOccurrence,
- is_read_only=True)
- _meeting_timezone = TimeZoneField(field_uri='calendar:MeetingTimeZone', deprecated_from=EXCHANGE_2010,
- is_searchable=False)
- _start_timezone = TimeZoneField(field_uri='calendar:StartTimeZone', supported_from=EXCHANGE_2010,
- is_searchable=False)
- _end_timezone = TimeZoneField(field_uri='calendar:EndTimeZone', supported_from=EXCHANGE_2010,
- is_searchable=False)
- conference_type = EnumAsIntField(field_uri='calendar:ConferenceType', enum=CONFERENCE_TYPES, min=0,
- default=None, is_required_after_save=True)
- allow_new_time_proposal = BooleanField(field_uri='calendar:AllowNewTimeProposal', default=None,
- is_required_after_save=True, is_searchable=False)
- is_online_meeting = BooleanField(field_uri='calendar:IsOnlineMeeting', default=None,
- is_read_only=True)
- meeting_workspace_url = URIField(field_uri='calendar:MeetingWorkspaceUrl')
- net_show_url = URIField(field_uri='calendar:NetShowUrl')
+ ELEMENT_NAME = "CalendarItem"
+
+ uid = TextField(field_uri="calendar:UID", is_required_after_save=True, is_searchable=False)
+ recurrence_id = DateTimeField(field_uri="calendar:RecurrenceId", is_read_only=True)
+ start = DateOrDateTimeField(field_uri="calendar:Start", is_required=True)
+ end = DateOrDateTimeField(field_uri="calendar:End", is_required=True)
+ original_start = DateTimeField(field_uri="calendar:OriginalStart", is_read_only=True)
+ is_all_day = BooleanField(field_uri="calendar:IsAllDayEvent", is_required=True, default=False)
+ legacy_free_busy_status = FreeBusyStatusField(
+ field_uri="calendar:LegacyFreeBusyStatus", is_required=True, default="Busy"
+ )
+ location = TextField(field_uri="calendar:Location")
+ when = TextField(field_uri="calendar:When")
+ is_meeting = BooleanField(field_uri="calendar:IsMeeting", is_read_only=True)
+ is_cancelled = BooleanField(field_uri="calendar:IsCancelled", is_read_only=True)
+ is_recurring = BooleanField(field_uri="calendar:IsRecurring", is_read_only=True)
+ meeting_request_was_sent = BooleanField(field_uri="calendar:MeetingRequestWasSent", is_read_only=True)
+ is_response_requested = BooleanField(
+ field_uri="calendar:IsResponseRequested", default=None, is_required_after_save=True, is_searchable=False
+ )
+ type = ChoiceField(
+ field_uri="calendar:CalendarItemType", choices={Choice(c) for c in CALENDAR_ITEM_CHOICES}, is_read_only=True
+ )
+ my_response_type = ChoiceField(
+ field_uri="calendar:MyResponseType", choices={Choice(c) for c in Attendee.RESPONSE_TYPES}, is_read_only=True
+ )
+ organizer = MailboxField(field_uri="calendar:Organizer", is_read_only=True)
+ required_attendees = AttendeesField(field_uri="calendar:RequiredAttendees", is_searchable=False)
+ optional_attendees = AttendeesField(field_uri="calendar:OptionalAttendees", is_searchable=False)
+ resources = AttendeesField(field_uri="calendar:Resources", is_searchable=False)
+ conflicting_meeting_count = IntegerField(field_uri="calendar:ConflictingMeetingCount", is_read_only=True)
+ adjacent_meeting_count = IntegerField(field_uri="calendar:AdjacentMeetingCount", is_read_only=True)
+ conflicting_meetings = EWSElementListField(
+ field_uri="calendar:ConflictingMeetings", value_cls="CalendarItem", namespace=Item.NAMESPACE, is_read_only=True
+ )
+ adjacent_meetings = EWSElementListField(
+ field_uri="calendar:AdjacentMeetings", value_cls="CalendarItem", namespace=Item.NAMESPACE, is_read_only=True
+ )
+ duration = CharField(field_uri="calendar:Duration", is_read_only=True)
+ appointment_reply_time = DateTimeField(field_uri="calendar:AppointmentReplyTime", is_read_only=True)
+ appointment_sequence_number = IntegerField(field_uri="calendar:AppointmentSequenceNumber", is_read_only=True)
+ appointment_state = AppointmentStateField(field_uri="calendar:AppointmentState", is_read_only=True)
+ recurrence = RecurrenceField(field_uri="calendar:Recurrence", is_searchable=False)
+ first_occurrence = OccurrenceField(
+ field_uri="calendar:FirstOccurrence", value_cls=FirstOccurrence, is_read_only=True
+ )
+ last_occurrence = OccurrenceField(field_uri="calendar:LastOccurrence", value_cls=LastOccurrence, is_read_only=True)
+ modified_occurrences = OccurrenceListField(
+ field_uri="calendar:ModifiedOccurrences", value_cls=Occurrence, is_read_only=True
+ )
+ deleted_occurrences = OccurrenceListField(
+ field_uri="calendar:DeletedOccurrences", value_cls=DeletedOccurrence, is_read_only=True
+ )
+ _meeting_timezone = TimeZoneField(
+ field_uri="calendar:MeetingTimeZone", deprecated_from=EXCHANGE_2010, is_searchable=False
+ )
+ _start_timezone = TimeZoneField(
+ field_uri="calendar:StartTimeZone", supported_from=EXCHANGE_2010, is_searchable=False
+ )
+ _end_timezone = TimeZoneField(field_uri="calendar:EndTimeZone", supported_from=EXCHANGE_2010, is_searchable=False)
+ conference_type = EnumAsIntField(
+ field_uri="calendar:ConferenceType", enum=CONFERENCE_TYPES, min=0, default=None, is_required_after_save=True
+ )
+ allow_new_time_proposal = BooleanField(
+ field_uri="calendar:AllowNewTimeProposal", default=None, is_required_after_save=True, is_searchable=False
+ )
+ is_online_meeting = BooleanField(field_uri="calendar:IsOnlineMeeting", default=None, is_read_only=True)
+ meeting_workspace_url = URIField(field_uri="calendar:MeetingWorkspaceUrl")
+ net_show_url = URIField(field_uri="calendar:NetShowUrl")
def occurrence(self, index):
"""Get an occurrence of a recurring master by index. No query is sent to the server to actually fetch the item.
@@ -1086,9 +1157,7 @@ Inherited members
def cancel(self, **kwargs):
return CancelCalendarItem(
- account=self.account,
- reference_item_id=ReferenceItemId(id=self.id, changekey=self.changekey),
- **kwargs
+ account=self.account, reference_item_id=ReferenceItemId(id=self.id, changekey=self.changekey), **kwargs
).send()
def _update_fieldnames(self):
@@ -1096,8 +1165,8 @@ Inherited members
if self.type == OCCURRENCE:
# Some CalendarItem fields cannot be updated when the item is an occurrence. The values are empty when we
# receive them so would have been updated because they are set to None.
- update_fields.remove('recurrence')
- update_fields.remove('uid')
+ update_fields.remove("recurrence")
+ update_fields.remove("uid")
return update_fields
@classmethod
@@ -1107,15 +1176,15 @@ Inherited members
# applicable.
if not item.is_all_day:
return item
- for field_name in ('start', 'end'):
+ for field_name in ("start", "end"):
val = getattr(item, field_name)
if val is None:
continue
# Return just the date part of the value. Subtract 1 day from the date if this is the end field. This is
# the inverse of what we do in .to_xml(). Convert to the local timezone before getting the date.
- if field_name == 'end':
+ if field_name == "end":
val -= datetime.timedelta(days=1)
- tz = getattr(item, f'_{field_name}_timezone')
+ tz = getattr(item, f"_{field_name}_timezone")
setattr(item, field_name, val.astimezone(tz).date())
return item
@@ -1123,11 +1192,11 @@ Inherited members
meeting_tz_field, start_tz_field, end_tz_field = CalendarItem.timezone_fields()
if self.account.version.build < EXCHANGE_2010:
return meeting_tz_field
- if field_name == 'start':
+ if field_name == "start":
return start_tz_field
- if field_name == 'end':
+ if field_name == "end":
return end_tz_field
- raise ValueError('Unsupported field_name')
+ raise ValueError("Unsupported field_name")
def date_to_datetime(self, field_name):
# EWS always expects a datetime. If we have a date value, then convert it to datetime in the local
@@ -1136,7 +1205,7 @@ Inherited members
value = getattr(self, field_name)
tz = getattr(self, self.tz_field_for_field_name(field_name).name)
value = EWSDateTime.combine(value, datetime.time(0, 0)).replace(tzinfo=tz)
- if field_name == 'end':
+ if field_name == "end":
value += datetime.timedelta(days=1)
return value
@@ -1150,7 +1219,7 @@ Inherited members
elem = super().to_xml(version=version)
if not self.is_all_day:
return elem
- for field_name in ('start', 'end'):
+ for field_name in ("start", "end"):
value = getattr(self, field_name)
if value is None:
continue
@@ -1201,15 +1270,15 @@ Static methods
# applicable.
if not item.is_all_day:
return item
- for field_name in ('start', 'end'):
+ for field_name in ("start", "end"):
val = getattr(item, field_name)
if val is None:
continue
# Return just the date part of the value. Subtract 1 day from the date if this is the end field. This is
# the inverse of what we do in .to_xml(). Convert to the local timezone before getting the date.
- if field_name == 'end':
+ if field_name == "end":
val -= datetime.timedelta(days=1)
- tz = getattr(item, f'_{field_name}_timezone')
+ tz = getattr(item, f"_{field_name}_timezone")
setattr(item, field_name, val.astimezone(tz).date())
return item
@@ -1397,9 +1466,7 @@ Methods
def cancel(self, **kwargs):
return CancelCalendarItem(
- account=self.account,
- reference_item_id=ReferenceItemId(id=self.id, changekey=self.changekey),
- **kwargs
+ account=self.account, reference_item_id=ReferenceItemId(id=self.id, changekey=self.changekey), **kwargs
).send()
class CancelCalendarItem(BaseReplyItem):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/cancelcalendaritem"""
- ELEMENT_NAME = 'CancelCalendarItem'
- author_idx = BaseReplyItem.FIELDS.index_by_name('author')
- FIELDS = BaseReplyItem.FIELDS[:author_idx] + BaseReplyItem.FIELDS[author_idx + 1:]
+ ELEMENT_NAME = "CancelCalendarItem"
+ author_idx = BaseReplyItem.FIELDS.index_by_name("author")
+ FIELDS = BaseReplyItem.FIELDS[:author_idx] + BaseReplyItem.FIELDS[author_idx + 1 :]
class DeclineItem(BaseMeetingReplyItem):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/declineitem"""
- ELEMENT_NAME = 'DeclineItem'
+ ELEMENT_NAME = "DeclineItem"
class MeetingCancellation(BaseMeetingItem):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/meetingcancellation"""
- ELEMENT_NAME = 'MeetingCancellation'
+ ELEMENT_NAME = "MeetingCancellation"
class MeetingMessage(BaseMeetingItem):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/meetingmessage"""
- ELEMENT_NAME = 'MeetingMessage'
+ ELEMENT_NAME = "MeetingMessage"
class MeetingRequest(BaseMeetingItem, AcceptDeclineMixIn):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/meetingrequest"""
- ELEMENT_NAME = 'MeetingRequest'
-
- meeting_request_type = ChoiceField(field_uri='meetingRequest:MeetingRequestType', choices={
- Choice('FullUpdate'), Choice('InformationalUpdate'), Choice('NewMeetingRequest'), Choice('None'),
- Choice('Outdated'), Choice('PrincipalWantsCopy'), Choice('SilentUpdate')
- }, default='None')
- intended_free_busy_status = ChoiceField(field_uri='meetingRequest:IntendedFreeBusyStatus', choices={
- Choice('Free'), Choice('Tentative'), Choice('Busy'), Choice('OOF'), Choice('NoData')
- }, is_required=True, default='Busy')
+ ELEMENT_NAME = "MeetingRequest"
+
+ meeting_request_type = ChoiceField(
+ field_uri="meetingRequest:MeetingRequestType",
+ choices={
+ Choice("FullUpdate"),
+ Choice("InformationalUpdate"),
+ Choice("NewMeetingRequest"),
+ Choice("None"),
+ Choice("Outdated"),
+ Choice("PrincipalWantsCopy"),
+ Choice("SilentUpdate"),
+ },
+ default="None",
+ )
+ intended_free_busy_status = ChoiceField(
+ field_uri="meetingRequest:IntendedFreeBusyStatus",
+ choices={Choice("Free"), Choice("Tentative"), Choice("Busy"), Choice("OOF"), Choice("NoData")},
+ is_required=True,
+ default="Busy",
+ )
# This element also has some fields from CalendarItem
- start_idx = CalendarItem.FIELDS.index_by_name('start')
- is_response_requested_idx = CalendarItem.FIELDS.index_by_name('is_response_requested')
- FIELDS = BaseMeetingItem.FIELDS \
- + CalendarItem.FIELDS[start_idx:is_response_requested_idx]\
- + CalendarItem.FIELDS[is_response_requested_idx + 1:]
+ start_idx = CalendarItem.FIELDS.index_by_name("start")
+ is_response_requested_idx = CalendarItem.FIELDS.index_by_name("is_response_requested")
+ FIELDS = (
+ BaseMeetingItem.FIELDS
+ + CalendarItem.FIELDS[start_idx:is_response_requested_idx]
+ + CalendarItem.FIELDS[is_response_requested_idx + 1 :]
+ )
class MeetingResponse(BaseMeetingItem):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/meetingresponse"""
- ELEMENT_NAME = 'MeetingResponse'
+ ELEMENT_NAME = "MeetingResponse"
- received_by = MailboxField(field_uri='message:ReceivedBy', is_read_only=True)
- received_representing = MailboxField(field_uri='message:ReceivedRepresenting', is_read_only=True)
- proposed_start = DateTimeField(field_uri='meeting:ProposedStart', supported_from=EXCHANGE_2013)
- proposed_end = DateTimeField(field_uri='meeting:ProposedEnd', supported_from=EXCHANGE_2013)
+ proposed_start = DateTimeField(field_uri="meeting:ProposedStart", supported_from=EXCHANGE_2013)
+ proposed_end = DateTimeField(field_uri="meeting:ProposedEnd", supported_from=EXCHANGE_2013)
var received_by
var received_representing
class TentativelyAcceptItem(BaseMeetingReplyItem):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/tentativelyacceptitem"""
- ELEMENT_NAME = 'TentativelyAcceptItem'
+ ELEMENT_NAME = "TentativelyAcceptItem"
is_read_receipt_requested
is_response_requested
message_id
received_by
received_representing
received_representing_idx
references
reply_to
reply_to_idx
response_type
sender
sender_idx
FIELDS
proposed_end
proposed_start
received_by
received_representing
exchangelib.items.contact
import datetime
import logging
-from .item import Item
-from ..fields import BooleanField, Base64Field, TextField, ChoiceField, URIField, DateTimeBackedDateField, \
- PhoneNumberField, EmailAddressesField, PhysicalAddressField, Choice, MemberListField, CharField, TextListField, \
- EmailAddressField, IdElementField, EWSElementField, DateTimeField, EWSElementListField, \
- BodyContentAttributedValueField, StringAttributedValueField, PhoneNumberAttributedValueField, \
- PersonaPhoneNumberField, EmailAddressAttributedValueField, PostalAddressAttributedValueField, MailboxField, \
- MailboxListField
-from ..properties import PersonaId, IdChangeKeyMixIn, CompleteName, Attribution, EmailAddress, Address, FolderId
+from ..fields import (
+ Base64Field,
+ BodyContentAttributedValueField,
+ BooleanField,
+ CharField,
+ Choice,
+ ChoiceField,
+ DateTimeBackedDateField,
+ DateTimeField,
+ EmailAddressAttributedValueField,
+ EmailAddressesField,
+ EmailAddressField,
+ EWSElementField,
+ EWSElementListField,
+ IdElementField,
+ MailboxField,
+ MailboxListField,
+ MemberListField,
+ PersonaPhoneNumberField,
+ PhoneNumberAttributedValueField,
+ PhoneNumberField,
+ PhysicalAddressField,
+ PostalAddressAttributedValueField,
+ StringAttributedValueField,
+ TextField,
+ TextListField,
+ URIField,
+)
+from ..properties import Address, Attribution, CompleteName, EmailAddress, FolderId, IdChangeKeyMixIn, PersonaId
from ..util import TNS
from ..version import EXCHANGE_2010, EXCHANGE_2010_SP2
+from .item import Item
log = logging.getLogger(__name__)
@@ -46,193 +68,219 @@ Module exchangelib.items.contact
class Contact(Item):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/contact"""
- ELEMENT_NAME = 'Contact'
+ ELEMENT_NAME = "Contact"
- file_as = TextField(field_uri='contacts:FileAs')
- file_as_mapping = ChoiceField(field_uri='contacts:FileAsMapping', choices={
- Choice('None'), Choice('LastCommaFirst'), Choice('FirstSpaceLast'), Choice('Company'),
- Choice('LastCommaFirstCompany'), Choice('CompanyLastFirst'), Choice('LastFirst'),
- Choice('LastFirstCompany'), Choice('CompanyLastCommaFirst'), Choice('LastFirstSuffix'),
- Choice('LastSpaceFirstCompany'), Choice('CompanyLastSpaceFirst'), Choice('LastSpaceFirst'),
- Choice('DisplayName'), Choice('FirstName'), Choice('LastFirstMiddleSuffix'), Choice('LastName'),
- Choice('Empty'),
- })
- display_name = TextField(field_uri='contacts:DisplayName', is_required=True)
- given_name = CharField(field_uri='contacts:GivenName')
- initials = TextField(field_uri='contacts:Initials')
- middle_name = CharField(field_uri='contacts:MiddleName')
- nickname = TextField(field_uri='contacts:Nickname')
- complete_name = EWSElementField(field_uri='contacts:CompleteName', value_cls=CompleteName, is_read_only=True)
- company_name = TextField(field_uri='contacts:CompanyName')
- email_addresses = EmailAddressesField(field_uri='contacts:EmailAddress')
- physical_addresses = PhysicalAddressField(field_uri='contacts:PhysicalAddress')
- phone_numbers = PhoneNumberField(field_uri='contacts:PhoneNumber')
- assistant_name = TextField(field_uri='contacts:AssistantName')
- birthday = DateTimeBackedDateField(field_uri='contacts:Birthday', default_time=datetime.time(11, 59))
- business_homepage = URIField(field_uri='contacts:BusinessHomePage')
- children = TextListField(field_uri='contacts:Children')
- companies = TextListField(field_uri='contacts:Companies', is_searchable=False)
- contact_source = ChoiceField(field_uri='contacts:ContactSource', choices={
- Choice('Store'), Choice('ActiveDirectory')
- }, is_read_only=True)
- department = TextField(field_uri='contacts:Department')
- generation = TextField(field_uri='contacts:Generation')
- im_addresses = CharField(field_uri='contacts:ImAddresses', is_read_only=True)
- job_title = TextField(field_uri='contacts:JobTitle')
- manager = TextField(field_uri='contacts:Manager')
- mileage = TextField(field_uri='contacts:Mileage')
- office = TextField(field_uri='contacts:OfficeLocation')
- postal_address_index = ChoiceField(field_uri='contacts:PostalAddressIndex', choices={
- Choice('Business'), Choice('Home'), Choice('Other'), Choice('None')
- }, default='None', is_required_after_save=True)
- profession = TextField(field_uri='contacts:Profession')
- spouse_name = TextField(field_uri='contacts:SpouseName')
- surname = CharField(field_uri='contacts:Surname')
- wedding_anniversary = DateTimeBackedDateField(field_uri='contacts:WeddingAnniversary',
- default_time=datetime.time(11, 59))
- has_picture = BooleanField(field_uri='contacts:HasPicture', supported_from=EXCHANGE_2010, is_read_only=True)
- phonetic_full_name = TextField(field_uri='contacts:PhoneticFullName', supported_from=EXCHANGE_2010_SP2,
- is_read_only=True)
- phonetic_first_name = TextField(field_uri='contacts:PhoneticFirstName', supported_from=EXCHANGE_2010_SP2,
- is_read_only=True)
- phonetic_last_name = TextField(field_uri='contacts:PhoneticLastName', supported_from=EXCHANGE_2010_SP2,
- is_read_only=True)
- email_alias = EmailAddressField(field_uri='contacts:Alias', is_read_only=True,
- supported_from=EXCHANGE_2010_SP2)
+ file_as = TextField(field_uri="contacts:FileAs")
+ file_as_mapping = ChoiceField(
+ field_uri="contacts:FileAsMapping",
+ choices={
+ Choice("None"),
+ Choice("LastCommaFirst"),
+ Choice("FirstSpaceLast"),
+ Choice("Company"),
+ Choice("LastCommaFirstCompany"),
+ Choice("CompanyLastFirst"),
+ Choice("LastFirst"),
+ Choice("LastFirstCompany"),
+ Choice("CompanyLastCommaFirst"),
+ Choice("LastFirstSuffix"),
+ Choice("LastSpaceFirstCompany"),
+ Choice("CompanyLastSpaceFirst"),
+ Choice("LastSpaceFirst"),
+ Choice("DisplayName"),
+ Choice("FirstName"),
+ Choice("LastFirstMiddleSuffix"),
+ Choice("LastName"),
+ Choice("Empty"),
+ },
+ )
+ display_name = TextField(field_uri="contacts:DisplayName", is_required=True)
+ given_name = CharField(field_uri="contacts:GivenName")
+ initials = TextField(field_uri="contacts:Initials")
+ middle_name = CharField(field_uri="contacts:MiddleName")
+ nickname = TextField(field_uri="contacts:Nickname")
+ complete_name = EWSElementField(field_uri="contacts:CompleteName", value_cls=CompleteName, is_read_only=True)
+ company_name = TextField(field_uri="contacts:CompanyName")
+ email_addresses = EmailAddressesField(field_uri="contacts:EmailAddress")
+ physical_addresses = PhysicalAddressField(field_uri="contacts:PhysicalAddress")
+ phone_numbers = PhoneNumberField(field_uri="contacts:PhoneNumber")
+ assistant_name = TextField(field_uri="contacts:AssistantName")
+ birthday = DateTimeBackedDateField(field_uri="contacts:Birthday", default_time=datetime.time(11, 59))
+ business_homepage = URIField(field_uri="contacts:BusinessHomePage")
+ children = TextListField(field_uri="contacts:Children")
+ companies = TextListField(field_uri="contacts:Companies", is_searchable=False)
+ contact_source = ChoiceField(
+ field_uri="contacts:ContactSource", choices={Choice("Store"), Choice("ActiveDirectory")}, is_read_only=True
+ )
+ department = TextField(field_uri="contacts:Department")
+ generation = TextField(field_uri="contacts:Generation")
+ im_addresses = CharField(field_uri="contacts:ImAddresses", is_read_only=True)
+ job_title = TextField(field_uri="contacts:JobTitle")
+ manager = TextField(field_uri="contacts:Manager")
+ mileage = TextField(field_uri="contacts:Mileage")
+ office = TextField(field_uri="contacts:OfficeLocation")
+ postal_address_index = ChoiceField(
+ field_uri="contacts:PostalAddressIndex",
+ choices={Choice("Business"), Choice("Home"), Choice("Other"), Choice("None")},
+ default="None",
+ is_required_after_save=True,
+ )
+ profession = TextField(field_uri="contacts:Profession")
+ spouse_name = TextField(field_uri="contacts:SpouseName")
+ surname = CharField(field_uri="contacts:Surname")
+ wedding_anniversary = DateTimeBackedDateField(
+ field_uri="contacts:WeddingAnniversary", default_time=datetime.time(11, 59)
+ )
+ has_picture = BooleanField(field_uri="contacts:HasPicture", supported_from=EXCHANGE_2010, is_read_only=True)
+ phonetic_full_name = TextField(
+ field_uri="contacts:PhoneticFullName", supported_from=EXCHANGE_2010_SP2, is_read_only=True
+ )
+ phonetic_first_name = TextField(
+ field_uri="contacts:PhoneticFirstName", supported_from=EXCHANGE_2010_SP2, is_read_only=True
+ )
+ phonetic_last_name = TextField(
+ field_uri="contacts:PhoneticLastName", supported_from=EXCHANGE_2010_SP2, is_read_only=True
+ )
+ email_alias = EmailAddressField(field_uri="contacts:Alias", is_read_only=True, supported_from=EXCHANGE_2010_SP2)
# 'notes' is documented in MSDN but apparently unused. Writing to it raises ErrorInvalidPropertyRequest. OWA
# put entries into the 'notes' form field into the 'body' field.
- notes = CharField(field_uri='contacts:Notes', supported_from=EXCHANGE_2010_SP2, is_read_only=True)
+ notes = CharField(field_uri="contacts:Notes", supported_from=EXCHANGE_2010_SP2, is_read_only=True)
# 'photo' is documented in MSDN but apparently unused. Writing to it raises ErrorInvalidPropertyRequest. OWA
# adds photos as FileAttachments on the contact item (with 'is_contact_photo=True'), which automatically flips
# the 'has_picture' field.
- photo = Base64Field(field_uri='contacts:Photo', supported_from=EXCHANGE_2010_SP2, is_read_only=True)
- user_smime_certificate = Base64Field(field_uri='contacts:UserSMIMECertificate', supported_from=EXCHANGE_2010_SP2,
- is_read_only=True)
- ms_exchange_certificate = Base64Field(field_uri='contacts:MSExchangeCertificate', supported_from=EXCHANGE_2010_SP2,
- is_read_only=True)
- directory_id = TextField(field_uri='contacts:DirectoryId', supported_from=EXCHANGE_2010_SP2, is_read_only=True)
- manager_mailbox = MailboxField(field_uri='contacts:ManagerMailbox', supported_from=EXCHANGE_2010_SP2,
- is_read_only=True)
- direct_reports = MailboxListField(field_uri='contacts:DirectReports', supported_from=EXCHANGE_2010_SP2,
- is_read_only=True)
+ photo = Base64Field(field_uri="contacts:Photo", supported_from=EXCHANGE_2010_SP2, is_read_only=True)
+ user_smime_certificate = Base64Field(
+ field_uri="contacts:UserSMIMECertificate", supported_from=EXCHANGE_2010_SP2, is_read_only=True
+ )
+ ms_exchange_certificate = Base64Field(
+ field_uri="contacts:MSExchangeCertificate", supported_from=EXCHANGE_2010_SP2, is_read_only=True
+ )
+ directory_id = TextField(field_uri="contacts:DirectoryId", supported_from=EXCHANGE_2010_SP2, is_read_only=True)
+ manager_mailbox = MailboxField(
+ field_uri="contacts:ManagerMailbox", supported_from=EXCHANGE_2010_SP2, is_read_only=True
+ )
+ direct_reports = MailboxListField(
+ field_uri="contacts:DirectReports", supported_from=EXCHANGE_2010_SP2, is_read_only=True
+ )
class Persona(IdChangeKeyMixIn):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/persona"""
- ELEMENT_NAME = 'Persona'
+ ELEMENT_NAME = "Persona"
ID_ELEMENT_CLS = PersonaId
- _id = IdElementField(field_uri='persona:PersonaId', value_cls=ID_ELEMENT_CLS, namespace=TNS)
- persona_type = CharField(field_uri='persona:PersonaType')
- persona_object_type = TextField(field_uri='persona:PersonaObjectStatus')
- creation_time = DateTimeField(field_uri='persona:CreationTime')
- bodies = BodyContentAttributedValueField(field_uri='persona:Bodies')
- display_name_first_last_sort_key = TextField(field_uri='persona:DisplayNameFirstLastSortKey')
- display_name_last_first_sort_key = TextField(field_uri='persona:DisplayNameLastFirstSortKey')
- company_sort_key = TextField(field_uri='persona:CompanyNameSortKey')
- home_sort_key = TextField(field_uri='persona:HomeCitySortKey')
- work_city_sort_key = TextField(field_uri='persona:WorkCitySortKey')
- display_name_first_last_header = CharField(field_uri='persona:DisplayNameFirstLastHeader')
- display_name_last_first_header = CharField(field_uri='persona:DisplayNameLastFirstHeader')
- file_as_header = TextField(field_uri='persona:FileAsHeader')
- display_name = CharField(field_uri='persona:DisplayName')
- display_name_first_last = CharField(field_uri='persona:DisplayNameFirstLast')
- display_name_last_first = CharField(field_uri='persona:DisplayNameLastFirst')
- file_as = CharField(field_uri='persona:FileAs')
- file_as_id = TextField(field_uri='persona:FileAsId')
- display_name_prefix = CharField(field_uri='persona:DisplayNamePrefix')
- given_name = CharField(field_uri='persona:GivenName')
- middle_name = CharField(field_uri='persona:MiddleName')
- surname = CharField(field_uri='persona:Surname')
- generation = CharField(field_uri='persona:Generation')
- nickname = TextField(field_uri='persona:Nickname')
- yomi_company_name = TextField(field_uri='persona:YomiCompanyName')
- yomi_first_name = TextField(field_uri='persona:YomiFirstName')
- yomi_last_name = TextField(field_uri='persona:YomiLastName')
- title = CharField(field_uri='persona:Title')
- department = TextField(field_uri='persona:Department')
- company_name = CharField(field_uri='persona:CompanyName')
- email_address = EWSElementField(field_uri='persona:EmailAddress', value_cls=EmailAddress)
- email_addresses = EWSElementListField(field_uri='persona:EmailAddresses', value_cls=Address)
- PhoneNumber = PersonaPhoneNumberField(field_uri='persona:PhoneNumber')
- im_address = CharField(field_uri='persona:ImAddress')
- home_city = CharField(field_uri='persona:HomeCity')
- work_city = CharField(field_uri='persona:WorkCity')
- relevance_score = CharField(field_uri='persona:RelevanceScore')
- folder_ids = EWSElementListField(field_uri='persona:FolderIds', value_cls=FolderId)
- attributions = EWSElementListField(field_uri='persona:Attributions', value_cls=Attribution)
- display_names = StringAttributedValueField(field_uri='persona:DisplayNames')
- file_ases = StringAttributedValueField(field_uri='persona:FileAses')
- file_as_ids = StringAttributedValueField(field_uri='persona:FileAsIds')
- display_name_prefixes = StringAttributedValueField(field_uri='persona:DisplayNamePrefixes')
- given_names = StringAttributedValueField(field_uri='persona:GivenNames')
- middle_names = StringAttributedValueField(field_uri='persona:MiddleNames')
- surnames = StringAttributedValueField(field_uri='persona:Surnames')
- generations = StringAttributedValueField(field_uri='persona:Generations')
- nicknames = StringAttributedValueField(field_uri='persona:Nicknames')
- initials = StringAttributedValueField(field_uri='persona:Initials')
- yomi_company_names = StringAttributedValueField(field_uri='persona:YomiCompanyNames')
- yomi_first_names = StringAttributedValueField(field_uri='persona:YomiFirstNames')
- yomi_last_names = StringAttributedValueField(field_uri='persona:YomiLastNames')
- business_phone_numbers = PhoneNumberAttributedValueField(field_uri='persona:BusinessPhoneNumbers')
- business_phone_numbers2 = PhoneNumberAttributedValueField(field_uri='persona:BusinessPhoneNumbers2')
- home_phones = PhoneNumberAttributedValueField(field_uri='persona:HomePhones')
- home_phones2 = PhoneNumberAttributedValueField(field_uri='persona:HomePhones2')
- mobile_phones = PhoneNumberAttributedValueField(field_uri='persona:MobilePhones')
- mobile_phones2 = PhoneNumberAttributedValueField(field_uri='persona:MobilePhones2')
- assistant_phone_numbers = PhoneNumberAttributedValueField(field_uri='persona:AssistantPhoneNumbers')
- callback_phones = PhoneNumberAttributedValueField(field_uri='persona:CallbackPhones')
- car_phones = PhoneNumberAttributedValueField(field_uri='persona:CarPhones')
- home_faxes = PhoneNumberAttributedValueField(field_uri='persona:HomeFaxes')
- organization_main_phones = PhoneNumberAttributedValueField(field_uri='persona:OrganizationMainPhones')
- other_faxes = PhoneNumberAttributedValueField(field_uri='persona:OtherFaxes')
- other_telephones = PhoneNumberAttributedValueField(field_uri='persona:OtherTelephones')
- other_phones2 = PhoneNumberAttributedValueField(field_uri='persona:OtherPhones2')
- pagers = PhoneNumberAttributedValueField(field_uri='persona:Pagers')
- radio_phones = PhoneNumberAttributedValueField(field_uri='persona:RadioPhones')
- telex_numbers = PhoneNumberAttributedValueField(field_uri='persona:TelexNumbers')
- tty_tdd_phone_numbers = PhoneNumberAttributedValueField(field_uri='persona:TTYTDDPhoneNumbers')
- work_faxes = PhoneNumberAttributedValueField(field_uri='persona:WorkFaxes')
- emails1 = EmailAddressAttributedValueField(field_uri='persona:Emails1')
- emails2 = EmailAddressAttributedValueField(field_uri='persona:Emails2')
- emails3 = EmailAddressAttributedValueField(field_uri='persona:Emails3')
- business_home_pages = StringAttributedValueField(field_uri='persona:BusinessHomePages')
- personal_home_pages = StringAttributedValueField(field_uri='persona:PersonalHomePages')
- office_locations = StringAttributedValueField(field_uri='persona:OfficeLocations')
- im_addresses = StringAttributedValueField(field_uri='persona:ImAddresses')
- im_addresses2 = StringAttributedValueField(field_uri='persona:ImAddresses2')
- im_addresses3 = StringAttributedValueField(field_uri='persona:ImAddresses3')
- business_addresses = PostalAddressAttributedValueField(field_uri='persona:BusinessAddresses')
- home_addresses = PostalAddressAttributedValueField(field_uri='persona:HomeAddresses')
- other_addresses = PostalAddressAttributedValueField(field_uri='persona:OtherAddresses')
- titles = StringAttributedValueField(field_uri='persona:Titles')
- departments = StringAttributedValueField(field_uri='persona:Departments')
- company_names = StringAttributedValueField(field_uri='persona:CompanyNames')
- managers = StringAttributedValueField(field_uri='persona:Managers')
- assistant_names = StringAttributedValueField(field_uri='persona:AssistantNames')
- professions = StringAttributedValueField(field_uri='persona:Professions')
- spouse_names = StringAttributedValueField(field_uri='persona:SpouseNames')
- children = StringAttributedValueField(field_uri='persona:Children')
- schools = StringAttributedValueField(field_uri='persona:Schools')
- hobbies = StringAttributedValueField(field_uri='persona:Hobbies')
- wedding_anniversaries = StringAttributedValueField(field_uri='persona:WeddingAnniversaries')
- birthdays = StringAttributedValueField(field_uri='persona:Birthdays')
- locations = StringAttributedValueField(field_uri='persona:Locations')
- # ExtendedPropertyAttributedValueField('extended_properties', field_uri='persona:ExtendedProperties')
+ _id = IdElementField(field_uri="persona:PersonaId", value_cls=ID_ELEMENT_CLS, namespace=TNS)
+ persona_type = CharField(field_uri="persona:PersonaType")
+ persona_object_type = TextField(field_uri="persona:PersonaObjectStatus")
+ creation_time = DateTimeField(field_uri="persona:CreationTime")
+ bodies = BodyContentAttributedValueField(field_uri="persona:Bodies")
+ display_name_first_last_sort_key = TextField(field_uri="persona:DisplayNameFirstLastSortKey")
+ display_name_last_first_sort_key = TextField(field_uri="persona:DisplayNameLastFirstSortKey")
+ company_sort_key = TextField(field_uri="persona:CompanyNameSortKey")
+ home_sort_key = TextField(field_uri="persona:HomeCitySortKey")
+ work_city_sort_key = TextField(field_uri="persona:WorkCitySortKey")
+ display_name_first_last_header = CharField(field_uri="persona:DisplayNameFirstLastHeader")
+ display_name_last_first_header = CharField(field_uri="persona:DisplayNameLastFirstHeader")
+ file_as_header = TextField(field_uri="persona:FileAsHeader")
+ display_name = CharField(field_uri="persona:DisplayName")
+ display_name_first_last = CharField(field_uri="persona:DisplayNameFirstLast")
+ display_name_last_first = CharField(field_uri="persona:DisplayNameLastFirst")
+ file_as = CharField(field_uri="persona:FileAs")
+ file_as_id = TextField(field_uri="persona:FileAsId")
+ display_name_prefix = CharField(field_uri="persona:DisplayNamePrefix")
+ given_name = CharField(field_uri="persona:GivenName")
+ middle_name = CharField(field_uri="persona:MiddleName")
+ surname = CharField(field_uri="persona:Surname")
+ generation = CharField(field_uri="persona:Generation")
+ nickname = TextField(field_uri="persona:Nickname")
+ yomi_company_name = TextField(field_uri="persona:YomiCompanyName")
+ yomi_first_name = TextField(field_uri="persona:YomiFirstName")
+ yomi_last_name = TextField(field_uri="persona:YomiLastName")
+ title = CharField(field_uri="persona:Title")
+ department = TextField(field_uri="persona:Department")
+ company_name = CharField(field_uri="persona:CompanyName")
+ email_address = EWSElementField(field_uri="persona:EmailAddress", value_cls=EmailAddress)
+ email_addresses = EWSElementListField(field_uri="persona:EmailAddresses", value_cls=Address)
+ PhoneNumber = PersonaPhoneNumberField(field_uri="persona:PhoneNumber")
+ im_address = CharField(field_uri="persona:ImAddress")
+ home_city = CharField(field_uri="persona:HomeCity")
+ work_city = CharField(field_uri="persona:WorkCity")
+ relevance_score = CharField(field_uri="persona:RelevanceScore")
+ folder_ids = EWSElementListField(field_uri="persona:FolderIds", value_cls=FolderId)
+ attributions = EWSElementListField(field_uri="persona:Attributions", value_cls=Attribution)
+ display_names = StringAttributedValueField(field_uri="persona:DisplayNames")
+ file_ases = StringAttributedValueField(field_uri="persona:FileAses")
+ file_as_ids = StringAttributedValueField(field_uri="persona:FileAsIds")
+ display_name_prefixes = StringAttributedValueField(field_uri="persona:DisplayNamePrefixes")
+ given_names = StringAttributedValueField(field_uri="persona:GivenNames")
+ middle_names = StringAttributedValueField(field_uri="persona:MiddleNames")
+ surnames = StringAttributedValueField(field_uri="persona:Surnames")
+ generations = StringAttributedValueField(field_uri="persona:Generations")
+ nicknames = StringAttributedValueField(field_uri="persona:Nicknames")
+ initials = StringAttributedValueField(field_uri="persona:Initials")
+ yomi_company_names = StringAttributedValueField(field_uri="persona:YomiCompanyNames")
+ yomi_first_names = StringAttributedValueField(field_uri="persona:YomiFirstNames")
+ yomi_last_names = StringAttributedValueField(field_uri="persona:YomiLastNames")
+ business_phone_numbers = PhoneNumberAttributedValueField(field_uri="persona:BusinessPhoneNumbers")
+ business_phone_numbers2 = PhoneNumberAttributedValueField(field_uri="persona:BusinessPhoneNumbers2")
+ home_phones = PhoneNumberAttributedValueField(field_uri="persona:HomePhones")
+ home_phones2 = PhoneNumberAttributedValueField(field_uri="persona:HomePhones2")
+ mobile_phones = PhoneNumberAttributedValueField(field_uri="persona:MobilePhones")
+ mobile_phones2 = PhoneNumberAttributedValueField(field_uri="persona:MobilePhones2")
+ assistant_phone_numbers = PhoneNumberAttributedValueField(field_uri="persona:AssistantPhoneNumbers")
+ callback_phones = PhoneNumberAttributedValueField(field_uri="persona:CallbackPhones")
+ car_phones = PhoneNumberAttributedValueField(field_uri="persona:CarPhones")
+ home_faxes = PhoneNumberAttributedValueField(field_uri="persona:HomeFaxes")
+ organization_main_phones = PhoneNumberAttributedValueField(field_uri="persona:OrganizationMainPhones")
+ other_faxes = PhoneNumberAttributedValueField(field_uri="persona:OtherFaxes")
+ other_telephones = PhoneNumberAttributedValueField(field_uri="persona:OtherTelephones")
+ other_phones2 = PhoneNumberAttributedValueField(field_uri="persona:OtherPhones2")
+ pagers = PhoneNumberAttributedValueField(field_uri="persona:Pagers")
+ radio_phones = PhoneNumberAttributedValueField(field_uri="persona:RadioPhones")
+ telex_numbers = PhoneNumberAttributedValueField(field_uri="persona:TelexNumbers")
+ tty_tdd_phone_numbers = PhoneNumberAttributedValueField(field_uri="persona:TTYTDDPhoneNumbers")
+ work_faxes = PhoneNumberAttributedValueField(field_uri="persona:WorkFaxes")
+ emails1 = EmailAddressAttributedValueField(field_uri="persona:Emails1")
+ emails2 = EmailAddressAttributedValueField(field_uri="persona:Emails2")
+ emails3 = EmailAddressAttributedValueField(field_uri="persona:Emails3")
+ business_home_pages = StringAttributedValueField(field_uri="persona:BusinessHomePages")
+ personal_home_pages = StringAttributedValueField(field_uri="persona:PersonalHomePages")
+ office_locations = StringAttributedValueField(field_uri="persona:OfficeLocations")
+ im_addresses = StringAttributedValueField(field_uri="persona:ImAddresses")
+ im_addresses2 = StringAttributedValueField(field_uri="persona:ImAddresses2")
+ im_addresses3 = StringAttributedValueField(field_uri="persona:ImAddresses3")
+ business_addresses = PostalAddressAttributedValueField(field_uri="persona:BusinessAddresses")
+ home_addresses = PostalAddressAttributedValueField(field_uri="persona:HomeAddresses")
+ other_addresses = PostalAddressAttributedValueField(field_uri="persona:OtherAddresses")
+ titles = StringAttributedValueField(field_uri="persona:Titles")
+ departments = StringAttributedValueField(field_uri="persona:Departments")
+ company_names = StringAttributedValueField(field_uri="persona:CompanyNames")
+ managers = StringAttributedValueField(field_uri="persona:Managers")
+ assistant_names = StringAttributedValueField(field_uri="persona:AssistantNames")
+ professions = StringAttributedValueField(field_uri="persona:Professions")
+ spouse_names = StringAttributedValueField(field_uri="persona:SpouseNames")
+ children = StringAttributedValueField(field_uri="persona:Children")
+ schools = StringAttributedValueField(field_uri="persona:Schools")
+ hobbies = StringAttributedValueField(field_uri="persona:Hobbies")
+ wedding_anniversaries = StringAttributedValueField(field_uri="persona:WeddingAnniversaries")
+ birthdays = StringAttributedValueField(field_uri="persona:Birthdays")
+ locations = StringAttributedValueField(field_uri="persona:Locations")
+ # This class has an additional field of type "ExtendedPropertyAttributedValueField" and
+ # field_uri 'persona:ExtendedProperties'
class DistributionList(Item):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/distributionlist"""
- ELEMENT_NAME = 'DistributionList'
+ ELEMENT_NAME = "DistributionList"
- display_name = CharField(field_uri='contacts:DisplayName', is_required=True)
- file_as = CharField(field_uri='contacts:FileAs', is_read_only=True)
- contact_source = ChoiceField(field_uri='contacts:ContactSource', choices={
- Choice('Store'), Choice('ActiveDirectory')
- }, is_read_only=True)
- members = MemberListField(field_uri='distributionlist:Members')
+ display_name = CharField(field_uri="contacts:DisplayName", is_required=True)
+ file_as = CharField(field_uri="contacts:FileAs", is_read_only=True)
+ contact_source = ChoiceField(
+ field_uri="contacts:ContactSource", choices={Choice("Store"), Choice("ActiveDirectory")}, is_read_only=True
+ )
+ members = MemberListField(field_uri="distributionlist:Members")
class Contact(Item):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/contact"""
- ELEMENT_NAME = 'Contact'
+ ELEMENT_NAME = "Contact"
- file_as = TextField(field_uri='contacts:FileAs')
- file_as_mapping = ChoiceField(field_uri='contacts:FileAsMapping', choices={
- Choice('None'), Choice('LastCommaFirst'), Choice('FirstSpaceLast'), Choice('Company'),
- Choice('LastCommaFirstCompany'), Choice('CompanyLastFirst'), Choice('LastFirst'),
- Choice('LastFirstCompany'), Choice('CompanyLastCommaFirst'), Choice('LastFirstSuffix'),
- Choice('LastSpaceFirstCompany'), Choice('CompanyLastSpaceFirst'), Choice('LastSpaceFirst'),
- Choice('DisplayName'), Choice('FirstName'), Choice('LastFirstMiddleSuffix'), Choice('LastName'),
- Choice('Empty'),
- })
- display_name = TextField(field_uri='contacts:DisplayName', is_required=True)
- given_name = CharField(field_uri='contacts:GivenName')
- initials = TextField(field_uri='contacts:Initials')
- middle_name = CharField(field_uri='contacts:MiddleName')
- nickname = TextField(field_uri='contacts:Nickname')
- complete_name = EWSElementField(field_uri='contacts:CompleteName', value_cls=CompleteName, is_read_only=True)
- company_name = TextField(field_uri='contacts:CompanyName')
- email_addresses = EmailAddressesField(field_uri='contacts:EmailAddress')
- physical_addresses = PhysicalAddressField(field_uri='contacts:PhysicalAddress')
- phone_numbers = PhoneNumberField(field_uri='contacts:PhoneNumber')
- assistant_name = TextField(field_uri='contacts:AssistantName')
- birthday = DateTimeBackedDateField(field_uri='contacts:Birthday', default_time=datetime.time(11, 59))
- business_homepage = URIField(field_uri='contacts:BusinessHomePage')
- children = TextListField(field_uri='contacts:Children')
- companies = TextListField(field_uri='contacts:Companies', is_searchable=False)
- contact_source = ChoiceField(field_uri='contacts:ContactSource', choices={
- Choice('Store'), Choice('ActiveDirectory')
- }, is_read_only=True)
- department = TextField(field_uri='contacts:Department')
- generation = TextField(field_uri='contacts:Generation')
- im_addresses = CharField(field_uri='contacts:ImAddresses', is_read_only=True)
- job_title = TextField(field_uri='contacts:JobTitle')
- manager = TextField(field_uri='contacts:Manager')
- mileage = TextField(field_uri='contacts:Mileage')
- office = TextField(field_uri='contacts:OfficeLocation')
- postal_address_index = ChoiceField(field_uri='contacts:PostalAddressIndex', choices={
- Choice('Business'), Choice('Home'), Choice('Other'), Choice('None')
- }, default='None', is_required_after_save=True)
- profession = TextField(field_uri='contacts:Profession')
- spouse_name = TextField(field_uri='contacts:SpouseName')
- surname = CharField(field_uri='contacts:Surname')
- wedding_anniversary = DateTimeBackedDateField(field_uri='contacts:WeddingAnniversary',
- default_time=datetime.time(11, 59))
- has_picture = BooleanField(field_uri='contacts:HasPicture', supported_from=EXCHANGE_2010, is_read_only=True)
- phonetic_full_name = TextField(field_uri='contacts:PhoneticFullName', supported_from=EXCHANGE_2010_SP2,
- is_read_only=True)
- phonetic_first_name = TextField(field_uri='contacts:PhoneticFirstName', supported_from=EXCHANGE_2010_SP2,
- is_read_only=True)
- phonetic_last_name = TextField(field_uri='contacts:PhoneticLastName', supported_from=EXCHANGE_2010_SP2,
- is_read_only=True)
- email_alias = EmailAddressField(field_uri='contacts:Alias', is_read_only=True,
- supported_from=EXCHANGE_2010_SP2)
+ file_as = TextField(field_uri="contacts:FileAs")
+ file_as_mapping = ChoiceField(
+ field_uri="contacts:FileAsMapping",
+ choices={
+ Choice("None"),
+ Choice("LastCommaFirst"),
+ Choice("FirstSpaceLast"),
+ Choice("Company"),
+ Choice("LastCommaFirstCompany"),
+ Choice("CompanyLastFirst"),
+ Choice("LastFirst"),
+ Choice("LastFirstCompany"),
+ Choice("CompanyLastCommaFirst"),
+ Choice("LastFirstSuffix"),
+ Choice("LastSpaceFirstCompany"),
+ Choice("CompanyLastSpaceFirst"),
+ Choice("LastSpaceFirst"),
+ Choice("DisplayName"),
+ Choice("FirstName"),
+ Choice("LastFirstMiddleSuffix"),
+ Choice("LastName"),
+ Choice("Empty"),
+ },
+ )
+ display_name = TextField(field_uri="contacts:DisplayName", is_required=True)
+ given_name = CharField(field_uri="contacts:GivenName")
+ initials = TextField(field_uri="contacts:Initials")
+ middle_name = CharField(field_uri="contacts:MiddleName")
+ nickname = TextField(field_uri="contacts:Nickname")
+ complete_name = EWSElementField(field_uri="contacts:CompleteName", value_cls=CompleteName, is_read_only=True)
+ company_name = TextField(field_uri="contacts:CompanyName")
+ email_addresses = EmailAddressesField(field_uri="contacts:EmailAddress")
+ physical_addresses = PhysicalAddressField(field_uri="contacts:PhysicalAddress")
+ phone_numbers = PhoneNumberField(field_uri="contacts:PhoneNumber")
+ assistant_name = TextField(field_uri="contacts:AssistantName")
+ birthday = DateTimeBackedDateField(field_uri="contacts:Birthday", default_time=datetime.time(11, 59))
+ business_homepage = URIField(field_uri="contacts:BusinessHomePage")
+ children = TextListField(field_uri="contacts:Children")
+ companies = TextListField(field_uri="contacts:Companies", is_searchable=False)
+ contact_source = ChoiceField(
+ field_uri="contacts:ContactSource", choices={Choice("Store"), Choice("ActiveDirectory")}, is_read_only=True
+ )
+ department = TextField(field_uri="contacts:Department")
+ generation = TextField(field_uri="contacts:Generation")
+ im_addresses = CharField(field_uri="contacts:ImAddresses", is_read_only=True)
+ job_title = TextField(field_uri="contacts:JobTitle")
+ manager = TextField(field_uri="contacts:Manager")
+ mileage = TextField(field_uri="contacts:Mileage")
+ office = TextField(field_uri="contacts:OfficeLocation")
+ postal_address_index = ChoiceField(
+ field_uri="contacts:PostalAddressIndex",
+ choices={Choice("Business"), Choice("Home"), Choice("Other"), Choice("None")},
+ default="None",
+ is_required_after_save=True,
+ )
+ profession = TextField(field_uri="contacts:Profession")
+ spouse_name = TextField(field_uri="contacts:SpouseName")
+ surname = CharField(field_uri="contacts:Surname")
+ wedding_anniversary = DateTimeBackedDateField(
+ field_uri="contacts:WeddingAnniversary", default_time=datetime.time(11, 59)
+ )
+ has_picture = BooleanField(field_uri="contacts:HasPicture", supported_from=EXCHANGE_2010, is_read_only=True)
+ phonetic_full_name = TextField(
+ field_uri="contacts:PhoneticFullName", supported_from=EXCHANGE_2010_SP2, is_read_only=True
+ )
+ phonetic_first_name = TextField(
+ field_uri="contacts:PhoneticFirstName", supported_from=EXCHANGE_2010_SP2, is_read_only=True
+ )
+ phonetic_last_name = TextField(
+ field_uri="contacts:PhoneticLastName", supported_from=EXCHANGE_2010_SP2, is_read_only=True
+ )
+ email_alias = EmailAddressField(field_uri="contacts:Alias", is_read_only=True, supported_from=EXCHANGE_2010_SP2)
# 'notes' is documented in MSDN but apparently unused. Writing to it raises ErrorInvalidPropertyRequest. OWA
# put entries into the 'notes' form field into the 'body' field.
- notes = CharField(field_uri='contacts:Notes', supported_from=EXCHANGE_2010_SP2, is_read_only=True)
+ notes = CharField(field_uri="contacts:Notes", supported_from=EXCHANGE_2010_SP2, is_read_only=True)
# 'photo' is documented in MSDN but apparently unused. Writing to it raises ErrorInvalidPropertyRequest. OWA
# adds photos as FileAttachments on the contact item (with 'is_contact_photo=True'), which automatically flips
# the 'has_picture' field.
- photo = Base64Field(field_uri='contacts:Photo', supported_from=EXCHANGE_2010_SP2, is_read_only=True)
- user_smime_certificate = Base64Field(field_uri='contacts:UserSMIMECertificate', supported_from=EXCHANGE_2010_SP2,
- is_read_only=True)
- ms_exchange_certificate = Base64Field(field_uri='contacts:MSExchangeCertificate', supported_from=EXCHANGE_2010_SP2,
- is_read_only=True)
- directory_id = TextField(field_uri='contacts:DirectoryId', supported_from=EXCHANGE_2010_SP2, is_read_only=True)
- manager_mailbox = MailboxField(field_uri='contacts:ManagerMailbox', supported_from=EXCHANGE_2010_SP2,
- is_read_only=True)
- direct_reports = MailboxListField(field_uri='contacts:DirectReports', supported_from=EXCHANGE_2010_SP2,
- is_read_only=True)
+ photo = Base64Field(field_uri="contacts:Photo", supported_from=EXCHANGE_2010_SP2, is_read_only=True)
+ user_smime_certificate = Base64Field(
+ field_uri="contacts:UserSMIMECertificate", supported_from=EXCHANGE_2010_SP2, is_read_only=True
+ )
+ ms_exchange_certificate = Base64Field(
+ field_uri="contacts:MSExchangeCertificate", supported_from=EXCHANGE_2010_SP2, is_read_only=True
+ )
+ directory_id = TextField(field_uri="contacts:DirectoryId", supported_from=EXCHANGE_2010_SP2, is_read_only=True)
+ manager_mailbox = MailboxField(
+ field_uri="contacts:ManagerMailbox", supported_from=EXCHANGE_2010_SP2, is_read_only=True
+ )
+ direct_reports = MailboxListField(
+ field_uri="contacts:DirectReports", supported_from=EXCHANGE_2010_SP2, is_read_only=True
+ )
class DistributionList(Item):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/distributionlist"""
- ELEMENT_NAME = 'DistributionList'
+ ELEMENT_NAME = "DistributionList"
- display_name = CharField(field_uri='contacts:DisplayName', is_required=True)
- file_as = CharField(field_uri='contacts:FileAs', is_read_only=True)
- contact_source = ChoiceField(field_uri='contacts:ContactSource', choices={
- Choice('Store'), Choice('ActiveDirectory')
- }, is_read_only=True)
- members = MemberListField(field_uri='distributionlist:Members')
+ display_name = CharField(field_uri="contacts:DisplayName", is_required=True)
+ file_as = CharField(field_uri="contacts:FileAs", is_read_only=True)
+ contact_source = ChoiceField(
+ field_uri="contacts:ContactSource", choices={Choice("Store"), Choice("ActiveDirectory")}, is_read_only=True
+ )
+ members = MemberListField(field_uri="distributionlist:Members")
class Persona(IdChangeKeyMixIn):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/persona"""
- ELEMENT_NAME = 'Persona'
+ ELEMENT_NAME = "Persona"
ID_ELEMENT_CLS = PersonaId
- _id = IdElementField(field_uri='persona:PersonaId', value_cls=ID_ELEMENT_CLS, namespace=TNS)
- persona_type = CharField(field_uri='persona:PersonaType')
- persona_object_type = TextField(field_uri='persona:PersonaObjectStatus')
- creation_time = DateTimeField(field_uri='persona:CreationTime')
- bodies = BodyContentAttributedValueField(field_uri='persona:Bodies')
- display_name_first_last_sort_key = TextField(field_uri='persona:DisplayNameFirstLastSortKey')
- display_name_last_first_sort_key = TextField(field_uri='persona:DisplayNameLastFirstSortKey')
- company_sort_key = TextField(field_uri='persona:CompanyNameSortKey')
- home_sort_key = TextField(field_uri='persona:HomeCitySortKey')
- work_city_sort_key = TextField(field_uri='persona:WorkCitySortKey')
- display_name_first_last_header = CharField(field_uri='persona:DisplayNameFirstLastHeader')
- display_name_last_first_header = CharField(field_uri='persona:DisplayNameLastFirstHeader')
- file_as_header = TextField(field_uri='persona:FileAsHeader')
- display_name = CharField(field_uri='persona:DisplayName')
- display_name_first_last = CharField(field_uri='persona:DisplayNameFirstLast')
- display_name_last_first = CharField(field_uri='persona:DisplayNameLastFirst')
- file_as = CharField(field_uri='persona:FileAs')
- file_as_id = TextField(field_uri='persona:FileAsId')
- display_name_prefix = CharField(field_uri='persona:DisplayNamePrefix')
- given_name = CharField(field_uri='persona:GivenName')
- middle_name = CharField(field_uri='persona:MiddleName')
- surname = CharField(field_uri='persona:Surname')
- generation = CharField(field_uri='persona:Generation')
- nickname = TextField(field_uri='persona:Nickname')
- yomi_company_name = TextField(field_uri='persona:YomiCompanyName')
- yomi_first_name = TextField(field_uri='persona:YomiFirstName')
- yomi_last_name = TextField(field_uri='persona:YomiLastName')
- title = CharField(field_uri='persona:Title')
- department = TextField(field_uri='persona:Department')
- company_name = CharField(field_uri='persona:CompanyName')
- email_address = EWSElementField(field_uri='persona:EmailAddress', value_cls=EmailAddress)
- email_addresses = EWSElementListField(field_uri='persona:EmailAddresses', value_cls=Address)
- PhoneNumber = PersonaPhoneNumberField(field_uri='persona:PhoneNumber')
- im_address = CharField(field_uri='persona:ImAddress')
- home_city = CharField(field_uri='persona:HomeCity')
- work_city = CharField(field_uri='persona:WorkCity')
- relevance_score = CharField(field_uri='persona:RelevanceScore')
- folder_ids = EWSElementListField(field_uri='persona:FolderIds', value_cls=FolderId)
- attributions = EWSElementListField(field_uri='persona:Attributions', value_cls=Attribution)
- display_names = StringAttributedValueField(field_uri='persona:DisplayNames')
- file_ases = StringAttributedValueField(field_uri='persona:FileAses')
- file_as_ids = StringAttributedValueField(field_uri='persona:FileAsIds')
- display_name_prefixes = StringAttributedValueField(field_uri='persona:DisplayNamePrefixes')
- given_names = StringAttributedValueField(field_uri='persona:GivenNames')
- middle_names = StringAttributedValueField(field_uri='persona:MiddleNames')
- surnames = StringAttributedValueField(field_uri='persona:Surnames')
- generations = StringAttributedValueField(field_uri='persona:Generations')
- nicknames = StringAttributedValueField(field_uri='persona:Nicknames')
- initials = StringAttributedValueField(field_uri='persona:Initials')
- yomi_company_names = StringAttributedValueField(field_uri='persona:YomiCompanyNames')
- yomi_first_names = StringAttributedValueField(field_uri='persona:YomiFirstNames')
- yomi_last_names = StringAttributedValueField(field_uri='persona:YomiLastNames')
- business_phone_numbers = PhoneNumberAttributedValueField(field_uri='persona:BusinessPhoneNumbers')
- business_phone_numbers2 = PhoneNumberAttributedValueField(field_uri='persona:BusinessPhoneNumbers2')
- home_phones = PhoneNumberAttributedValueField(field_uri='persona:HomePhones')
- home_phones2 = PhoneNumberAttributedValueField(field_uri='persona:HomePhones2')
- mobile_phones = PhoneNumberAttributedValueField(field_uri='persona:MobilePhones')
- mobile_phones2 = PhoneNumberAttributedValueField(field_uri='persona:MobilePhones2')
- assistant_phone_numbers = PhoneNumberAttributedValueField(field_uri='persona:AssistantPhoneNumbers')
- callback_phones = PhoneNumberAttributedValueField(field_uri='persona:CallbackPhones')
- car_phones = PhoneNumberAttributedValueField(field_uri='persona:CarPhones')
- home_faxes = PhoneNumberAttributedValueField(field_uri='persona:HomeFaxes')
- organization_main_phones = PhoneNumberAttributedValueField(field_uri='persona:OrganizationMainPhones')
- other_faxes = PhoneNumberAttributedValueField(field_uri='persona:OtherFaxes')
- other_telephones = PhoneNumberAttributedValueField(field_uri='persona:OtherTelephones')
- other_phones2 = PhoneNumberAttributedValueField(field_uri='persona:OtherPhones2')
- pagers = PhoneNumberAttributedValueField(field_uri='persona:Pagers')
- radio_phones = PhoneNumberAttributedValueField(field_uri='persona:RadioPhones')
- telex_numbers = PhoneNumberAttributedValueField(field_uri='persona:TelexNumbers')
- tty_tdd_phone_numbers = PhoneNumberAttributedValueField(field_uri='persona:TTYTDDPhoneNumbers')
- work_faxes = PhoneNumberAttributedValueField(field_uri='persona:WorkFaxes')
- emails1 = EmailAddressAttributedValueField(field_uri='persona:Emails1')
- emails2 = EmailAddressAttributedValueField(field_uri='persona:Emails2')
- emails3 = EmailAddressAttributedValueField(field_uri='persona:Emails3')
- business_home_pages = StringAttributedValueField(field_uri='persona:BusinessHomePages')
- personal_home_pages = StringAttributedValueField(field_uri='persona:PersonalHomePages')
- office_locations = StringAttributedValueField(field_uri='persona:OfficeLocations')
- im_addresses = StringAttributedValueField(field_uri='persona:ImAddresses')
- im_addresses2 = StringAttributedValueField(field_uri='persona:ImAddresses2')
- im_addresses3 = StringAttributedValueField(field_uri='persona:ImAddresses3')
- business_addresses = PostalAddressAttributedValueField(field_uri='persona:BusinessAddresses')
- home_addresses = PostalAddressAttributedValueField(field_uri='persona:HomeAddresses')
- other_addresses = PostalAddressAttributedValueField(field_uri='persona:OtherAddresses')
- titles = StringAttributedValueField(field_uri='persona:Titles')
- departments = StringAttributedValueField(field_uri='persona:Departments')
- company_names = StringAttributedValueField(field_uri='persona:CompanyNames')
- managers = StringAttributedValueField(field_uri='persona:Managers')
- assistant_names = StringAttributedValueField(field_uri='persona:AssistantNames')
- professions = StringAttributedValueField(field_uri='persona:Professions')
- spouse_names = StringAttributedValueField(field_uri='persona:SpouseNames')
- children = StringAttributedValueField(field_uri='persona:Children')
- schools = StringAttributedValueField(field_uri='persona:Schools')
- hobbies = StringAttributedValueField(field_uri='persona:Hobbies')
- wedding_anniversaries = StringAttributedValueField(field_uri='persona:WeddingAnniversaries')
- birthdays = StringAttributedValueField(field_uri='persona:Birthdays')
- locations = StringAttributedValueField(field_uri='persona:Locations')
+ _id = IdElementField(field_uri="persona:PersonaId", value_cls=ID_ELEMENT_CLS, namespace=TNS)
+ persona_type = CharField(field_uri="persona:PersonaType")
+ persona_object_type = TextField(field_uri="persona:PersonaObjectStatus")
+ creation_time = DateTimeField(field_uri="persona:CreationTime")
+ bodies = BodyContentAttributedValueField(field_uri="persona:Bodies")
+ display_name_first_last_sort_key = TextField(field_uri="persona:DisplayNameFirstLastSortKey")
+ display_name_last_first_sort_key = TextField(field_uri="persona:DisplayNameLastFirstSortKey")
+ company_sort_key = TextField(field_uri="persona:CompanyNameSortKey")
+ home_sort_key = TextField(field_uri="persona:HomeCitySortKey")
+ work_city_sort_key = TextField(field_uri="persona:WorkCitySortKey")
+ display_name_first_last_header = CharField(field_uri="persona:DisplayNameFirstLastHeader")
+ display_name_last_first_header = CharField(field_uri="persona:DisplayNameLastFirstHeader")
+ file_as_header = TextField(field_uri="persona:FileAsHeader")
+ display_name = CharField(field_uri="persona:DisplayName")
+ display_name_first_last = CharField(field_uri="persona:DisplayNameFirstLast")
+ display_name_last_first = CharField(field_uri="persona:DisplayNameLastFirst")
+ file_as = CharField(field_uri="persona:FileAs")
+ file_as_id = TextField(field_uri="persona:FileAsId")
+ display_name_prefix = CharField(field_uri="persona:DisplayNamePrefix")
+ given_name = CharField(field_uri="persona:GivenName")
+ middle_name = CharField(field_uri="persona:MiddleName")
+ surname = CharField(field_uri="persona:Surname")
+ generation = CharField(field_uri="persona:Generation")
+ nickname = TextField(field_uri="persona:Nickname")
+ yomi_company_name = TextField(field_uri="persona:YomiCompanyName")
+ yomi_first_name = TextField(field_uri="persona:YomiFirstName")
+ yomi_last_name = TextField(field_uri="persona:YomiLastName")
+ title = CharField(field_uri="persona:Title")
+ department = TextField(field_uri="persona:Department")
+ company_name = CharField(field_uri="persona:CompanyName")
+ email_address = EWSElementField(field_uri="persona:EmailAddress", value_cls=EmailAddress)
+ email_addresses = EWSElementListField(field_uri="persona:EmailAddresses", value_cls=Address)
+ PhoneNumber = PersonaPhoneNumberField(field_uri="persona:PhoneNumber")
+ im_address = CharField(field_uri="persona:ImAddress")
+ home_city = CharField(field_uri="persona:HomeCity")
+ work_city = CharField(field_uri="persona:WorkCity")
+ relevance_score = CharField(field_uri="persona:RelevanceScore")
+ folder_ids = EWSElementListField(field_uri="persona:FolderIds", value_cls=FolderId)
+ attributions = EWSElementListField(field_uri="persona:Attributions", value_cls=Attribution)
+ display_names = StringAttributedValueField(field_uri="persona:DisplayNames")
+ file_ases = StringAttributedValueField(field_uri="persona:FileAses")
+ file_as_ids = StringAttributedValueField(field_uri="persona:FileAsIds")
+ display_name_prefixes = StringAttributedValueField(field_uri="persona:DisplayNamePrefixes")
+ given_names = StringAttributedValueField(field_uri="persona:GivenNames")
+ middle_names = StringAttributedValueField(field_uri="persona:MiddleNames")
+ surnames = StringAttributedValueField(field_uri="persona:Surnames")
+ generations = StringAttributedValueField(field_uri="persona:Generations")
+ nicknames = StringAttributedValueField(field_uri="persona:Nicknames")
+ initials = StringAttributedValueField(field_uri="persona:Initials")
+ yomi_company_names = StringAttributedValueField(field_uri="persona:YomiCompanyNames")
+ yomi_first_names = StringAttributedValueField(field_uri="persona:YomiFirstNames")
+ yomi_last_names = StringAttributedValueField(field_uri="persona:YomiLastNames")
+ business_phone_numbers = PhoneNumberAttributedValueField(field_uri="persona:BusinessPhoneNumbers")
+ business_phone_numbers2 = PhoneNumberAttributedValueField(field_uri="persona:BusinessPhoneNumbers2")
+ home_phones = PhoneNumberAttributedValueField(field_uri="persona:HomePhones")
+ home_phones2 = PhoneNumberAttributedValueField(field_uri="persona:HomePhones2")
+ mobile_phones = PhoneNumberAttributedValueField(field_uri="persona:MobilePhones")
+ mobile_phones2 = PhoneNumberAttributedValueField(field_uri="persona:MobilePhones2")
+ assistant_phone_numbers = PhoneNumberAttributedValueField(field_uri="persona:AssistantPhoneNumbers")
+ callback_phones = PhoneNumberAttributedValueField(field_uri="persona:CallbackPhones")
+ car_phones = PhoneNumberAttributedValueField(field_uri="persona:CarPhones")
+ home_faxes = PhoneNumberAttributedValueField(field_uri="persona:HomeFaxes")
+ organization_main_phones = PhoneNumberAttributedValueField(field_uri="persona:OrganizationMainPhones")
+ other_faxes = PhoneNumberAttributedValueField(field_uri="persona:OtherFaxes")
+ other_telephones = PhoneNumberAttributedValueField(field_uri="persona:OtherTelephones")
+ other_phones2 = PhoneNumberAttributedValueField(field_uri="persona:OtherPhones2")
+ pagers = PhoneNumberAttributedValueField(field_uri="persona:Pagers")
+ radio_phones = PhoneNumberAttributedValueField(field_uri="persona:RadioPhones")
+ telex_numbers = PhoneNumberAttributedValueField(field_uri="persona:TelexNumbers")
+ tty_tdd_phone_numbers = PhoneNumberAttributedValueField(field_uri="persona:TTYTDDPhoneNumbers")
+ work_faxes = PhoneNumberAttributedValueField(field_uri="persona:WorkFaxes")
+ emails1 = EmailAddressAttributedValueField(field_uri="persona:Emails1")
+ emails2 = EmailAddressAttributedValueField(field_uri="persona:Emails2")
+ emails3 = EmailAddressAttributedValueField(field_uri="persona:Emails3")
+ business_home_pages = StringAttributedValueField(field_uri="persona:BusinessHomePages")
+ personal_home_pages = StringAttributedValueField(field_uri="persona:PersonalHomePages")
+ office_locations = StringAttributedValueField(field_uri="persona:OfficeLocations")
+ im_addresses = StringAttributedValueField(field_uri="persona:ImAddresses")
+ im_addresses2 = StringAttributedValueField(field_uri="persona:ImAddresses2")
+ im_addresses3 = StringAttributedValueField(field_uri="persona:ImAddresses3")
+ business_addresses = PostalAddressAttributedValueField(field_uri="persona:BusinessAddresses")
+ home_addresses = PostalAddressAttributedValueField(field_uri="persona:HomeAddresses")
+ other_addresses = PostalAddressAttributedValueField(field_uri="persona:OtherAddresses")
+ titles = StringAttributedValueField(field_uri="persona:Titles")
+ departments = StringAttributedValueField(field_uri="persona:Departments")
+ company_names = StringAttributedValueField(field_uri="persona:CompanyNames")
+ managers = StringAttributedValueField(field_uri="persona:Managers")
+ assistant_names = StringAttributedValueField(field_uri="persona:AssistantNames")
+ professions = StringAttributedValueField(field_uri="persona:Professions")
+ spouse_names = StringAttributedValueField(field_uri="persona:SpouseNames")
+ children = StringAttributedValueField(field_uri="persona:Children")
+ schools = StringAttributedValueField(field_uri="persona:Schools")
+ hobbies = StringAttributedValueField(field_uri="persona:Hobbies")
+ wedding_anniversaries = StringAttributedValueField(field_uri="persona:WeddingAnniversaries")
+ birthdays = StringAttributedValueField(field_uri="persona:Birthdays")
+ locations = StringAttributedValueField(field_uri="persona:Locations")
exchangelib.items
from .base import RegisterMixIn, BulkCreateResult, MESSAGE_DISPOSITION_CHOICES, SAVE_ONLY, SEND_ONLY, \
- ID_ONLY, DEFAULT, ALL_PROPERTIES, SEND_MEETING_INVITATIONS_CHOICES, SEND_TO_NONE, SEND_ONLY_TO_ALL, \
- SEND_MEETING_INVITATIONS_AND_CANCELLATIONS_CHOICES, SEND_ONLY_TO_CHANGED, SEND_TO_CHANGED_AND_SAVE_COPY, \
- SEND_MEETING_CANCELLATIONS_CHOICES, AFFECTED_TASK_OCCURRENCES_CHOICES, ALL_OCCURRENCES, \
- SPECIFIED_OCCURRENCE_ONLY, CONFLICT_RESOLUTION_CHOICES, NEVER_OVERWRITE, AUTO_RESOLVE, ALWAYS_OVERWRITE, \
- DELETE_TYPE_CHOICES, HARD_DELETE, SOFT_DELETE, MOVE_TO_DELETED_ITEMS, SEND_TO_ALL_AND_SAVE_COPY, \
- SEND_AND_SAVE_COPY, SHAPE_CHOICES
-from .calendar_item import CalendarItem, AcceptItem, TentativelyAcceptItem, DeclineItem, CancelCalendarItem, \
- MeetingMessage, MeetingRequest, MeetingResponse, MeetingCancellation, CONFERENCE_TYPES
-from .contact import Contact, Persona, DistributionList
+from .base import (
+ AFFECTED_TASK_OCCURRENCES_CHOICES,
+ ALL_OCCURRENCES,
+ ALL_PROPERTIES,
+ ALWAYS_OVERWRITE,
+ AUTO_RESOLVE,
+ CONFLICT_RESOLUTION_CHOICES,
+ DEFAULT,
+ DELETE_TYPE_CHOICES,
+ HARD_DELETE,
+ ID_ONLY,
+ MESSAGE_DISPOSITION_CHOICES,
+ MOVE_TO_DELETED_ITEMS,
+ NEVER_OVERWRITE,
+ SAVE_ONLY,
+ SEND_AND_SAVE_COPY,
+ SEND_MEETING_CANCELLATIONS_CHOICES,
+ SEND_MEETING_INVITATIONS_AND_CANCELLATIONS_CHOICES,
+ SEND_MEETING_INVITATIONS_CHOICES,
+ SEND_ONLY,
+ SEND_ONLY_TO_ALL,
+ SEND_ONLY_TO_CHANGED,
+ SEND_TO_ALL_AND_SAVE_COPY,
+ SEND_TO_CHANGED_AND_SAVE_COPY,
+ SEND_TO_NONE,
+ SHAPE_CHOICES,
+ SOFT_DELETE,
+ SPECIFIED_OCCURRENCE_ONLY,
+ BulkCreateResult,
+ RegisterMixIn,
+)
+from .calendar_item import (
+ CONFERENCE_TYPES,
+ AcceptItem,
+ CalendarItem,
+ CancelCalendarItem,
+ DeclineItem,
+ MeetingCancellation,
+ MeetingMessage,
+ MeetingRequest,
+ MeetingResponse,
+ TentativelyAcceptItem,
+)
+from .contact import Contact, DistributionList, Persona
from .item import BaseItem, Item
-from .message import Message, ReplyToItem, ReplyAllToItem, ForwardItem
+from .message import ForwardItem, Message, ReplyAllToItem, ReplyToItem
from .post import PostItem, PostReplyItem
from .task import Task
# Traversal enums
-SHALLOW = 'Shallow'
-SOFT_DELETED = 'SoftDeleted'
-ASSOCIATED = 'Associated'
+SHALLOW = "Shallow"
+SOFT_DELETED = "SoftDeleted"
+ASSOCIATED = "Associated"
ITEM_TRAVERSAL_CHOICES = (SHALLOW, SOFT_DELETED, ASSOCIATED)
# Contacts search (ResolveNames) scope enums
-ACTIVE_DIRECTORY = 'ActiveDirectory'
-ACTIVE_DIRECTORY_CONTACTS = 'ActiveDirectoryContacts'
-CONTACTS = 'Contacts'
-CONTACTS_ACTIVE_DIRECTORY = 'ContactsActiveDirectory'
+ACTIVE_DIRECTORY = "ActiveDirectory"
+ACTIVE_DIRECTORY_CONTACTS = "ActiveDirectoryContacts"
+CONTACTS = "Contacts"
+CONTACTS_ACTIVE_DIRECTORY = "ContactsActiveDirectory"
SEARCH_SCOPE_CHOICES = (ACTIVE_DIRECTORY, ACTIVE_DIRECTORY_CONTACTS, CONTACTS, CONTACTS_ACTIVE_DIRECTORY)
-ITEM_CLASSES = (CalendarItem, Contact, DistributionList, Item, Message, MeetingMessage, MeetingRequest,
- MeetingResponse, MeetingCancellation, PostItem, Task)
+ITEM_CLASSES = (
+ CalendarItem,
+ Contact,
+ DistributionList,
+ Item,
+ Message,
+ MeetingMessage,
+ MeetingRequest,
+ MeetingResponse,
+ MeetingCancellation,
+ PostItem,
+ Task,
+)
__all__ = [
- 'RegisterMixIn', 'MESSAGE_DISPOSITION_CHOICES', 'SAVE_ONLY', 'SEND_ONLY', 'SEND_AND_SAVE_COPY',
- 'CalendarItem', 'AcceptItem', 'TentativelyAcceptItem', 'DeclineItem', 'CancelCalendarItem',
- 'MeetingRequest', 'MeetingResponse', 'MeetingCancellation', 'CONFERENCE_TYPES',
- 'Contact', 'Persona', 'DistributionList',
- 'SEND_MEETING_INVITATIONS_CHOICES', 'SEND_TO_NONE', 'SEND_ONLY_TO_ALL', 'SEND_TO_ALL_AND_SAVE_COPY',
- 'SEND_MEETING_INVITATIONS_AND_CANCELLATIONS_CHOICES', 'SEND_ONLY_TO_CHANGED', 'SEND_TO_CHANGED_AND_SAVE_COPY',
- 'SEND_MEETING_CANCELLATIONS_CHOICES', 'AFFECTED_TASK_OCCURRENCES_CHOICES', 'ALL_OCCURRENCES',
- 'SPECIFIED_OCCURRENCE_ONLY', 'CONFLICT_RESOLUTION_CHOICES', 'NEVER_OVERWRITE', 'AUTO_RESOLVE', 'ALWAYS_OVERWRITE',
- 'DELETE_TYPE_CHOICES', 'HARD_DELETE', 'SOFT_DELETE', 'MOVE_TO_DELETED_ITEMS', 'BaseItem', 'Item',
- 'BulkCreateResult',
- 'Message', 'ReplyToItem', 'ReplyAllToItem', 'ForwardItem',
- 'PostItem', 'PostReplyItem',
- 'Task',
- 'ITEM_TRAVERSAL_CHOICES', 'SHALLOW', 'SOFT_DELETED', 'ASSOCIATED',
- 'SHAPE_CHOICES', 'ID_ONLY', 'DEFAULT', 'ALL_PROPERTIES',
- 'SEARCH_SCOPE_CHOICES', 'ACTIVE_DIRECTORY', 'ACTIVE_DIRECTORY_CONTACTS', 'CONTACTS', 'CONTACTS_ACTIVE_DIRECTORY',
- 'ITEM_CLASSES',
+ "RegisterMixIn",
+ "MESSAGE_DISPOSITION_CHOICES",
+ "SAVE_ONLY",
+ "SEND_ONLY",
+ "SEND_AND_SAVE_COPY",
+ "CalendarItem",
+ "AcceptItem",
+ "TentativelyAcceptItem",
+ "DeclineItem",
+ "CancelCalendarItem",
+ "MeetingRequest",
+ "MeetingResponse",
+ "MeetingCancellation",
+ "CONFERENCE_TYPES",
+ "Contact",
+ "Persona",
+ "DistributionList",
+ "SEND_MEETING_INVITATIONS_CHOICES",
+ "SEND_TO_NONE",
+ "SEND_ONLY_TO_ALL",
+ "SEND_TO_ALL_AND_SAVE_COPY",
+ "SEND_MEETING_INVITATIONS_AND_CANCELLATIONS_CHOICES",
+ "SEND_ONLY_TO_CHANGED",
+ "SEND_TO_CHANGED_AND_SAVE_COPY",
+ "SEND_MEETING_CANCELLATIONS_CHOICES",
+ "AFFECTED_TASK_OCCURRENCES_CHOICES",
+ "ALL_OCCURRENCES",
+ "SPECIFIED_OCCURRENCE_ONLY",
+ "CONFLICT_RESOLUTION_CHOICES",
+ "NEVER_OVERWRITE",
+ "AUTO_RESOLVE",
+ "ALWAYS_OVERWRITE",
+ "DELETE_TYPE_CHOICES",
+ "HARD_DELETE",
+ "SOFT_DELETE",
+ "MOVE_TO_DELETED_ITEMS",
+ "BaseItem",
+ "Item",
+ "BulkCreateResult",
+ "Message",
+ "ReplyToItem",
+ "ReplyAllToItem",
+ "ForwardItem",
+ "PostItem",
+ "PostReplyItem",
+ "Task",
+ "ITEM_TRAVERSAL_CHOICES",
+ "SHALLOW",
+ "SOFT_DELETED",
+ "ASSOCIATED",
+ "SHAPE_CHOICES",
+ "ID_ONLY",
+ "DEFAULT",
+ "ALL_PROPERTIES",
+ "SEARCH_SCOPE_CHOICES",
+ "ACTIVE_DIRECTORY",
+ "ACTIVE_DIRECTORY_CONTACTS",
+ "CONTACTS",
+ "CONTACTS_ACTIVE_DIRECTORY",
+ "ITEM_CLASSES",
]
class AcceptItem(BaseMeetingReplyItem):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/acceptitem"""
- ELEMENT_NAME = 'AcceptItem'
+ ELEMENT_NAME = "AcceptItem"
class BulkCreateResult(BaseItem):
"""A dummy class to store return values from a CreateItem service call."""
- attachments = AttachmentField(field_uri='item:Attachments') # ItemAttachment or FileAttachment
+ attachments = AttachmentField(field_uri="item:Attachments") # ItemAttachment or FileAttachment
def __init__(self, **kwargs):
super().__init__(**kwargs)
@@ -374,66 +463,75 @@ Inherited members
class CalendarItem(Item, AcceptDeclineMixIn):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/calendaritem"""
- ELEMENT_NAME = 'CalendarItem'
-
- uid = TextField(field_uri='calendar:UID', is_required_after_save=True, is_searchable=False)
- recurrence_id = DateTimeField(field_uri='calendar:RecurrenceId', is_read_only=True)
- start = DateOrDateTimeField(field_uri='calendar:Start', is_required=True)
- end = DateOrDateTimeField(field_uri='calendar:End', is_required=True)
- original_start = DateTimeField(field_uri='calendar:OriginalStart', is_read_only=True)
- is_all_day = BooleanField(field_uri='calendar:IsAllDayEvent', is_required=True, default=False)
- legacy_free_busy_status = FreeBusyStatusField(field_uri='calendar:LegacyFreeBusyStatus', is_required=True,
- default='Busy')
- location = TextField(field_uri='calendar:Location')
- when = TextField(field_uri='calendar:When')
- is_meeting = BooleanField(field_uri='calendar:IsMeeting', is_read_only=True)
- is_cancelled = BooleanField(field_uri='calendar:IsCancelled', is_read_only=True)
- is_recurring = BooleanField(field_uri='calendar:IsRecurring', is_read_only=True)
- meeting_request_was_sent = BooleanField(field_uri='calendar:MeetingRequestWasSent', is_read_only=True)
- is_response_requested = BooleanField(field_uri='calendar:IsResponseRequested', default=None,
- is_required_after_save=True, is_searchable=False)
- type = ChoiceField(field_uri='calendar:CalendarItemType', choices={Choice(c) for c in CALENDAR_ITEM_CHOICES},
- is_read_only=True)
- my_response_type = ChoiceField(field_uri='calendar:MyResponseType', choices={
- Choice(c) for c in Attendee.RESPONSE_TYPES
- }, is_read_only=True)
- organizer = MailboxField(field_uri='calendar:Organizer', is_read_only=True)
- required_attendees = AttendeesField(field_uri='calendar:RequiredAttendees', is_searchable=False)
- optional_attendees = AttendeesField(field_uri='calendar:OptionalAttendees', is_searchable=False)
- resources = AttendeesField(field_uri='calendar:Resources', is_searchable=False)
- conflicting_meeting_count = IntegerField(field_uri='calendar:ConflictingMeetingCount', is_read_only=True)
- adjacent_meeting_count = IntegerField(field_uri='calendar:AdjacentMeetingCount', is_read_only=True)
- conflicting_meetings = EWSElementListField(field_uri='calendar:ConflictingMeetings', value_cls='CalendarItem',
- namespace=Item.NAMESPACE, is_read_only=True)
- adjacent_meetings = EWSElementListField(field_uri='calendar:AdjacentMeetings', value_cls='CalendarItem',
- namespace=Item.NAMESPACE, is_read_only=True)
- duration = CharField(field_uri='calendar:Duration', is_read_only=True)
- appointment_reply_time = DateTimeField(field_uri='calendar:AppointmentReplyTime', is_read_only=True)
- appointment_sequence_number = IntegerField(field_uri='calendar:AppointmentSequenceNumber', is_read_only=True)
- appointment_state = AppointmentStateField(field_uri='calendar:AppointmentState', is_read_only=True)
- recurrence = RecurrenceField(field_uri='calendar:Recurrence', is_searchable=False)
- first_occurrence = OccurrenceField(field_uri='calendar:FirstOccurrence', value_cls=FirstOccurrence,
- is_read_only=True)
- last_occurrence = OccurrenceField(field_uri='calendar:LastOccurrence', value_cls=LastOccurrence,
- is_read_only=True)
- modified_occurrences = OccurrenceListField(field_uri='calendar:ModifiedOccurrences', value_cls=Occurrence,
- is_read_only=True)
- deleted_occurrences = OccurrenceListField(field_uri='calendar:DeletedOccurrences', value_cls=DeletedOccurrence,
- is_read_only=True)
- _meeting_timezone = TimeZoneField(field_uri='calendar:MeetingTimeZone', deprecated_from=EXCHANGE_2010,
- is_searchable=False)
- _start_timezone = TimeZoneField(field_uri='calendar:StartTimeZone', supported_from=EXCHANGE_2010,
- is_searchable=False)
- _end_timezone = TimeZoneField(field_uri='calendar:EndTimeZone', supported_from=EXCHANGE_2010,
- is_searchable=False)
- conference_type = EnumAsIntField(field_uri='calendar:ConferenceType', enum=CONFERENCE_TYPES, min=0,
- default=None, is_required_after_save=True)
- allow_new_time_proposal = BooleanField(field_uri='calendar:AllowNewTimeProposal', default=None,
- is_required_after_save=True, is_searchable=False)
- is_online_meeting = BooleanField(field_uri='calendar:IsOnlineMeeting', default=None,
- is_read_only=True)
- meeting_workspace_url = URIField(field_uri='calendar:MeetingWorkspaceUrl')
- net_show_url = URIField(field_uri='calendar:NetShowUrl')
+ ELEMENT_NAME = "CalendarItem"
+
+ uid = TextField(field_uri="calendar:UID", is_required_after_save=True, is_searchable=False)
+ recurrence_id = DateTimeField(field_uri="calendar:RecurrenceId", is_read_only=True)
+ start = DateOrDateTimeField(field_uri="calendar:Start", is_required=True)
+ end = DateOrDateTimeField(field_uri="calendar:End", is_required=True)
+ original_start = DateTimeField(field_uri="calendar:OriginalStart", is_read_only=True)
+ is_all_day = BooleanField(field_uri="calendar:IsAllDayEvent", is_required=True, default=False)
+ legacy_free_busy_status = FreeBusyStatusField(
+ field_uri="calendar:LegacyFreeBusyStatus", is_required=True, default="Busy"
+ )
+ location = TextField(field_uri="calendar:Location")
+ when = TextField(field_uri="calendar:When")
+ is_meeting = BooleanField(field_uri="calendar:IsMeeting", is_read_only=True)
+ is_cancelled = BooleanField(field_uri="calendar:IsCancelled", is_read_only=True)
+ is_recurring = BooleanField(field_uri="calendar:IsRecurring", is_read_only=True)
+ meeting_request_was_sent = BooleanField(field_uri="calendar:MeetingRequestWasSent", is_read_only=True)
+ is_response_requested = BooleanField(
+ field_uri="calendar:IsResponseRequested", default=None, is_required_after_save=True, is_searchable=False
+ )
+ type = ChoiceField(
+ field_uri="calendar:CalendarItemType", choices={Choice(c) for c in CALENDAR_ITEM_CHOICES}, is_read_only=True
+ )
+ my_response_type = ChoiceField(
+ field_uri="calendar:MyResponseType", choices={Choice(c) for c in Attendee.RESPONSE_TYPES}, is_read_only=True
+ )
+ organizer = MailboxField(field_uri="calendar:Organizer", is_read_only=True)
+ required_attendees = AttendeesField(field_uri="calendar:RequiredAttendees", is_searchable=False)
+ optional_attendees = AttendeesField(field_uri="calendar:OptionalAttendees", is_searchable=False)
+ resources = AttendeesField(field_uri="calendar:Resources", is_searchable=False)
+ conflicting_meeting_count = IntegerField(field_uri="calendar:ConflictingMeetingCount", is_read_only=True)
+ adjacent_meeting_count = IntegerField(field_uri="calendar:AdjacentMeetingCount", is_read_only=True)
+ conflicting_meetings = EWSElementListField(
+ field_uri="calendar:ConflictingMeetings", value_cls="CalendarItem", namespace=Item.NAMESPACE, is_read_only=True
+ )
+ adjacent_meetings = EWSElementListField(
+ field_uri="calendar:AdjacentMeetings", value_cls="CalendarItem", namespace=Item.NAMESPACE, is_read_only=True
+ )
+ duration = CharField(field_uri="calendar:Duration", is_read_only=True)
+ appointment_reply_time = DateTimeField(field_uri="calendar:AppointmentReplyTime", is_read_only=True)
+ appointment_sequence_number = IntegerField(field_uri="calendar:AppointmentSequenceNumber", is_read_only=True)
+ appointment_state = AppointmentStateField(field_uri="calendar:AppointmentState", is_read_only=True)
+ recurrence = RecurrenceField(field_uri="calendar:Recurrence", is_searchable=False)
+ first_occurrence = OccurrenceField(
+ field_uri="calendar:FirstOccurrence", value_cls=FirstOccurrence, is_read_only=True
+ )
+ last_occurrence = OccurrenceField(field_uri="calendar:LastOccurrence", value_cls=LastOccurrence, is_read_only=True)
+ modified_occurrences = OccurrenceListField(
+ field_uri="calendar:ModifiedOccurrences", value_cls=Occurrence, is_read_only=True
+ )
+ deleted_occurrences = OccurrenceListField(
+ field_uri="calendar:DeletedOccurrences", value_cls=DeletedOccurrence, is_read_only=True
+ )
+ _meeting_timezone = TimeZoneField(
+ field_uri="calendar:MeetingTimeZone", deprecated_from=EXCHANGE_2010, is_searchable=False
+ )
+ _start_timezone = TimeZoneField(
+ field_uri="calendar:StartTimeZone", supported_from=EXCHANGE_2010, is_searchable=False
+ )
+ _end_timezone = TimeZoneField(field_uri="calendar:EndTimeZone", supported_from=EXCHANGE_2010, is_searchable=False)
+ conference_type = EnumAsIntField(
+ field_uri="calendar:ConferenceType", enum=CONFERENCE_TYPES, min=0, default=None, is_required_after_save=True
+ )
+ allow_new_time_proposal = BooleanField(
+ field_uri="calendar:AllowNewTimeProposal", default=None, is_required_after_save=True, is_searchable=False
+ )
+ is_online_meeting = BooleanField(field_uri="calendar:IsOnlineMeeting", default=None, is_read_only=True)
+ meeting_workspace_url = URIField(field_uri="calendar:MeetingWorkspaceUrl")
+ net_show_url = URIField(field_uri="calendar:NetShowUrl")
def occurrence(self, index):
"""Get an occurrence of a recurring master by index. No query is sent to the server to actually fetch the item.
@@ -504,9 +602,7 @@ Inherited members
def cancel(self, **kwargs):
return CancelCalendarItem(
- account=self.account,
- reference_item_id=ReferenceItemId(id=self.id, changekey=self.changekey),
- **kwargs
+ account=self.account, reference_item_id=ReferenceItemId(id=self.id, changekey=self.changekey), **kwargs
).send()
def _update_fieldnames(self):
@@ -514,8 +610,8 @@ Inherited members
if self.type == OCCURRENCE:
# Some CalendarItem fields cannot be updated when the item is an occurrence. The values are empty when we
# receive them so would have been updated because they are set to None.
- update_fields.remove('recurrence')
- update_fields.remove('uid')
+ update_fields.remove("recurrence")
+ update_fields.remove("uid")
return update_fields
@classmethod
@@ -525,15 +621,15 @@ Inherited members
# applicable.
if not item.is_all_day:
return item
- for field_name in ('start', 'end'):
+ for field_name in ("start", "end"):
val = getattr(item, field_name)
if val is None:
continue
# Return just the date part of the value. Subtract 1 day from the date if this is the end field. This is
# the inverse of what we do in .to_xml(). Convert to the local timezone before getting the date.
- if field_name == 'end':
+ if field_name == "end":
val -= datetime.timedelta(days=1)
- tz = getattr(item, f'_{field_name}_timezone')
+ tz = getattr(item, f"_{field_name}_timezone")
setattr(item, field_name, val.astimezone(tz).date())
return item
@@ -541,11 +637,11 @@ Inherited members
meeting_tz_field, start_tz_field, end_tz_field = CalendarItem.timezone_fields()
if self.account.version.build < EXCHANGE_2010:
return meeting_tz_field
- if field_name == 'start':
+ if field_name == "start":
return start_tz_field
- if field_name == 'end':
+ if field_name == "end":
return end_tz_field
- raise ValueError('Unsupported field_name')
+ raise ValueError("Unsupported field_name")
def date_to_datetime(self, field_name):
# EWS always expects a datetime. If we have a date value, then convert it to datetime in the local
@@ -554,7 +650,7 @@ Inherited members
value = getattr(self, field_name)
tz = getattr(self, self.tz_field_for_field_name(field_name).name)
value = EWSDateTime.combine(value, datetime.time(0, 0)).replace(tzinfo=tz)
- if field_name == 'end':
+ if field_name == "end":
value += datetime.timedelta(days=1)
return value
@@ -568,7 +664,7 @@ Inherited members
elem = super().to_xml(version=version)
if not self.is_all_day:
return elem
- for field_name in ('start', 'end'):
+ for field_name in ("start", "end"):
value = getattr(self, field_name)
if value is None:
continue
@@ -619,15 +715,15 @@ Static methods
# applicable.
if not item.is_all_day:
return item
- for field_name in ('start', 'end'):
+ for field_name in ("start", "end"):
val = getattr(item, field_name)
if val is None:
continue
# Return just the date part of the value. Subtract 1 day from the date if this is the end field. This is
# the inverse of what we do in .to_xml(). Convert to the local timezone before getting the date.
- if field_name == 'end':
+ if field_name == "end":
val -= datetime.timedelta(days=1)
- tz = getattr(item, f'_{field_name}_timezone')
+ tz = getattr(item, f"_{field_name}_timezone")
setattr(item, field_name, val.astimezone(tz).date())
return item
@@ -815,9 +911,7 @@ Methods
def cancel(self, **kwargs):
return CancelCalendarItem(
- account=self.account,
- reference_item_id=ReferenceItemId(id=self.id, changekey=self.changekey),
- **kwargs
+ account=self.account, reference_item_id=ReferenceItemId(id=self.id, changekey=self.changekey), **kwargs
).send()
@@ -890,7 +984,7 @@ Methods
value = getattr(self, field_name)
tz = getattr(self, self.tz_field_for_field_name(field_name).name)
value = EWSDateTime.combine(value, datetime.time(0, 0)).replace(tzinfo=tz)
- if field_name == 'end':
+ if field_name == "end":
value += datetime.timedelta(days=1)
return value
@@ -971,7 +1065,7 @@ class CancelCalendarItem(BaseReplyItem):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/cancelcalendaritem"""
- ELEMENT_NAME = 'CancelCalendarItem'
- author_idx = BaseReplyItem.FIELDS.index_by_name('author')
- FIELDS = BaseReplyItem.FIELDS[:author_idx] + BaseReplyItem.FIELDS[author_idx + 1:]
+ ELEMENT_NAME = "CancelCalendarItem"
+ author_idx = BaseReplyItem.FIELDS.index_by_name("author")
+ FIELDS = BaseReplyItem.FIELDS[:author_idx] + BaseReplyItem.FIELDS[author_idx + 1 :]
class Contact(Item):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/contact"""
- ELEMENT_NAME = 'Contact'
-
- file_as = TextField(field_uri='contacts:FileAs')
- file_as_mapping = ChoiceField(field_uri='contacts:FileAsMapping', choices={
- Choice('None'), Choice('LastCommaFirst'), Choice('FirstSpaceLast'), Choice('Company'),
- Choice('LastCommaFirstCompany'), Choice('CompanyLastFirst'), Choice('LastFirst'),
- Choice('LastFirstCompany'), Choice('CompanyLastCommaFirst'), Choice('LastFirstSuffix'),
- Choice('LastSpaceFirstCompany'), Choice('CompanyLastSpaceFirst'), Choice('LastSpaceFirst'),
- Choice('DisplayName'), Choice('FirstName'), Choice('LastFirstMiddleSuffix'), Choice('LastName'),
- Choice('Empty'),
- })
- display_name = TextField(field_uri='contacts:DisplayName', is_required=True)
- given_name = CharField(field_uri='contacts:GivenName')
- initials = TextField(field_uri='contacts:Initials')
- middle_name = CharField(field_uri='contacts:MiddleName')
- nickname = TextField(field_uri='contacts:Nickname')
- complete_name = EWSElementField(field_uri='contacts:CompleteName', value_cls=CompleteName, is_read_only=True)
- company_name = TextField(field_uri='contacts:CompanyName')
- email_addresses = EmailAddressesField(field_uri='contacts:EmailAddress')
- physical_addresses = PhysicalAddressField(field_uri='contacts:PhysicalAddress')
- phone_numbers = PhoneNumberField(field_uri='contacts:PhoneNumber')
- assistant_name = TextField(field_uri='contacts:AssistantName')
- birthday = DateTimeBackedDateField(field_uri='contacts:Birthday', default_time=datetime.time(11, 59))
- business_homepage = URIField(field_uri='contacts:BusinessHomePage')
- children = TextListField(field_uri='contacts:Children')
- companies = TextListField(field_uri='contacts:Companies', is_searchable=False)
- contact_source = ChoiceField(field_uri='contacts:ContactSource', choices={
- Choice('Store'), Choice('ActiveDirectory')
- }, is_read_only=True)
- department = TextField(field_uri='contacts:Department')
- generation = TextField(field_uri='contacts:Generation')
- im_addresses = CharField(field_uri='contacts:ImAddresses', is_read_only=True)
- job_title = TextField(field_uri='contacts:JobTitle')
- manager = TextField(field_uri='contacts:Manager')
- mileage = TextField(field_uri='contacts:Mileage')
- office = TextField(field_uri='contacts:OfficeLocation')
- postal_address_index = ChoiceField(field_uri='contacts:PostalAddressIndex', choices={
- Choice('Business'), Choice('Home'), Choice('Other'), Choice('None')
- }, default='None', is_required_after_save=True)
- profession = TextField(field_uri='contacts:Profession')
- spouse_name = TextField(field_uri='contacts:SpouseName')
- surname = CharField(field_uri='contacts:Surname')
- wedding_anniversary = DateTimeBackedDateField(field_uri='contacts:WeddingAnniversary',
- default_time=datetime.time(11, 59))
- has_picture = BooleanField(field_uri='contacts:HasPicture', supported_from=EXCHANGE_2010, is_read_only=True)
- phonetic_full_name = TextField(field_uri='contacts:PhoneticFullName', supported_from=EXCHANGE_2010_SP2,
- is_read_only=True)
- phonetic_first_name = TextField(field_uri='contacts:PhoneticFirstName', supported_from=EXCHANGE_2010_SP2,
- is_read_only=True)
- phonetic_last_name = TextField(field_uri='contacts:PhoneticLastName', supported_from=EXCHANGE_2010_SP2,
- is_read_only=True)
- email_alias = EmailAddressField(field_uri='contacts:Alias', is_read_only=True,
- supported_from=EXCHANGE_2010_SP2)
+ ELEMENT_NAME = "Contact"
+
+ file_as = TextField(field_uri="contacts:FileAs")
+ file_as_mapping = ChoiceField(
+ field_uri="contacts:FileAsMapping",
+ choices={
+ Choice("None"),
+ Choice("LastCommaFirst"),
+ Choice("FirstSpaceLast"),
+ Choice("Company"),
+ Choice("LastCommaFirstCompany"),
+ Choice("CompanyLastFirst"),
+ Choice("LastFirst"),
+ Choice("LastFirstCompany"),
+ Choice("CompanyLastCommaFirst"),
+ Choice("LastFirstSuffix"),
+ Choice("LastSpaceFirstCompany"),
+ Choice("CompanyLastSpaceFirst"),
+ Choice("LastSpaceFirst"),
+ Choice("DisplayName"),
+ Choice("FirstName"),
+ Choice("LastFirstMiddleSuffix"),
+ Choice("LastName"),
+ Choice("Empty"),
+ },
+ )
+ display_name = TextField(field_uri="contacts:DisplayName", is_required=True)
+ given_name = CharField(field_uri="contacts:GivenName")
+ initials = TextField(field_uri="contacts:Initials")
+ middle_name = CharField(field_uri="contacts:MiddleName")
+ nickname = TextField(field_uri="contacts:Nickname")
+ complete_name = EWSElementField(field_uri="contacts:CompleteName", value_cls=CompleteName, is_read_only=True)
+ company_name = TextField(field_uri="contacts:CompanyName")
+ email_addresses = EmailAddressesField(field_uri="contacts:EmailAddress")
+ physical_addresses = PhysicalAddressField(field_uri="contacts:PhysicalAddress")
+ phone_numbers = PhoneNumberField(field_uri="contacts:PhoneNumber")
+ assistant_name = TextField(field_uri="contacts:AssistantName")
+ birthday = DateTimeBackedDateField(field_uri="contacts:Birthday", default_time=datetime.time(11, 59))
+ business_homepage = URIField(field_uri="contacts:BusinessHomePage")
+ children = TextListField(field_uri="contacts:Children")
+ companies = TextListField(field_uri="contacts:Companies", is_searchable=False)
+ contact_source = ChoiceField(
+ field_uri="contacts:ContactSource", choices={Choice("Store"), Choice("ActiveDirectory")}, is_read_only=True
+ )
+ department = TextField(field_uri="contacts:Department")
+ generation = TextField(field_uri="contacts:Generation")
+ im_addresses = CharField(field_uri="contacts:ImAddresses", is_read_only=True)
+ job_title = TextField(field_uri="contacts:JobTitle")
+ manager = TextField(field_uri="contacts:Manager")
+ mileage = TextField(field_uri="contacts:Mileage")
+ office = TextField(field_uri="contacts:OfficeLocation")
+ postal_address_index = ChoiceField(
+ field_uri="contacts:PostalAddressIndex",
+ choices={Choice("Business"), Choice("Home"), Choice("Other"), Choice("None")},
+ default="None",
+ is_required_after_save=True,
+ )
+ profession = TextField(field_uri="contacts:Profession")
+ spouse_name = TextField(field_uri="contacts:SpouseName")
+ surname = CharField(field_uri="contacts:Surname")
+ wedding_anniversary = DateTimeBackedDateField(
+ field_uri="contacts:WeddingAnniversary", default_time=datetime.time(11, 59)
+ )
+ has_picture = BooleanField(field_uri="contacts:HasPicture", supported_from=EXCHANGE_2010, is_read_only=True)
+ phonetic_full_name = TextField(
+ field_uri="contacts:PhoneticFullName", supported_from=EXCHANGE_2010_SP2, is_read_only=True
+ )
+ phonetic_first_name = TextField(
+ field_uri="contacts:PhoneticFirstName", supported_from=EXCHANGE_2010_SP2, is_read_only=True
+ )
+ phonetic_last_name = TextField(
+ field_uri="contacts:PhoneticLastName", supported_from=EXCHANGE_2010_SP2, is_read_only=True
+ )
+ email_alias = EmailAddressField(field_uri="contacts:Alias", is_read_only=True, supported_from=EXCHANGE_2010_SP2)
# 'notes' is documented in MSDN but apparently unused. Writing to it raises ErrorInvalidPropertyRequest. OWA
# put entries into the 'notes' form field into the 'body' field.
- notes = CharField(field_uri='contacts:Notes', supported_from=EXCHANGE_2010_SP2, is_read_only=True)
+ notes = CharField(field_uri="contacts:Notes", supported_from=EXCHANGE_2010_SP2, is_read_only=True)
# 'photo' is documented in MSDN but apparently unused. Writing to it raises ErrorInvalidPropertyRequest. OWA
# adds photos as FileAttachments on the contact item (with 'is_contact_photo=True'), which automatically flips
# the 'has_picture' field.
- photo = Base64Field(field_uri='contacts:Photo', supported_from=EXCHANGE_2010_SP2, is_read_only=True)
- user_smime_certificate = Base64Field(field_uri='contacts:UserSMIMECertificate', supported_from=EXCHANGE_2010_SP2,
- is_read_only=True)
- ms_exchange_certificate = Base64Field(field_uri='contacts:MSExchangeCertificate', supported_from=EXCHANGE_2010_SP2,
- is_read_only=True)
- directory_id = TextField(field_uri='contacts:DirectoryId', supported_from=EXCHANGE_2010_SP2, is_read_only=True)
- manager_mailbox = MailboxField(field_uri='contacts:ManagerMailbox', supported_from=EXCHANGE_2010_SP2,
- is_read_only=True)
- direct_reports = MailboxListField(field_uri='contacts:DirectReports', supported_from=EXCHANGE_2010_SP2,
- is_read_only=True)
+ photo = Base64Field(field_uri="contacts:Photo", supported_from=EXCHANGE_2010_SP2, is_read_only=True)
+ user_smime_certificate = Base64Field(
+ field_uri="contacts:UserSMIMECertificate", supported_from=EXCHANGE_2010_SP2, is_read_only=True
+ )
+ ms_exchange_certificate = Base64Field(
+ field_uri="contacts:MSExchangeCertificate", supported_from=EXCHANGE_2010_SP2, is_read_only=True
+ )
+ directory_id = TextField(field_uri="contacts:DirectoryId", supported_from=EXCHANGE_2010_SP2, is_read_only=True)
+ manager_mailbox = MailboxField(
+ field_uri="contacts:ManagerMailbox", supported_from=EXCHANGE_2010_SP2, is_read_only=True
+ )
+ direct_reports = MailboxListField(
+ field_uri="contacts:DirectReports", supported_from=EXCHANGE_2010_SP2, is_read_only=True
+ )
class DeclineItem(BaseMeetingReplyItem):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/declineitem"""
- ELEMENT_NAME = 'DeclineItem'
+ ELEMENT_NAME = "DeclineItem"
class DistributionList(Item):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/distributionlist"""
- ELEMENT_NAME = 'DistributionList'
+ ELEMENT_NAME = "DistributionList"
- display_name = CharField(field_uri='contacts:DisplayName', is_required=True)
- file_as = CharField(field_uri='contacts:FileAs', is_read_only=True)
- contact_source = ChoiceField(field_uri='contacts:ContactSource', choices={
- Choice('Store'), Choice('ActiveDirectory')
- }, is_read_only=True)
- members = MemberListField(field_uri='distributionlist:Members')
+ display_name = CharField(field_uri="contacts:DisplayName", is_required=True)
+ file_as = CharField(field_uri="contacts:FileAs", is_read_only=True)
+ contact_source = ChoiceField(
+ field_uri="contacts:ContactSource", choices={Choice("Store"), Choice("ActiveDirectory")}, is_read_only=True
+ )
+ members = MemberListField(field_uri="distributionlist:Members")
class ForwardItem(BaseReplyItem):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/forwarditem"""
- ELEMENT_NAME = 'ForwardItem'
+ ELEMENT_NAME = "ForwardItem"
class Item(BaseItem):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/item"""
- ELEMENT_NAME = 'Item'
-
- mime_content = MimeContentField(field_uri='item:MimeContent', is_read_only_after_send=True)
- _id = BaseItem.FIELDS['_id']
- parent_folder_id = EWSElementField(field_uri='item:ParentFolderId', value_cls=ParentFolderId, is_read_only=True)
- item_class = CharField(field_uri='item:ItemClass', is_read_only=True)
- subject = CharField(field_uri='item:Subject')
- sensitivity = ChoiceField(field_uri='item:Sensitivity', choices={
- Choice('Normal'), Choice('Personal'), Choice('Private'), Choice('Confidential')
- }, is_required=True, default='Normal')
- text_body = TextField(field_uri='item:TextBody', is_read_only=True, supported_from=EXCHANGE_2013)
- body = BodyField(field_uri='item:Body') # Accepts and returns Body or HTMLBody instances
- attachments = AttachmentField(field_uri='item:Attachments') # ItemAttachment or FileAttachment
- datetime_received = DateTimeField(field_uri='item:DateTimeReceived', is_read_only=True)
- size = IntegerField(field_uri='item:Size', is_read_only=True) # Item size in bytes
- categories = CharListField(field_uri='item:Categories')
- importance = ChoiceField(field_uri='item:Importance', choices={
- Choice('Low'), Choice('Normal'), Choice('High')
- }, is_required=True, default='Normal')
- in_reply_to = TextField(field_uri='item:InReplyTo')
- is_submitted = BooleanField(field_uri='item:IsSubmitted', is_read_only=True)
- is_draft = BooleanField(field_uri='item:IsDraft', is_read_only=True)
- is_from_me = BooleanField(field_uri='item:IsFromMe', is_read_only=True)
- is_resend = BooleanField(field_uri='item:IsResend', is_read_only=True)
- is_unmodified = BooleanField(field_uri='item:IsUnmodified', is_read_only=True)
- headers = MessageHeaderField(field_uri='item:InternetMessageHeaders', is_read_only=True)
- datetime_sent = DateTimeField(field_uri='item:DateTimeSent', is_read_only=True)
- datetime_created = DateTimeField(field_uri='item:DateTimeCreated', is_read_only=True)
- response_objects = EWSElementField(field_uri='item:ResponseObjects', value_cls=ResponseObjects,
- is_read_only=True,)
+ ELEMENT_NAME = "Item"
+
+ mime_content = MimeContentField(field_uri="item:MimeContent", is_read_only_after_send=True)
+ _id = BaseItem.FIELDS["_id"]
+ parent_folder_id = EWSElementField(field_uri="item:ParentFolderId", value_cls=ParentFolderId, is_read_only=True)
+ item_class = CharField(field_uri="item:ItemClass", is_read_only=True)
+ subject = CharField(field_uri="item:Subject")
+ sensitivity = ChoiceField(
+ field_uri="item:Sensitivity",
+ choices={Choice("Normal"), Choice("Personal"), Choice("Private"), Choice("Confidential")},
+ is_required=True,
+ default="Normal",
+ )
+ text_body = TextField(field_uri="item:TextBody", is_read_only=True, supported_from=EXCHANGE_2013)
+ body = BodyField(field_uri="item:Body") # Accepts and returns Body or HTMLBody instances
+ attachments = AttachmentField(field_uri="item:Attachments") # ItemAttachment or FileAttachment
+ datetime_received = DateTimeField(field_uri="item:DateTimeReceived", is_read_only=True)
+ size = IntegerField(field_uri="item:Size", is_read_only=True) # Item size in bytes
+ categories = CharListField(field_uri="item:Categories")
+ importance = ChoiceField(
+ field_uri="item:Importance",
+ choices={Choice("Low"), Choice("Normal"), Choice("High")},
+ is_required=True,
+ default="Normal",
+ )
+ in_reply_to = TextField(field_uri="item:InReplyTo")
+ is_submitted = BooleanField(field_uri="item:IsSubmitted", is_read_only=True)
+ is_draft = BooleanField(field_uri="item:IsDraft", is_read_only=True)
+ is_from_me = BooleanField(field_uri="item:IsFromMe", is_read_only=True)
+ is_resend = BooleanField(field_uri="item:IsResend", is_read_only=True)
+ is_unmodified = BooleanField(field_uri="item:IsUnmodified", is_read_only=True)
+ headers = MessageHeaderField(field_uri="item:InternetMessageHeaders", is_read_only=True)
+ datetime_sent = DateTimeField(field_uri="item:DateTimeSent", is_read_only=True)
+ datetime_created = DateTimeField(field_uri="item:DateTimeCreated", is_read_only=True)
+ response_objects = EWSElementField(
+ field_uri="item:ResponseObjects",
+ value_cls=ResponseObjects,
+ is_read_only=True,
+ )
# Placeholder for ResponseObjects
- reminder_due_by = DateTimeField(field_uri='item:ReminderDueBy', is_required_after_save=True, is_searchable=False)
- reminder_is_set = BooleanField(field_uri='item:ReminderIsSet', is_required=True, default=False)
- reminder_minutes_before_start = IntegerField(field_uri='item:ReminderMinutesBeforeStart',
- is_required_after_save=True, min=0, default=0)
- display_cc = TextField(field_uri='item:DisplayCc', is_read_only=True)
- display_to = TextField(field_uri='item:DisplayTo', is_read_only=True)
- has_attachments = BooleanField(field_uri='item:HasAttachments', is_read_only=True)
+ reminder_due_by = DateTimeField(field_uri="item:ReminderDueBy", is_required_after_save=True, is_searchable=False)
+ reminder_is_set = BooleanField(field_uri="item:ReminderIsSet", is_required=True, default=False)
+ reminder_minutes_before_start = IntegerField(
+ field_uri="item:ReminderMinutesBeforeStart", is_required_after_save=True, min=0, default=0
+ )
+ display_cc = TextField(field_uri="item:DisplayCc", is_read_only=True)
+ display_to = TextField(field_uri="item:DisplayTo", is_read_only=True)
+ has_attachments = BooleanField(field_uri="item:HasAttachments", is_read_only=True)
# ExtendedProperty fields go here
- culture = CultureField(field_uri='item:Culture', is_required_after_save=True, is_searchable=False)
- effective_rights = EffectiveRightsField(field_uri='item:EffectiveRights', is_read_only=True)
- last_modified_name = CharField(field_uri='item:LastModifiedName', is_read_only=True)
- last_modified_time = DateTimeField(field_uri='item:LastModifiedTime', is_read_only=True)
- is_associated = BooleanField(field_uri='item:IsAssociated', is_read_only=True, supported_from=EXCHANGE_2010)
- web_client_read_form_query_string = URIField(field_uri='item:WebClientReadFormQueryString', is_read_only=True,
- supported_from=EXCHANGE_2010)
- web_client_edit_form_query_string = URIField(field_uri='item:WebClientEditFormQueryString', is_read_only=True,
- supported_from=EXCHANGE_2010)
- conversation_id = EWSElementField(field_uri='item:ConversationId', value_cls=ConversationId,
- is_read_only=True, supported_from=EXCHANGE_2010)
- unique_body = BodyField(field_uri='item:UniqueBody', is_read_only=True, supported_from=EXCHANGE_2010)
+ culture = CultureField(field_uri="item:Culture", is_required_after_save=True, is_searchable=False)
+ effective_rights = EffectiveRightsField(field_uri="item:EffectiveRights", is_read_only=True)
+ last_modified_name = CharField(field_uri="item:LastModifiedName", is_read_only=True)
+ last_modified_time = DateTimeField(field_uri="item:LastModifiedTime", is_read_only=True)
+ is_associated = BooleanField(field_uri="item:IsAssociated", is_read_only=True, supported_from=EXCHANGE_2010)
+ web_client_read_form_query_string = URIField(
+ field_uri="item:WebClientReadFormQueryString", is_read_only=True, supported_from=EXCHANGE_2010
+ )
+ web_client_edit_form_query_string = URIField(
+ field_uri="item:WebClientEditFormQueryString", is_read_only=True, supported_from=EXCHANGE_2010
+ )
+ conversation_id = EWSElementField(
+ field_uri="item:ConversationId", value_cls=ConversationId, is_read_only=True, supported_from=EXCHANGE_2010
+ )
+ unique_body = BodyField(field_uri="item:UniqueBody", is_read_only=True, supported_from=EXCHANGE_2010)
FIELDS = Fields()
# Used to register extended properties
- INSERT_AFTER_FIELD = 'has_attachments'
+ INSERT_AFTER_FIELD = "has_attachments"
def __init__(self, **kwargs):
super().__init__(**kwargs)
@@ -1640,16 +1772,19 @@ Inherited members
def save(self, update_fields=None, conflict_resolution=AUTO_RESOLVE, send_meeting_invitations=SEND_TO_NONE):
from .task import Task
+
if self.id:
item_id, changekey = self._update(
update_fieldnames=update_fields,
message_disposition=SAVE_ONLY,
conflict_resolution=conflict_resolution,
- send_meeting_invitations=send_meeting_invitations
+ send_meeting_invitations=send_meeting_invitations,
)
- if self.id != item_id \
- and not isinstance(self._id, (OccurrenceItemId, RecurringMasterItemId)) \
- and not isinstance(self, Task):
+ if (
+ self.id != item_id
+ and not isinstance(self._id, (OccurrenceItemId, RecurringMasterItemId))
+ and not isinstance(self, Task)
+ ):
# When we update an item with an OccurrenceItemId as ID, EWS returns the ID of the occurrence, so
# the ID of this item changes.
#
@@ -1684,6 +1819,7 @@ Inherited members
# Return a BulkCreateResult because we want to return the ID of both the main item *and* attachments. In send
# and send-and-save-copy mode, the server does not return an ID, so we just return True.
from ..services import CreateItem
+
return CreateItem(account=self.account).get(
items=[self],
folder=self.folder,
@@ -1693,27 +1829,28 @@ Inherited members
def _update_fieldnames(self):
from .contact import Contact, DistributionList
+
# Return the list of fields we are allowed to update
update_fieldnames = []
for f in self.supported_fields(version=self.account.version):
- if f.name == 'attachments':
+ if f.name == "attachments":
# Attachments are handled separately after item creation
continue
if f.is_read_only:
# These cannot be changed
continue
if (f.is_required or f.is_required_after_save) and (
- getattr(self, f.name) is None or (f.is_list and not getattr(self, f.name))
+ getattr(self, f.name) is None or (f.is_list and not getattr(self, f.name))
):
# These are required and cannot be deleted
continue
if not self.is_draft and f.is_read_only_after_send:
# These cannot be changed when the item is no longer a draft
continue
- if f.name == 'message_id' and f.is_read_only_after_send:
+ if f.name == "message_id" and f.is_read_only_after_send:
# 'message_id' doesn't support updating, no matter the draft status
continue
- if f.name == 'mime_content' and isinstance(self, (Contact, DistributionList)):
+ if f.name == "mime_content" and isinstance(self, (Contact, DistributionList)):
# Contact and DistributionList don't support updating mime_content, no matter the draft status
continue
update_fieldnames.append(f.name)
@@ -1722,8 +1859,9 @@ Inherited members
@require_account
def _update(self, update_fieldnames, message_disposition, conflict_resolution, send_meeting_invitations):
from ..services import UpdateItem
+
if not self.changekey:
- raise ValueError(f'{self.__class__.__name__} must have changekey')
+ raise ValueError(f"{self.__class__.__name__} must have changekey")
if not update_fieldnames:
# The fields to update was not specified explicitly. Update all fields where update is possible
update_fieldnames = self._update_fieldnames()
@@ -1741,6 +1879,7 @@ Inherited members
# Updates the item based on fresh data from EWS
from ..folders import Folder
from ..services import GetItem
+
additional_fields = {
FieldPath(field=f) for f in Folder(root=self.account.root).allowed_item_fields(version=self.account.version)
}
@@ -1759,6 +1898,7 @@ Inherited members
@require_id
def copy(self, to_folder):
from ..services import CopyItem
+
# If 'to_folder' is a public folder or a folder in a different mailbox then None is returned
return CopyItem(account=self.account).get(
items=[self],
@@ -1769,6 +1909,7 @@ Inherited members
@require_id
def move(self, to_folder):
from ..services import MoveItem
+
res = MoveItem(account=self.account).get(
items=[self],
to_folder=to_folder,
@@ -1781,32 +1922,57 @@ Inherited members
self._id = self.ID_ELEMENT_CLS(*res)
self.folder = to_folder
- def move_to_trash(self, send_meeting_cancellations=SEND_TO_NONE, affected_task_occurrences=ALL_OCCURRENCES,
- suppress_read_receipts=True):
+ def move_to_trash(
+ self,
+ send_meeting_cancellations=SEND_TO_NONE,
+ affected_task_occurrences=ALL_OCCURRENCES,
+ suppress_read_receipts=True,
+ ):
# Delete and move to the trash folder.
- self._delete(delete_type=MOVE_TO_DELETED_ITEMS, send_meeting_cancellations=send_meeting_cancellations,
- affected_task_occurrences=affected_task_occurrences, suppress_read_receipts=suppress_read_receipts)
+ self._delete(
+ delete_type=MOVE_TO_DELETED_ITEMS,
+ send_meeting_cancellations=send_meeting_cancellations,
+ affected_task_occurrences=affected_task_occurrences,
+ suppress_read_receipts=suppress_read_receipts,
+ )
self._id = None
self.folder = self.account.trash
- def soft_delete(self, send_meeting_cancellations=SEND_TO_NONE, affected_task_occurrences=ALL_OCCURRENCES,
- suppress_read_receipts=True):
+ def soft_delete(
+ self,
+ send_meeting_cancellations=SEND_TO_NONE,
+ affected_task_occurrences=ALL_OCCURRENCES,
+ suppress_read_receipts=True,
+ ):
# Delete and move to the dumpster, if it is enabled.
- self._delete(delete_type=SOFT_DELETE, send_meeting_cancellations=send_meeting_cancellations,
- affected_task_occurrences=affected_task_occurrences, suppress_read_receipts=suppress_read_receipts)
+ self._delete(
+ delete_type=SOFT_DELETE,
+ send_meeting_cancellations=send_meeting_cancellations,
+ affected_task_occurrences=affected_task_occurrences,
+ suppress_read_receipts=suppress_read_receipts,
+ )
self._id = None
self.folder = self.account.recoverable_items_deletions
- def delete(self, send_meeting_cancellations=SEND_TO_NONE, affected_task_occurrences=ALL_OCCURRENCES,
- suppress_read_receipts=True):
+ def delete(
+ self,
+ send_meeting_cancellations=SEND_TO_NONE,
+ affected_task_occurrences=ALL_OCCURRENCES,
+ suppress_read_receipts=True,
+ ):
# Remove the item permanently. No copies are stored anywhere.
- self._delete(delete_type=HARD_DELETE, send_meeting_cancellations=send_meeting_cancellations,
- affected_task_occurrences=affected_task_occurrences, suppress_read_receipts=suppress_read_receipts)
+ self._delete(
+ delete_type=HARD_DELETE,
+ send_meeting_cancellations=send_meeting_cancellations,
+ affected_task_occurrences=affected_task_occurrences,
+ suppress_read_receipts=suppress_read_receipts,
+ )
self._id, self.folder = None, None
@require_id
def _delete(self, delete_type, send_meeting_cancellations, affected_task_occurrences, suppress_read_receipts):
from ..services import DeleteItem
+
DeleteItem(account=self.account).get(
items=[self],
delete_type=delete_type,
@@ -1818,6 +1984,7 @@ Inherited members
@require_id
def archive(self, to_folder):
from ..services import ArchiveItem
+
return ArchiveItem(account=self.account).get(items=[self], to_folder=to_folder, expect_result=True)
def attach(self, attachments):
@@ -1856,7 +2023,7 @@ Inherited members
attachments = list(attachments)
for a in attachments:
if a.parent_item is not self:
- raise ValueError('Attachment does not belong to this item')
+ raise ValueError("Attachment does not belong to this item")
if self.id:
# Item is already created. Detach the attachment server-side now
a.detach()
@@ -1866,6 +2033,7 @@ Inherited members
@require_id
def create_forward(self, subject, body, to_recipients, cc_recipients=None, bcc_recipients=None):
from .message import ForwardItem
+
return ForwardItem(
account=self.account,
reference_item_id=ReferenceItemId(id=self.id, changekey=self.changekey),
@@ -2083,6 +2251,7 @@ Methods
@require_id
def archive(self, to_folder):
from ..services import ArchiveItem
+
return ArchiveItem(account=self.account).get(items=[self], to_folder=to_folder, expect_result=True)
@@ -2132,6 +2301,7 @@ Methods
@require_id
def copy(self, to_folder):
from ..services import CopyItem
+
# If 'to_folder' is a public folder or a folder in a different mailbox then None is returned
return CopyItem(account=self.account).get(
items=[self],
@@ -2152,6 +2322,7 @@ Methods
@require_id
def create_forward(self, subject, body, to_recipients, cc_recipients=None, bcc_recipients=None):
from .message import ForwardItem
+
return ForwardItem(
account=self.account,
reference_item_id=ReferenceItemId(id=self.id, changekey=self.changekey),
@@ -2172,11 +2343,19 @@ Methods
Expand source code
-def delete(self, send_meeting_cancellations=SEND_TO_NONE, affected_task_occurrences=ALL_OCCURRENCES,
- suppress_read_receipts=True):
+def delete(
+ self,
+ send_meeting_cancellations=SEND_TO_NONE,
+ affected_task_occurrences=ALL_OCCURRENCES,
+ suppress_read_receipts=True,
+):
# Remove the item permanently. No copies are stored anywhere.
- self._delete(delete_type=HARD_DELETE, send_meeting_cancellations=send_meeting_cancellations,
- affected_task_occurrences=affected_task_occurrences, suppress_read_receipts=suppress_read_receipts)
+ self._delete(
+ delete_type=HARD_DELETE,
+ send_meeting_cancellations=send_meeting_cancellations,
+ affected_task_occurrences=affected_task_occurrences,
+ suppress_read_receipts=suppress_read_receipts,
+ )
self._id, self.folder = None, None
@@ -2209,7 +2388,7 @@ Methods
attachments = list(attachments)
for a in attachments:
if a.parent_item is not self:
- raise ValueError('Attachment does not belong to this item')
+ raise ValueError("Attachment does not belong to this item")
if self.id:
# Item is already created. Detach the attachment server-side now
a.detach()
@@ -2248,6 +2427,7 @@ Methods
@require_id
def move(self, to_folder):
from ..services import MoveItem
+
res = MoveItem(account=self.account).get(
items=[self],
to_folder=to_folder,
@@ -2270,11 +2450,19 @@ Methods
Expand source code
-def move_to_trash(self, send_meeting_cancellations=SEND_TO_NONE, affected_task_occurrences=ALL_OCCURRENCES,
- suppress_read_receipts=True):
+def move_to_trash(
+ self,
+ send_meeting_cancellations=SEND_TO_NONE,
+ affected_task_occurrences=ALL_OCCURRENCES,
+ suppress_read_receipts=True,
+):
# Delete and move to the trash folder.
- self._delete(delete_type=MOVE_TO_DELETED_ITEMS, send_meeting_cancellations=send_meeting_cancellations,
- affected_task_occurrences=affected_task_occurrences, suppress_read_receipts=suppress_read_receipts)
+ self._delete(
+ delete_type=MOVE_TO_DELETED_ITEMS,
+ send_meeting_cancellations=send_meeting_cancellations,
+ affected_task_occurrences=affected_task_occurrences,
+ suppress_read_receipts=suppress_read_receipts,
+ )
self._id = None
self.folder = self.account.trash
@@ -2293,6 +2481,7 @@ Methods
# Updates the item based on fresh data from EWS
from ..folders import Folder
from ..services import GetItem
+
additional_fields = {
FieldPath(field=f) for f in Folder(root=self.account.root).allowed_item_fields(version=self.account.version)
}
@@ -2320,16 +2509,19 @@ Methods
def save(self, update_fields=None, conflict_resolution=AUTO_RESOLVE, send_meeting_invitations=SEND_TO_NONE):
from .task import Task
+
if self.id:
item_id, changekey = self._update(
update_fieldnames=update_fields,
message_disposition=SAVE_ONLY,
conflict_resolution=conflict_resolution,
- send_meeting_invitations=send_meeting_invitations
+ send_meeting_invitations=send_meeting_invitations,
)
- if self.id != item_id \
- and not isinstance(self._id, (OccurrenceItemId, RecurringMasterItemId)) \
- and not isinstance(self, Task):
+ if (
+ self.id != item_id
+ and not isinstance(self._id, (OccurrenceItemId, RecurringMasterItemId))
+ and not isinstance(self, Task)
+ ):
# When we update an item with an OccurrenceItemId as ID, EWS returns the ID of the occurrence, so
# the ID of this item changes.
#
@@ -2369,11 +2561,19 @@ Methods
Expand source code
-def soft_delete(self, send_meeting_cancellations=SEND_TO_NONE, affected_task_occurrences=ALL_OCCURRENCES,
- suppress_read_receipts=True):
+def soft_delete(
+ self,
+ send_meeting_cancellations=SEND_TO_NONE,
+ affected_task_occurrences=ALL_OCCURRENCES,
+ suppress_read_receipts=True,
+):
# Delete and move to the dumpster, if it is enabled.
- self._delete(delete_type=SOFT_DELETE, send_meeting_cancellations=send_meeting_cancellations,
- affected_task_occurrences=affected_task_occurrences, suppress_read_receipts=suppress_read_receipts)
+ self._delete(
+ delete_type=SOFT_DELETE,
+ send_meeting_cancellations=send_meeting_cancellations,
+ affected_task_occurrences=affected_task_occurrences,
+ suppress_read_receipts=suppress_read_receipts,
+ )
self._id = None
self.folder = self.account.recoverable_items_deletions
@@ -2414,7 +2614,7 @@ Inherited members
class MeetingCancellation(BaseMeetingItem):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/meetingcancellation"""
- ELEMENT_NAME = 'MeetingCancellation'
+ ELEMENT_NAME = "MeetingCancellation"
Ancestors
@@ -2469,22 +2669,36 @@ Inherited members
class MeetingRequest(BaseMeetingItem, AcceptDeclineMixIn):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/meetingrequest"""
- ELEMENT_NAME = 'MeetingRequest'
+ ELEMENT_NAME = "MeetingRequest"
- meeting_request_type = ChoiceField(field_uri='meetingRequest:MeetingRequestType', choices={
- Choice('FullUpdate'), Choice('InformationalUpdate'), Choice('NewMeetingRequest'), Choice('None'),
- Choice('Outdated'), Choice('PrincipalWantsCopy'), Choice('SilentUpdate')
- }, default='None')
- intended_free_busy_status = ChoiceField(field_uri='meetingRequest:IntendedFreeBusyStatus', choices={
- Choice('Free'), Choice('Tentative'), Choice('Busy'), Choice('OOF'), Choice('NoData')
- }, is_required=True, default='Busy')
+ meeting_request_type = ChoiceField(
+ field_uri="meetingRequest:MeetingRequestType",
+ choices={
+ Choice("FullUpdate"),
+ Choice("InformationalUpdate"),
+ Choice("NewMeetingRequest"),
+ Choice("None"),
+ Choice("Outdated"),
+ Choice("PrincipalWantsCopy"),
+ Choice("SilentUpdate"),
+ },
+ default="None",
+ )
+ intended_free_busy_status = ChoiceField(
+ field_uri="meetingRequest:IntendedFreeBusyStatus",
+ choices={Choice("Free"), Choice("Tentative"), Choice("Busy"), Choice("OOF"), Choice("NoData")},
+ is_required=True,
+ default="Busy",
+ )
# This element also has some fields from CalendarItem
- start_idx = CalendarItem.FIELDS.index_by_name('start')
- is_response_requested_idx = CalendarItem.FIELDS.index_by_name('is_response_requested')
- FIELDS = BaseMeetingItem.FIELDS \
- + CalendarItem.FIELDS[start_idx:is_response_requested_idx]\
- + CalendarItem.FIELDS[is_response_requested_idx + 1:]
+ start_idx = CalendarItem.FIELDS.index_by_name("start")
+ is_response_requested_idx = CalendarItem.FIELDS.index_by_name("is_response_requested")
+ FIELDS = (
+ BaseMeetingItem.FIELDS
+ + CalendarItem.FIELDS[start_idx:is_response_requested_idx]
+ + CalendarItem.FIELDS[is_response_requested_idx + 1 :]
+ )
Ancestors
@@ -2703,12 +2917,10 @@ Inherited members
class MeetingResponse(BaseMeetingItem):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/meetingresponse"""
- ELEMENT_NAME = 'MeetingResponse'
+ ELEMENT_NAME = "MeetingResponse"
- received_by = MailboxField(field_uri='message:ReceivedBy', is_read_only=True)
- received_representing = MailboxField(field_uri='message:ReceivedRepresenting', is_read_only=True)
- proposed_start = DateTimeField(field_uri='meeting:ProposedStart', supported_from=EXCHANGE_2013)
- proposed_end = DateTimeField(field_uri='meeting:ProposedEnd', supported_from=EXCHANGE_2013)
+ proposed_start = DateTimeField(field_uri="meeting:ProposedStart", supported_from=EXCHANGE_2013)
+ proposed_end = DateTimeField(field_uri="meeting:ProposedEnd", supported_from=EXCHANGE_2013)
Ancestors
@@ -2740,14 +2952,6 @@ Instance variables
-
-var received_by
--
-
-
-var received_representing
--
-
-
Inherited members
@@ -2789,37 +2993,52 @@ Inherited members
https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/message-ex15websvcsotherref
"""
- ELEMENT_NAME = 'Message'
-
- sender = MailboxField(field_uri='message:Sender', is_read_only=True, is_read_only_after_send=True)
- to_recipients = MailboxListField(field_uri='message:ToRecipients', is_read_only_after_send=True,
- is_searchable=False)
- cc_recipients = MailboxListField(field_uri='message:CcRecipients', is_read_only_after_send=True,
- is_searchable=False)
- bcc_recipients = MailboxListField(field_uri='message:BccRecipients', is_read_only_after_send=True,
- is_searchable=False)
- is_read_receipt_requested = BooleanField(field_uri='message:IsReadReceiptRequested',
- is_required=True, default=False, is_read_only_after_send=True)
- is_delivery_receipt_requested = BooleanField(field_uri='message:IsDeliveryReceiptRequested', is_required=True,
- default=False, is_read_only_after_send=True)
- conversation_index = Base64Field(field_uri='message:ConversationIndex', is_read_only=True)
- conversation_topic = CharField(field_uri='message:ConversationTopic', is_read_only=True)
+ ELEMENT_NAME = "Message"
+
+ sender = MailboxField(field_uri="message:Sender", is_read_only=True, is_read_only_after_send=True)
+ to_recipients = MailboxListField(
+ field_uri="message:ToRecipients", is_read_only_after_send=True, is_searchable=False
+ )
+ cc_recipients = MailboxListField(
+ field_uri="message:CcRecipients", is_read_only_after_send=True, is_searchable=False
+ )
+ bcc_recipients = MailboxListField(
+ field_uri="message:BccRecipients", is_read_only_after_send=True, is_searchable=False
+ )
+ is_read_receipt_requested = BooleanField(
+ field_uri="message:IsReadReceiptRequested", is_required=True, default=False, is_read_only_after_send=True
+ )
+ is_delivery_receipt_requested = BooleanField(
+ field_uri="message:IsDeliveryReceiptRequested", is_required=True, default=False, is_read_only_after_send=True
+ )
+ conversation_index = Base64Field(field_uri="message:ConversationIndex", is_read_only=True)
+ conversation_topic = CharField(field_uri="message:ConversationTopic", is_read_only=True)
# Rename 'From' to 'author'. We can't use fieldname 'from' since it's a Python keyword.
- author = MailboxField(field_uri='message:From', is_read_only_after_send=True)
- message_id = CharField(field_uri='message:InternetMessageId', is_read_only_after_send=True)
- is_read = BooleanField(field_uri='message:IsRead', is_required=True, default=False)
- is_response_requested = BooleanField(field_uri='message:IsResponseRequested', default=False, is_required=True)
- references = TextField(field_uri='message:References')
- reply_to = MailboxListField(field_uri='message:ReplyTo', is_read_only_after_send=True, is_searchable=False)
- received_by = MailboxField(field_uri='message:ReceivedBy', is_read_only=True)
- received_representing = MailboxField(field_uri='message:ReceivedRepresenting', is_read_only=True)
- reminder_message_data = EWSElementField(field_uri='message:ReminderMessageData', value_cls=ReminderMessageData,
- supported_from=EXCHANGE_2013_SP1, is_read_only=True)
+ author = MailboxField(field_uri="message:From", is_read_only_after_send=True)
+ message_id = CharField(field_uri="message:InternetMessageId", is_read_only_after_send=True)
+ is_read = BooleanField(field_uri="message:IsRead", is_required=True, default=False)
+ is_response_requested = BooleanField(field_uri="message:IsResponseRequested", default=False, is_required=True)
+ references = TextField(field_uri="message:References")
+ reply_to = MailboxListField(field_uri="message:ReplyTo", is_read_only_after_send=True, is_searchable=False)
+ received_by = MailboxField(field_uri="message:ReceivedBy", is_read_only=True)
+ received_representing = MailboxField(field_uri="message:ReceivedRepresenting", is_read_only=True)
+ reminder_message_data = EWSElementField(
+ field_uri="message:ReminderMessageData",
+ value_cls=ReminderMessageData,
+ supported_from=EXCHANGE_2013_SP1,
+ is_read_only=True,
+ )
@require_account
- def send(self, save_copy=True, copy_to_folder=None, conflict_resolution=AUTO_RESOLVE,
- send_meeting_invitations=SEND_TO_NONE):
+ def send(
+ self,
+ save_copy=True,
+ copy_to_folder=None,
+ conflict_resolution=AUTO_RESOLVE,
+ send_meeting_invitations=SEND_TO_NONE,
+ ):
from ..services import SendItem
+
# Only sends a message. The message can either be an existing draft stored in EWS or a new message that does
# not yet exist in EWS.
if copy_to_folder and not save_copy:
@@ -2837,42 +3056,48 @@ Inherited members
if copy_to_folder:
# This would better be done via send_and_save() but lets just support it here
self.folder = copy_to_folder
- return self.send_and_save(conflict_resolution=conflict_resolution,
- send_meeting_invitations=send_meeting_invitations)
+ return self.send_and_save(
+ conflict_resolution=conflict_resolution, send_meeting_invitations=send_meeting_invitations
+ )
if self.account.version.build < EXCHANGE_2013 and self.attachments:
# At least some versions prior to Exchange 2013 can't send attachments immediately. You need to first save,
# then attach, then send. This is done in send_and_save(). send() will delete the item again.
- self.send_and_save(conflict_resolution=conflict_resolution,
- send_meeting_invitations=send_meeting_invitations)
+ self.send_and_save(
+ conflict_resolution=conflict_resolution, send_meeting_invitations=send_meeting_invitations
+ )
return None
self._create(message_disposition=SEND_ONLY, send_meeting_invitations=send_meeting_invitations)
return None
- def send_and_save(self, update_fields=None, conflict_resolution=AUTO_RESOLVE,
- send_meeting_invitations=SEND_TO_NONE):
+ def send_and_save(
+ self, update_fields=None, conflict_resolution=AUTO_RESOLVE, send_meeting_invitations=SEND_TO_NONE
+ ):
# Sends Message and saves a copy in the parent folder. Does not return an ItemId.
if self.id:
self._update(
update_fieldnames=update_fields,
message_disposition=SEND_AND_SAVE_COPY,
conflict_resolution=conflict_resolution,
- send_meeting_invitations=send_meeting_invitations
+ send_meeting_invitations=send_meeting_invitations,
)
else:
if self.account.version.build < EXCHANGE_2013 and self.attachments:
# At least some versions prior to Exchange 2013 can't send-and-save attachments immediately. You need
# to first save, then attach, then send. This is done in save().
- self.save(update_fields=update_fields, conflict_resolution=conflict_resolution,
- send_meeting_invitations=send_meeting_invitations)
- self.send(save_copy=False, conflict_resolution=conflict_resolution,
- send_meeting_invitations=send_meeting_invitations)
- else:
- self._create(
- message_disposition=SEND_AND_SAVE_COPY,
- send_meeting_invitations=send_meeting_invitations
+ self.save(
+ update_fields=update_fields,
+ conflict_resolution=conflict_resolution,
+ send_meeting_invitations=send_meeting_invitations,
)
+ self.send(
+ save_copy=False,
+ conflict_resolution=conflict_resolution,
+ send_meeting_invitations=send_meeting_invitations,
+ )
+ else:
+ self._create(message_disposition=SEND_AND_SAVE_COPY, send_meeting_invitations=send_meeting_invitations)
@require_id
def create_reply(self, subject, body, to_recipients=None, cc_recipients=None, bcc_recipients=None):
@@ -2891,13 +3116,7 @@ Inherited members
)
def reply(self, subject, body, to_recipients=None, cc_recipients=None, bcc_recipients=None):
- self.create_reply(
- subject,
- body,
- to_recipients,
- cc_recipients,
- bcc_recipients
- ).send()
+ self.create_reply(subject, body, to_recipients, cc_recipients, bcc_recipients).send()
@require_id
def create_reply_all(self, subject, body):
@@ -2926,6 +3145,7 @@ Inherited members
:return:
"""
from ..services import MarkAsJunk
+
res = MarkAsJunk(account=self.account).get(
items=[self], is_junk=is_junk, move_item=move_item, expect_result=move_item
)
@@ -3099,6 +3319,7 @@ Methods
:return:
"""
from ..services import MarkAsJunk
+
res = MarkAsJunk(account=self.account).get(
items=[self], is_junk=is_junk, move_item=move_item, expect_result=move_item
)
@@ -3118,13 +3339,7 @@ Methods
Expand source code
def reply(self, subject, body, to_recipients=None, cc_recipients=None, bcc_recipients=None):
- self.create_reply(
- subject,
- body,
- to_recipients,
- cc_recipients,
- bcc_recipients
- ).send()
+ self.create_reply(subject, body, to_recipients, cc_recipients, bcc_recipients).send()
@@ -3150,9 +3365,15 @@ Methods
Expand source code
@require_account
-def send(self, save_copy=True, copy_to_folder=None, conflict_resolution=AUTO_RESOLVE,
- send_meeting_invitations=SEND_TO_NONE):
+def send(
+ self,
+ save_copy=True,
+ copy_to_folder=None,
+ conflict_resolution=AUTO_RESOLVE,
+ send_meeting_invitations=SEND_TO_NONE,
+):
from ..services import SendItem
+
# Only sends a message. The message can either be an existing draft stored in EWS or a new message that does
# not yet exist in EWS.
if copy_to_folder and not save_copy:
@@ -3170,14 +3391,16 @@ Methods
if copy_to_folder:
# This would better be done via send_and_save() but lets just support it here
self.folder = copy_to_folder
- return self.send_and_save(conflict_resolution=conflict_resolution,
- send_meeting_invitations=send_meeting_invitations)
+ return self.send_and_save(
+ conflict_resolution=conflict_resolution, send_meeting_invitations=send_meeting_invitations
+ )
if self.account.version.build < EXCHANGE_2013 and self.attachments:
# At least some versions prior to Exchange 2013 can't send attachments immediately. You need to first save,
# then attach, then send. This is done in send_and_save(). send() will delete the item again.
- self.send_and_save(conflict_resolution=conflict_resolution,
- send_meeting_invitations=send_meeting_invitations)
+ self.send_and_save(
+ conflict_resolution=conflict_resolution, send_meeting_invitations=send_meeting_invitations
+ )
return None
self._create(message_disposition=SEND_ONLY, send_meeting_invitations=send_meeting_invitations)
@@ -3193,29 +3416,33 @@ Methods
Expand source code
-def send_and_save(self, update_fields=None, conflict_resolution=AUTO_RESOLVE,
- send_meeting_invitations=SEND_TO_NONE):
+def send_and_save(
+ self, update_fields=None, conflict_resolution=AUTO_RESOLVE, send_meeting_invitations=SEND_TO_NONE
+):
# Sends Message and saves a copy in the parent folder. Does not return an ItemId.
if self.id:
self._update(
update_fieldnames=update_fields,
message_disposition=SEND_AND_SAVE_COPY,
conflict_resolution=conflict_resolution,
- send_meeting_invitations=send_meeting_invitations
+ send_meeting_invitations=send_meeting_invitations,
)
else:
if self.account.version.build < EXCHANGE_2013 and self.attachments:
# At least some versions prior to Exchange 2013 can't send-and-save attachments immediately. You need
# to first save, then attach, then send. This is done in save().
- self.save(update_fields=update_fields, conflict_resolution=conflict_resolution,
- send_meeting_invitations=send_meeting_invitations)
- self.send(save_copy=False, conflict_resolution=conflict_resolution,
- send_meeting_invitations=send_meeting_invitations)
+ self.save(
+ update_fields=update_fields,
+ conflict_resolution=conflict_resolution,
+ send_meeting_invitations=send_meeting_invitations,
+ )
+ self.send(
+ save_copy=False,
+ conflict_resolution=conflict_resolution,
+ send_meeting_invitations=send_meeting_invitations,
+ )
else:
- self._create(
- message_disposition=SEND_AND_SAVE_COPY,
- send_meeting_invitations=send_meeting_invitations
- )
+ self._create(message_disposition=SEND_AND_SAVE_COPY, send_meeting_invitations=send_meeting_invitations)
@@ -3251,105 +3478,105 @@ Inherited members
class Persona(IdChangeKeyMixIn):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/persona"""
- ELEMENT_NAME = 'Persona'
+ ELEMENT_NAME = "Persona"
ID_ELEMENT_CLS = PersonaId
- _id = IdElementField(field_uri='persona:PersonaId', value_cls=ID_ELEMENT_CLS, namespace=TNS)
- persona_type = CharField(field_uri='persona:PersonaType')
- persona_object_type = TextField(field_uri='persona:PersonaObjectStatus')
- creation_time = DateTimeField(field_uri='persona:CreationTime')
- bodies = BodyContentAttributedValueField(field_uri='persona:Bodies')
- display_name_first_last_sort_key = TextField(field_uri='persona:DisplayNameFirstLastSortKey')
- display_name_last_first_sort_key = TextField(field_uri='persona:DisplayNameLastFirstSortKey')
- company_sort_key = TextField(field_uri='persona:CompanyNameSortKey')
- home_sort_key = TextField(field_uri='persona:HomeCitySortKey')
- work_city_sort_key = TextField(field_uri='persona:WorkCitySortKey')
- display_name_first_last_header = CharField(field_uri='persona:DisplayNameFirstLastHeader')
- display_name_last_first_header = CharField(field_uri='persona:DisplayNameLastFirstHeader')
- file_as_header = TextField(field_uri='persona:FileAsHeader')
- display_name = CharField(field_uri='persona:DisplayName')
- display_name_first_last = CharField(field_uri='persona:DisplayNameFirstLast')
- display_name_last_first = CharField(field_uri='persona:DisplayNameLastFirst')
- file_as = CharField(field_uri='persona:FileAs')
- file_as_id = TextField(field_uri='persona:FileAsId')
- display_name_prefix = CharField(field_uri='persona:DisplayNamePrefix')
- given_name = CharField(field_uri='persona:GivenName')
- middle_name = CharField(field_uri='persona:MiddleName')
- surname = CharField(field_uri='persona:Surname')
- generation = CharField(field_uri='persona:Generation')
- nickname = TextField(field_uri='persona:Nickname')
- yomi_company_name = TextField(field_uri='persona:YomiCompanyName')
- yomi_first_name = TextField(field_uri='persona:YomiFirstName')
- yomi_last_name = TextField(field_uri='persona:YomiLastName')
- title = CharField(field_uri='persona:Title')
- department = TextField(field_uri='persona:Department')
- company_name = CharField(field_uri='persona:CompanyName')
- email_address = EWSElementField(field_uri='persona:EmailAddress', value_cls=EmailAddress)
- email_addresses = EWSElementListField(field_uri='persona:EmailAddresses', value_cls=Address)
- PhoneNumber = PersonaPhoneNumberField(field_uri='persona:PhoneNumber')
- im_address = CharField(field_uri='persona:ImAddress')
- home_city = CharField(field_uri='persona:HomeCity')
- work_city = CharField(field_uri='persona:WorkCity')
- relevance_score = CharField(field_uri='persona:RelevanceScore')
- folder_ids = EWSElementListField(field_uri='persona:FolderIds', value_cls=FolderId)
- attributions = EWSElementListField(field_uri='persona:Attributions', value_cls=Attribution)
- display_names = StringAttributedValueField(field_uri='persona:DisplayNames')
- file_ases = StringAttributedValueField(field_uri='persona:FileAses')
- file_as_ids = StringAttributedValueField(field_uri='persona:FileAsIds')
- display_name_prefixes = StringAttributedValueField(field_uri='persona:DisplayNamePrefixes')
- given_names = StringAttributedValueField(field_uri='persona:GivenNames')
- middle_names = StringAttributedValueField(field_uri='persona:MiddleNames')
- surnames = StringAttributedValueField(field_uri='persona:Surnames')
- generations = StringAttributedValueField(field_uri='persona:Generations')
- nicknames = StringAttributedValueField(field_uri='persona:Nicknames')
- initials = StringAttributedValueField(field_uri='persona:Initials')
- yomi_company_names = StringAttributedValueField(field_uri='persona:YomiCompanyNames')
- yomi_first_names = StringAttributedValueField(field_uri='persona:YomiFirstNames')
- yomi_last_names = StringAttributedValueField(field_uri='persona:YomiLastNames')
- business_phone_numbers = PhoneNumberAttributedValueField(field_uri='persona:BusinessPhoneNumbers')
- business_phone_numbers2 = PhoneNumberAttributedValueField(field_uri='persona:BusinessPhoneNumbers2')
- home_phones = PhoneNumberAttributedValueField(field_uri='persona:HomePhones')
- home_phones2 = PhoneNumberAttributedValueField(field_uri='persona:HomePhones2')
- mobile_phones = PhoneNumberAttributedValueField(field_uri='persona:MobilePhones')
- mobile_phones2 = PhoneNumberAttributedValueField(field_uri='persona:MobilePhones2')
- assistant_phone_numbers = PhoneNumberAttributedValueField(field_uri='persona:AssistantPhoneNumbers')
- callback_phones = PhoneNumberAttributedValueField(field_uri='persona:CallbackPhones')
- car_phones = PhoneNumberAttributedValueField(field_uri='persona:CarPhones')
- home_faxes = PhoneNumberAttributedValueField(field_uri='persona:HomeFaxes')
- organization_main_phones = PhoneNumberAttributedValueField(field_uri='persona:OrganizationMainPhones')
- other_faxes = PhoneNumberAttributedValueField(field_uri='persona:OtherFaxes')
- other_telephones = PhoneNumberAttributedValueField(field_uri='persona:OtherTelephones')
- other_phones2 = PhoneNumberAttributedValueField(field_uri='persona:OtherPhones2')
- pagers = PhoneNumberAttributedValueField(field_uri='persona:Pagers')
- radio_phones = PhoneNumberAttributedValueField(field_uri='persona:RadioPhones')
- telex_numbers = PhoneNumberAttributedValueField(field_uri='persona:TelexNumbers')
- tty_tdd_phone_numbers = PhoneNumberAttributedValueField(field_uri='persona:TTYTDDPhoneNumbers')
- work_faxes = PhoneNumberAttributedValueField(field_uri='persona:WorkFaxes')
- emails1 = EmailAddressAttributedValueField(field_uri='persona:Emails1')
- emails2 = EmailAddressAttributedValueField(field_uri='persona:Emails2')
- emails3 = EmailAddressAttributedValueField(field_uri='persona:Emails3')
- business_home_pages = StringAttributedValueField(field_uri='persona:BusinessHomePages')
- personal_home_pages = StringAttributedValueField(field_uri='persona:PersonalHomePages')
- office_locations = StringAttributedValueField(field_uri='persona:OfficeLocations')
- im_addresses = StringAttributedValueField(field_uri='persona:ImAddresses')
- im_addresses2 = StringAttributedValueField(field_uri='persona:ImAddresses2')
- im_addresses3 = StringAttributedValueField(field_uri='persona:ImAddresses3')
- business_addresses = PostalAddressAttributedValueField(field_uri='persona:BusinessAddresses')
- home_addresses = PostalAddressAttributedValueField(field_uri='persona:HomeAddresses')
- other_addresses = PostalAddressAttributedValueField(field_uri='persona:OtherAddresses')
- titles = StringAttributedValueField(field_uri='persona:Titles')
- departments = StringAttributedValueField(field_uri='persona:Departments')
- company_names = StringAttributedValueField(field_uri='persona:CompanyNames')
- managers = StringAttributedValueField(field_uri='persona:Managers')
- assistant_names = StringAttributedValueField(field_uri='persona:AssistantNames')
- professions = StringAttributedValueField(field_uri='persona:Professions')
- spouse_names = StringAttributedValueField(field_uri='persona:SpouseNames')
- children = StringAttributedValueField(field_uri='persona:Children')
- schools = StringAttributedValueField(field_uri='persona:Schools')
- hobbies = StringAttributedValueField(field_uri='persona:Hobbies')
- wedding_anniversaries = StringAttributedValueField(field_uri='persona:WeddingAnniversaries')
- birthdays = StringAttributedValueField(field_uri='persona:Birthdays')
- locations = StringAttributedValueField(field_uri='persona:Locations')
+ _id = IdElementField(field_uri="persona:PersonaId", value_cls=ID_ELEMENT_CLS, namespace=TNS)
+ persona_type = CharField(field_uri="persona:PersonaType")
+ persona_object_type = TextField(field_uri="persona:PersonaObjectStatus")
+ creation_time = DateTimeField(field_uri="persona:CreationTime")
+ bodies = BodyContentAttributedValueField(field_uri="persona:Bodies")
+ display_name_first_last_sort_key = TextField(field_uri="persona:DisplayNameFirstLastSortKey")
+ display_name_last_first_sort_key = TextField(field_uri="persona:DisplayNameLastFirstSortKey")
+ company_sort_key = TextField(field_uri="persona:CompanyNameSortKey")
+ home_sort_key = TextField(field_uri="persona:HomeCitySortKey")
+ work_city_sort_key = TextField(field_uri="persona:WorkCitySortKey")
+ display_name_first_last_header = CharField(field_uri="persona:DisplayNameFirstLastHeader")
+ display_name_last_first_header = CharField(field_uri="persona:DisplayNameLastFirstHeader")
+ file_as_header = TextField(field_uri="persona:FileAsHeader")
+ display_name = CharField(field_uri="persona:DisplayName")
+ display_name_first_last = CharField(field_uri="persona:DisplayNameFirstLast")
+ display_name_last_first = CharField(field_uri="persona:DisplayNameLastFirst")
+ file_as = CharField(field_uri="persona:FileAs")
+ file_as_id = TextField(field_uri="persona:FileAsId")
+ display_name_prefix = CharField(field_uri="persona:DisplayNamePrefix")
+ given_name = CharField(field_uri="persona:GivenName")
+ middle_name = CharField(field_uri="persona:MiddleName")
+ surname = CharField(field_uri="persona:Surname")
+ generation = CharField(field_uri="persona:Generation")
+ nickname = TextField(field_uri="persona:Nickname")
+ yomi_company_name = TextField(field_uri="persona:YomiCompanyName")
+ yomi_first_name = TextField(field_uri="persona:YomiFirstName")
+ yomi_last_name = TextField(field_uri="persona:YomiLastName")
+ title = CharField(field_uri="persona:Title")
+ department = TextField(field_uri="persona:Department")
+ company_name = CharField(field_uri="persona:CompanyName")
+ email_address = EWSElementField(field_uri="persona:EmailAddress", value_cls=EmailAddress)
+ email_addresses = EWSElementListField(field_uri="persona:EmailAddresses", value_cls=Address)
+ PhoneNumber = PersonaPhoneNumberField(field_uri="persona:PhoneNumber")
+ im_address = CharField(field_uri="persona:ImAddress")
+ home_city = CharField(field_uri="persona:HomeCity")
+ work_city = CharField(field_uri="persona:WorkCity")
+ relevance_score = CharField(field_uri="persona:RelevanceScore")
+ folder_ids = EWSElementListField(field_uri="persona:FolderIds", value_cls=FolderId)
+ attributions = EWSElementListField(field_uri="persona:Attributions", value_cls=Attribution)
+ display_names = StringAttributedValueField(field_uri="persona:DisplayNames")
+ file_ases = StringAttributedValueField(field_uri="persona:FileAses")
+ file_as_ids = StringAttributedValueField(field_uri="persona:FileAsIds")
+ display_name_prefixes = StringAttributedValueField(field_uri="persona:DisplayNamePrefixes")
+ given_names = StringAttributedValueField(field_uri="persona:GivenNames")
+ middle_names = StringAttributedValueField(field_uri="persona:MiddleNames")
+ surnames = StringAttributedValueField(field_uri="persona:Surnames")
+ generations = StringAttributedValueField(field_uri="persona:Generations")
+ nicknames = StringAttributedValueField(field_uri="persona:Nicknames")
+ initials = StringAttributedValueField(field_uri="persona:Initials")
+ yomi_company_names = StringAttributedValueField(field_uri="persona:YomiCompanyNames")
+ yomi_first_names = StringAttributedValueField(field_uri="persona:YomiFirstNames")
+ yomi_last_names = StringAttributedValueField(field_uri="persona:YomiLastNames")
+ business_phone_numbers = PhoneNumberAttributedValueField(field_uri="persona:BusinessPhoneNumbers")
+ business_phone_numbers2 = PhoneNumberAttributedValueField(field_uri="persona:BusinessPhoneNumbers2")
+ home_phones = PhoneNumberAttributedValueField(field_uri="persona:HomePhones")
+ home_phones2 = PhoneNumberAttributedValueField(field_uri="persona:HomePhones2")
+ mobile_phones = PhoneNumberAttributedValueField(field_uri="persona:MobilePhones")
+ mobile_phones2 = PhoneNumberAttributedValueField(field_uri="persona:MobilePhones2")
+ assistant_phone_numbers = PhoneNumberAttributedValueField(field_uri="persona:AssistantPhoneNumbers")
+ callback_phones = PhoneNumberAttributedValueField(field_uri="persona:CallbackPhones")
+ car_phones = PhoneNumberAttributedValueField(field_uri="persona:CarPhones")
+ home_faxes = PhoneNumberAttributedValueField(field_uri="persona:HomeFaxes")
+ organization_main_phones = PhoneNumberAttributedValueField(field_uri="persona:OrganizationMainPhones")
+ other_faxes = PhoneNumberAttributedValueField(field_uri="persona:OtherFaxes")
+ other_telephones = PhoneNumberAttributedValueField(field_uri="persona:OtherTelephones")
+ other_phones2 = PhoneNumberAttributedValueField(field_uri="persona:OtherPhones2")
+ pagers = PhoneNumberAttributedValueField(field_uri="persona:Pagers")
+ radio_phones = PhoneNumberAttributedValueField(field_uri="persona:RadioPhones")
+ telex_numbers = PhoneNumberAttributedValueField(field_uri="persona:TelexNumbers")
+ tty_tdd_phone_numbers = PhoneNumberAttributedValueField(field_uri="persona:TTYTDDPhoneNumbers")
+ work_faxes = PhoneNumberAttributedValueField(field_uri="persona:WorkFaxes")
+ emails1 = EmailAddressAttributedValueField(field_uri="persona:Emails1")
+ emails2 = EmailAddressAttributedValueField(field_uri="persona:Emails2")
+ emails3 = EmailAddressAttributedValueField(field_uri="persona:Emails3")
+ business_home_pages = StringAttributedValueField(field_uri="persona:BusinessHomePages")
+ personal_home_pages = StringAttributedValueField(field_uri="persona:PersonalHomePages")
+ office_locations = StringAttributedValueField(field_uri="persona:OfficeLocations")
+ im_addresses = StringAttributedValueField(field_uri="persona:ImAddresses")
+ im_addresses2 = StringAttributedValueField(field_uri="persona:ImAddresses2")
+ im_addresses3 = StringAttributedValueField(field_uri="persona:ImAddresses3")
+ business_addresses = PostalAddressAttributedValueField(field_uri="persona:BusinessAddresses")
+ home_addresses = PostalAddressAttributedValueField(field_uri="persona:HomeAddresses")
+ other_addresses = PostalAddressAttributedValueField(field_uri="persona:OtherAddresses")
+ titles = StringAttributedValueField(field_uri="persona:Titles")
+ departments = StringAttributedValueField(field_uri="persona:Departments")
+ company_names = StringAttributedValueField(field_uri="persona:CompanyNames")
+ managers = StringAttributedValueField(field_uri="persona:Managers")
+ assistant_names = StringAttributedValueField(field_uri="persona:AssistantNames")
+ professions = StringAttributedValueField(field_uri="persona:Professions")
+ spouse_names = StringAttributedValueField(field_uri="persona:SpouseNames")
+ children = StringAttributedValueField(field_uri="persona:Children")
+ schools = StringAttributedValueField(field_uri="persona:Schools")
+ hobbies = StringAttributedValueField(field_uri="persona:Hobbies")
+ wedding_anniversaries = StringAttributedValueField(field_uri="persona:WeddingAnniversaries")
+ birthdays = StringAttributedValueField(field_uri="persona:Birthdays")
+ locations = StringAttributedValueField(field_uri="persona:Locations")
Ancestors
@@ -3784,18 +4011,18 @@ Inherited members
class PostItem(Item):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/postitem"""
- ELEMENT_NAME = 'PostItem'
+ ELEMENT_NAME = "PostItem"
- conversation_index = Message.FIELDS['conversation_index']
- conversation_topic = Message.FIELDS['conversation_topic']
+ conversation_index = Message.FIELDS["conversation_index"]
+ conversation_topic = Message.FIELDS["conversation_topic"]
- author = Message.FIELDS['author']
- message_id = Message.FIELDS['message_id']
- is_read = Message.FIELDS['is_read']
+ author = Message.FIELDS["author"]
+ message_id = Message.FIELDS["message_id"]
+ is_read = Message.FIELDS["is_read"]
- posted_time = DateTimeField(field_uri='postitem:PostedTime', is_read_only=True)
- references = TextField(field_uri='message:References')
- sender = MailboxField(field_uri='message:Sender', is_read_only=True, is_read_only_after_send=True)
+ posted_time = DateTimeField(field_uri="postitem:PostedTime", is_read_only=True)
+ references = TextField(field_uri="message:References")
+ sender = MailboxField(field_uri="message:Sender", is_read_only=True, is_read_only_after_send=True)
Ancestors
@@ -3888,15 +4115,15 @@ Inherited members
class PostReplyItem(Item):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/postreplyitem"""
- ELEMENT_NAME = 'PostReplyItem'
+ ELEMENT_NAME = "PostReplyItem"
# This element only has Item fields up to, and including, 'culture'
# TDO: Plus all message fields
- new_body = BodyField(field_uri='NewBodyContent') # Accepts and returns Body or HTMLBody instances
+ new_body = BodyField(field_uri="NewBodyContent") # Accepts and returns Body or HTMLBody instances
- culture_idx = Item.FIELDS.index_by_name('culture')
- sender_idx = Message.FIELDS.index_by_name('sender')
- FIELDS = Item.FIELDS[:culture_idx + 1] + Message.FIELDS[sender_idx:]
+ culture_idx = Item.FIELDS.index_by_name("culture")
+ sender_idx = Message.FIELDS.index_by_name("sender")
+ FIELDS = Item.FIELDS[: culture_idx + 1] + Message.FIELDS[sender_idx:]
Ancestors
@@ -4033,7 +4260,7 @@ Inherited members
"""Base class for classes that can change their list of supported fields dynamically."""
# This class implements dynamic fields on an element class, so we need to include __dict__ in __slots__
- __slots__ = '__dict__',
+ __slots__ = ("__dict__",)
INSERT_AFTER_FIELD = None
@@ -4046,7 +4273,7 @@ Inherited members
:return:
"""
if not cls.INSERT_AFTER_FIELD:
- raise ValueError(f'Class {cls} is missing INSERT_AFTER_FIELD value')
+ raise ValueError(f"Class {cls} is missing INSERT_AFTER_FIELD value")
try:
cls.get_field_by_fieldname(attr_name)
except InvalidField:
@@ -4149,7 +4376,7 @@ Static methods
:return:
"""
if not cls.INSERT_AFTER_FIELD:
- raise ValueError(f'Class {cls} is missing INSERT_AFTER_FIELD value')
+ raise ValueError(f"Class {cls} is missing INSERT_AFTER_FIELD value")
try:
cls.get_field_by_fieldname(attr_name)
except InvalidField:
@@ -4197,7 +4424,7 @@ Inherited members
class ReplyAllToItem(BaseReplyItem):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/replyalltoitem"""
- ELEMENT_NAME = 'ReplyAllToItem'
+ ELEMENT_NAME = "ReplyAllToItem"
Ancestors
@@ -4238,7 +4465,7 @@ Inherited members
class ReplyToItem(BaseReplyItem):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/replytoitem"""
- ELEMENT_NAME = 'ReplyToItem'
+ ELEMENT_NAME = "ReplyToItem"
class Task(Item):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/task"""
- ELEMENT_NAME = 'Task'
- NOT_STARTED = 'NotStarted'
- COMPLETED = 'Completed'
+ ELEMENT_NAME = "Task"
+ NOT_STARTED = "NotStarted"
+ COMPLETED = "Completed"
- actual_work = IntegerField(field_uri='task:ActualWork', min=0)
- assigned_time = DateTimeField(field_uri='task:AssignedTime', is_read_only=True)
- billing_information = TextField(field_uri='task:BillingInformation')
- change_count = IntegerField(field_uri='task:ChangeCount', is_read_only=True, min=0)
- companies = TextListField(field_uri='task:Companies')
+ actual_work = IntegerField(field_uri="task:ActualWork", min=0)
+ assigned_time = DateTimeField(field_uri="task:AssignedTime", is_read_only=True)
+ billing_information = TextField(field_uri="task:BillingInformation")
+ change_count = IntegerField(field_uri="task:ChangeCount", is_read_only=True, min=0)
+ companies = TextListField(field_uri="task:Companies")
# 'complete_date' can be set, but is ignored by the server, which sets it to now()
- complete_date = DateTimeField(field_uri='task:CompleteDate', is_read_only=True)
- contacts = TextListField(field_uri='task:Contacts')
- delegation_state = ChoiceField(field_uri='task:DelegationState', choices={
- Choice('NoMatch'), Choice('OwnNew'), Choice('Owned'), Choice('Accepted'), Choice('Declined'), Choice('Max')
- }, is_read_only=True)
- delegator = CharField(field_uri='task:Delegator', is_read_only=True)
- due_date = DateTimeBackedDateField(field_uri='task:DueDate')
- is_editable = BooleanField(field_uri='task:IsAssignmentEditable', is_read_only=True)
- is_complete = BooleanField(field_uri='task:IsComplete', is_read_only=True)
- is_recurring = BooleanField(field_uri='task:IsRecurring', is_read_only=True)
- is_team_task = BooleanField(field_uri='task:IsTeamTask', is_read_only=True)
- mileage = TextField(field_uri='task:Mileage')
- owner = CharField(field_uri='task:Owner', is_read_only=True)
- percent_complete = DecimalField(field_uri='task:PercentComplete', is_required=True, default=Decimal(0.0),
- min=Decimal(0), max=Decimal(100), is_searchable=False)
- recurrence = TaskRecurrenceField(field_uri='task:Recurrence', is_searchable=False)
- start_date = DateTimeBackedDateField(field_uri='task:StartDate')
- status = ChoiceField(field_uri='task:Status', choices={
- Choice(NOT_STARTED), Choice('InProgress'), Choice(COMPLETED), Choice('WaitingOnOthers'), Choice('Deferred')
- }, is_required=True, is_searchable=False, default=NOT_STARTED)
- status_description = CharField(field_uri='task:StatusDescription', is_read_only=True)
- total_work = IntegerField(field_uri='task:TotalWork', min=0)
+ complete_date = DateTimeField(field_uri="task:CompleteDate", is_read_only=True)
+ contacts = TextListField(field_uri="task:Contacts")
+ delegation_state = ChoiceField(
+ field_uri="task:DelegationState",
+ choices={
+ Choice("NoMatch"),
+ Choice("OwnNew"),
+ Choice("Owned"),
+ Choice("Accepted"),
+ Choice("Declined"),
+ Choice("Max"),
+ },
+ is_read_only=True,
+ )
+ delegator = CharField(field_uri="task:Delegator", is_read_only=True)
+ due_date = DateTimeBackedDateField(field_uri="task:DueDate")
+ is_editable = BooleanField(field_uri="task:IsAssignmentEditable", is_read_only=True)
+ is_complete = BooleanField(field_uri="task:IsComplete", is_read_only=True)
+ is_recurring = BooleanField(field_uri="task:IsRecurring", is_read_only=True)
+ is_team_task = BooleanField(field_uri="task:IsTeamTask", is_read_only=True)
+ mileage = TextField(field_uri="task:Mileage")
+ owner = CharField(field_uri="task:Owner", is_read_only=True)
+ percent_complete = DecimalField(
+ field_uri="task:PercentComplete",
+ is_required=True,
+ default=Decimal(0.0),
+ min=Decimal(0),
+ max=Decimal(100),
+ is_searchable=False,
+ )
+ recurrence = TaskRecurrenceField(field_uri="task:Recurrence", is_searchable=False)
+ start_date = DateTimeBackedDateField(field_uri="task:StartDate")
+ status = ChoiceField(
+ field_uri="task:Status",
+ choices={
+ Choice(NOT_STARTED),
+ Choice("InProgress"),
+ Choice(COMPLETED),
+ Choice("WaitingOnOthers"),
+ Choice("Deferred"),
+ },
+ is_required=True,
+ is_searchable=False,
+ default=NOT_STARTED,
+ )
+ status_description = CharField(field_uri="task:StatusDescription", is_read_only=True)
+ total_work = IntegerField(field_uri="task:TotalWork", min=0)
def clean(self, version=None):
super().clean(version=version)
if self.due_date and self.start_date and self.due_date < self.start_date:
- log.warning("'due_date' must be greater than 'start_date' (%s vs %s). Resetting 'due_date'",
- self.due_date, self.start_date)
+ log.warning(
+ "'due_date' must be greater than 'start_date' (%s vs %s). Resetting 'due_date'",
+ self.due_date,
+ self.start_date,
+ )
self.due_date = self.start_date
if self.complete_date:
if self.status != self.COMPLETED:
- log.warning("'status' must be '%s' when 'complete_date' is set (%s). Resetting",
- self.COMPLETED, self.status)
+ log.warning(
+ "'status' must be '%s' when 'complete_date' is set (%s). Resetting", self.COMPLETED, self.status
+ )
self.status = self.COMPLETED
now = datetime.datetime.now(tz=UTC)
if (self.complete_date - now).total_seconds() > 120:
@@ -4335,19 +4591,28 @@ Inherited members
log.warning("'complete_date' must be in the past (%s vs %s). Resetting", self.complete_date, now)
self.complete_date = now
if self.start_date and self.complete_date.date() < self.start_date:
- log.warning("'complete_date' must be greater than 'start_date' (%s vs %s). Resetting",
- self.complete_date, self.start_date)
+ log.warning(
+ "'complete_date' must be greater than 'start_date' (%s vs %s). Resetting",
+ self.complete_date,
+ self.start_date,
+ )
self.complete_date = EWSDateTime.combine(self.start_date, datetime.time(0, 0)).replace(tzinfo=UTC)
if self.percent_complete is not None:
if self.status == self.COMPLETED and self.percent_complete != Decimal(100):
# percent_complete must be 100% if task is complete
- log.warning("'percent_complete' must be 100 when 'status' is '%s' (%s). Resetting",
- self.COMPLETED, self.percent_complete)
+ log.warning(
+ "'percent_complete' must be 100 when 'status' is '%s' (%s). Resetting",
+ self.COMPLETED,
+ self.percent_complete,
+ )
self.percent_complete = Decimal(100)
elif self.status == self.NOT_STARTED and self.percent_complete != Decimal(0):
# percent_complete must be 0% if task is not started
- log.warning("'percent_complete' must be 0 when 'status' is '%s' (%s). Resetting",
- self.NOT_STARTED, self.percent_complete)
+ log.warning(
+ "'percent_complete' must be 0 when 'status' is '%s' (%s). Resetting",
+ self.NOT_STARTED,
+ self.percent_complete,
+ )
self.percent_complete = Decimal(0)
def complete(self):
@@ -4488,13 +4753,17 @@ Methods
def clean(self, version=None):
super().clean(version=version)
if self.due_date and self.start_date and self.due_date < self.start_date:
- log.warning("'due_date' must be greater than 'start_date' (%s vs %s). Resetting 'due_date'",
- self.due_date, self.start_date)
+ log.warning(
+ "'due_date' must be greater than 'start_date' (%s vs %s). Resetting 'due_date'",
+ self.due_date,
+ self.start_date,
+ )
self.due_date = self.start_date
if self.complete_date:
if self.status != self.COMPLETED:
- log.warning("'status' must be '%s' when 'complete_date' is set (%s). Resetting",
- self.COMPLETED, self.status)
+ log.warning(
+ "'status' must be '%s' when 'complete_date' is set (%s). Resetting", self.COMPLETED, self.status
+ )
self.status = self.COMPLETED
now = datetime.datetime.now(tz=UTC)
if (self.complete_date - now).total_seconds() > 120:
@@ -4503,19 +4772,28 @@ Methods
log.warning("'complete_date' must be in the past (%s vs %s). Resetting", self.complete_date, now)
self.complete_date = now
if self.start_date and self.complete_date.date() < self.start_date:
- log.warning("'complete_date' must be greater than 'start_date' (%s vs %s). Resetting",
- self.complete_date, self.start_date)
+ log.warning(
+ "'complete_date' must be greater than 'start_date' (%s vs %s). Resetting",
+ self.complete_date,
+ self.start_date,
+ )
self.complete_date = EWSDateTime.combine(self.start_date, datetime.time(0, 0)).replace(tzinfo=UTC)
if self.percent_complete is not None:
if self.status == self.COMPLETED and self.percent_complete != Decimal(100):
# percent_complete must be 100% if task is complete
- log.warning("'percent_complete' must be 100 when 'status' is '%s' (%s). Resetting",
- self.COMPLETED, self.percent_complete)
+ log.warning(
+ "'percent_complete' must be 100 when 'status' is '%s' (%s). Resetting",
+ self.COMPLETED,
+ self.percent_complete,
+ )
self.percent_complete = Decimal(100)
elif self.status == self.NOT_STARTED and self.percent_complete != Decimal(0):
# percent_complete must be 0% if task is not started
- log.warning("'percent_complete' must be 0 when 'status' is '%s' (%s). Resetting",
- self.NOT_STARTED, self.percent_complete)
+ log.warning(
+ "'percent_complete' must be 0 when 'status' is '%s' (%s). Resetting",
+ self.NOT_STARTED,
+ self.percent_complete,
+ )
self.percent_complete = Decimal(0)
@@ -4573,7 +4851,7 @@ Inherited members
class TentativelyAcceptItem(BaseMeetingReplyItem):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/tentativelyacceptitem"""
- ELEMENT_NAME = 'TentativelyAcceptItem'
+ ELEMENT_NAME = "TentativelyAcceptItem"
FIELDS
proposed_end
proposed_start
received_by
received_representing
exchangelib.items.item
import logging
-from .base import BaseItem, SAVE_ONLY, SEND_AND_SAVE_COPY, ID_ONLY, SEND_TO_NONE, \
- AUTO_RESOLVE, SOFT_DELETE, HARD_DELETE, ALL_OCCURRENCES, MOVE_TO_DELETED_ITEMS
-from ..fields import BooleanField, IntegerField, TextField, CharListField, ChoiceField, URIField, BodyField, \
- DateTimeField, MessageHeaderField, AttachmentField, Choice, EWSElementField, EffectiveRightsField, CultureField, \
- CharField, MimeContentField, FieldPath
-from ..properties import ConversationId, ParentFolderId, ReferenceItemId, OccurrenceItemId, RecurringMasterItemId, \
- ResponseObjects, Fields
+from ..fields import (
+ AttachmentField,
+ BodyField,
+ BooleanField,
+ CharField,
+ CharListField,
+ Choice,
+ ChoiceField,
+ CultureField,
+ DateTimeField,
+ EffectiveRightsField,
+ EWSElementField,
+ FieldPath,
+ IntegerField,
+ MessageHeaderField,
+ MimeContentField,
+ TextField,
+ URIField,
+)
+from ..properties import (
+ ConversationId,
+ Fields,
+ OccurrenceItemId,
+ ParentFolderId,
+ RecurringMasterItemId,
+ ReferenceItemId,
+ ResponseObjects,
+)
from ..util import is_iterable, require_account, require_id
from ..version import EXCHANGE_2010, EXCHANGE_2013
+from .base import (
+ ALL_OCCURRENCES,
+ AUTO_RESOLVE,
+ HARD_DELETE,
+ ID_ONLY,
+ MOVE_TO_DELETED_ITEMS,
+ SAVE_ONLY,
+ SEND_AND_SAVE_COPY,
+ SEND_TO_NONE,
+ SOFT_DELETE,
+ BaseItem,
+)
log = logging.getLogger(__name__)
@@ -44,62 +77,75 @@ Module exchangelib.items.item
class Item(BaseItem):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/item"""
- ELEMENT_NAME = 'Item'
-
- mime_content = MimeContentField(field_uri='item:MimeContent', is_read_only_after_send=True)
- _id = BaseItem.FIELDS['_id']
- parent_folder_id = EWSElementField(field_uri='item:ParentFolderId', value_cls=ParentFolderId, is_read_only=True)
- item_class = CharField(field_uri='item:ItemClass', is_read_only=True)
- subject = CharField(field_uri='item:Subject')
- sensitivity = ChoiceField(field_uri='item:Sensitivity', choices={
- Choice('Normal'), Choice('Personal'), Choice('Private'), Choice('Confidential')
- }, is_required=True, default='Normal')
- text_body = TextField(field_uri='item:TextBody', is_read_only=True, supported_from=EXCHANGE_2013)
- body = BodyField(field_uri='item:Body') # Accepts and returns Body or HTMLBody instances
- attachments = AttachmentField(field_uri='item:Attachments') # ItemAttachment or FileAttachment
- datetime_received = DateTimeField(field_uri='item:DateTimeReceived', is_read_only=True)
- size = IntegerField(field_uri='item:Size', is_read_only=True) # Item size in bytes
- categories = CharListField(field_uri='item:Categories')
- importance = ChoiceField(field_uri='item:Importance', choices={
- Choice('Low'), Choice('Normal'), Choice('High')
- }, is_required=True, default='Normal')
- in_reply_to = TextField(field_uri='item:InReplyTo')
- is_submitted = BooleanField(field_uri='item:IsSubmitted', is_read_only=True)
- is_draft = BooleanField(field_uri='item:IsDraft', is_read_only=True)
- is_from_me = BooleanField(field_uri='item:IsFromMe', is_read_only=True)
- is_resend = BooleanField(field_uri='item:IsResend', is_read_only=True)
- is_unmodified = BooleanField(field_uri='item:IsUnmodified', is_read_only=True)
- headers = MessageHeaderField(field_uri='item:InternetMessageHeaders', is_read_only=True)
- datetime_sent = DateTimeField(field_uri='item:DateTimeSent', is_read_only=True)
- datetime_created = DateTimeField(field_uri='item:DateTimeCreated', is_read_only=True)
- response_objects = EWSElementField(field_uri='item:ResponseObjects', value_cls=ResponseObjects,
- is_read_only=True,)
+ ELEMENT_NAME = "Item"
+
+ mime_content = MimeContentField(field_uri="item:MimeContent", is_read_only_after_send=True)
+ _id = BaseItem.FIELDS["_id"]
+ parent_folder_id = EWSElementField(field_uri="item:ParentFolderId", value_cls=ParentFolderId, is_read_only=True)
+ item_class = CharField(field_uri="item:ItemClass", is_read_only=True)
+ subject = CharField(field_uri="item:Subject")
+ sensitivity = ChoiceField(
+ field_uri="item:Sensitivity",
+ choices={Choice("Normal"), Choice("Personal"), Choice("Private"), Choice("Confidential")},
+ is_required=True,
+ default="Normal",
+ )
+ text_body = TextField(field_uri="item:TextBody", is_read_only=True, supported_from=EXCHANGE_2013)
+ body = BodyField(field_uri="item:Body") # Accepts and returns Body or HTMLBody instances
+ attachments = AttachmentField(field_uri="item:Attachments") # ItemAttachment or FileAttachment
+ datetime_received = DateTimeField(field_uri="item:DateTimeReceived", is_read_only=True)
+ size = IntegerField(field_uri="item:Size", is_read_only=True) # Item size in bytes
+ categories = CharListField(field_uri="item:Categories")
+ importance = ChoiceField(
+ field_uri="item:Importance",
+ choices={Choice("Low"), Choice("Normal"), Choice("High")},
+ is_required=True,
+ default="Normal",
+ )
+ in_reply_to = TextField(field_uri="item:InReplyTo")
+ is_submitted = BooleanField(field_uri="item:IsSubmitted", is_read_only=True)
+ is_draft = BooleanField(field_uri="item:IsDraft", is_read_only=True)
+ is_from_me = BooleanField(field_uri="item:IsFromMe", is_read_only=True)
+ is_resend = BooleanField(field_uri="item:IsResend", is_read_only=True)
+ is_unmodified = BooleanField(field_uri="item:IsUnmodified", is_read_only=True)
+ headers = MessageHeaderField(field_uri="item:InternetMessageHeaders", is_read_only=True)
+ datetime_sent = DateTimeField(field_uri="item:DateTimeSent", is_read_only=True)
+ datetime_created = DateTimeField(field_uri="item:DateTimeCreated", is_read_only=True)
+ response_objects = EWSElementField(
+ field_uri="item:ResponseObjects",
+ value_cls=ResponseObjects,
+ is_read_only=True,
+ )
# Placeholder for ResponseObjects
- reminder_due_by = DateTimeField(field_uri='item:ReminderDueBy', is_required_after_save=True, is_searchable=False)
- reminder_is_set = BooleanField(field_uri='item:ReminderIsSet', is_required=True, default=False)
- reminder_minutes_before_start = IntegerField(field_uri='item:ReminderMinutesBeforeStart',
- is_required_after_save=True, min=0, default=0)
- display_cc = TextField(field_uri='item:DisplayCc', is_read_only=True)
- display_to = TextField(field_uri='item:DisplayTo', is_read_only=True)
- has_attachments = BooleanField(field_uri='item:HasAttachments', is_read_only=True)
+ reminder_due_by = DateTimeField(field_uri="item:ReminderDueBy", is_required_after_save=True, is_searchable=False)
+ reminder_is_set = BooleanField(field_uri="item:ReminderIsSet", is_required=True, default=False)
+ reminder_minutes_before_start = IntegerField(
+ field_uri="item:ReminderMinutesBeforeStart", is_required_after_save=True, min=0, default=0
+ )
+ display_cc = TextField(field_uri="item:DisplayCc", is_read_only=True)
+ display_to = TextField(field_uri="item:DisplayTo", is_read_only=True)
+ has_attachments = BooleanField(field_uri="item:HasAttachments", is_read_only=True)
# ExtendedProperty fields go here
- culture = CultureField(field_uri='item:Culture', is_required_after_save=True, is_searchable=False)
- effective_rights = EffectiveRightsField(field_uri='item:EffectiveRights', is_read_only=True)
- last_modified_name = CharField(field_uri='item:LastModifiedName', is_read_only=True)
- last_modified_time = DateTimeField(field_uri='item:LastModifiedTime', is_read_only=True)
- is_associated = BooleanField(field_uri='item:IsAssociated', is_read_only=True, supported_from=EXCHANGE_2010)
- web_client_read_form_query_string = URIField(field_uri='item:WebClientReadFormQueryString', is_read_only=True,
- supported_from=EXCHANGE_2010)
- web_client_edit_form_query_string = URIField(field_uri='item:WebClientEditFormQueryString', is_read_only=True,
- supported_from=EXCHANGE_2010)
- conversation_id = EWSElementField(field_uri='item:ConversationId', value_cls=ConversationId,
- is_read_only=True, supported_from=EXCHANGE_2010)
- unique_body = BodyField(field_uri='item:UniqueBody', is_read_only=True, supported_from=EXCHANGE_2010)
+ culture = CultureField(field_uri="item:Culture", is_required_after_save=True, is_searchable=False)
+ effective_rights = EffectiveRightsField(field_uri="item:EffectiveRights", is_read_only=True)
+ last_modified_name = CharField(field_uri="item:LastModifiedName", is_read_only=True)
+ last_modified_time = DateTimeField(field_uri="item:LastModifiedTime", is_read_only=True)
+ is_associated = BooleanField(field_uri="item:IsAssociated", is_read_only=True, supported_from=EXCHANGE_2010)
+ web_client_read_form_query_string = URIField(
+ field_uri="item:WebClientReadFormQueryString", is_read_only=True, supported_from=EXCHANGE_2010
+ )
+ web_client_edit_form_query_string = URIField(
+ field_uri="item:WebClientEditFormQueryString", is_read_only=True, supported_from=EXCHANGE_2010
+ )
+ conversation_id = EWSElementField(
+ field_uri="item:ConversationId", value_cls=ConversationId, is_read_only=True, supported_from=EXCHANGE_2010
+ )
+ unique_body = BodyField(field_uri="item:UniqueBody", is_read_only=True, supported_from=EXCHANGE_2010)
FIELDS = Fields()
# Used to register extended properties
- INSERT_AFTER_FIELD = 'has_attachments'
+ INSERT_AFTER_FIELD = "has_attachments"
def __init__(self, **kwargs):
super().__init__(**kwargs)
@@ -116,16 +162,19 @@ Module exchangelib.items.item
def save(self, update_fields=None, conflict_resolution=AUTO_RESOLVE, send_meeting_invitations=SEND_TO_NONE):
from .task import Task
+
if self.id:
item_id, changekey = self._update(
update_fieldnames=update_fields,
message_disposition=SAVE_ONLY,
conflict_resolution=conflict_resolution,
- send_meeting_invitations=send_meeting_invitations
+ send_meeting_invitations=send_meeting_invitations,
)
- if self.id != item_id \
- and not isinstance(self._id, (OccurrenceItemId, RecurringMasterItemId)) \
- and not isinstance(self, Task):
+ if (
+ self.id != item_id
+ and not isinstance(self._id, (OccurrenceItemId, RecurringMasterItemId))
+ and not isinstance(self, Task)
+ ):
# When we update an item with an OccurrenceItemId as ID, EWS returns the ID of the occurrence, so
# the ID of this item changes.
#
@@ -160,6 +209,7 @@ Module exchangelib.items.item
# Return a BulkCreateResult because we want to return the ID of both the main item *and* attachments. In send
# and send-and-save-copy mode, the server does not return an ID, so we just return True.
from ..services import CreateItem
+
return CreateItem(account=self.account).get(
items=[self],
folder=self.folder,
@@ -169,27 +219,28 @@ Module exchangelib.items.item
def _update_fieldnames(self):
from .contact import Contact, DistributionList
+
# Return the list of fields we are allowed to update
update_fieldnames = []
for f in self.supported_fields(version=self.account.version):
- if f.name == 'attachments':
+ if f.name == "attachments":
# Attachments are handled separately after item creation
continue
if f.is_read_only:
# These cannot be changed
continue
if (f.is_required or f.is_required_after_save) and (
- getattr(self, f.name) is None or (f.is_list and not getattr(self, f.name))
+ getattr(self, f.name) is None or (f.is_list and not getattr(self, f.name))
):
# These are required and cannot be deleted
continue
if not self.is_draft and f.is_read_only_after_send:
# These cannot be changed when the item is no longer a draft
continue
- if f.name == 'message_id' and f.is_read_only_after_send:
+ if f.name == "message_id" and f.is_read_only_after_send:
# 'message_id' doesn't support updating, no matter the draft status
continue
- if f.name == 'mime_content' and isinstance(self, (Contact, DistributionList)):
+ if f.name == "mime_content" and isinstance(self, (Contact, DistributionList)):
# Contact and DistributionList don't support updating mime_content, no matter the draft status
continue
update_fieldnames.append(f.name)
@@ -198,8 +249,9 @@ Module exchangelib.items.item
@require_account
def _update(self, update_fieldnames, message_disposition, conflict_resolution, send_meeting_invitations):
from ..services import UpdateItem
+
if not self.changekey:
- raise ValueError(f'{self.__class__.__name__} must have changekey')
+ raise ValueError(f"{self.__class__.__name__} must have changekey")
if not update_fieldnames:
# The fields to update was not specified explicitly. Update all fields where update is possible
update_fieldnames = self._update_fieldnames()
@@ -217,6 +269,7 @@ Module exchangelib.items.item
# Updates the item based on fresh data from EWS
from ..folders import Folder
from ..services import GetItem
+
additional_fields = {
FieldPath(field=f) for f in Folder(root=self.account.root).allowed_item_fields(version=self.account.version)
}
@@ -235,6 +288,7 @@ Module exchangelib.items.item
@require_id
def copy(self, to_folder):
from ..services import CopyItem
+
# If 'to_folder' is a public folder or a folder in a different mailbox then None is returned
return CopyItem(account=self.account).get(
items=[self],
@@ -245,6 +299,7 @@ Module exchangelib.items.item
@require_id
def move(self, to_folder):
from ..services import MoveItem
+
res = MoveItem(account=self.account).get(
items=[self],
to_folder=to_folder,
@@ -257,32 +312,57 @@ Module exchangelib.items.item
self._id = self.ID_ELEMENT_CLS(*res)
self.folder = to_folder
- def move_to_trash(self, send_meeting_cancellations=SEND_TO_NONE, affected_task_occurrences=ALL_OCCURRENCES,
- suppress_read_receipts=True):
+ def move_to_trash(
+ self,
+ send_meeting_cancellations=SEND_TO_NONE,
+ affected_task_occurrences=ALL_OCCURRENCES,
+ suppress_read_receipts=True,
+ ):
# Delete and move to the trash folder.
- self._delete(delete_type=MOVE_TO_DELETED_ITEMS, send_meeting_cancellations=send_meeting_cancellations,
- affected_task_occurrences=affected_task_occurrences, suppress_read_receipts=suppress_read_receipts)
+ self._delete(
+ delete_type=MOVE_TO_DELETED_ITEMS,
+ send_meeting_cancellations=send_meeting_cancellations,
+ affected_task_occurrences=affected_task_occurrences,
+ suppress_read_receipts=suppress_read_receipts,
+ )
self._id = None
self.folder = self.account.trash
- def soft_delete(self, send_meeting_cancellations=SEND_TO_NONE, affected_task_occurrences=ALL_OCCURRENCES,
- suppress_read_receipts=True):
+ def soft_delete(
+ self,
+ send_meeting_cancellations=SEND_TO_NONE,
+ affected_task_occurrences=ALL_OCCURRENCES,
+ suppress_read_receipts=True,
+ ):
# Delete and move to the dumpster, if it is enabled.
- self._delete(delete_type=SOFT_DELETE, send_meeting_cancellations=send_meeting_cancellations,
- affected_task_occurrences=affected_task_occurrences, suppress_read_receipts=suppress_read_receipts)
+ self._delete(
+ delete_type=SOFT_DELETE,
+ send_meeting_cancellations=send_meeting_cancellations,
+ affected_task_occurrences=affected_task_occurrences,
+ suppress_read_receipts=suppress_read_receipts,
+ )
self._id = None
self.folder = self.account.recoverable_items_deletions
- def delete(self, send_meeting_cancellations=SEND_TO_NONE, affected_task_occurrences=ALL_OCCURRENCES,
- suppress_read_receipts=True):
+ def delete(
+ self,
+ send_meeting_cancellations=SEND_TO_NONE,
+ affected_task_occurrences=ALL_OCCURRENCES,
+ suppress_read_receipts=True,
+ ):
# Remove the item permanently. No copies are stored anywhere.
- self._delete(delete_type=HARD_DELETE, send_meeting_cancellations=send_meeting_cancellations,
- affected_task_occurrences=affected_task_occurrences, suppress_read_receipts=suppress_read_receipts)
+ self._delete(
+ delete_type=HARD_DELETE,
+ send_meeting_cancellations=send_meeting_cancellations,
+ affected_task_occurrences=affected_task_occurrences,
+ suppress_read_receipts=suppress_read_receipts,
+ )
self._id, self.folder = None, None
@require_id
def _delete(self, delete_type, send_meeting_cancellations, affected_task_occurrences, suppress_read_receipts):
from ..services import DeleteItem
+
DeleteItem(account=self.account).get(
items=[self],
delete_type=delete_type,
@@ -294,6 +374,7 @@ Module exchangelib.items.item
@require_id
def archive(self, to_folder):
from ..services import ArchiveItem
+
return ArchiveItem(account=self.account).get(items=[self], to_folder=to_folder, expect_result=True)
def attach(self, attachments):
@@ -332,7 +413,7 @@ Module exchangelib.items.item
attachments = list(attachments)
for a in attachments:
if a.parent_item is not self:
- raise ValueError('Attachment does not belong to this item')
+ raise ValueError("Attachment does not belong to this item")
if self.id:
# Item is already created. Detach the attachment server-side now
a.detach()
@@ -342,6 +423,7 @@ Module exchangelib.items.item
@require_id
def create_forward(self, subject, body, to_recipients, cc_recipients=None, bcc_recipients=None):
from .message import ForwardItem
+
return ForwardItem(
account=self.account,
reference_item_id=ReferenceItemId(id=self.id, changekey=self.changekey),
@@ -389,62 +471,75 @@ Classes
class Item(BaseItem):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/item"""
- ELEMENT_NAME = 'Item'
-
- mime_content = MimeContentField(field_uri='item:MimeContent', is_read_only_after_send=True)
- _id = BaseItem.FIELDS['_id']
- parent_folder_id = EWSElementField(field_uri='item:ParentFolderId', value_cls=ParentFolderId, is_read_only=True)
- item_class = CharField(field_uri='item:ItemClass', is_read_only=True)
- subject = CharField(field_uri='item:Subject')
- sensitivity = ChoiceField(field_uri='item:Sensitivity', choices={
- Choice('Normal'), Choice('Personal'), Choice('Private'), Choice('Confidential')
- }, is_required=True, default='Normal')
- text_body = TextField(field_uri='item:TextBody', is_read_only=True, supported_from=EXCHANGE_2013)
- body = BodyField(field_uri='item:Body') # Accepts and returns Body or HTMLBody instances
- attachments = AttachmentField(field_uri='item:Attachments') # ItemAttachment or FileAttachment
- datetime_received = DateTimeField(field_uri='item:DateTimeReceived', is_read_only=True)
- size = IntegerField(field_uri='item:Size', is_read_only=True) # Item size in bytes
- categories = CharListField(field_uri='item:Categories')
- importance = ChoiceField(field_uri='item:Importance', choices={
- Choice('Low'), Choice('Normal'), Choice('High')
- }, is_required=True, default='Normal')
- in_reply_to = TextField(field_uri='item:InReplyTo')
- is_submitted = BooleanField(field_uri='item:IsSubmitted', is_read_only=True)
- is_draft = BooleanField(field_uri='item:IsDraft', is_read_only=True)
- is_from_me = BooleanField(field_uri='item:IsFromMe', is_read_only=True)
- is_resend = BooleanField(field_uri='item:IsResend', is_read_only=True)
- is_unmodified = BooleanField(field_uri='item:IsUnmodified', is_read_only=True)
- headers = MessageHeaderField(field_uri='item:InternetMessageHeaders', is_read_only=True)
- datetime_sent = DateTimeField(field_uri='item:DateTimeSent', is_read_only=True)
- datetime_created = DateTimeField(field_uri='item:DateTimeCreated', is_read_only=True)
- response_objects = EWSElementField(field_uri='item:ResponseObjects', value_cls=ResponseObjects,
- is_read_only=True,)
+ ELEMENT_NAME = "Item"
+
+ mime_content = MimeContentField(field_uri="item:MimeContent", is_read_only_after_send=True)
+ _id = BaseItem.FIELDS["_id"]
+ parent_folder_id = EWSElementField(field_uri="item:ParentFolderId", value_cls=ParentFolderId, is_read_only=True)
+ item_class = CharField(field_uri="item:ItemClass", is_read_only=True)
+ subject = CharField(field_uri="item:Subject")
+ sensitivity = ChoiceField(
+ field_uri="item:Sensitivity",
+ choices={Choice("Normal"), Choice("Personal"), Choice("Private"), Choice("Confidential")},
+ is_required=True,
+ default="Normal",
+ )
+ text_body = TextField(field_uri="item:TextBody", is_read_only=True, supported_from=EXCHANGE_2013)
+ body = BodyField(field_uri="item:Body") # Accepts and returns Body or HTMLBody instances
+ attachments = AttachmentField(field_uri="item:Attachments") # ItemAttachment or FileAttachment
+ datetime_received = DateTimeField(field_uri="item:DateTimeReceived", is_read_only=True)
+ size = IntegerField(field_uri="item:Size", is_read_only=True) # Item size in bytes
+ categories = CharListField(field_uri="item:Categories")
+ importance = ChoiceField(
+ field_uri="item:Importance",
+ choices={Choice("Low"), Choice("Normal"), Choice("High")},
+ is_required=True,
+ default="Normal",
+ )
+ in_reply_to = TextField(field_uri="item:InReplyTo")
+ is_submitted = BooleanField(field_uri="item:IsSubmitted", is_read_only=True)
+ is_draft = BooleanField(field_uri="item:IsDraft", is_read_only=True)
+ is_from_me = BooleanField(field_uri="item:IsFromMe", is_read_only=True)
+ is_resend = BooleanField(field_uri="item:IsResend", is_read_only=True)
+ is_unmodified = BooleanField(field_uri="item:IsUnmodified", is_read_only=True)
+ headers = MessageHeaderField(field_uri="item:InternetMessageHeaders", is_read_only=True)
+ datetime_sent = DateTimeField(field_uri="item:DateTimeSent", is_read_only=True)
+ datetime_created = DateTimeField(field_uri="item:DateTimeCreated", is_read_only=True)
+ response_objects = EWSElementField(
+ field_uri="item:ResponseObjects",
+ value_cls=ResponseObjects,
+ is_read_only=True,
+ )
# Placeholder for ResponseObjects
- reminder_due_by = DateTimeField(field_uri='item:ReminderDueBy', is_required_after_save=True, is_searchable=False)
- reminder_is_set = BooleanField(field_uri='item:ReminderIsSet', is_required=True, default=False)
- reminder_minutes_before_start = IntegerField(field_uri='item:ReminderMinutesBeforeStart',
- is_required_after_save=True, min=0, default=0)
- display_cc = TextField(field_uri='item:DisplayCc', is_read_only=True)
- display_to = TextField(field_uri='item:DisplayTo', is_read_only=True)
- has_attachments = BooleanField(field_uri='item:HasAttachments', is_read_only=True)
+ reminder_due_by = DateTimeField(field_uri="item:ReminderDueBy", is_required_after_save=True, is_searchable=False)
+ reminder_is_set = BooleanField(field_uri="item:ReminderIsSet", is_required=True, default=False)
+ reminder_minutes_before_start = IntegerField(
+ field_uri="item:ReminderMinutesBeforeStart", is_required_after_save=True, min=0, default=0
+ )
+ display_cc = TextField(field_uri="item:DisplayCc", is_read_only=True)
+ display_to = TextField(field_uri="item:DisplayTo", is_read_only=True)
+ has_attachments = BooleanField(field_uri="item:HasAttachments", is_read_only=True)
# ExtendedProperty fields go here
- culture = CultureField(field_uri='item:Culture', is_required_after_save=True, is_searchable=False)
- effective_rights = EffectiveRightsField(field_uri='item:EffectiveRights', is_read_only=True)
- last_modified_name = CharField(field_uri='item:LastModifiedName', is_read_only=True)
- last_modified_time = DateTimeField(field_uri='item:LastModifiedTime', is_read_only=True)
- is_associated = BooleanField(field_uri='item:IsAssociated', is_read_only=True, supported_from=EXCHANGE_2010)
- web_client_read_form_query_string = URIField(field_uri='item:WebClientReadFormQueryString', is_read_only=True,
- supported_from=EXCHANGE_2010)
- web_client_edit_form_query_string = URIField(field_uri='item:WebClientEditFormQueryString', is_read_only=True,
- supported_from=EXCHANGE_2010)
- conversation_id = EWSElementField(field_uri='item:ConversationId', value_cls=ConversationId,
- is_read_only=True, supported_from=EXCHANGE_2010)
- unique_body = BodyField(field_uri='item:UniqueBody', is_read_only=True, supported_from=EXCHANGE_2010)
+ culture = CultureField(field_uri="item:Culture", is_required_after_save=True, is_searchable=False)
+ effective_rights = EffectiveRightsField(field_uri="item:EffectiveRights", is_read_only=True)
+ last_modified_name = CharField(field_uri="item:LastModifiedName", is_read_only=True)
+ last_modified_time = DateTimeField(field_uri="item:LastModifiedTime", is_read_only=True)
+ is_associated = BooleanField(field_uri="item:IsAssociated", is_read_only=True, supported_from=EXCHANGE_2010)
+ web_client_read_form_query_string = URIField(
+ field_uri="item:WebClientReadFormQueryString", is_read_only=True, supported_from=EXCHANGE_2010
+ )
+ web_client_edit_form_query_string = URIField(
+ field_uri="item:WebClientEditFormQueryString", is_read_only=True, supported_from=EXCHANGE_2010
+ )
+ conversation_id = EWSElementField(
+ field_uri="item:ConversationId", value_cls=ConversationId, is_read_only=True, supported_from=EXCHANGE_2010
+ )
+ unique_body = BodyField(field_uri="item:UniqueBody", is_read_only=True, supported_from=EXCHANGE_2010)
FIELDS = Fields()
# Used to register extended properties
- INSERT_AFTER_FIELD = 'has_attachments'
+ INSERT_AFTER_FIELD = "has_attachments"
def __init__(self, **kwargs):
super().__init__(**kwargs)
@@ -461,16 +556,19 @@ Classes
def save(self, update_fields=None, conflict_resolution=AUTO_RESOLVE, send_meeting_invitations=SEND_TO_NONE):
from .task import Task
+
if self.id:
item_id, changekey = self._update(
update_fieldnames=update_fields,
message_disposition=SAVE_ONLY,
conflict_resolution=conflict_resolution,
- send_meeting_invitations=send_meeting_invitations
+ send_meeting_invitations=send_meeting_invitations,
)
- if self.id != item_id \
- and not isinstance(self._id, (OccurrenceItemId, RecurringMasterItemId)) \
- and not isinstance(self, Task):
+ if (
+ self.id != item_id
+ and not isinstance(self._id, (OccurrenceItemId, RecurringMasterItemId))
+ and not isinstance(self, Task)
+ ):
# When we update an item with an OccurrenceItemId as ID, EWS returns the ID of the occurrence, so
# the ID of this item changes.
#
@@ -505,6 +603,7 @@ Classes
# Return a BulkCreateResult because we want to return the ID of both the main item *and* attachments. In send
# and send-and-save-copy mode, the server does not return an ID, so we just return True.
from ..services import CreateItem
+
return CreateItem(account=self.account).get(
items=[self],
folder=self.folder,
@@ -514,27 +613,28 @@ Classes
def _update_fieldnames(self):
from .contact import Contact, DistributionList
+
# Return the list of fields we are allowed to update
update_fieldnames = []
for f in self.supported_fields(version=self.account.version):
- if f.name == 'attachments':
+ if f.name == "attachments":
# Attachments are handled separately after item creation
continue
if f.is_read_only:
# These cannot be changed
continue
if (f.is_required or f.is_required_after_save) and (
- getattr(self, f.name) is None or (f.is_list and not getattr(self, f.name))
+ getattr(self, f.name) is None or (f.is_list and not getattr(self, f.name))
):
# These are required and cannot be deleted
continue
if not self.is_draft and f.is_read_only_after_send:
# These cannot be changed when the item is no longer a draft
continue
- if f.name == 'message_id' and f.is_read_only_after_send:
+ if f.name == "message_id" and f.is_read_only_after_send:
# 'message_id' doesn't support updating, no matter the draft status
continue
- if f.name == 'mime_content' and isinstance(self, (Contact, DistributionList)):
+ if f.name == "mime_content" and isinstance(self, (Contact, DistributionList)):
# Contact and DistributionList don't support updating mime_content, no matter the draft status
continue
update_fieldnames.append(f.name)
@@ -543,8 +643,9 @@ Classes
@require_account
def _update(self, update_fieldnames, message_disposition, conflict_resolution, send_meeting_invitations):
from ..services import UpdateItem
+
if not self.changekey:
- raise ValueError(f'{self.__class__.__name__} must have changekey')
+ raise ValueError(f"{self.__class__.__name__} must have changekey")
if not update_fieldnames:
# The fields to update was not specified explicitly. Update all fields where update is possible
update_fieldnames = self._update_fieldnames()
@@ -562,6 +663,7 @@ Classes
# Updates the item based on fresh data from EWS
from ..folders import Folder
from ..services import GetItem
+
additional_fields = {
FieldPath(field=f) for f in Folder(root=self.account.root).allowed_item_fields(version=self.account.version)
}
@@ -580,6 +682,7 @@ Classes
@require_id
def copy(self, to_folder):
from ..services import CopyItem
+
# If 'to_folder' is a public folder or a folder in a different mailbox then None is returned
return CopyItem(account=self.account).get(
items=[self],
@@ -590,6 +693,7 @@ Classes
@require_id
def move(self, to_folder):
from ..services import MoveItem
+
res = MoveItem(account=self.account).get(
items=[self],
to_folder=to_folder,
@@ -602,32 +706,57 @@ Classes
self._id = self.ID_ELEMENT_CLS(*res)
self.folder = to_folder
- def move_to_trash(self, send_meeting_cancellations=SEND_TO_NONE, affected_task_occurrences=ALL_OCCURRENCES,
- suppress_read_receipts=True):
+ def move_to_trash(
+ self,
+ send_meeting_cancellations=SEND_TO_NONE,
+ affected_task_occurrences=ALL_OCCURRENCES,
+ suppress_read_receipts=True,
+ ):
# Delete and move to the trash folder.
- self._delete(delete_type=MOVE_TO_DELETED_ITEMS, send_meeting_cancellations=send_meeting_cancellations,
- affected_task_occurrences=affected_task_occurrences, suppress_read_receipts=suppress_read_receipts)
+ self._delete(
+ delete_type=MOVE_TO_DELETED_ITEMS,
+ send_meeting_cancellations=send_meeting_cancellations,
+ affected_task_occurrences=affected_task_occurrences,
+ suppress_read_receipts=suppress_read_receipts,
+ )
self._id = None
self.folder = self.account.trash
- def soft_delete(self, send_meeting_cancellations=SEND_TO_NONE, affected_task_occurrences=ALL_OCCURRENCES,
- suppress_read_receipts=True):
+ def soft_delete(
+ self,
+ send_meeting_cancellations=SEND_TO_NONE,
+ affected_task_occurrences=ALL_OCCURRENCES,
+ suppress_read_receipts=True,
+ ):
# Delete and move to the dumpster, if it is enabled.
- self._delete(delete_type=SOFT_DELETE, send_meeting_cancellations=send_meeting_cancellations,
- affected_task_occurrences=affected_task_occurrences, suppress_read_receipts=suppress_read_receipts)
+ self._delete(
+ delete_type=SOFT_DELETE,
+ send_meeting_cancellations=send_meeting_cancellations,
+ affected_task_occurrences=affected_task_occurrences,
+ suppress_read_receipts=suppress_read_receipts,
+ )
self._id = None
self.folder = self.account.recoverable_items_deletions
- def delete(self, send_meeting_cancellations=SEND_TO_NONE, affected_task_occurrences=ALL_OCCURRENCES,
- suppress_read_receipts=True):
+ def delete(
+ self,
+ send_meeting_cancellations=SEND_TO_NONE,
+ affected_task_occurrences=ALL_OCCURRENCES,
+ suppress_read_receipts=True,
+ ):
# Remove the item permanently. No copies are stored anywhere.
- self._delete(delete_type=HARD_DELETE, send_meeting_cancellations=send_meeting_cancellations,
- affected_task_occurrences=affected_task_occurrences, suppress_read_receipts=suppress_read_receipts)
+ self._delete(
+ delete_type=HARD_DELETE,
+ send_meeting_cancellations=send_meeting_cancellations,
+ affected_task_occurrences=affected_task_occurrences,
+ suppress_read_receipts=suppress_read_receipts,
+ )
self._id, self.folder = None, None
@require_id
def _delete(self, delete_type, send_meeting_cancellations, affected_task_occurrences, suppress_read_receipts):
from ..services import DeleteItem
+
DeleteItem(account=self.account).get(
items=[self],
delete_type=delete_type,
@@ -639,6 +768,7 @@ Classes
@require_id
def archive(self, to_folder):
from ..services import ArchiveItem
+
return ArchiveItem(account=self.account).get(items=[self], to_folder=to_folder, expect_result=True)
def attach(self, attachments):
@@ -677,7 +807,7 @@ Classes
attachments = list(attachments)
for a in attachments:
if a.parent_item is not self:
- raise ValueError('Attachment does not belong to this item')
+ raise ValueError("Attachment does not belong to this item")
if self.id:
# Item is already created. Detach the attachment server-side now
a.detach()
@@ -687,6 +817,7 @@ Classes
@require_id
def create_forward(self, subject, body, to_recipients, cc_recipients=None, bcc_recipients=None):
from .message import ForwardItem
+
return ForwardItem(
account=self.account,
reference_item_id=ReferenceItemId(id=self.id, changekey=self.changekey),
@@ -904,6 +1035,7 @@ Methods
@require_id
def archive(self, to_folder):
from ..services import ArchiveItem
+
return ArchiveItem(account=self.account).get(items=[self], to_folder=to_folder, expect_result=True)
@@ -953,6 +1085,7 @@ Methods
@require_id
def copy(self, to_folder):
from ..services import CopyItem
+
# If 'to_folder' is a public folder or a folder in a different mailbox then None is returned
return CopyItem(account=self.account).get(
items=[self],
@@ -973,6 +1106,7 @@ Methods
@require_id
def create_forward(self, subject, body, to_recipients, cc_recipients=None, bcc_recipients=None):
from .message import ForwardItem
+
return ForwardItem(
account=self.account,
reference_item_id=ReferenceItemId(id=self.id, changekey=self.changekey),
@@ -993,11 +1127,19 @@ Methods
Expand source code
-def delete(self, send_meeting_cancellations=SEND_TO_NONE, affected_task_occurrences=ALL_OCCURRENCES,
- suppress_read_receipts=True):
+def delete(
+ self,
+ send_meeting_cancellations=SEND_TO_NONE,
+ affected_task_occurrences=ALL_OCCURRENCES,
+ suppress_read_receipts=True,
+):
# Remove the item permanently. No copies are stored anywhere.
- self._delete(delete_type=HARD_DELETE, send_meeting_cancellations=send_meeting_cancellations,
- affected_task_occurrences=affected_task_occurrences, suppress_read_receipts=suppress_read_receipts)
+ self._delete(
+ delete_type=HARD_DELETE,
+ send_meeting_cancellations=send_meeting_cancellations,
+ affected_task_occurrences=affected_task_occurrences,
+ suppress_read_receipts=suppress_read_receipts,
+ )
self._id, self.folder = None, None
@@ -1030,7 +1172,7 @@ Methods
attachments = list(attachments)
for a in attachments:
if a.parent_item is not self:
- raise ValueError('Attachment does not belong to this item')
+ raise ValueError("Attachment does not belong to this item")
if self.id:
# Item is already created. Detach the attachment server-side now
a.detach()
@@ -1069,6 +1211,7 @@ Methods
@require_id
def move(self, to_folder):
from ..services import MoveItem
+
res = MoveItem(account=self.account).get(
items=[self],
to_folder=to_folder,
@@ -1091,11 +1234,19 @@ Methods
Expand source code
-def move_to_trash(self, send_meeting_cancellations=SEND_TO_NONE, affected_task_occurrences=ALL_OCCURRENCES,
- suppress_read_receipts=True):
+def move_to_trash(
+ self,
+ send_meeting_cancellations=SEND_TO_NONE,
+ affected_task_occurrences=ALL_OCCURRENCES,
+ suppress_read_receipts=True,
+):
# Delete and move to the trash folder.
- self._delete(delete_type=MOVE_TO_DELETED_ITEMS, send_meeting_cancellations=send_meeting_cancellations,
- affected_task_occurrences=affected_task_occurrences, suppress_read_receipts=suppress_read_receipts)
+ self._delete(
+ delete_type=MOVE_TO_DELETED_ITEMS,
+ send_meeting_cancellations=send_meeting_cancellations,
+ affected_task_occurrences=affected_task_occurrences,
+ suppress_read_receipts=suppress_read_receipts,
+ )
self._id = None
self.folder = self.account.trash
@@ -1114,6 +1265,7 @@ Methods
# Updates the item based on fresh data from EWS
from ..folders import Folder
from ..services import GetItem
+
additional_fields = {
FieldPath(field=f) for f in Folder(root=self.account.root).allowed_item_fields(version=self.account.version)
}
@@ -1141,16 +1293,19 @@ Methods
def save(self, update_fields=None, conflict_resolution=AUTO_RESOLVE, send_meeting_invitations=SEND_TO_NONE):
from .task import Task
+
if self.id:
item_id, changekey = self._update(
update_fieldnames=update_fields,
message_disposition=SAVE_ONLY,
conflict_resolution=conflict_resolution,
- send_meeting_invitations=send_meeting_invitations
+ send_meeting_invitations=send_meeting_invitations,
)
- if self.id != item_id \
- and not isinstance(self._id, (OccurrenceItemId, RecurringMasterItemId)) \
- and not isinstance(self, Task):
+ if (
+ self.id != item_id
+ and not isinstance(self._id, (OccurrenceItemId, RecurringMasterItemId))
+ and not isinstance(self, Task)
+ ):
# When we update an item with an OccurrenceItemId as ID, EWS returns the ID of the occurrence, so
# the ID of this item changes.
#
@@ -1190,11 +1345,19 @@ Methods
Expand source code
-def soft_delete(self, send_meeting_cancellations=SEND_TO_NONE, affected_task_occurrences=ALL_OCCURRENCES,
- suppress_read_receipts=True):
+def soft_delete(
+ self,
+ send_meeting_cancellations=SEND_TO_NONE,
+ affected_task_occurrences=ALL_OCCURRENCES,
+ suppress_read_receipts=True,
+):
# Delete and move to the dumpster, if it is enabled.
- self._delete(delete_type=SOFT_DELETE, send_meeting_cancellations=send_meeting_cancellations,
- affected_task_occurrences=affected_task_occurrences, suppress_read_receipts=suppress_read_receipts)
+ self._delete(
+ delete_type=SOFT_DELETE,
+ send_meeting_cancellations=send_meeting_cancellations,
+ affected_task_occurrences=affected_task_occurrences,
+ suppress_read_receipts=suppress_read_receipts,
+ )
self._id = None
self.folder = self.account.recoverable_items_deletions
diff --git a/docs/exchangelib/items/message.html b/docs/exchangelib/items/message.html
index df2d7089..a5aafdb6 100644
--- a/docs/exchangelib/items/message.html
+++ b/docs/exchangelib/items/message.html
@@ -28,12 +28,12 @@ Module exchangelib.items.message
import logging
-from .base import BaseReplyItem, AUTO_RESOLVE, SEND_TO_NONE, SEND_ONLY, SEND_AND_SAVE_COPY
-from .item import Item
-from ..fields import BooleanField, Base64Field, TextField, MailboxField, MailboxListField, CharField, EWSElementField
+from ..fields import Base64Field, BooleanField, CharField, EWSElementField, MailboxField, MailboxListField, TextField
from ..properties import ReferenceItemId, ReminderMessageData
from ..util import require_account, require_id
from ..version import EXCHANGE_2013, EXCHANGE_2013_SP1
+from .base import AUTO_RESOLVE, SEND_AND_SAVE_COPY, SEND_ONLY, SEND_TO_NONE, BaseReplyItem
+from .item import Item
log = logging.getLogger(__name__)
@@ -43,37 +43,52 @@ Module exchangelib.items.message
https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/message-ex15websvcsotherref
"""
- ELEMENT_NAME = 'Message'
-
- sender = MailboxField(field_uri='message:Sender', is_read_only=True, is_read_only_after_send=True)
- to_recipients = MailboxListField(field_uri='message:ToRecipients', is_read_only_after_send=True,
- is_searchable=False)
- cc_recipients = MailboxListField(field_uri='message:CcRecipients', is_read_only_after_send=True,
- is_searchable=False)
- bcc_recipients = MailboxListField(field_uri='message:BccRecipients', is_read_only_after_send=True,
- is_searchable=False)
- is_read_receipt_requested = BooleanField(field_uri='message:IsReadReceiptRequested',
- is_required=True, default=False, is_read_only_after_send=True)
- is_delivery_receipt_requested = BooleanField(field_uri='message:IsDeliveryReceiptRequested', is_required=True,
- default=False, is_read_only_after_send=True)
- conversation_index = Base64Field(field_uri='message:ConversationIndex', is_read_only=True)
- conversation_topic = CharField(field_uri='message:ConversationTopic', is_read_only=True)
+ ELEMENT_NAME = "Message"
+
+ sender = MailboxField(field_uri="message:Sender", is_read_only=True, is_read_only_after_send=True)
+ to_recipients = MailboxListField(
+ field_uri="message:ToRecipients", is_read_only_after_send=True, is_searchable=False
+ )
+ cc_recipients = MailboxListField(
+ field_uri="message:CcRecipients", is_read_only_after_send=True, is_searchable=False
+ )
+ bcc_recipients = MailboxListField(
+ field_uri="message:BccRecipients", is_read_only_after_send=True, is_searchable=False
+ )
+ is_read_receipt_requested = BooleanField(
+ field_uri="message:IsReadReceiptRequested", is_required=True, default=False, is_read_only_after_send=True
+ )
+ is_delivery_receipt_requested = BooleanField(
+ field_uri="message:IsDeliveryReceiptRequested", is_required=True, default=False, is_read_only_after_send=True
+ )
+ conversation_index = Base64Field(field_uri="message:ConversationIndex", is_read_only=True)
+ conversation_topic = CharField(field_uri="message:ConversationTopic", is_read_only=True)
# Rename 'From' to 'author'. We can't use fieldname 'from' since it's a Python keyword.
- author = MailboxField(field_uri='message:From', is_read_only_after_send=True)
- message_id = CharField(field_uri='message:InternetMessageId', is_read_only_after_send=True)
- is_read = BooleanField(field_uri='message:IsRead', is_required=True, default=False)
- is_response_requested = BooleanField(field_uri='message:IsResponseRequested', default=False, is_required=True)
- references = TextField(field_uri='message:References')
- reply_to = MailboxListField(field_uri='message:ReplyTo', is_read_only_after_send=True, is_searchable=False)
- received_by = MailboxField(field_uri='message:ReceivedBy', is_read_only=True)
- received_representing = MailboxField(field_uri='message:ReceivedRepresenting', is_read_only=True)
- reminder_message_data = EWSElementField(field_uri='message:ReminderMessageData', value_cls=ReminderMessageData,
- supported_from=EXCHANGE_2013_SP1, is_read_only=True)
+ author = MailboxField(field_uri="message:From", is_read_only_after_send=True)
+ message_id = CharField(field_uri="message:InternetMessageId", is_read_only_after_send=True)
+ is_read = BooleanField(field_uri="message:IsRead", is_required=True, default=False)
+ is_response_requested = BooleanField(field_uri="message:IsResponseRequested", default=False, is_required=True)
+ references = TextField(field_uri="message:References")
+ reply_to = MailboxListField(field_uri="message:ReplyTo", is_read_only_after_send=True, is_searchable=False)
+ received_by = MailboxField(field_uri="message:ReceivedBy", is_read_only=True)
+ received_representing = MailboxField(field_uri="message:ReceivedRepresenting", is_read_only=True)
+ reminder_message_data = EWSElementField(
+ field_uri="message:ReminderMessageData",
+ value_cls=ReminderMessageData,
+ supported_from=EXCHANGE_2013_SP1,
+ is_read_only=True,
+ )
@require_account
- def send(self, save_copy=True, copy_to_folder=None, conflict_resolution=AUTO_RESOLVE,
- send_meeting_invitations=SEND_TO_NONE):
+ def send(
+ self,
+ save_copy=True,
+ copy_to_folder=None,
+ conflict_resolution=AUTO_RESOLVE,
+ send_meeting_invitations=SEND_TO_NONE,
+ ):
from ..services import SendItem
+
# Only sends a message. The message can either be an existing draft stored in EWS or a new message that does
# not yet exist in EWS.
if copy_to_folder and not save_copy:
@@ -91,42 +106,48 @@ Module exchangelib.items.message
if copy_to_folder:
# This would better be done via send_and_save() but lets just support it here
self.folder = copy_to_folder
- return self.send_and_save(conflict_resolution=conflict_resolution,
- send_meeting_invitations=send_meeting_invitations)
+ return self.send_and_save(
+ conflict_resolution=conflict_resolution, send_meeting_invitations=send_meeting_invitations
+ )
if self.account.version.build < EXCHANGE_2013 and self.attachments:
# At least some versions prior to Exchange 2013 can't send attachments immediately. You need to first save,
# then attach, then send. This is done in send_and_save(). send() will delete the item again.
- self.send_and_save(conflict_resolution=conflict_resolution,
- send_meeting_invitations=send_meeting_invitations)
+ self.send_and_save(
+ conflict_resolution=conflict_resolution, send_meeting_invitations=send_meeting_invitations
+ )
return None
self._create(message_disposition=SEND_ONLY, send_meeting_invitations=send_meeting_invitations)
return None
- def send_and_save(self, update_fields=None, conflict_resolution=AUTO_RESOLVE,
- send_meeting_invitations=SEND_TO_NONE):
+ def send_and_save(
+ self, update_fields=None, conflict_resolution=AUTO_RESOLVE, send_meeting_invitations=SEND_TO_NONE
+ ):
# Sends Message and saves a copy in the parent folder. Does not return an ItemId.
if self.id:
self._update(
update_fieldnames=update_fields,
message_disposition=SEND_AND_SAVE_COPY,
conflict_resolution=conflict_resolution,
- send_meeting_invitations=send_meeting_invitations
+ send_meeting_invitations=send_meeting_invitations,
)
else:
if self.account.version.build < EXCHANGE_2013 and self.attachments:
# At least some versions prior to Exchange 2013 can't send-and-save attachments immediately. You need
# to first save, then attach, then send. This is done in save().
- self.save(update_fields=update_fields, conflict_resolution=conflict_resolution,
- send_meeting_invitations=send_meeting_invitations)
- self.send(save_copy=False, conflict_resolution=conflict_resolution,
- send_meeting_invitations=send_meeting_invitations)
- else:
- self._create(
- message_disposition=SEND_AND_SAVE_COPY,
- send_meeting_invitations=send_meeting_invitations
+ self.save(
+ update_fields=update_fields,
+ conflict_resolution=conflict_resolution,
+ send_meeting_invitations=send_meeting_invitations,
)
+ self.send(
+ save_copy=False,
+ conflict_resolution=conflict_resolution,
+ send_meeting_invitations=send_meeting_invitations,
+ )
+ else:
+ self._create(message_disposition=SEND_AND_SAVE_COPY, send_meeting_invitations=send_meeting_invitations)
@require_id
def create_reply(self, subject, body, to_recipients=None, cc_recipients=None, bcc_recipients=None):
@@ -145,13 +166,7 @@ Module exchangelib.items.message
)
def reply(self, subject, body, to_recipients=None, cc_recipients=None, bcc_recipients=None):
- self.create_reply(
- subject,
- body,
- to_recipients,
- cc_recipients,
- bcc_recipients
- ).send()
+ self.create_reply(subject, body, to_recipients, cc_recipients, bcc_recipients).send()
@require_id
def create_reply_all(self, subject, body):
@@ -180,6 +195,7 @@ Module exchangelib.items.message
:return:
"""
from ..services import MarkAsJunk
+
res = MarkAsJunk(account=self.account).get(
items=[self], is_junk=is_junk, move_item=move_item, expect_result=move_item
)
@@ -192,19 +208,19 @@ Module exchangelib.items.message
class ReplyToItem(BaseReplyItem):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/replytoitem"""
- ELEMENT_NAME = 'ReplyToItem'
+ ELEMENT_NAME = "ReplyToItem"
class ReplyAllToItem(BaseReplyItem):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/replyalltoitem"""
- ELEMENT_NAME = 'ReplyAllToItem'
+ ELEMENT_NAME = "ReplyAllToItem"
class ForwardItem(BaseReplyItem):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/forwarditem"""
- ELEMENT_NAME = 'ForwardItem'
+ ELEMENT_NAME = "ForwardItem"
@@ -229,7 +245,7 @@ Classes
class ForwardItem(BaseReplyItem):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/forwarditem"""
- ELEMENT_NAME = 'ForwardItem'
+ ELEMENT_NAME = "ForwardItem"
Ancestors
@@ -278,37 +294,52 @@ Inherited members
https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/message-ex15websvcsotherref
"""
- ELEMENT_NAME = 'Message'
-
- sender = MailboxField(field_uri='message:Sender', is_read_only=True, is_read_only_after_send=True)
- to_recipients = MailboxListField(field_uri='message:ToRecipients', is_read_only_after_send=True,
- is_searchable=False)
- cc_recipients = MailboxListField(field_uri='message:CcRecipients', is_read_only_after_send=True,
- is_searchable=False)
- bcc_recipients = MailboxListField(field_uri='message:BccRecipients', is_read_only_after_send=True,
- is_searchable=False)
- is_read_receipt_requested = BooleanField(field_uri='message:IsReadReceiptRequested',
- is_required=True, default=False, is_read_only_after_send=True)
- is_delivery_receipt_requested = BooleanField(field_uri='message:IsDeliveryReceiptRequested', is_required=True,
- default=False, is_read_only_after_send=True)
- conversation_index = Base64Field(field_uri='message:ConversationIndex', is_read_only=True)
- conversation_topic = CharField(field_uri='message:ConversationTopic', is_read_only=True)
+ ELEMENT_NAME = "Message"
+
+ sender = MailboxField(field_uri="message:Sender", is_read_only=True, is_read_only_after_send=True)
+ to_recipients = MailboxListField(
+ field_uri="message:ToRecipients", is_read_only_after_send=True, is_searchable=False
+ )
+ cc_recipients = MailboxListField(
+ field_uri="message:CcRecipients", is_read_only_after_send=True, is_searchable=False
+ )
+ bcc_recipients = MailboxListField(
+ field_uri="message:BccRecipients", is_read_only_after_send=True, is_searchable=False
+ )
+ is_read_receipt_requested = BooleanField(
+ field_uri="message:IsReadReceiptRequested", is_required=True, default=False, is_read_only_after_send=True
+ )
+ is_delivery_receipt_requested = BooleanField(
+ field_uri="message:IsDeliveryReceiptRequested", is_required=True, default=False, is_read_only_after_send=True
+ )
+ conversation_index = Base64Field(field_uri="message:ConversationIndex", is_read_only=True)
+ conversation_topic = CharField(field_uri="message:ConversationTopic", is_read_only=True)
# Rename 'From' to 'author'. We can't use fieldname 'from' since it's a Python keyword.
- author = MailboxField(field_uri='message:From', is_read_only_after_send=True)
- message_id = CharField(field_uri='message:InternetMessageId', is_read_only_after_send=True)
- is_read = BooleanField(field_uri='message:IsRead', is_required=True, default=False)
- is_response_requested = BooleanField(field_uri='message:IsResponseRequested', default=False, is_required=True)
- references = TextField(field_uri='message:References')
- reply_to = MailboxListField(field_uri='message:ReplyTo', is_read_only_after_send=True, is_searchable=False)
- received_by = MailboxField(field_uri='message:ReceivedBy', is_read_only=True)
- received_representing = MailboxField(field_uri='message:ReceivedRepresenting', is_read_only=True)
- reminder_message_data = EWSElementField(field_uri='message:ReminderMessageData', value_cls=ReminderMessageData,
- supported_from=EXCHANGE_2013_SP1, is_read_only=True)
+ author = MailboxField(field_uri="message:From", is_read_only_after_send=True)
+ message_id = CharField(field_uri="message:InternetMessageId", is_read_only_after_send=True)
+ is_read = BooleanField(field_uri="message:IsRead", is_required=True, default=False)
+ is_response_requested = BooleanField(field_uri="message:IsResponseRequested", default=False, is_required=True)
+ references = TextField(field_uri="message:References")
+ reply_to = MailboxListField(field_uri="message:ReplyTo", is_read_only_after_send=True, is_searchable=False)
+ received_by = MailboxField(field_uri="message:ReceivedBy", is_read_only=True)
+ received_representing = MailboxField(field_uri="message:ReceivedRepresenting", is_read_only=True)
+ reminder_message_data = EWSElementField(
+ field_uri="message:ReminderMessageData",
+ value_cls=ReminderMessageData,
+ supported_from=EXCHANGE_2013_SP1,
+ is_read_only=True,
+ )
@require_account
- def send(self, save_copy=True, copy_to_folder=None, conflict_resolution=AUTO_RESOLVE,
- send_meeting_invitations=SEND_TO_NONE):
+ def send(
+ self,
+ save_copy=True,
+ copy_to_folder=None,
+ conflict_resolution=AUTO_RESOLVE,
+ send_meeting_invitations=SEND_TO_NONE,
+ ):
from ..services import SendItem
+
# Only sends a message. The message can either be an existing draft stored in EWS or a new message that does
# not yet exist in EWS.
if copy_to_folder and not save_copy:
@@ -326,42 +357,48 @@ Inherited members
if copy_to_folder:
# This would better be done via send_and_save() but lets just support it here
self.folder = copy_to_folder
- return self.send_and_save(conflict_resolution=conflict_resolution,
- send_meeting_invitations=send_meeting_invitations)
+ return self.send_and_save(
+ conflict_resolution=conflict_resolution, send_meeting_invitations=send_meeting_invitations
+ )
if self.account.version.build < EXCHANGE_2013 and self.attachments:
# At least some versions prior to Exchange 2013 can't send attachments immediately. You need to first save,
# then attach, then send. This is done in send_and_save(). send() will delete the item again.
- self.send_and_save(conflict_resolution=conflict_resolution,
- send_meeting_invitations=send_meeting_invitations)
+ self.send_and_save(
+ conflict_resolution=conflict_resolution, send_meeting_invitations=send_meeting_invitations
+ )
return None
self._create(message_disposition=SEND_ONLY, send_meeting_invitations=send_meeting_invitations)
return None
- def send_and_save(self, update_fields=None, conflict_resolution=AUTO_RESOLVE,
- send_meeting_invitations=SEND_TO_NONE):
+ def send_and_save(
+ self, update_fields=None, conflict_resolution=AUTO_RESOLVE, send_meeting_invitations=SEND_TO_NONE
+ ):
# Sends Message and saves a copy in the parent folder. Does not return an ItemId.
if self.id:
self._update(
update_fieldnames=update_fields,
message_disposition=SEND_AND_SAVE_COPY,
conflict_resolution=conflict_resolution,
- send_meeting_invitations=send_meeting_invitations
+ send_meeting_invitations=send_meeting_invitations,
)
else:
if self.account.version.build < EXCHANGE_2013 and self.attachments:
# At least some versions prior to Exchange 2013 can't send-and-save attachments immediately. You need
# to first save, then attach, then send. This is done in save().
- self.save(update_fields=update_fields, conflict_resolution=conflict_resolution,
- send_meeting_invitations=send_meeting_invitations)
- self.send(save_copy=False, conflict_resolution=conflict_resolution,
- send_meeting_invitations=send_meeting_invitations)
- else:
- self._create(
- message_disposition=SEND_AND_SAVE_COPY,
- send_meeting_invitations=send_meeting_invitations
+ self.save(
+ update_fields=update_fields,
+ conflict_resolution=conflict_resolution,
+ send_meeting_invitations=send_meeting_invitations,
+ )
+ self.send(
+ save_copy=False,
+ conflict_resolution=conflict_resolution,
+ send_meeting_invitations=send_meeting_invitations,
)
+ else:
+ self._create(message_disposition=SEND_AND_SAVE_COPY, send_meeting_invitations=send_meeting_invitations)
@require_id
def create_reply(self, subject, body, to_recipients=None, cc_recipients=None, bcc_recipients=None):
@@ -380,13 +417,7 @@ Inherited members
)
def reply(self, subject, body, to_recipients=None, cc_recipients=None, bcc_recipients=None):
- self.create_reply(
- subject,
- body,
- to_recipients,
- cc_recipients,
- bcc_recipients
- ).send()
+ self.create_reply(subject, body, to_recipients, cc_recipients, bcc_recipients).send()
@require_id
def create_reply_all(self, subject, body):
@@ -415,6 +446,7 @@ Inherited members
:return:
"""
from ..services import MarkAsJunk
+
res = MarkAsJunk(account=self.account).get(
items=[self], is_junk=is_junk, move_item=move_item, expect_result=move_item
)
@@ -588,6 +620,7 @@ Methods
:return:
"""
from ..services import MarkAsJunk
+
res = MarkAsJunk(account=self.account).get(
items=[self], is_junk=is_junk, move_item=move_item, expect_result=move_item
)
@@ -607,13 +640,7 @@ Methods
Expand source code
def reply(self, subject, body, to_recipients=None, cc_recipients=None, bcc_recipients=None):
- self.create_reply(
- subject,
- body,
- to_recipients,
- cc_recipients,
- bcc_recipients
- ).send()
+ self.create_reply(subject, body, to_recipients, cc_recipients, bcc_recipients).send()
@@ -639,9 +666,15 @@ Methods
Expand source code
@require_account
-def send(self, save_copy=True, copy_to_folder=None, conflict_resolution=AUTO_RESOLVE,
- send_meeting_invitations=SEND_TO_NONE):
+def send(
+ self,
+ save_copy=True,
+ copy_to_folder=None,
+ conflict_resolution=AUTO_RESOLVE,
+ send_meeting_invitations=SEND_TO_NONE,
+):
from ..services import SendItem
+
# Only sends a message. The message can either be an existing draft stored in EWS or a new message that does
# not yet exist in EWS.
if copy_to_folder and not save_copy:
@@ -659,14 +692,16 @@ Methods
if copy_to_folder:
# This would better be done via send_and_save() but lets just support it here
self.folder = copy_to_folder
- return self.send_and_save(conflict_resolution=conflict_resolution,
- send_meeting_invitations=send_meeting_invitations)
+ return self.send_and_save(
+ conflict_resolution=conflict_resolution, send_meeting_invitations=send_meeting_invitations
+ )
if self.account.version.build < EXCHANGE_2013 and self.attachments:
# At least some versions prior to Exchange 2013 can't send attachments immediately. You need to first save,
# then attach, then send. This is done in send_and_save(). send() will delete the item again.
- self.send_and_save(conflict_resolution=conflict_resolution,
- send_meeting_invitations=send_meeting_invitations)
+ self.send_and_save(
+ conflict_resolution=conflict_resolution, send_meeting_invitations=send_meeting_invitations
+ )
return None
self._create(message_disposition=SEND_ONLY, send_meeting_invitations=send_meeting_invitations)
@@ -682,29 +717,33 @@ Methods
Expand source code
-def send_and_save(self, update_fields=None, conflict_resolution=AUTO_RESOLVE,
- send_meeting_invitations=SEND_TO_NONE):
+def send_and_save(
+ self, update_fields=None, conflict_resolution=AUTO_RESOLVE, send_meeting_invitations=SEND_TO_NONE
+):
# Sends Message and saves a copy in the parent folder. Does not return an ItemId.
if self.id:
self._update(
update_fieldnames=update_fields,
message_disposition=SEND_AND_SAVE_COPY,
conflict_resolution=conflict_resolution,
- send_meeting_invitations=send_meeting_invitations
+ send_meeting_invitations=send_meeting_invitations,
)
else:
if self.account.version.build < EXCHANGE_2013 and self.attachments:
# At least some versions prior to Exchange 2013 can't send-and-save attachments immediately. You need
# to first save, then attach, then send. This is done in save().
- self.save(update_fields=update_fields, conflict_resolution=conflict_resolution,
- send_meeting_invitations=send_meeting_invitations)
- self.send(save_copy=False, conflict_resolution=conflict_resolution,
- send_meeting_invitations=send_meeting_invitations)
+ self.save(
+ update_fields=update_fields,
+ conflict_resolution=conflict_resolution,
+ send_meeting_invitations=send_meeting_invitations,
+ )
+ self.send(
+ save_copy=False,
+ conflict_resolution=conflict_resolution,
+ send_meeting_invitations=send_meeting_invitations,
+ )
else:
- self._create(
- message_disposition=SEND_AND_SAVE_COPY,
- send_meeting_invitations=send_meeting_invitations
- )
+ self._create(message_disposition=SEND_AND_SAVE_COPY, send_meeting_invitations=send_meeting_invitations)
@@ -740,7 +779,7 @@ Inherited members
class ReplyAllToItem(BaseReplyItem):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/replyalltoitem"""
- ELEMENT_NAME = 'ReplyAllToItem'
+ ELEMENT_NAME = "ReplyAllToItem"
Ancestors
@@ -781,7 +820,7 @@ Inherited members
class ReplyToItem(BaseReplyItem):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/replytoitem"""
- ELEMENT_NAME = 'ReplyToItem'
+ ELEMENT_NAME = "ReplyToItem"
Ancestors
diff --git a/docs/exchangelib/items/post.html b/docs/exchangelib/items/post.html
index 75ccf70b..a7dabb52 100644
--- a/docs/exchangelib/items/post.html
+++ b/docs/exchangelib/items/post.html
@@ -28,9 +28,9 @@ Module exchangelib.items.post
import logging
+from ..fields import BodyField, DateTimeField, MailboxField, TextField
from .item import Item
from .message import Message
-from ..fields import TextField, BodyField, DateTimeField, MailboxField
log = logging.getLogger(__name__)
@@ -38,32 +38,32 @@ Module exchangelib.items.post
class PostItem(Item):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/postitem"""
- ELEMENT_NAME = 'PostItem'
+ ELEMENT_NAME = "PostItem"
- conversation_index = Message.FIELDS['conversation_index']
- conversation_topic = Message.FIELDS['conversation_topic']
+ conversation_index = Message.FIELDS["conversation_index"]
+ conversation_topic = Message.FIELDS["conversation_topic"]
- author = Message.FIELDS['author']
- message_id = Message.FIELDS['message_id']
- is_read = Message.FIELDS['is_read']
+ author = Message.FIELDS["author"]
+ message_id = Message.FIELDS["message_id"]
+ is_read = Message.FIELDS["is_read"]
- posted_time = DateTimeField(field_uri='postitem:PostedTime', is_read_only=True)
- references = TextField(field_uri='message:References')
- sender = MailboxField(field_uri='message:Sender', is_read_only=True, is_read_only_after_send=True)
+ posted_time = DateTimeField(field_uri="postitem:PostedTime", is_read_only=True)
+ references = TextField(field_uri="message:References")
+ sender = MailboxField(field_uri="message:Sender", is_read_only=True, is_read_only_after_send=True)
class PostReplyItem(Item):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/postreplyitem"""
- ELEMENT_NAME = 'PostReplyItem'
+ ELEMENT_NAME = "PostReplyItem"
# This element only has Item fields up to, and including, 'culture'
# TDO: Plus all message fields
- new_body = BodyField(field_uri='NewBodyContent') # Accepts and returns Body or HTMLBody instances
+ new_body = BodyField(field_uri="NewBodyContent") # Accepts and returns Body or HTMLBody instances
- culture_idx = Item.FIELDS.index_by_name('culture')
- sender_idx = Message.FIELDS.index_by_name('sender')
- FIELDS = Item.FIELDS[:culture_idx + 1] + Message.FIELDS[sender_idx:]
+ culture_idx = Item.FIELDS.index_by_name("culture")
+ sender_idx = Message.FIELDS.index_by_name("sender")
+ FIELDS = Item.FIELDS[: culture_idx + 1] + Message.FIELDS[sender_idx:]
@@ -93,18 +93,18 @@ Classes
class PostItem(Item):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/postitem"""
- ELEMENT_NAME = 'PostItem'
+ ELEMENT_NAME = "PostItem"
- conversation_index = Message.FIELDS['conversation_index']
- conversation_topic = Message.FIELDS['conversation_topic']
+ conversation_index = Message.FIELDS["conversation_index"]
+ conversation_topic = Message.FIELDS["conversation_topic"]
- author = Message.FIELDS['author']
- message_id = Message.FIELDS['message_id']
- is_read = Message.FIELDS['is_read']
+ author = Message.FIELDS["author"]
+ message_id = Message.FIELDS["message_id"]
+ is_read = Message.FIELDS["is_read"]
- posted_time = DateTimeField(field_uri='postitem:PostedTime', is_read_only=True)
- references = TextField(field_uri='message:References')
- sender = MailboxField(field_uri='message:Sender', is_read_only=True, is_read_only_after_send=True)
+ posted_time = DateTimeField(field_uri="postitem:PostedTime", is_read_only=True)
+ references = TextField(field_uri="message:References")
+ sender = MailboxField(field_uri="message:Sender", is_read_only=True, is_read_only_after_send=True)
Ancestors
@@ -197,15 +197,15 @@ Inherited members
class PostReplyItem(Item):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/postreplyitem"""
- ELEMENT_NAME = 'PostReplyItem'
+ ELEMENT_NAME = "PostReplyItem"
# This element only has Item fields up to, and including, 'culture'
# TDO: Plus all message fields
- new_body = BodyField(field_uri='NewBodyContent') # Accepts and returns Body or HTMLBody instances
+ new_body = BodyField(field_uri="NewBodyContent") # Accepts and returns Body or HTMLBody instances
- culture_idx = Item.FIELDS.index_by_name('culture')
- sender_idx = Message.FIELDS.index_by_name('sender')
- FIELDS = Item.FIELDS[:culture_idx + 1] + Message.FIELDS[sender_idx:]
+ culture_idx = Item.FIELDS.index_by_name("culture")
+ sender_idx = Message.FIELDS.index_by_name("sender")
+ FIELDS = Item.FIELDS[: culture_idx + 1] + Message.FIELDS[sender_idx:]
Ancestors
diff --git a/docs/exchangelib/items/task.html b/docs/exchangelib/items/task.html
index 4cdbe4a0..3dd931a9 100644
--- a/docs/exchangelib/items/task.html
+++ b/docs/exchangelib/items/task.html
@@ -30,10 +30,21 @@ Module exchangelib.items.task
import logging
from decimal import Decimal
+from ..ewsdatetime import UTC, EWSDateTime
+from ..fields import (
+ BooleanField,
+ CharField,
+ Choice,
+ ChoiceField,
+ DateTimeBackedDateField,
+ DateTimeField,
+ DecimalField,
+ IntegerField,
+ TaskRecurrenceField,
+ TextField,
+ TextListField,
+)
from .item import Item
-from ..ewsdatetime import EWSDateTime, UTC
-from ..fields import BooleanField, IntegerField, DecimalField, TextField, ChoiceField, DateTimeField, Choice, \
- CharField, TextListField, TaskRecurrenceField, DateTimeBackedDateField
log = logging.getLogger(__name__)
@@ -41,49 +52,78 @@ Module exchangelib.items.task
class Task(Item):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/task"""
- ELEMENT_NAME = 'Task'
- NOT_STARTED = 'NotStarted'
- COMPLETED = 'Completed'
+ ELEMENT_NAME = "Task"
+ NOT_STARTED = "NotStarted"
+ COMPLETED = "Completed"
- actual_work = IntegerField(field_uri='task:ActualWork', min=0)
- assigned_time = DateTimeField(field_uri='task:AssignedTime', is_read_only=True)
- billing_information = TextField(field_uri='task:BillingInformation')
- change_count = IntegerField(field_uri='task:ChangeCount', is_read_only=True, min=0)
- companies = TextListField(field_uri='task:Companies')
+ actual_work = IntegerField(field_uri="task:ActualWork", min=0)
+ assigned_time = DateTimeField(field_uri="task:AssignedTime", is_read_only=True)
+ billing_information = TextField(field_uri="task:BillingInformation")
+ change_count = IntegerField(field_uri="task:ChangeCount", is_read_only=True, min=0)
+ companies = TextListField(field_uri="task:Companies")
# 'complete_date' can be set, but is ignored by the server, which sets it to now()
- complete_date = DateTimeField(field_uri='task:CompleteDate', is_read_only=True)
- contacts = TextListField(field_uri='task:Contacts')
- delegation_state = ChoiceField(field_uri='task:DelegationState', choices={
- Choice('NoMatch'), Choice('OwnNew'), Choice('Owned'), Choice('Accepted'), Choice('Declined'), Choice('Max')
- }, is_read_only=True)
- delegator = CharField(field_uri='task:Delegator', is_read_only=True)
- due_date = DateTimeBackedDateField(field_uri='task:DueDate')
- is_editable = BooleanField(field_uri='task:IsAssignmentEditable', is_read_only=True)
- is_complete = BooleanField(field_uri='task:IsComplete', is_read_only=True)
- is_recurring = BooleanField(field_uri='task:IsRecurring', is_read_only=True)
- is_team_task = BooleanField(field_uri='task:IsTeamTask', is_read_only=True)
- mileage = TextField(field_uri='task:Mileage')
- owner = CharField(field_uri='task:Owner', is_read_only=True)
- percent_complete = DecimalField(field_uri='task:PercentComplete', is_required=True, default=Decimal(0.0),
- min=Decimal(0), max=Decimal(100), is_searchable=False)
- recurrence = TaskRecurrenceField(field_uri='task:Recurrence', is_searchable=False)
- start_date = DateTimeBackedDateField(field_uri='task:StartDate')
- status = ChoiceField(field_uri='task:Status', choices={
- Choice(NOT_STARTED), Choice('InProgress'), Choice(COMPLETED), Choice('WaitingOnOthers'), Choice('Deferred')
- }, is_required=True, is_searchable=False, default=NOT_STARTED)
- status_description = CharField(field_uri='task:StatusDescription', is_read_only=True)
- total_work = IntegerField(field_uri='task:TotalWork', min=0)
+ complete_date = DateTimeField(field_uri="task:CompleteDate", is_read_only=True)
+ contacts = TextListField(field_uri="task:Contacts")
+ delegation_state = ChoiceField(
+ field_uri="task:DelegationState",
+ choices={
+ Choice("NoMatch"),
+ Choice("OwnNew"),
+ Choice("Owned"),
+ Choice("Accepted"),
+ Choice("Declined"),
+ Choice("Max"),
+ },
+ is_read_only=True,
+ )
+ delegator = CharField(field_uri="task:Delegator", is_read_only=True)
+ due_date = DateTimeBackedDateField(field_uri="task:DueDate")
+ is_editable = BooleanField(field_uri="task:IsAssignmentEditable", is_read_only=True)
+ is_complete = BooleanField(field_uri="task:IsComplete", is_read_only=True)
+ is_recurring = BooleanField(field_uri="task:IsRecurring", is_read_only=True)
+ is_team_task = BooleanField(field_uri="task:IsTeamTask", is_read_only=True)
+ mileage = TextField(field_uri="task:Mileage")
+ owner = CharField(field_uri="task:Owner", is_read_only=True)
+ percent_complete = DecimalField(
+ field_uri="task:PercentComplete",
+ is_required=True,
+ default=Decimal(0.0),
+ min=Decimal(0),
+ max=Decimal(100),
+ is_searchable=False,
+ )
+ recurrence = TaskRecurrenceField(field_uri="task:Recurrence", is_searchable=False)
+ start_date = DateTimeBackedDateField(field_uri="task:StartDate")
+ status = ChoiceField(
+ field_uri="task:Status",
+ choices={
+ Choice(NOT_STARTED),
+ Choice("InProgress"),
+ Choice(COMPLETED),
+ Choice("WaitingOnOthers"),
+ Choice("Deferred"),
+ },
+ is_required=True,
+ is_searchable=False,
+ default=NOT_STARTED,
+ )
+ status_description = CharField(field_uri="task:StatusDescription", is_read_only=True)
+ total_work = IntegerField(field_uri="task:TotalWork", min=0)
def clean(self, version=None):
super().clean(version=version)
if self.due_date and self.start_date and self.due_date < self.start_date:
- log.warning("'due_date' must be greater than 'start_date' (%s vs %s). Resetting 'due_date'",
- self.due_date, self.start_date)
+ log.warning(
+ "'due_date' must be greater than 'start_date' (%s vs %s). Resetting 'due_date'",
+ self.due_date,
+ self.start_date,
+ )
self.due_date = self.start_date
if self.complete_date:
if self.status != self.COMPLETED:
- log.warning("'status' must be '%s' when 'complete_date' is set (%s). Resetting",
- self.COMPLETED, self.status)
+ log.warning(
+ "'status' must be '%s' when 'complete_date' is set (%s). Resetting", self.COMPLETED, self.status
+ )
self.status = self.COMPLETED
now = datetime.datetime.now(tz=UTC)
if (self.complete_date - now).total_seconds() > 120:
@@ -92,19 +132,28 @@ Module exchangelib.items.task
log.warning("'complete_date' must be in the past (%s vs %s). Resetting", self.complete_date, now)
self.complete_date = now
if self.start_date and self.complete_date.date() < self.start_date:
- log.warning("'complete_date' must be greater than 'start_date' (%s vs %s). Resetting",
- self.complete_date, self.start_date)
+ log.warning(
+ "'complete_date' must be greater than 'start_date' (%s vs %s). Resetting",
+ self.complete_date,
+ self.start_date,
+ )
self.complete_date = EWSDateTime.combine(self.start_date, datetime.time(0, 0)).replace(tzinfo=UTC)
if self.percent_complete is not None:
if self.status == self.COMPLETED and self.percent_complete != Decimal(100):
# percent_complete must be 100% if task is complete
- log.warning("'percent_complete' must be 100 when 'status' is '%s' (%s). Resetting",
- self.COMPLETED, self.percent_complete)
+ log.warning(
+ "'percent_complete' must be 100 when 'status' is '%s' (%s). Resetting",
+ self.COMPLETED,
+ self.percent_complete,
+ )
self.percent_complete = Decimal(100)
elif self.status == self.NOT_STARTED and self.percent_complete != Decimal(0):
# percent_complete must be 0% if task is not started
- log.warning("'percent_complete' must be 0 when 'status' is '%s' (%s). Resetting",
- self.NOT_STARTED, self.percent_complete)
+ log.warning(
+ "'percent_complete' must be 0 when 'status' is '%s' (%s). Resetting",
+ self.NOT_STARTED,
+ self.percent_complete,
+ )
self.percent_complete = Decimal(0)
def complete(self):
@@ -141,49 +190,78 @@ Classes
class Task(Item):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/task"""
- ELEMENT_NAME = 'Task'
- NOT_STARTED = 'NotStarted'
- COMPLETED = 'Completed'
+ ELEMENT_NAME = "Task"
+ NOT_STARTED = "NotStarted"
+ COMPLETED = "Completed"
- actual_work = IntegerField(field_uri='task:ActualWork', min=0)
- assigned_time = DateTimeField(field_uri='task:AssignedTime', is_read_only=True)
- billing_information = TextField(field_uri='task:BillingInformation')
- change_count = IntegerField(field_uri='task:ChangeCount', is_read_only=True, min=0)
- companies = TextListField(field_uri='task:Companies')
+ actual_work = IntegerField(field_uri="task:ActualWork", min=0)
+ assigned_time = DateTimeField(field_uri="task:AssignedTime", is_read_only=True)
+ billing_information = TextField(field_uri="task:BillingInformation")
+ change_count = IntegerField(field_uri="task:ChangeCount", is_read_only=True, min=0)
+ companies = TextListField(field_uri="task:Companies")
# 'complete_date' can be set, but is ignored by the server, which sets it to now()
- complete_date = DateTimeField(field_uri='task:CompleteDate', is_read_only=True)
- contacts = TextListField(field_uri='task:Contacts')
- delegation_state = ChoiceField(field_uri='task:DelegationState', choices={
- Choice('NoMatch'), Choice('OwnNew'), Choice('Owned'), Choice('Accepted'), Choice('Declined'), Choice('Max')
- }, is_read_only=True)
- delegator = CharField(field_uri='task:Delegator', is_read_only=True)
- due_date = DateTimeBackedDateField(field_uri='task:DueDate')
- is_editable = BooleanField(field_uri='task:IsAssignmentEditable', is_read_only=True)
- is_complete = BooleanField(field_uri='task:IsComplete', is_read_only=True)
- is_recurring = BooleanField(field_uri='task:IsRecurring', is_read_only=True)
- is_team_task = BooleanField(field_uri='task:IsTeamTask', is_read_only=True)
- mileage = TextField(field_uri='task:Mileage')
- owner = CharField(field_uri='task:Owner', is_read_only=True)
- percent_complete = DecimalField(field_uri='task:PercentComplete', is_required=True, default=Decimal(0.0),
- min=Decimal(0), max=Decimal(100), is_searchable=False)
- recurrence = TaskRecurrenceField(field_uri='task:Recurrence', is_searchable=False)
- start_date = DateTimeBackedDateField(field_uri='task:StartDate')
- status = ChoiceField(field_uri='task:Status', choices={
- Choice(NOT_STARTED), Choice('InProgress'), Choice(COMPLETED), Choice('WaitingOnOthers'), Choice('Deferred')
- }, is_required=True, is_searchable=False, default=NOT_STARTED)
- status_description = CharField(field_uri='task:StatusDescription', is_read_only=True)
- total_work = IntegerField(field_uri='task:TotalWork', min=0)
+ complete_date = DateTimeField(field_uri="task:CompleteDate", is_read_only=True)
+ contacts = TextListField(field_uri="task:Contacts")
+ delegation_state = ChoiceField(
+ field_uri="task:DelegationState",
+ choices={
+ Choice("NoMatch"),
+ Choice("OwnNew"),
+ Choice("Owned"),
+ Choice("Accepted"),
+ Choice("Declined"),
+ Choice("Max"),
+ },
+ is_read_only=True,
+ )
+ delegator = CharField(field_uri="task:Delegator", is_read_only=True)
+ due_date = DateTimeBackedDateField(field_uri="task:DueDate")
+ is_editable = BooleanField(field_uri="task:IsAssignmentEditable", is_read_only=True)
+ is_complete = BooleanField(field_uri="task:IsComplete", is_read_only=True)
+ is_recurring = BooleanField(field_uri="task:IsRecurring", is_read_only=True)
+ is_team_task = BooleanField(field_uri="task:IsTeamTask", is_read_only=True)
+ mileage = TextField(field_uri="task:Mileage")
+ owner = CharField(field_uri="task:Owner", is_read_only=True)
+ percent_complete = DecimalField(
+ field_uri="task:PercentComplete",
+ is_required=True,
+ default=Decimal(0.0),
+ min=Decimal(0),
+ max=Decimal(100),
+ is_searchable=False,
+ )
+ recurrence = TaskRecurrenceField(field_uri="task:Recurrence", is_searchable=False)
+ start_date = DateTimeBackedDateField(field_uri="task:StartDate")
+ status = ChoiceField(
+ field_uri="task:Status",
+ choices={
+ Choice(NOT_STARTED),
+ Choice("InProgress"),
+ Choice(COMPLETED),
+ Choice("WaitingOnOthers"),
+ Choice("Deferred"),
+ },
+ is_required=True,
+ is_searchable=False,
+ default=NOT_STARTED,
+ )
+ status_description = CharField(field_uri="task:StatusDescription", is_read_only=True)
+ total_work = IntegerField(field_uri="task:TotalWork", min=0)
def clean(self, version=None):
super().clean(version=version)
if self.due_date and self.start_date and self.due_date < self.start_date:
- log.warning("'due_date' must be greater than 'start_date' (%s vs %s). Resetting 'due_date'",
- self.due_date, self.start_date)
+ log.warning(
+ "'due_date' must be greater than 'start_date' (%s vs %s). Resetting 'due_date'",
+ self.due_date,
+ self.start_date,
+ )
self.due_date = self.start_date
if self.complete_date:
if self.status != self.COMPLETED:
- log.warning("'status' must be '%s' when 'complete_date' is set (%s). Resetting",
- self.COMPLETED, self.status)
+ log.warning(
+ "'status' must be '%s' when 'complete_date' is set (%s). Resetting", self.COMPLETED, self.status
+ )
self.status = self.COMPLETED
now = datetime.datetime.now(tz=UTC)
if (self.complete_date - now).total_seconds() > 120:
@@ -192,19 +270,28 @@ Classes
log.warning("'complete_date' must be in the past (%s vs %s). Resetting", self.complete_date, now)
self.complete_date = now
if self.start_date and self.complete_date.date() < self.start_date:
- log.warning("'complete_date' must be greater than 'start_date' (%s vs %s). Resetting",
- self.complete_date, self.start_date)
+ log.warning(
+ "'complete_date' must be greater than 'start_date' (%s vs %s). Resetting",
+ self.complete_date,
+ self.start_date,
+ )
self.complete_date = EWSDateTime.combine(self.start_date, datetime.time(0, 0)).replace(tzinfo=UTC)
if self.percent_complete is not None:
if self.status == self.COMPLETED and self.percent_complete != Decimal(100):
# percent_complete must be 100% if task is complete
- log.warning("'percent_complete' must be 100 when 'status' is '%s' (%s). Resetting",
- self.COMPLETED, self.percent_complete)
+ log.warning(
+ "'percent_complete' must be 100 when 'status' is '%s' (%s). Resetting",
+ self.COMPLETED,
+ self.percent_complete,
+ )
self.percent_complete = Decimal(100)
elif self.status == self.NOT_STARTED and self.percent_complete != Decimal(0):
# percent_complete must be 0% if task is not started
- log.warning("'percent_complete' must be 0 when 'status' is '%s' (%s). Resetting",
- self.NOT_STARTED, self.percent_complete)
+ log.warning(
+ "'percent_complete' must be 0 when 'status' is '%s' (%s). Resetting",
+ self.NOT_STARTED,
+ self.percent_complete,
+ )
self.percent_complete = Decimal(0)
def complete(self):
@@ -345,13 +432,17 @@ Methods
def clean(self, version=None):
super().clean(version=version)
if self.due_date and self.start_date and self.due_date < self.start_date:
- log.warning("'due_date' must be greater than 'start_date' (%s vs %s). Resetting 'due_date'",
- self.due_date, self.start_date)
+ log.warning(
+ "'due_date' must be greater than 'start_date' (%s vs %s). Resetting 'due_date'",
+ self.due_date,
+ self.start_date,
+ )
self.due_date = self.start_date
if self.complete_date:
if self.status != self.COMPLETED:
- log.warning("'status' must be '%s' when 'complete_date' is set (%s). Resetting",
- self.COMPLETED, self.status)
+ log.warning(
+ "'status' must be '%s' when 'complete_date' is set (%s). Resetting", self.COMPLETED, self.status
+ )
self.status = self.COMPLETED
now = datetime.datetime.now(tz=UTC)
if (self.complete_date - now).total_seconds() > 120:
@@ -360,19 +451,28 @@ Methods
log.warning("'complete_date' must be in the past (%s vs %s). Resetting", self.complete_date, now)
self.complete_date = now
if self.start_date and self.complete_date.date() < self.start_date:
- log.warning("'complete_date' must be greater than 'start_date' (%s vs %s). Resetting",
- self.complete_date, self.start_date)
+ log.warning(
+ "'complete_date' must be greater than 'start_date' (%s vs %s). Resetting",
+ self.complete_date,
+ self.start_date,
+ )
self.complete_date = EWSDateTime.combine(self.start_date, datetime.time(0, 0)).replace(tzinfo=UTC)
if self.percent_complete is not None:
if self.status == self.COMPLETED and self.percent_complete != Decimal(100):
# percent_complete must be 100% if task is complete
- log.warning("'percent_complete' must be 100 when 'status' is '%s' (%s). Resetting",
- self.COMPLETED, self.percent_complete)
+ log.warning(
+ "'percent_complete' must be 100 when 'status' is '%s' (%s). Resetting",
+ self.COMPLETED,
+ self.percent_complete,
+ )
self.percent_complete = Decimal(100)
elif self.status == self.NOT_STARTED and self.percent_complete != Decimal(0):
# percent_complete must be 0% if task is not started
- log.warning("'percent_complete' must be 0 when 'status' is '%s' (%s). Resetting",
- self.NOT_STARTED, self.percent_complete)
+ log.warning(
+ "'percent_complete' must be 0 when 'status' is '%s' (%s). Resetting",
+ self.NOT_STARTED,
+ self.percent_complete,
+ )
self.percent_complete = Decimal(0)
diff --git a/docs/exchangelib/properties.html b/docs/exchangelib/properties.html
index 91a438d6..8684a767 100644
--- a/docs/exchangelib/properties.html
+++ b/docs/exchangelib/properties.html
@@ -35,14 +35,49 @@ Module exchangelib.properties
from inspect import getmro
from threading import Lock
-from .errors import TimezoneDefinitionInvalidForYear, InvalidTypeError
-from .fields import SubField, TextField, EmailAddressField, ChoiceField, DateTimeField, EWSElementField, MailboxField, \
- Choice, BooleanField, IdField, ExtendedPropertyField, IntegerField, TimeField, EnumField, CharField, EmailField, \
- EWSElementListField, EnumListField, FreeBusyStatusField, UnknownEntriesField, MessageField, RecipientAddressField, \
- RoutingTypeField, WEEKDAY_NAMES, FieldPath, Field, AssociatedCalendarItemIdField, ReferenceItemIdField, \
- Base64Field, TypeValueField, DictionaryField, IdElementField, CharListField, GenericEventListField, \
- DateTimeBackedDateField, TimeDeltaField, TransitionListField, InvalidField, InvalidFieldForVersion
-from .util import get_xml_attr, create_element, set_xml_value, value_to_xml_text, MNS, TNS
+from .errors import InvalidTypeError, TimezoneDefinitionInvalidForYear
+from .fields import (
+ WEEKDAY_NAMES,
+ AssociatedCalendarItemIdField,
+ Base64Field,
+ BooleanField,
+ CharField,
+ CharListField,
+ Choice,
+ ChoiceField,
+ DateTimeBackedDateField,
+ DateTimeField,
+ DictionaryField,
+ EmailAddressField,
+ EmailField,
+ EnumField,
+ EnumListField,
+ EWSElementField,
+ EWSElementListField,
+ ExtendedPropertyField,
+ Field,
+ FieldPath,
+ FreeBusyStatusField,
+ GenericEventListField,
+ IdElementField,
+ IdField,
+ IntegerField,
+ InvalidField,
+ InvalidFieldForVersion,
+ MailboxField,
+ MessageField,
+ RecipientAddressField,
+ ReferenceItemIdField,
+ RoutingTypeField,
+ SubField,
+ TextField,
+ TimeDeltaField,
+ TimeField,
+ TransitionListField,
+ TypeValueField,
+ UnknownEntriesField,
+)
+from .util import MNS, TNS, create_element, get_xml_attr, set_xml_value, value_to_xml_text
from .version import EXCHANGE_2013, Build
log = logging.getLogger(__name__)
@@ -57,7 +92,7 @@ Module exchangelib.properties
for f in fields:
# Check for duplicate field names
if f.name in self._dict:
- raise ValueError(f'Field {f!r} is a duplicate')
+ raise ValueError(f"Field {f!r} is a duplicate")
self._dict[f.name] = f
def __getitem__(self, idx_or_slice):
@@ -89,11 +124,11 @@ Module exchangelib.properties
for i, f in enumerate(self):
if f.name == field_name:
return i
- raise ValueError(f'Unknown field name {field_name!r}')
+ raise ValueError(f"Unknown field name {field_name!r}")
def insert(self, index, field):
if field.name in self._dict:
- raise ValueError(f'Field {field!r} is a duplicate')
+ raise ValueError(f"Field {field!r} is a duplicate")
super().insert(index, field)
self._dict[field.name] = field
@@ -112,7 +147,7 @@ Module exchangelib.properties
MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/body
"""
- body_type = 'Text'
+ body_type = "Text"
def __add__(self, other):
# Make sure Body('') + 'foo' returns a Body type
@@ -133,7 +168,7 @@ Module exchangelib.properties
MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/body
"""
- body_type = 'HTML'
+ body_type = "HTML"
class UID(bytes):
@@ -148,22 +183,15 @@ Module exchangelib.properties
account.calendar.filter(global_object_id=UID('261cbc18-1f65-5a0a-bd11-23b1e224cc2f'))
"""
- _HEADER = binascii.hexlify(bytearray((
- 0x04, 0x00, 0x00, 0x00,
- 0x82, 0x00, 0xE0, 0x00,
- 0x74, 0xC5, 0xB7, 0x10,
- 0x1A, 0x82, 0xE0, 0x08)))
+ _HEADER = binascii.hexlify(
+ bytearray((0x04, 0x00, 0x00, 0x00, 0x82, 0x00, 0xE0, 0x00, 0x74, 0xC5, 0xB7, 0x10, 0x1A, 0x82, 0xE0, 0x08))
+ )
- _EXCEPTION_REPLACEMENT_TIME = binascii.hexlify(bytearray((
- 0, 0, 0, 0)))
+ _EXCEPTION_REPLACEMENT_TIME = binascii.hexlify(bytearray((0, 0, 0, 0)))
- _CREATION_TIME = binascii.hexlify(bytearray((
- 0, 0, 0, 0,
- 0, 0, 0, 0)))
+ _CREATION_TIME = binascii.hexlify(bytearray((0, 0, 0, 0, 0, 0, 0, 0)))
- _RESERVED = binascii.hexlify(bytearray((
- 0, 0, 0, 0,
- 0, 0, 0, 0)))
+ _RESERVED = binascii.hexlify(bytearray((0, 0, 0, 0, 0, 0, 0, 0)))
# https://docs.microsoft.com/en-us/openspecs/exchange_server_protocols/ms-oxocal/1d3aac05-a7b9-45cc-a213-47f0a0a2c5c1
# https://docs.microsoft.com/en-us/openspecs/exchange_server_protocols/ms-asemail/e7424ddc-dd10-431e-a0b7-5c794863370e
@@ -171,12 +199,12 @@ Module exchangelib.properties
# https://stackoverflow.com/questions/33757805
def __new__(cls, uid):
- payload = binascii.hexlify(bytearray(f'vCal-Uid\x01\x00\x00\x00{uid}\x00'.encode('ascii')))
- length = binascii.hexlify(bytearray(struct.pack('<I', int(len(payload)/2))))
- encoding = b''.join([
- cls._HEADER, cls._EXCEPTION_REPLACEMENT_TIME, cls._CREATION_TIME, cls._RESERVED, length, payload
- ])
- return super().__new__(cls, codecs.decode(encoding, 'hex'))
+ payload = binascii.hexlify(bytearray(f"vCal-Uid\x01\x00\x00\x00{uid}\x00".encode("ascii")))
+ length = binascii.hexlify(bytearray(struct.pack("<I", int(len(payload) / 2))))
+ encoding = b"".join(
+ [cls._HEADER, cls._EXCEPTION_REPLACEMENT_TIME, cls._CREATION_TIME, cls._RESERVED, length, payload]
+ )
+ return super().__new__(cls, codecs.decode(encoding, "hex"))
@classmethod
def to_global_object_id(cls, uid):
@@ -185,7 +213,7 @@ Module exchangelib.properties
def _mangle(field_name):
- return f'__{field_name}'
+ return f"__{field_name}"
class EWSMeta(type, metaclass=abc.ABCMeta):
@@ -202,23 +230,23 @@ Module exchangelib.properties
# Build a list of fields defined on this and all base classes
base_fields = Fields()
for base in bases:
- if hasattr(base, 'FIELDS'):
+ if hasattr(base, "FIELDS"):
base_fields += base.FIELDS
# FIELDS defined on a model overrides the base class fields
- fields = kwargs.get('FIELDS', base_fields) + local_fields
+ fields = kwargs.get("FIELDS", base_fields) + local_fields
# Include all fields as class attributes so we can use them as instance attributes
kwargs.update({_mangle(f.name): f for f in fields})
# Calculate __slots__ so we don't have to hard-code it on the model
- kwargs['__slots__'] = tuple(f.name for f in fields if f.name not in base_fields) + kwargs.get('__slots__', ())
+ kwargs["__slots__"] = tuple(f.name for f in fields if f.name not in base_fields) + kwargs.get("__slots__", ())
# FIELDS is mentioned in docs and expected by internal code. Add it here, but only if the class has its own
# fields. Otherwise, we want the implicit FIELDS from the base class (used for injecting custom fields on the
# Folder class, making the custom field available for subclasses).
if local_fields:
- kwargs['FIELDS'] = fields
+ kwargs["FIELDS"] = fields
cls = super().__new__(mcs, name, bases, kwargs)
cls._slots_keys = mcs._get_slots_keys(cls)
return cls
@@ -228,7 +256,7 @@ Module exchangelib.properties
seen = set()
keys = []
for c in reversed(getmro(cls)):
- if not hasattr(c, '__slots__'):
+ if not hasattr(c, "__slots__"):
continue
for k in c.__slots__:
if k in seen:
@@ -242,7 +270,7 @@ Module exchangelib.properties
def __getattribute__(cls, k):
"""Return Field instances via their mangled class attribute"""
try:
- return super().__getattribute__('__dict__')[_mangle(k)]
+ return super().__getattribute__("__dict__")[_mangle(k)]
except KeyError:
return super().__getattribute__(k)
@@ -274,7 +302,7 @@ Module exchangelib.properties
# Property setters
return super().__setattr__(key, value)
raise AttributeError(
- f'{key!r} is not a valid attribute. See {self.__class__.__name__}.FIELDS for valid field names'
+ f"{key!r} is not a valid attribute. See {self.__class__.__name__}.FIELDS for valid field names"
)
def clean(self, version=None):
@@ -336,19 +364,19 @@ Module exchangelib.properties
@classmethod
def request_tag(cls):
if not cls.ELEMENT_NAME:
- raise ValueError(f'Class {cls} is missing the ELEMENT_NAME attribute')
+ raise ValueError(f"Class {cls} is missing the ELEMENT_NAME attribute")
return {
- TNS: f't:{cls.ELEMENT_NAME}',
- MNS: f'm:{cls.ELEMENT_NAME}',
+ TNS: f"t:{cls.ELEMENT_NAME}",
+ MNS: f"m:{cls.ELEMENT_NAME}",
}[cls.NAMESPACE]
@classmethod
def response_tag(cls):
if not cls.NAMESPACE:
- raise ValueError(f'Class {cls} is missing the NAMESPACE attribute')
+ raise ValueError(f"Class {cls} is missing the NAMESPACE attribute")
if not cls.ELEMENT_NAME:
- raise ValueError(f'Class {cls} is missing the ELEMENT_NAME attribute')
- return f'{{{cls.NAMESPACE}}}{cls.ELEMENT_NAME}'
+ raise ValueError(f"Class {cls} is missing the ELEMENT_NAME attribute")
+ return f"{{{cls.NAMESPACE}}}{cls.ELEMENT_NAME}"
@classmethod
def attribute_fields(cls):
@@ -432,22 +460,20 @@ Module exchangelib.properties
return field_vals
def __str__(self):
- args_str = ', '.join(
- f'{name}={val!r}' for name, val in self._field_vals() if val is not None
- )
- return f'{self.__class__.__name__}({args_str})'
+ args_str = ", ".join(f"{name}={val!r}" for name, val in self._field_vals() if val is not None)
+ return f"{self.__class__.__name__}({args_str})"
def __repr__(self):
- args_str = ', '.join(f'{name}={val!r}' for name, val in self._field_vals())
- return f'{self.__class__.__name__}({args_str})'
+ args_str = ", ".join(f"{name}={val!r}" for name, val in self._field_vals())
+ return f"{self.__class__.__name__}({args_str})"
class MessageHeader(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/internetmessageheader"""
- ELEMENT_NAME = 'InternetMessageHeader'
+ ELEMENT_NAME = "InternetMessageHeader"
- name = TextField(field_uri='HeaderName', is_attribute=True)
+ name = TextField(field_uri="HeaderName", is_attribute=True)
value = SubField()
@@ -470,9 +496,9 @@ Module exchangelib.properties
MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/itemid
"""
- ELEMENT_NAME = 'ItemId'
- ID_ATTR = 'Id'
- CHANGEKEY_ATTR = 'ChangeKey'
+ ELEMENT_NAME = "ItemId"
+ ID_ATTR = "Id"
+ CHANGEKEY_ATTR = "ChangeKey"
id = IdField(field_uri=ID_ATTR, is_required=True)
changekey = IdField(field_uri=CHANGEKEY_ATTR, is_required=False)
@@ -481,17 +507,17 @@ Module exchangelib.properties
class ParentItemId(ItemId):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/parentitemid"""
- ELEMENT_NAME = 'ParentItemId'
+ ELEMENT_NAME = "ParentItemId"
NAMESPACE = MNS
class RootItemId(BaseItemId):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/rootitemid"""
- ELEMENT_NAME = 'RootItemId'
+ ELEMENT_NAME = "RootItemId"
NAMESPACE = MNS
- ID_ATTR = 'RootItemId'
- CHANGEKEY_ATTR = 'RootItemChangeKey'
+ ID_ATTR = "RootItemId"
+ CHANGEKEY_ATTR = "RootItemChangeKey"
id = IdField(field_uri=ID_ATTR, is_required=True)
changekey = IdField(field_uri=CHANGEKEY_ATTR, is_required=True)
@@ -502,13 +528,13 @@ Module exchangelib.properties
https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/associatedcalendaritemid
"""
- ELEMENT_NAME = 'AssociatedCalendarItemId'
+ ELEMENT_NAME = "AssociatedCalendarItemId"
class ConversationId(ItemId):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/conversationid"""
- ELEMENT_NAME = 'ConversationId'
+ ELEMENT_NAME = "ConversationId"
# ChangeKey attribute is sometimes required, see MSDN link
@@ -516,45 +542,45 @@ Module exchangelib.properties
class ParentFolderId(ItemId):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/parentfolderid"""
- ELEMENT_NAME = 'ParentFolderId'
+ ELEMENT_NAME = "ParentFolderId"
class ReferenceItemId(ItemId):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/referenceitemid"""
- ELEMENT_NAME = 'ReferenceItemId'
+ ELEMENT_NAME = "ReferenceItemId"
class PersonaId(ItemId):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/personaid"""
- ELEMENT_NAME = 'PersonaId'
+ ELEMENT_NAME = "PersonaId"
NAMESPACE = MNS
@classmethod
def response_tag(cls):
# This element is in MNS in the request and TNS in the response...
- return f'{{{TNS}}}{cls.ELEMENT_NAME}'
+ return f"{{{TNS}}}{cls.ELEMENT_NAME}"
class SourceId(ItemId):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/sourceid"""
- ELEMENT_NAME = 'SourceId'
+ ELEMENT_NAME = "SourceId"
class FolderId(ItemId):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/folderid"""
- ELEMENT_NAME = 'FolderId'
+ ELEMENT_NAME = "FolderId"
class RecurringMasterItemId(BaseItemId):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/recurringmasteritemid"""
- ELEMENT_NAME = 'RecurringMasterItemId'
- ID_ATTR = 'OccurrenceId'
- CHANGEKEY_ATTR = 'ChangeKey'
+ ELEMENT_NAME = "RecurringMasterItemId"
+ ID_ATTR = "OccurrenceId"
+ CHANGEKEY_ATTR = "ChangeKey"
id = IdField(field_uri=ID_ATTR, is_required=True)
changekey = IdField(field_uri=CHANGEKEY_ATTR, is_required=False)
@@ -563,19 +589,19 @@ Module exchangelib.properties
class OccurrenceItemId(BaseItemId):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/occurrenceitemid"""
- ELEMENT_NAME = 'OccurrenceItemId'
- ID_ATTR = 'RecurringMasterId'
- CHANGEKEY_ATTR = 'ChangeKey'
+ ELEMENT_NAME = "OccurrenceItemId"
+ ID_ATTR = "RecurringMasterId"
+ CHANGEKEY_ATTR = "ChangeKey"
id = IdField(field_uri=ID_ATTR, is_required=True)
changekey = IdField(field_uri=CHANGEKEY_ATTR, is_required=False)
- instance_index = IntegerField(field_uri='InstanceIndex', is_attribute=True, is_required=True, min=1)
+ instance_index = IntegerField(field_uri="InstanceIndex", is_attribute=True, is_required=True, min=1)
class MovedItemId(ItemId):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/moveditemid"""
- ELEMENT_NAME = 'MovedItemId'
+ ELEMENT_NAME = "MovedItemId"
NAMESPACE = MNS
@classmethod
@@ -587,20 +613,26 @@ Module exchangelib.properties
class Mailbox(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/mailbox"""
- ELEMENT_NAME = 'Mailbox'
- MAILBOX = 'Mailbox'
- ONE_OFF = 'OneOff'
+ ELEMENT_NAME = "Mailbox"
+ MAILBOX = "Mailbox"
+ ONE_OFF = "OneOff"
MAILBOX_TYPE_CHOICES = {
- Choice(MAILBOX), Choice('PublicDL'), Choice('PrivateDL'), Choice('Contact'), Choice('PublicFolder'),
- Choice('Unknown'), Choice(ONE_OFF), Choice('GroupMailbox', supported_from=EXCHANGE_2013)
- }
-
- name = TextField(field_uri='Name')
- email_address = EmailAddressField(field_uri='EmailAddress')
+ Choice(MAILBOX),
+ Choice("PublicDL"),
+ Choice("PrivateDL"),
+ Choice("Contact"),
+ Choice("PublicFolder"),
+ Choice("Unknown"),
+ Choice(ONE_OFF),
+ Choice("GroupMailbox", supported_from=EXCHANGE_2013),
+ }
+
+ name = TextField(field_uri="Name")
+ email_address = EmailAddressField(field_uri="EmailAddress")
# RoutingType values are not restricted:
# https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/routingtype-emailaddresstype
- routing_type = TextField(field_uri='RoutingType', default='SMTP')
- mailbox_type = ChoiceField(field_uri='MailboxType', choices=MAILBOX_TYPE_CHOICES, default=MAILBOX)
+ routing_type = TextField(field_uri="RoutingType", default="SMTP")
+ mailbox_type = ChoiceField(field_uri="MailboxType", choices=MAILBOX_TYPE_CHOICES, default=MAILBOX)
item_id = EWSElementField(value_cls=ItemId, is_read_only=True)
def clean(self, version=None):
@@ -633,7 +665,7 @@ Module exchangelib.properties
MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/sendingas
"""
- ELEMENT_NAME = 'SendingAs'
+ ELEMENT_NAME = "SendingAs"
NAMESPACE = MNS
@@ -643,7 +675,7 @@ Module exchangelib.properties
MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/recipientaddress
"""
- ELEMENT_NAME = 'RecipientAddress'
+ ELEMENT_NAME = "RecipientAddress"
class EmailAddress(Mailbox):
@@ -652,7 +684,7 @@ Module exchangelib.properties
MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/emailaddress-emailaddresstype
"""
- ELEMENT_NAME = 'EmailAddress'
+ ELEMENT_NAME = "EmailAddress"
class Address(Mailbox):
@@ -661,7 +693,7 @@ Module exchangelib.properties
MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/address-emailaddresstype
"""
- ELEMENT_NAME = 'Address'
+ ELEMENT_NAME = "Address"
class AvailabilityMailbox(EWSElement):
@@ -670,13 +702,13 @@ Module exchangelib.properties
MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/mailbox-availability
"""
- ELEMENT_NAME = 'Mailbox'
+ ELEMENT_NAME = "Mailbox"
- name = TextField(field_uri='Name')
- email_address = EmailAddressField(field_uri='Address', is_required=True)
+ name = TextField(field_uri="Name")
+ email_address = EmailAddressField(field_uri="Address", is_required=True)
# RoutingType values restricted to EX and SMTP:
# https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/routingtype-emailaddress
- routing_type = RoutingTypeField(field_uri='RoutingType')
+ routing_type = RoutingTypeField(field_uri="RoutingType")
def __hash__(self):
# Exchange may add 'name' on insert. We're satisfied if the email address matches.
@@ -687,7 +719,7 @@ Module exchangelib.properties
@classmethod
def from_mailbox(cls, mailbox):
if not isinstance(mailbox, Mailbox):
- raise InvalidTypeError('mailbox', mailbox, Mailbox)
+ raise InvalidTypeError("mailbox", mailbox, Mailbox)
return cls(name=mailbox.name, email_address=mailbox.email_address, routing_type=mailbox.routing_type)
@@ -696,29 +728,30 @@ Module exchangelib.properties
MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/email-emailaddresstype
"""
- ELEMENT_NAME = 'Email'
+ ELEMENT_NAME = "Email"
class MailboxData(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/mailboxdata"""
- ELEMENT_NAME = 'MailboxData'
- ATTENDEE_TYPES = {'Optional', 'Organizer', 'Required', 'Resource', 'Room'}
+ ELEMENT_NAME = "MailboxData"
+ ATTENDEE_TYPES = {"Optional", "Organizer", "Required", "Resource", "Room"}
email = EmailField()
- attendee_type = ChoiceField(field_uri='AttendeeType', choices={Choice(c) for c in ATTENDEE_TYPES})
- exclude_conflicts = BooleanField(field_uri='ExcludeConflicts')
+ attendee_type = ChoiceField(field_uri="AttendeeType", choices={Choice(c) for c in ATTENDEE_TYPES})
+ exclude_conflicts = BooleanField(field_uri="ExcludeConflicts")
class DistinguishedFolderId(FolderId):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/distinguishedfolderid"""
- ELEMENT_NAME = 'DistinguishedFolderId'
+ ELEMENT_NAME = "DistinguishedFolderId"
mailbox = MailboxField()
def clean(self, version=None):
from .folders import PublicFoldersRoot
+
super().clean(version=version)
if self.id == PublicFoldersRoot.DISTINGUISHED_FOLDER_ID:
# Avoid "ErrorInvalidOperation: It is not valid to specify a mailbox with the public folder root" from EWS
@@ -728,10 +761,10 @@ Module exchangelib.properties
class TimeWindow(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/timewindow"""
- ELEMENT_NAME = 'TimeWindow'
+ ELEMENT_NAME = "TimeWindow"
- start = DateTimeField(field_uri='StartTime', is_required=True)
- end = DateTimeField(field_uri='EndTime', is_required=True)
+ start = DateTimeField(field_uri="StartTime", is_required=True)
+ end = DateTimeField(field_uri="EndTime", is_required=True)
def clean(self, version=None):
if self.start >= self.end:
@@ -742,27 +775,30 @@ Module exchangelib.properties
class FreeBusyViewOptions(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/freebusyviewoptions"""
- ELEMENT_NAME = 'FreeBusyViewOptions'
- REQUESTED_VIEWS = {'MergedOnly', 'FreeBusy', 'FreeBusyMerged', 'Detailed', 'DetailedMerged'}
+ ELEMENT_NAME = "FreeBusyViewOptions"
+ REQUESTED_VIEWS = {"MergedOnly", "FreeBusy", "FreeBusyMerged", "Detailed", "DetailedMerged"}
time_window = EWSElementField(value_cls=TimeWindow, is_required=True)
# Interval value is in minutes
- merged_free_busy_interval = IntegerField(field_uri='MergedFreeBusyIntervalInMinutes', min=5, max=1440, default=30,
- is_required=True)
- requested_view = ChoiceField(field_uri='RequestedView', choices={Choice(c) for c in REQUESTED_VIEWS},
- is_required=True) # Choice('None') is also valid, but only for responses
+ merged_free_busy_interval = IntegerField(
+ field_uri="MergedFreeBusyIntervalInMinutes", min=5, max=1440, default=30, is_required=True
+ )
+ requested_view = ChoiceField(
+ field_uri="RequestedView", choices={Choice(c) for c in REQUESTED_VIEWS}, is_required=True
+ ) # Choice('None') is also valid, but only for responses
class Attendee(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/attendee"""
- ELEMENT_NAME = 'Attendee'
- RESPONSE_TYPES = {'Unknown', 'Organizer', 'Tentative', 'Accept', 'Decline', 'NoResponseReceived'}
+ ELEMENT_NAME = "Attendee"
+ RESPONSE_TYPES = {"Unknown", "Organizer", "Tentative", "Accept", "Decline", "NoResponseReceived"}
mailbox = MailboxField(is_required=True)
- response_type = ChoiceField(field_uri='ResponseType', choices={Choice(c) for c in RESPONSE_TYPES},
- default='Unknown')
- last_response_time = DateTimeField(field_uri='LastResponseTime')
+ response_type = ChoiceField(
+ field_uri="ResponseType", choices={Choice(c) for c in RESPONSE_TYPES}, default="Unknown"
+ )
+ last_response_time = DateTimeField(field_uri="LastResponseTime")
def __hash__(self):
return hash(self.mailbox)
@@ -771,11 +807,11 @@ Module exchangelib.properties
class TimeZoneTransition(EWSElement, metaclass=EWSMeta):
"""Base class for StandardTime and DaylightTime classes."""
- bias = IntegerField(field_uri='Bias', is_required=True) # Offset from the default bias, in minutes
- time = TimeField(field_uri='Time', is_required=True)
- occurrence = IntegerField(field_uri='DayOrder', is_required=True) # n'th occurrence of weekday in iso_month
- iso_month = IntegerField(field_uri='Month', is_required=True)
- weekday = EnumField(field_uri='DayOfWeek', enum=WEEKDAY_NAMES, is_required=True)
+ bias = IntegerField(field_uri="Bias", is_required=True) # Offset from the default bias, in minutes
+ time = TimeField(field_uri="Time", is_required=True)
+ occurrence = IntegerField(field_uri="DayOrder", is_required=True) # n'th occurrence of weekday in iso_month
+ iso_month = IntegerField(field_uri="Month", is_required=True)
+ weekday = EnumField(field_uri="DayOfWeek", enum=WEEKDAY_NAMES, is_required=True)
# 'Year' is not implemented yet
@classmethod
@@ -797,21 +833,21 @@ Module exchangelib.properties
class StandardTime(TimeZoneTransition):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/standardtime"""
- ELEMENT_NAME = 'StandardTime'
+ ELEMENT_NAME = "StandardTime"
class DaylightTime(TimeZoneTransition):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/daylighttime"""
- ELEMENT_NAME = 'DaylightTime'
+ ELEMENT_NAME = "DaylightTime"
class TimeZone(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/timezone-availability"""
- ELEMENT_NAME = 'TimeZone'
+ ELEMENT_NAME = "TimeZone"
- bias = IntegerField(field_uri='Bias', is_required=True) # Standard (non-DST) offset from UTC, in minutes
+ bias = IntegerField(field_uri="Bias", is_required=True) # Standard (non-DST) offset from UTC, in minutes
standard_time = EWSElementField(value_cls=StandardTime)
daylight_time = EWSElementField(value_cls=DaylightTime)
@@ -832,7 +868,7 @@ Module exchangelib.properties
for_year=for_year,
)
if candidate == self:
- log.debug('Found exact candidate: %s (%s)', tz_definition.id, tz_definition.name)
+ log.debug("Found exact candidate: %s (%s)", tz_definition.id, tz_definition.name)
# We prefer this timezone over anything else. Return immediately.
return tz_definition.id
# Reduce list based on base bias and standard / daylight bias values
@@ -854,14 +890,14 @@ Module exchangelib.properties
continue
if candidate.daylight_time.bias != self.daylight_time.bias:
continue
- log.debug('Found candidate with matching biases: %s (%s)', tz_definition.id, tz_definition.name)
+ log.debug("Found candidate with matching biases: %s (%s)", tz_definition.id, tz_definition.name)
candidates.add(tz_definition.id)
if not candidates:
- raise ValueError('No server timezones match this timezone definition')
+ raise ValueError("No server timezones match this timezone definition")
if len(candidates) == 1:
- log.info('Could not find an exact timezone match for %s. Selecting the best candidate', self)
+ log.info("Could not find an exact timezone match for %s. Selecting the best candidate", self)
else:
- log.warning('Could not find an exact timezone match for %s. Selecting a random candidate', self)
+ log.warning("Could not find an exact timezone match for %s. Selecting a random candidate", self)
return candidates.pop()
@classmethod
@@ -874,12 +910,12 @@ Module exchangelib.properties
class CalendarView(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/calendarview"""
- ELEMENT_NAME = 'CalendarView'
+ ELEMENT_NAME = "CalendarView"
NAMESPACE = MNS
- start = DateTimeField(field_uri='StartDate', is_required=True, is_attribute=True)
- end = DateTimeField(field_uri='EndDate', is_required=True, is_attribute=True)
- max_items = IntegerField(field_uri='MaxEntriesReturned', min=1, is_attribute=True)
+ start = DateTimeField(field_uri="StartDate", is_required=True, is_attribute=True)
+ end = DateTimeField(field_uri="EndDate", is_required=True, is_attribute=True)
+ max_items = IntegerField(field_uri="MaxEntriesReturned", min=1, is_attribute=True)
def clean(self, version=None):
super().clean(version=version)
@@ -890,53 +926,61 @@ Module exchangelib.properties
class CalendarEventDetails(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/calendareventdetails"""
- ELEMENT_NAME = 'CalendarEventDetails'
+ ELEMENT_NAME = "CalendarEventDetails"
- id = CharField(field_uri='ID')
- subject = CharField(field_uri='Subject')
- location = CharField(field_uri='Location')
- is_meeting = BooleanField(field_uri='IsMeeting')
- is_recurring = BooleanField(field_uri='IsRecurring')
- is_exception = BooleanField(field_uri='IsException')
- is_reminder_set = BooleanField(field_uri='IsReminderSet')
- is_private = BooleanField(field_uri='IsPrivate')
+ id = CharField(field_uri="ID")
+ subject = CharField(field_uri="Subject")
+ location = CharField(field_uri="Location")
+ is_meeting = BooleanField(field_uri="IsMeeting")
+ is_recurring = BooleanField(field_uri="IsRecurring")
+ is_exception = BooleanField(field_uri="IsException")
+ is_reminder_set = BooleanField(field_uri="IsReminderSet")
+ is_private = BooleanField(field_uri="IsPrivate")
class CalendarEvent(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/calendarevent"""
- ELEMENT_NAME = 'CalendarEvent'
+ ELEMENT_NAME = "CalendarEvent"
- start = DateTimeField(field_uri='StartTime')
- end = DateTimeField(field_uri='EndTime')
- busy_type = FreeBusyStatusField(field_uri='BusyType', is_required=True, default='Busy')
+ start = DateTimeField(field_uri="StartTime")
+ end = DateTimeField(field_uri="EndTime")
+ busy_type = FreeBusyStatusField(field_uri="BusyType", is_required=True, default="Busy")
details = EWSElementField(value_cls=CalendarEventDetails)
class WorkingPeriod(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/workingperiod"""
- ELEMENT_NAME = 'WorkingPeriod'
+ ELEMENT_NAME = "WorkingPeriod"
- weekdays = EnumListField(field_uri='DayOfWeek', enum=WEEKDAY_NAMES, is_required=True)
- start = TimeField(field_uri='StartTimeInMinutes', is_required=True)
- end = TimeField(field_uri='EndTimeInMinutes', is_required=True)
+ weekdays = EnumListField(field_uri="DayOfWeek", enum=WEEKDAY_NAMES, is_required=True)
+ start = TimeField(field_uri="StartTimeInMinutes", is_required=True)
+ end = TimeField(field_uri="EndTimeInMinutes", is_required=True)
class FreeBusyView(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/freebusyview"""
- ELEMENT_NAME = 'FreeBusyView'
+ ELEMENT_NAME = "FreeBusyView"
NAMESPACE = MNS
- view_type = ChoiceField(field_uri='FreeBusyViewType', choices={
- Choice('None'), Choice('MergedOnly'), Choice('FreeBusy'), Choice('FreeBusyMerged'), Choice('Detailed'),
- Choice('DetailedMerged'),
- }, is_required=True)
+ view_type = ChoiceField(
+ field_uri="FreeBusyViewType",
+ choices={
+ Choice("None"),
+ Choice("MergedOnly"),
+ Choice("FreeBusy"),
+ Choice("FreeBusyMerged"),
+ Choice("Detailed"),
+ Choice("DetailedMerged"),
+ },
+ is_required=True,
+ )
# A string of digits. Each digit points to a position in .fields.FREE_BUSY_CHOICES
- merged = CharField(field_uri='MergedFreeBusy')
- calendar_events = EWSElementListField(field_uri='CalendarEventArray', value_cls=CalendarEvent)
+ merged = CharField(field_uri="MergedFreeBusy")
+ calendar_events = EWSElementListField(field_uri="CalendarEventArray", value_cls=CalendarEvent)
# WorkingPeriod is located inside the WorkingPeriodArray element which is inside the WorkingHours element
- working_hours = EWSElementListField(field_uri='WorkingPeriodArray', value_cls=WorkingPeriod)
+ working_hours = EWSElementListField(field_uri="WorkingPeriodArray", value_cls=WorkingPeriod)
# TimeZone is also inside the WorkingHours element. It contains information about the timezone which the
# account is located in.
working_hours_timezone = EWSElementField(value_cls=TimeZone)
@@ -944,9 +988,9 @@ Module exchangelib.properties
@classmethod
def from_xml(cls, elem, account):
kwargs = {}
- working_hours_elem = elem.find(f'{{{TNS}}}WorkingHours')
+ working_hours_elem = elem.find(f"{{{TNS}}}WorkingHours")
for f in cls.FIELDS:
- if f.name in ['working_hours', 'working_hours_timezone']:
+ if f.name in ["working_hours", "working_hours_timezone"]:
if working_hours_elem is None:
continue
kwargs[f.name] = f.from_xml(elem=working_hours_elem, account=account)
@@ -959,29 +1003,29 @@ Module exchangelib.properties
class RoomList(Mailbox):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/roomlist"""
- ELEMENT_NAME = 'RoomList'
+ ELEMENT_NAME = "RoomList"
NAMESPACE = MNS
@classmethod
def response_tag(cls):
# In a GetRoomLists response, room lists are delivered as Address elements. See
# https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/address-emailaddresstype
- return f'{{{TNS}}}Address'
+ return f"{{{TNS}}}Address"
class Room(Mailbox):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/room"""
- ELEMENT_NAME = 'Room'
+ ELEMENT_NAME = "Room"
@classmethod
def from_xml(cls, elem, account):
- id_elem = elem.find(f'{{{TNS}}}Id')
+ id_elem = elem.find(f"{{{TNS}}}Id")
item_id_elem = id_elem.find(ItemId.response_tag())
kwargs = dict(
- name=get_xml_attr(id_elem, f'{{{TNS}}}Name'),
- email_address=get_xml_attr(id_elem, f'{{{TNS}}}EmailAddress'),
- mailbox_type=get_xml_attr(id_elem, f'{{{TNS}}}MailboxType'),
+ name=get_xml_attr(id_elem, f"{{{TNS}}}Name"),
+ email_address=get_xml_attr(id_elem, f"{{{TNS}}}EmailAddress"),
+ mailbox_type=get_xml_attr(id_elem, f"{{{TNS}}}MailboxType"),
item_id=ItemId.from_xml(elem=item_id_elem, account=account) if item_id_elem else None,
)
cls._clear(elem)
@@ -993,12 +1037,12 @@ Module exchangelib.properties
https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/member-ex15websvcsotherref
"""
- ELEMENT_NAME = 'Member'
+ ELEMENT_NAME = "Member"
mailbox = MailboxField(is_required=True)
- status = ChoiceField(field_uri='Status', choices={
- Choice('Unrecognized'), Choice('Normal'), Choice('Demoted')
- }, default='Normal')
+ status = ChoiceField(
+ field_uri="Status", choices={Choice("Unrecognized"), Choice("Normal"), Choice("Demoted")}, default="Normal"
+ )
def __hash__(self):
return hash(self.mailbox)
@@ -1007,58 +1051,74 @@ Module exchangelib.properties
class UserId(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/userid"""
- ELEMENT_NAME = 'UserId'
+ ELEMENT_NAME = "UserId"
- sid = CharField(field_uri='SID')
- primary_smtp_address = EmailAddressField(field_uri='PrimarySmtpAddress')
- display_name = CharField(field_uri='DisplayName')
- distinguished_user = ChoiceField(field_uri='DistinguishedUser', choices={
- Choice('Default'), Choice('Anonymous')
- })
- external_user_identity = CharField(field_uri='ExternalUserIdentity')
+ sid = CharField(field_uri="SID")
+ primary_smtp_address = EmailAddressField(field_uri="PrimarySmtpAddress")
+ display_name = CharField(field_uri="DisplayName")
+ distinguished_user = ChoiceField(field_uri="DistinguishedUser", choices={Choice("Default"), Choice("Anonymous")})
+ external_user_identity = CharField(field_uri="ExternalUserIdentity")
class BasePermission(EWSElement, metaclass=EWSMeta):
"""Base class for the Permission and CalendarPermission classes"""
- PERMISSION_ENUM = {Choice('None'), Choice('Owned'), Choice('All')}
+ PERMISSION_ENUM = {Choice("None"), Choice("Owned"), Choice("All")}
- can_create_items = BooleanField(field_uri='CanCreateItems', default=False)
- can_create_subfolders = BooleanField(field_uri='CanCreateSubfolders', default=False)
- is_folder_owner = BooleanField(field_uri='IsFolderOwner', default=False)
- is_folder_visible = BooleanField(field_uri='IsFolderVisible', default=False)
- is_folder_contact = BooleanField(field_uri='IsFolderContact', default=False)
- edit_items = ChoiceField(field_uri='EditItems', choices=PERMISSION_ENUM, default='None')
- delete_items = ChoiceField(field_uri='DeleteItems', choices=PERMISSION_ENUM, default='None')
- read_items = ChoiceField(field_uri='ReadItems', choices={Choice('None'), Choice('FullDetails')}, default='None')
+ can_create_items = BooleanField(field_uri="CanCreateItems", default=False)
+ can_create_subfolders = BooleanField(field_uri="CanCreateSubfolders", default=False)
+ is_folder_owner = BooleanField(field_uri="IsFolderOwner", default=False)
+ is_folder_visible = BooleanField(field_uri="IsFolderVisible", default=False)
+ is_folder_contact = BooleanField(field_uri="IsFolderContact", default=False)
+ edit_items = ChoiceField(field_uri="EditItems", choices=PERMISSION_ENUM, default="None")
+ delete_items = ChoiceField(field_uri="DeleteItems", choices=PERMISSION_ENUM, default="None")
+ read_items = ChoiceField(field_uri="ReadItems", choices={Choice("None"), Choice("FullDetails")}, default="None")
user_id = EWSElementField(value_cls=UserId, is_required=True)
class Permission(BasePermission):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/permission"""
- ELEMENT_NAME = 'Permission'
+ ELEMENT_NAME = "Permission"
LEVEL_CHOICES = (
- 'None', 'Owner', 'PublishingEditor', 'Editor', 'PublishingAuthor', 'Author', 'NoneditingAuthor', 'Reviewer',
- 'Contributor', 'Custom',
+ "None",
+ "Owner",
+ "PublishingEditor",
+ "Editor",
+ "PublishingAuthor",
+ "Author",
+ "NoneditingAuthor",
+ "Reviewer",
+ "Contributor",
+ "Custom",
)
permission_level = ChoiceField(
- field_uri='CalendarPermissionLevel', choices={Choice(c) for c in LEVEL_CHOICES}, default=LEVEL_CHOICES[0]
+ field_uri="CalendarPermissionLevel", choices={Choice(c) for c in LEVEL_CHOICES}, default=LEVEL_CHOICES[0]
)
class CalendarPermission(BasePermission):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/calendarpermission"""
- ELEMENT_NAME = 'CalendarPermission'
+ ELEMENT_NAME = "CalendarPermission"
LEVEL_CHOICES = (
- 'None', 'Owner', 'PublishingEditor', 'Editor', 'PublishingAuthor', 'Author', 'NoneditingAuthor', 'Reviewer',
- 'Contributor', 'FreeBusyTimeOnly', 'FreeBusyTimeAndSubjectAndLocation', 'Custom',
+ "None",
+ "Owner",
+ "PublishingEditor",
+ "Editor",
+ "PublishingAuthor",
+ "Author",
+ "NoneditingAuthor",
+ "Reviewer",
+ "Contributor",
+ "FreeBusyTimeOnly",
+ "FreeBusyTimeAndSubjectAndLocation",
+ "Custom",
)
calendar_permission_level = ChoiceField(
- field_uri='CalendarPermissionLevel', choices={Choice(c) for c in LEVEL_CHOICES}, default=LEVEL_CHOICES[0]
+ field_uri="CalendarPermissionLevel", choices={Choice(c) for c in LEVEL_CHOICES}, default=LEVEL_CHOICES[0]
)
@@ -1070,25 +1130,25 @@ Module exchangelib.properties
"""
# For simplicity, we implement the two distinct but equally names elements as one class.
- ELEMENT_NAME = 'PermissionSet'
+ ELEMENT_NAME = "PermissionSet"
- permissions = EWSElementListField(field_uri='Permissions', value_cls=Permission)
- calendar_permissions = EWSElementListField(field_uri='CalendarPermissions', value_cls=CalendarPermission)
- unknown_entries = UnknownEntriesField(field_uri='UnknownEntries')
+ permissions = EWSElementListField(field_uri="Permissions", value_cls=Permission)
+ calendar_permissions = EWSElementListField(field_uri="CalendarPermissions", value_cls=CalendarPermission)
+ unknown_entries = UnknownEntriesField(field_uri="UnknownEntries")
class EffectiveRights(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/effectiverights"""
- ELEMENT_NAME = 'EffectiveRights'
+ ELEMENT_NAME = "EffectiveRights"
- create_associated = BooleanField(field_uri='CreateAssociated', default=False)
- create_contents = BooleanField(field_uri='CreateContents', default=False)
- create_hierarchy = BooleanField(field_uri='CreateHierarchy', default=False)
- delete = BooleanField(field_uri='Delete', default=False)
- modify = BooleanField(field_uri='Modify', default=False)
- read = BooleanField(field_uri='Read', default=False)
- view_private_items = BooleanField(field_uri='ViewPrivateItems', default=False)
+ create_associated = BooleanField(field_uri="CreateAssociated", default=False)
+ create_contents = BooleanField(field_uri="CreateContents", default=False)
+ create_hierarchy = BooleanField(field_uri="CreateHierarchy", default=False)
+ delete = BooleanField(field_uri="Delete", default=False)
+ modify = BooleanField(field_uri="Modify", default=False)
+ read = BooleanField(field_uri="Read", default=False)
+ view_private_items = BooleanField(field_uri="ViewPrivateItems", default=False)
def __contains__(self, item):
return getattr(self, item, False)
@@ -1097,92 +1157,102 @@ Module exchangelib.properties
class DelegatePermissions(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/delegatepermissions"""
- ELEMENT_NAME = 'DelegatePermissions'
+ ELEMENT_NAME = "DelegatePermissions"
PERMISSION_LEVEL_CHOICES = {
- Choice('None'), Choice('Editor'), Choice('Reviewer'), Choice('Author'), Choice('Custom'),
- }
-
- calendar_folder_permission_level = ChoiceField(field_uri='CalendarFolderPermissionLevel',
- choices=PERMISSION_LEVEL_CHOICES, default='None')
- tasks_folder_permission_level = ChoiceField(field_uri='TasksFolderPermissionLevel',
- choices=PERMISSION_LEVEL_CHOICES, default='None')
- inbox_folder_permission_level = ChoiceField(field_uri='InboxFolderPermissionLevel',
- choices=PERMISSION_LEVEL_CHOICES, default='None')
- contacts_folder_permission_level = ChoiceField(field_uri='ContactsFolderPermissionLevel',
- choices=PERMISSION_LEVEL_CHOICES, default='None')
- notes_folder_permission_level = ChoiceField(field_uri='NotesFolderPermissionLevel',
- choices=PERMISSION_LEVEL_CHOICES, default='None')
- journal_folder_permission_level = ChoiceField(field_uri='JournalFolderPermissionLevel',
- choices=PERMISSION_LEVEL_CHOICES, default='None')
+ Choice("None"),
+ Choice("Editor"),
+ Choice("Reviewer"),
+ Choice("Author"),
+ Choice("Custom"),
+ }
+
+ calendar_folder_permission_level = ChoiceField(
+ field_uri="CalendarFolderPermissionLevel", choices=PERMISSION_LEVEL_CHOICES, default="None"
+ )
+ tasks_folder_permission_level = ChoiceField(
+ field_uri="TasksFolderPermissionLevel", choices=PERMISSION_LEVEL_CHOICES, default="None"
+ )
+ inbox_folder_permission_level = ChoiceField(
+ field_uri="InboxFolderPermissionLevel", choices=PERMISSION_LEVEL_CHOICES, default="None"
+ )
+ contacts_folder_permission_level = ChoiceField(
+ field_uri="ContactsFolderPermissionLevel", choices=PERMISSION_LEVEL_CHOICES, default="None"
+ )
+ notes_folder_permission_level = ChoiceField(
+ field_uri="NotesFolderPermissionLevel", choices=PERMISSION_LEVEL_CHOICES, default="None"
+ )
+ journal_folder_permission_level = ChoiceField(
+ field_uri="JournalFolderPermissionLevel", choices=PERMISSION_LEVEL_CHOICES, default="None"
+ )
class DelegateUser(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/delegateuser"""
- ELEMENT_NAME = 'DelegateUser'
+ ELEMENT_NAME = "DelegateUser"
NAMESPACE = MNS
user_id = EWSElementField(value_cls=UserId)
delegate_permissions = EWSElementField(value_cls=DelegatePermissions)
- receive_copies_of_meeting_messages = BooleanField(field_uri='ReceiveCopiesOfMeetingMessages', default=False)
- view_private_items = BooleanField(field_uri='ViewPrivateItems', default=False)
+ receive_copies_of_meeting_messages = BooleanField(field_uri="ReceiveCopiesOfMeetingMessages", default=False)
+ view_private_items = BooleanField(field_uri="ViewPrivateItems", default=False)
class SearchableMailbox(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/searchablemailbox"""
- ELEMENT_NAME = 'SearchableMailbox'
+ ELEMENT_NAME = "SearchableMailbox"
- guid = CharField(field_uri='Guid')
- primary_smtp_address = EmailAddressField(field_uri='PrimarySmtpAddress')
- is_external = BooleanField(field_uri='IsExternalMailbox')
- external_email = EmailAddressField(field_uri='ExternalEmailAddress')
- display_name = CharField(field_uri='DisplayName')
- is_membership_group = BooleanField(field_uri='IsMembershipGroup')
- reference_id = CharField(field_uri='ReferenceId')
+ guid = CharField(field_uri="Guid")
+ primary_smtp_address = EmailAddressField(field_uri="PrimarySmtpAddress")
+ is_external = BooleanField(field_uri="IsExternalMailbox")
+ external_email = EmailAddressField(field_uri="ExternalEmailAddress")
+ display_name = CharField(field_uri="DisplayName")
+ is_membership_group = BooleanField(field_uri="IsMembershipGroup")
+ reference_id = CharField(field_uri="ReferenceId")
class FailedMailbox(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/failedmailbox"""
- ELEMENT_NAME = 'FailedMailbox'
+ ELEMENT_NAME = "FailedMailbox"
- mailbox = CharField(field_uri='Mailbox')
- error_code = IntegerField(field_uri='ErrorCode')
- error_message = CharField(field_uri='ErrorMessage')
- is_archive = BooleanField(field_uri='IsArchive')
+ mailbox = CharField(field_uri="Mailbox")
+ error_code = IntegerField(field_uri="ErrorCode")
+ error_message = CharField(field_uri="ErrorMessage")
+ is_archive = BooleanField(field_uri="IsArchive")
# MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/mailtipsrequested
MAIL_TIPS_TYPES = (
- 'All',
- 'OutOfOfficeMessage',
- 'MailboxFullStatus',
- 'CustomMailTip',
- 'ExternalMemberCount',
- 'TotalMemberCount',
- 'MaxMessageSize',
- 'DeliveryRestriction',
- 'ModerationStatus',
- 'InvalidRecipient',
+ "All",
+ "OutOfOfficeMessage",
+ "MailboxFullStatus",
+ "CustomMailTip",
+ "ExternalMemberCount",
+ "TotalMemberCount",
+ "MaxMessageSize",
+ "DeliveryRestriction",
+ "ModerationStatus",
+ "InvalidRecipient",
)
class OutOfOffice(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/outofoffice"""
- ELEMENT_NAME = 'OutOfOffice'
+ ELEMENT_NAME = "OutOfOffice"
- reply_body = MessageField(field_uri='ReplyBody')
- start = DateTimeField(field_uri='StartTime', is_required=False)
- end = DateTimeField(field_uri='EndTime', is_required=False)
+ reply_body = MessageField(field_uri="ReplyBody")
+ start = DateTimeField(field_uri="StartTime", is_required=False)
+ end = DateTimeField(field_uri="EndTime", is_required=False)
@classmethod
def duration_to_start_end(cls, elem, account):
kwargs = {}
- duration = elem.find(f'{{{TNS}}}Duration')
+ duration = elem.find(f"{{{TNS}}}Duration")
if duration is not None:
- for attr in ('start', 'end'):
+ for attr in ("start", "end"):
f = cls.get_field_by_fieldname(attr)
kwargs[attr] = f.from_xml(elem=duration, account=account)
return kwargs
@@ -1190,7 +1260,7 @@ Module exchangelib.properties
@classmethod
def from_xml(cls, elem, account):
kwargs = {}
- for attr in ('reply_body',):
+ for attr in ("reply_body",):
f = cls.get_field_by_fieldname(attr)
kwargs[attr] = f.from_xml(elem=elem, account=account)
kwargs.update(cls.duration_to_start_end(elem=elem, account=account))
@@ -1201,28 +1271,28 @@ Module exchangelib.properties
class MailTips(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/mailtips"""
- ELEMENT_NAME = 'MailTips'
+ ELEMENT_NAME = "MailTips"
NAMESPACE = MNS
recipient_address = RecipientAddressField()
- pending_mail_tips = ChoiceField(field_uri='PendingMailTips', choices={Choice(c) for c in MAIL_TIPS_TYPES})
+ pending_mail_tips = ChoiceField(field_uri="PendingMailTips", choices={Choice(c) for c in MAIL_TIPS_TYPES})
out_of_office = EWSElementField(value_cls=OutOfOffice)
- mailbox_full = BooleanField(field_uri='MailboxFull')
- custom_mail_tip = TextField(field_uri='CustomMailTip')
- total_member_count = IntegerField(field_uri='TotalMemberCount')
- external_member_count = IntegerField(field_uri='ExternalMemberCount')
- max_message_size = IntegerField(field_uri='MaxMessageSize')
- delivery_restricted = BooleanField(field_uri='DeliveryRestricted')
- is_moderated = BooleanField(field_uri='IsModerated')
- invalid_recipient = BooleanField(field_uri='InvalidRecipient')
-
-
-ENTRY_ID = 'EntryId' # The base64-encoded PR_ENTRYID property
-EWS_ID = 'EwsId' # The EWS format used in Exchange 2007 SP1 and later
-EWS_LEGACY_ID = 'EwsLegacyId' # The EWS format used in Exchange 2007 before SP1
-HEX_ENTRY_ID = 'HexEntryId' # The hexadecimal representation of the PR_ENTRYID property
-OWA_ID = 'OwaId' # The OWA format for Exchange 2007 and 2010
-STORE_ID = 'StoreId' # The Exchange Store format
+ mailbox_full = BooleanField(field_uri="MailboxFull")
+ custom_mail_tip = TextField(field_uri="CustomMailTip")
+ total_member_count = IntegerField(field_uri="TotalMemberCount")
+ external_member_count = IntegerField(field_uri="ExternalMemberCount")
+ max_message_size = IntegerField(field_uri="MaxMessageSize")
+ delivery_restricted = BooleanField(field_uri="DeliveryRestricted")
+ is_moderated = BooleanField(field_uri="IsModerated")
+ invalid_recipient = BooleanField(field_uri="InvalidRecipient")
+
+
+ENTRY_ID = "EntryId" # The base64-encoded PR_ENTRYID property
+EWS_ID = "EwsId" # The EWS format used in Exchange 2007 SP1 and later
+EWS_LEGACY_ID = "EwsLegacyId" # The EWS format used in Exchange 2007 before SP1
+HEX_ENTRY_ID = "HexEntryId" # The hexadecimal representation of the PR_ENTRYID property
+OWA_ID = "OwaId" # The OWA format for Exchange 2007 and 2010
+STORE_ID = "StoreId" # The Exchange Store format
# IdFormat enum
ID_FORMATS = (ENTRY_ID, EWS_ID, EWS_LEGACY_ID, HEX_ENTRY_ID, OWA_ID, STORE_ID)
@@ -1230,28 +1300,30 @@ Module exchangelib.properties
class AlternateId(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/alternateid"""
- ELEMENT_NAME = 'AlternateId'
+ ELEMENT_NAME = "AlternateId"
- id = CharField(field_uri='Id', is_required=True, is_attribute=True)
- format = ChoiceField(field_uri='Format', is_required=True, is_attribute=True,
- choices={Choice(c) for c in ID_FORMATS})
- mailbox = EmailAddressField(field_uri='Mailbox', is_required=True, is_attribute=True)
- is_archive = BooleanField(field_uri='IsArchive', is_required=False, is_attribute=True)
+ id = CharField(field_uri="Id", is_required=True, is_attribute=True)
+ format = ChoiceField(
+ field_uri="Format", is_required=True, is_attribute=True, choices={Choice(c) for c in ID_FORMATS}
+ )
+ mailbox = EmailAddressField(field_uri="Mailbox", is_required=True, is_attribute=True)
+ is_archive = BooleanField(field_uri="IsArchive", is_required=False, is_attribute=True)
@classmethod
def response_tag(cls):
# This element is in TNS in the request and MNS in the response...
- return f'{{{MNS}}}{cls.ELEMENT_NAME}'
+ return f"{{{MNS}}}{cls.ELEMENT_NAME}"
class AlternatePublicFolderId(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/alternatepublicfolderid"""
- ELEMENT_NAME = 'AlternatePublicFolderId'
+ ELEMENT_NAME = "AlternatePublicFolderId"
- folder_id = CharField(field_uri='FolderId', is_required=True, is_attribute=True)
- format = ChoiceField(field_uri='Format', is_required=True, is_attribute=True,
- choices={Choice(c) for c in ID_FORMATS})
+ folder_id = CharField(field_uri="FolderId", is_required=True, is_attribute=True)
+ format = ChoiceField(
+ field_uri="Format", is_required=True, is_attribute=True, choices={Choice(c) for c in ID_FORMATS}
+ )
class AlternatePublicFolderItemId(EWSElement):
@@ -1259,136 +1331,140 @@ Module exchangelib.properties
https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/alternatepublicfolderitemid
"""
- ELEMENT_NAME = 'AlternatePublicFolderItemId'
+ ELEMENT_NAME = "AlternatePublicFolderItemId"
- folder_id = CharField(field_uri='FolderId', is_required=True, is_attribute=True)
- format = ChoiceField(field_uri='Format', is_required=True, is_attribute=True,
- choices={Choice(c) for c in ID_FORMATS})
- item_id = CharField(field_uri='ItemId', is_required=True, is_attribute=True)
+ folder_id = CharField(field_uri="FolderId", is_required=True, is_attribute=True)
+ format = ChoiceField(
+ field_uri="Format", is_required=True, is_attribute=True, choices={Choice(c) for c in ID_FORMATS}
+ )
+ item_id = CharField(field_uri="ItemId", is_required=True, is_attribute=True)
class FieldURI(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/fielduri"""
- ELEMENT_NAME = 'FieldURI'
+ ELEMENT_NAME = "FieldURI"
- field_uri = CharField(field_uri='FieldURI', is_attribute=True, is_required=True)
+ field_uri = CharField(field_uri="FieldURI", is_attribute=True, is_required=True)
class IndexedFieldURI(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/indexedfielduri"""
- ELEMENT_NAME = 'IndexedFieldURI'
+ ELEMENT_NAME = "IndexedFieldURI"
- field_uri = CharField(field_uri='FieldURI', is_attribute=True, is_required=True)
- field_index = CharField(field_uri='FieldIndex', is_attribute=True, is_required=True)
+ field_uri = CharField(field_uri="FieldURI", is_attribute=True, is_required=True)
+ field_index = CharField(field_uri="FieldIndex", is_attribute=True, is_required=True)
class ExtendedFieldURI(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/extendedfielduri"""
- ELEMENT_NAME = 'ExtendedFieldURI'
+ ELEMENT_NAME = "ExtendedFieldURI"
- distinguished_property_set_id = CharField(field_uri='DistinguishedPropertySetId', is_attribute=True)
- property_set_id = CharField(field_uri='PropertySetId', is_attribute=True)
- property_tag = CharField(field_uri='PropertyTag', is_attribute=True)
- property_name = CharField(field_uri='PropertyName', is_attribute=True)
- property_id = CharField(field_uri='PropertyId', is_attribute=True)
- property_type = CharField(field_uri='PropertyType', is_attribute=True)
+ distinguished_property_set_id = CharField(field_uri="DistinguishedPropertySetId", is_attribute=True)
+ property_set_id = CharField(field_uri="PropertySetId", is_attribute=True)
+ property_tag = CharField(field_uri="PropertyTag", is_attribute=True)
+ property_name = CharField(field_uri="PropertyName", is_attribute=True)
+ property_id = CharField(field_uri="PropertyId", is_attribute=True)
+ property_type = CharField(field_uri="PropertyType", is_attribute=True)
class ExceptionFieldURI(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/exceptionfielduri"""
- ELEMENT_NAME = 'ExceptionFieldURI'
+ ELEMENT_NAME = "ExceptionFieldURI"
- field_uri = CharField(field_uri='FieldURI', is_attribute=True, is_required=True)
+ field_uri = CharField(field_uri="FieldURI", is_attribute=True, is_required=True)
class CompleteName(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/completename"""
- ELEMENT_NAME = 'CompleteName'
+ ELEMENT_NAME = "CompleteName"
- title = CharField(field_uri='Title')
- first_name = CharField(field_uri='FirstName')
- middle_name = CharField(field_uri='MiddleName')
- last_name = CharField(field_uri='LastName')
- suffix = CharField(field_uri='Suffix')
- initials = CharField(field_uri='Initials')
- full_name = CharField(field_uri='FullName')
- nickname = CharField(field_uri='Nickname')
- yomi_first_name = CharField(field_uri='YomiFirstName')
- yomi_last_name = CharField(field_uri='YomiLastName')
+ title = CharField(field_uri="Title")
+ first_name = CharField(field_uri="FirstName")
+ middle_name = CharField(field_uri="MiddleName")
+ last_name = CharField(field_uri="LastName")
+ suffix = CharField(field_uri="Suffix")
+ initials = CharField(field_uri="Initials")
+ full_name = CharField(field_uri="FullName")
+ nickname = CharField(field_uri="Nickname")
+ yomi_first_name = CharField(field_uri="YomiFirstName")
+ yomi_last_name = CharField(field_uri="YomiLastName")
class ReminderMessageData(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/remindermessagedata"""
- ELEMENT_NAME = 'ReminderMessageData'
+ ELEMENT_NAME = "ReminderMessageData"
- reminder_text = CharField(field_uri='ReminderText')
- location = CharField(field_uri='Location')
- start_time = TimeField(field_uri='StartTime')
- end_time = TimeField(field_uri='EndTime')
- associated_calendar_item_id = AssociatedCalendarItemIdField(field_uri='AssociatedCalendarItemId',
- supported_from=Build(15, 0, 913, 9))
+ reminder_text = CharField(field_uri="ReminderText")
+ location = CharField(field_uri="Location")
+ start_time = TimeField(field_uri="StartTime")
+ end_time = TimeField(field_uri="EndTime")
+ associated_calendar_item_id = AssociatedCalendarItemIdField(
+ field_uri="AssociatedCalendarItemId", supported_from=Build(15, 0, 913, 9)
+ )
class AcceptSharingInvitation(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/acceptsharinginvitation"""
- ELEMENT_NAME = 'AcceptSharingInvitation'
+ ELEMENT_NAME = "AcceptSharingInvitation"
- reference_item_id = ReferenceItemIdField(field_uri='item:ReferenceItemId')
+ reference_item_id = ReferenceItemIdField(field_uri="item:ReferenceItemId")
class SuppressReadReceipt(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/suppressreadreceipt"""
- ELEMENT_NAME = 'SuppressReadReceipt'
+ ELEMENT_NAME = "SuppressReadReceipt"
- reference_item_id = ReferenceItemIdField(field_uri='item:ReferenceItemId')
+ reference_item_id = ReferenceItemIdField(field_uri="item:ReferenceItemId")
class RemoveItem(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/removeitem"""
- ELEMENT_NAME = 'RemoveItem'
+ ELEMENT_NAME = "RemoveItem"
- reference_item_id = ReferenceItemIdField(field_uri='item:ReferenceItemId')
+ reference_item_id = ReferenceItemIdField(field_uri="item:ReferenceItemId")
class ResponseObjects(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/responseobjects"""
- ELEMENT_NAME = 'ResponseObjects'
+ ELEMENT_NAME = "ResponseObjects"
NAMESPACE = EWSElement.NAMESPACE
- accept_item = EWSElementField(field_uri='AcceptItem', value_cls='AcceptItem', namespace=NAMESPACE)
- tentatively_accept_item = EWSElementField(field_uri='TentativelyAcceptItem', value_cls='TentativelyAcceptItem',
- namespace=NAMESPACE)
- decline_item = EWSElementField(field_uri='DeclineItem', value_cls='DeclineItem', namespace=NAMESPACE)
- reply_to_item = EWSElementField(field_uri='ReplyToItem', value_cls='ReplyToItem', namespace=NAMESPACE)
- forward_item = EWSElementField(field_uri='ForwardItem', value_cls='ForwardItem', namespace=NAMESPACE)
- reply_all_to_item = EWSElementField(field_uri='ReplyAllToItem', value_cls='ReplyAllToItem', namespace=NAMESPACE)
- cancel_calendar_item = EWSElementField(field_uri='CancelCalendarItem', value_cls='CancelCalendarItem',
- namespace=NAMESPACE)
- remove_item = EWSElementField(field_uri='RemoveItem', value_cls=RemoveItem)
- post_reply_item = EWSElementField(field_uri='PostReplyItem', value_cls='PostReplyItem',
- namespace=EWSElement.NAMESPACE)
- success_read_receipt = EWSElementField(field_uri='SuppressReadReceipt', value_cls=SuppressReadReceipt)
- accept_sharing_invitation = EWSElementField(field_uri='AcceptSharingInvitation',
- value_cls=AcceptSharingInvitation)
+ accept_item = EWSElementField(field_uri="AcceptItem", value_cls="AcceptItem", namespace=NAMESPACE)
+ tentatively_accept_item = EWSElementField(
+ field_uri="TentativelyAcceptItem", value_cls="TentativelyAcceptItem", namespace=NAMESPACE
+ )
+ decline_item = EWSElementField(field_uri="DeclineItem", value_cls="DeclineItem", namespace=NAMESPACE)
+ reply_to_item = EWSElementField(field_uri="ReplyToItem", value_cls="ReplyToItem", namespace=NAMESPACE)
+ forward_item = EWSElementField(field_uri="ForwardItem", value_cls="ForwardItem", namespace=NAMESPACE)
+ reply_all_to_item = EWSElementField(field_uri="ReplyAllToItem", value_cls="ReplyAllToItem", namespace=NAMESPACE)
+ cancel_calendar_item = EWSElementField(
+ field_uri="CancelCalendarItem", value_cls="CancelCalendarItem", namespace=NAMESPACE
+ )
+ remove_item = EWSElementField(field_uri="RemoveItem", value_cls=RemoveItem)
+ post_reply_item = EWSElementField(
+ field_uri="PostReplyItem", value_cls="PostReplyItem", namespace=EWSElement.NAMESPACE
+ )
+ success_read_receipt = EWSElementField(field_uri="SuppressReadReceipt", value_cls=SuppressReadReceipt)
+ accept_sharing_invitation = EWSElementField(field_uri="AcceptSharingInvitation", value_cls=AcceptSharingInvitation)
class PhoneNumber(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/phonenumber"""
- ELEMENT_NAME = 'PhoneNumber'
+ ELEMENT_NAME = "PhoneNumber"
- number = CharField(field_uri='Number')
- type = CharField(field_uri='Type')
+ number = CharField(field_uri="Number")
+ type = CharField(field_uri="Type")
class IdChangeKeyMixIn(EWSElement, metaclass=EWSMeta):
@@ -1399,14 +1475,14 @@ Module exchangelib.properties
ID_ELEMENT_CLS = None
def __init__(self, **kwargs):
- _id, _changekey = kwargs.pop('id', None), kwargs.pop('changekey', None)
+ _id, _changekey = kwargs.pop("id", None), kwargs.pop("changekey", None)
if _id or _changekey:
- kwargs['_id'] = self.ID_ELEMENT_CLS(_id, _changekey)
+ kwargs["_id"] = self.ID_ELEMENT_CLS(_id, _changekey)
super().__init__(**kwargs)
@classmethod
def get_field_by_fieldname(cls, fieldname):
- if fieldname in ('id', 'changekey'):
+ if fieldname in ("id", "changekey"):
return cls.ID_ELEMENT_CLS.get_field_by_fieldname(fieldname=fieldname)
return super().get_field_by_fieldname(fieldname=fieldname)
@@ -1444,7 +1520,7 @@ Module exchangelib.properties
def to_id(self):
if self._id is None:
- raise ValueError('Must have an ID')
+ raise ValueError("Must have an ID")
return self._id
def __eq__(self, other):
@@ -1462,23 +1538,24 @@ Module exchangelib.properties
class DictionaryEntry(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/dictionaryentry"""
- ELEMENT_NAME = 'DictionaryEntry'
+ ELEMENT_NAME = "DictionaryEntry"
- key = TypeValueField(field_uri='DictionaryKey')
- value = TypeValueField(field_uri='DictionaryValue')
+ key = TypeValueField(field_uri="DictionaryKey")
+ value = TypeValueField(field_uri="DictionaryValue")
class UserConfigurationName(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/userconfigurationname"""
- ELEMENT_NAME = 'UserConfigurationName'
+ ELEMENT_NAME = "UserConfigurationName"
NAMESPACE = TNS
- name = CharField(field_uri='Name', is_attribute=True)
+ name = CharField(field_uri="Name", is_attribute=True)
folder = EWSElementField(value_cls=FolderId)
def clean(self, version=None):
from .folders import BaseFolder
+
if isinstance(self.folder, BaseFolder):
self.folder = self.folder.to_id()
super().clean(version=version)
@@ -1506,29 +1583,29 @@ Module exchangelib.properties
class UserConfiguration(IdChangeKeyMixIn):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/userconfiguration"""
- ELEMENT_NAME = 'UserConfiguration'
+ ELEMENT_NAME = "UserConfiguration"
NAMESPACE = MNS
ID_ELEMENT_CLS = ItemId
- _id = IdElementField(field_uri='ItemId', value_cls=ID_ELEMENT_CLS)
+ _id = IdElementField(field_uri="ItemId", value_cls=ID_ELEMENT_CLS)
user_configuration_name = EWSElementField(value_cls=UserConfigurationName)
- dictionary = DictionaryField(field_uri='Dictionary')
- xml_data = Base64Field(field_uri='XmlData')
- binary_data = Base64Field(field_uri='BinaryData')
+ dictionary = DictionaryField(field_uri="Dictionary")
+ xml_data = Base64Field(field_uri="XmlData")
+ binary_data = Base64Field(field_uri="BinaryData")
class Attribution(IdChangeKeyMixIn):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/phonenumber"""
- ELEMENT_NAME = 'Attribution'
+ ELEMENT_NAME = "Attribution"
ID_ELEMENT_CLS = SourceId
- ID = CharField(field_uri='Id')
- _id = IdElementField(field_uri='SourceId', value_cls=ID_ELEMENT_CLS)
- display_name = CharField(field_uri='DisplayName')
- is_writable = BooleanField(field_uri='IsWritable')
- is_quick_contact = BooleanField(field_uri='IsQuickContact')
- is_hidden = BooleanField(field_uri='IsHidden')
+ ID = CharField(field_uri="Id")
+ _id = IdElementField(field_uri="SourceId", value_cls=ID_ELEMENT_CLS)
+ display_name = CharField(field_uri="DisplayName")
+ is_writable = BooleanField(field_uri="IsWritable")
+ is_quick_contact = BooleanField(field_uri="IsQuickContact")
+ is_hidden = BooleanField(field_uri="IsHidden")
folder_id = EWSElementField(value_cls=FolderId)
@@ -1537,10 +1614,10 @@ Module exchangelib.properties
https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/value-bodycontenttype
"""
- ELEMENT_NAME = 'Value'
+ ELEMENT_NAME = "Value"
- value = CharField(field_uri='Value')
- body_type = CharField(field_uri='BodyType')
+ value = CharField(field_uri="Value")
+ body_type = CharField(field_uri="BodyType")
class BodyContentAttributedValue(EWSElement):
@@ -1548,10 +1625,10 @@ Module exchangelib.properties
https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/bodycontentattributedvalue
"""
- ELEMENT_NAME = 'BodyContentAttributedValue'
+ ELEMENT_NAME = "BodyContentAttributedValue"
value = EWSElementField(value_cls=BodyContentValue)
- attributions = EWSElementListField(field_uri='Attributions', value_cls=Attribution)
+ attributions = EWSElementListField(field_uri="Attributions", value_cls=Attribution)
class StringAttributedValue(EWSElement):
@@ -1559,10 +1636,10 @@ Module exchangelib.properties
https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/stringattributedvalue
"""
- ELEMENT_NAME = 'StringAttributedValue'
+ ELEMENT_NAME = "StringAttributedValue"
- value = CharField(field_uri='Value')
- attributions = CharListField(field_uri='Attributions', list_elem_name='Attribution')
+ value = CharField(field_uri="Value")
+ attributions = CharListField(field_uri="Attributions", list_elem_name="Attribution")
class PersonaPhoneNumberTypeValue(EWSElement):
@@ -1570,10 +1647,10 @@ Module exchangelib.properties
https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/value-personaphonenumbertype
"""
- ELEMENT_NAME = 'Value'
+ ELEMENT_NAME = "Value"
- number = CharField(field_uri='Number')
- type = CharField(field_uri='Type')
+ number = CharField(field_uri="Number")
+ type = CharField(field_uri="Type")
class PhoneNumberAttributedValue(EWSElement):
@@ -1581,10 +1658,10 @@ Module exchangelib.properties
https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/phonenumberattributedvalue
"""
- ELEMENT_NAME = 'PhoneNumberAttributedValue'
+ ELEMENT_NAME = "PhoneNumberAttributedValue"
value = EWSElementField(value_cls=PersonaPhoneNumberTypeValue)
- attributions = CharListField(field_uri='Attributions', list_elem_name='Attribution')
+ attributions = CharListField(field_uri="Attributions", list_elem_name="Attribution")
class EmailAddressTypeValue(Mailbox):
@@ -1592,9 +1669,9 @@ Module exchangelib.properties
https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/value-emailaddresstype
"""
- ELEMENT_NAME = 'Value'
+ ELEMENT_NAME = "Value"
- original_display_name = TextField(field_uri='OriginalDisplayName')
+ original_display_name = TextField(field_uri="OriginalDisplayName")
class EmailAddressAttributedValue(EWSElement):
@@ -1602,10 +1679,10 @@ Module exchangelib.properties
https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/emailaddressattributedvalue
"""
- ELEMENT_NAME = 'EmailAddressAttributedValue'
+ ELEMENT_NAME = "EmailAddressAttributedValue"
value = EWSElementField(value_cls=EmailAddressTypeValue)
- attributions = EWSElementListField(field_uri='Attributions', value_cls=Attribution)
+ attributions = EWSElementListField(field_uri="Attributions", value_cls=Attribution)
class PersonaPostalAddressTypeValue(Mailbox):
@@ -1613,23 +1690,23 @@ Module exchangelib.properties
https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/value-personapostaladdresstype
"""
- ELEMENT_NAME = 'Value'
-
- street = TextField(field_uri='Street')
- city = TextField(field_uri='City')
- state = TextField(field_uri='State')
- country = TextField(field_uri='Country')
- postal_code = TextField(field_uri='PostalCode')
- post_office_box = TextField(field_uri='PostOfficeBox')
- type = TextField(field_uri='Type')
- latitude = TextField(field_uri='Latitude')
- longitude = TextField(field_uri='Longitude')
- accuracy = TextField(field_uri='Accuracy')
- altitude = TextField(field_uri='Altitude')
- altitude_accuracy = TextField(field_uri='AltitudeAccuracy')
- formatted_address = TextField(field_uri='FormattedAddress')
- location_uri = TextField(field_uri='LocationUri')
- location_source = TextField(field_uri='LocationSource')
+ ELEMENT_NAME = "Value"
+
+ street = TextField(field_uri="Street")
+ city = TextField(field_uri="City")
+ state = TextField(field_uri="State")
+ country = TextField(field_uri="Country")
+ postal_code = TextField(field_uri="PostalCode")
+ post_office_box = TextField(field_uri="PostOfficeBox")
+ type = TextField(field_uri="Type")
+ latitude = TextField(field_uri="Latitude")
+ longitude = TextField(field_uri="Longitude")
+ accuracy = TextField(field_uri="Accuracy")
+ altitude = TextField(field_uri="Altitude")
+ altitude_accuracy = TextField(field_uri="AltitudeAccuracy")
+ formatted_address = TextField(field_uri="FormattedAddress")
+ location_uri = TextField(field_uri="LocationUri")
+ location_source = TextField(field_uri="LocationSource")
class PostalAddressAttributedValue(EWSElement):
@@ -1637,28 +1714,28 @@ Module exchangelib.properties
https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/postaladdressattributedvalue
"""
- ELEMENT_NAME = 'PostalAddressAttributedValue'
+ ELEMENT_NAME = "PostalAddressAttributedValue"
value = EWSElementField(value_cls=PersonaPostalAddressTypeValue)
- attributions = EWSElementListField(field_uri='Attributions', value_cls=Attribution)
+ attributions = EWSElementListField(field_uri="Attributions", value_cls=Attribution)
class Event(EWSElement, metaclass=EWSMeta):
"""Base class for all event types."""
- watermark = CharField(field_uri='Watermark')
+ watermark = CharField(field_uri="Watermark")
class TimestampEvent(Event, metaclass=EWSMeta):
"""Base class for both item and folder events with a timestamp."""
- FOLDER = 'folder'
- ITEM = 'item'
+ FOLDER = "folder"
+ ITEM = "item"
- timestamp = DateTimeField(field_uri='TimeStamp')
- item_id = EWSElementField(field_uri='ItemId', value_cls=ItemId)
- folder_id = EWSElementField(field_uri='FolderId', value_cls=FolderId)
- parent_folder_id = EWSElementField(field_uri='ParentFolderId', value_cls=ParentFolderId)
+ timestamp = DateTimeField(field_uri="TimeStamp")
+ item_id = EWSElementField(field_uri="ItemId", value_cls=ItemId)
+ folder_id = EWSElementField(field_uri="FolderId", value_cls=FolderId)
+ parent_folder_id = EWSElementField(field_uri="ParentFolderId", value_cls=ParentFolderId)
@property
def event_type(self):
@@ -1672,59 +1749,59 @@ Module exchangelib.properties
class OldTimestampEvent(TimestampEvent, metaclass=EWSMeta):
"""Base class for both item and folder copy/move events."""
- old_item_id = EWSElementField(field_uri='OldItemId', value_cls=ItemId)
- old_folder_id = EWSElementField(field_uri='OldFolderId', value_cls=FolderId)
- old_parent_folder_id = EWSElementField(field_uri='OldParentFolderId', value_cls=ParentFolderId)
+ old_item_id = EWSElementField(field_uri="OldItemId", value_cls=ItemId)
+ old_folder_id = EWSElementField(field_uri="OldFolderId", value_cls=FolderId)
+ old_parent_folder_id = EWSElementField(field_uri="OldParentFolderId", value_cls=ParentFolderId)
class CopiedEvent(OldTimestampEvent):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/copiedevent"""
- ELEMENT_NAME = 'CopiedEvent'
+ ELEMENT_NAME = "CopiedEvent"
class CreatedEvent(TimestampEvent):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/createdevent"""
- ELEMENT_NAME = 'CreatedEvent'
+ ELEMENT_NAME = "CreatedEvent"
class DeletedEvent(TimestampEvent):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/deletedevent"""
- ELEMENT_NAME = 'DeletedEvent'
+ ELEMENT_NAME = "DeletedEvent"
class ModifiedEvent(TimestampEvent):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/modifiedevent"""
- ELEMENT_NAME = 'ModifiedEvent'
+ ELEMENT_NAME = "ModifiedEvent"
- unread_count = IntegerField(field_uri='UnreadCount')
+ unread_count = IntegerField(field_uri="UnreadCount")
class MovedEvent(OldTimestampEvent):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/movedevent"""
- ELEMENT_NAME = 'MovedEvent'
+ ELEMENT_NAME = "MovedEvent"
class NewMailEvent(TimestampEvent):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/newmailevent"""
- ELEMENT_NAME = 'NewMailEvent'
+ ELEMENT_NAME = "NewMailEvent"
class StatusEvent(Event):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/statusevent"""
- ELEMENT_NAME = 'StatusEvent'
+ ELEMENT_NAME = "StatusEvent"
class FreeBusyChangedEvent(TimestampEvent):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/freebusychangedevent"""
- ELEMENT_NAME = 'FreeBusyChangedEvent'
+ ELEMENT_NAME = "FreeBusyChangedEvent"
class Notification(EWSElement):
@@ -1732,30 +1809,31 @@ Module exchangelib.properties
https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/notification-ex15websvcsotherref
"""
- ELEMENT_NAME = 'Notification'
+ ELEMENT_NAME = "Notification"
NAMESPACE = MNS
- subscription_id = CharField(field_uri='SubscriptionId')
- previous_watermark = CharField(field_uri='PreviousWatermark')
- more_events = BooleanField(field_uri='MoreEvents')
- events = GenericEventListField('')
+ subscription_id = CharField(field_uri="SubscriptionId")
+ previous_watermark = CharField(field_uri="PreviousWatermark")
+ more_events = BooleanField(field_uri="MoreEvents")
+ events = GenericEventListField("")
class BaseTransition(EWSElement, metaclass=EWSMeta):
"""Base class for all other transition classes"""
- to = CharField(field_uri='To')
- kind = CharField(field_uri='Kind', is_attribute=True) # An attribute on the 'To' element
+ to = CharField(field_uri="To")
+ kind = CharField(field_uri="Kind", is_attribute=True) # An attribute on the 'To' element
@staticmethod
def transition_model_from_tag(tag):
- return {cls.response_tag(): cls for cls in (
- Transition, AbsoluteDateTransition, RecurringDateTransition, RecurringDayTransition
- )}[tag]
+ return {
+ cls.response_tag(): cls
+ for cls in (Transition, AbsoluteDateTransition, RecurringDateTransition, RecurringDayTransition)
+ }[tag]
@classmethod
def from_xml(cls, elem, account):
- kind = elem.find(cls.get_field_by_fieldname('to').response_tag()).get('Kind')
+ kind = elem.find(cls.get_field_by_fieldname("to").response_tag()).get("Kind")
res = super().from_xml(elem=elem, account=account)
res.kind = kind
return res
@@ -1764,27 +1842,27 @@ Module exchangelib.properties
class Transition(BaseTransition):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/transition"""
- ELEMENT_NAME = 'Transition'
+ ELEMENT_NAME = "Transition"
class AbsoluteDateTransition(BaseTransition):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/absolutedatetransition"""
- ELEMENT_NAME = 'AbsoluteDateTransition'
+ ELEMENT_NAME = "AbsoluteDateTransition"
- date = DateTimeBackedDateField(field_uri='DateTime')
+ date = DateTimeBackedDateField(field_uri="DateTime")
class RecurringDayTransition(BaseTransition):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/recurringdaytransition"""
- ELEMENT_NAME = 'RecurringDayTransition'
+ ELEMENT_NAME = "RecurringDayTransition"
- offset = TimeDeltaField(field_uri='TimeOffset')
- month = IntegerField(field_uri='Month')
+ offset = TimeDeltaField(field_uri="TimeOffset")
+ month = IntegerField(field_uri="Month")
# Valid ISO 8601 weekday, as a number in range 1 -> 7 (1 being Monday)
- day_of_week = EnumField(field_uri='DayOfWeek', enum=WEEKDAY_NAMES)
- occurrence = IntegerField(field_uri='Occurrence')
+ day_of_week = EnumField(field_uri="DayOfWeek", enum=WEEKDAY_NAMES)
+ occurrence = IntegerField(field_uri="Occurrence")
@classmethod
def from_xml(cls, elem, account):
@@ -1798,24 +1876,24 @@ Module exchangelib.properties
class RecurringDateTransition(BaseTransition):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/recurringdatetransition"""
- ELEMENT_NAME = 'RecurringDateTransition'
+ ELEMENT_NAME = "RecurringDateTransition"
- offset = TimeDeltaField(field_uri='TimeOffset')
- month = IntegerField(field_uri='Month')
- day = IntegerField(field_uri='Day') # Day of month
+ offset = TimeDeltaField(field_uri="TimeOffset")
+ month = IntegerField(field_uri="Month")
+ day = IntegerField(field_uri="Day") # Day of month
class Period(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/period"""
- ELEMENT_NAME = 'Period'
+ ELEMENT_NAME = "Period"
- id = CharField(field_uri='Id', is_attribute=True)
- name = CharField(field_uri='Name', is_attribute=True)
- bias = TimeDeltaField(field_uri='Bias', is_attribute=True)
+ id = CharField(field_uri="Id", is_attribute=True)
+ name = CharField(field_uri="Name", is_attribute=True)
+ bias = TimeDeltaField(field_uri="Bias", is_attribute=True)
def _split_id(self):
- to_year, to_type = self.id.rsplit('/', 1)[1].split('-')
+ to_year, to_type = self.id.rsplit("/", 1)[1].split("-")
return int(to_year), to_type
@property
@@ -1834,23 +1912,23 @@ Module exchangelib.properties
class TransitionsGroup(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/transitionsgroup"""
- ELEMENT_NAME = 'TransitionsGroup'
+ ELEMENT_NAME = "TransitionsGroup"
- id = CharField(field_uri='Id', is_attribute=True)
+ id = CharField(field_uri="Id", is_attribute=True)
transitions = TransitionListField(value_cls=BaseTransition)
class TimeZoneDefinition(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/timezonedefinition"""
- ELEMENT_NAME = 'TimeZoneDefinition'
+ ELEMENT_NAME = "TimeZoneDefinition"
- id = CharField(field_uri='Id', is_attribute=True)
- name = CharField(field_uri='Name', is_attribute=True)
+ id = CharField(field_uri="Id", is_attribute=True)
+ name = CharField(field_uri="Name", is_attribute=True)
- periods = EWSElementListField(field_uri='Periods', value_cls=Period)
- transitions_groups = EWSElementListField(field_uri='TransitionsGroups', value_cls=TransitionsGroup)
- transitions = TransitionListField(field_uri='Transitions', value_cls=BaseTransition)
+ periods = EWSElementListField(field_uri="Periods", value_cls=Period)
+ transitions_groups = EWSElementListField(field_uri="TransitionsGroups", value_cls=TransitionsGroup)
+ transitions = TransitionListField(field_uri="Transitions", value_cls=BaseTransition)
@classmethod
def from_xml(cls, elem, account):
@@ -1862,11 +1940,11 @@ Module exchangelib.properties
for period in sorted(self.periods, key=lambda p: (p.year, p.type)):
if period.year > for_year:
break
- if period.type != 'Standard':
+ if period.type != "Standard":
continue
valid_period = period
if valid_period is None:
- raise TimezoneDefinitionInvalidForYear(f'Year {for_year} not included in periods {self.periods}')
+ raise TimezoneDefinitionInvalidForYear(f"Year {for_year} not included in periods {self.periods}")
return valid_period
def _get_transitions_group(self, for_year):
@@ -1874,20 +1952,20 @@ Module exchangelib.properties
transitions_group = None
transitions_groups_map = {tg.id: tg for tg in self.transitions_groups}
for transition in sorted(self.transitions, key=lambda t: t.to):
- if transition.kind != 'Group':
+ if transition.kind != "Group":
continue
if isinstance(transition, AbsoluteDateTransition) and transition.date.year > for_year:
break
transitions_group = transitions_groups_map[transition.to]
if transitions_group is None:
- raise ValueError(f'No valid transition group for year {for_year}: {self.transitions}')
+ raise ValueError(f"No valid transition group for year {for_year}: {self.transitions}")
return transitions_group
def get_std_and_dst(self, for_year):
# Return 'standard_time' and 'daylight_time' objects. We do unnecessary work here, but it keeps code simple.
transitions_group = self._get_transitions_group(for_year)
if not 0 <= len(transitions_group.transitions) <= 2:
- raise ValueError(f'Expected 0-2 transitions in transitions group {transitions_group}')
+ raise ValueError(f"Expected 0-2 transitions in transitions group {transitions_group}")
standard_period = self._get_standard_period(for_year)
periods_map = {p.id: p for p in self.periods}
@@ -1910,15 +1988,15 @@ Module exchangelib.properties
weekday=transition.day_of_week,
)
period = periods_map[transition.to]
- if period.name == 'Standard':
- transition_kwargs['bias'] = 0
+ if period.name == "Standard":
+ transition_kwargs["bias"] = 0
standard_time = StandardTime(**transition_kwargs)
continue
- if period.name == 'Daylight':
- transition_kwargs['bias'] = period.bias_in_minutes - standard_period.bias_in_minutes
+ if period.name == "Daylight":
+ transition_kwargs["bias"] = period.bias_in_minutes - standard_period.bias_in_minutes
daylight_time = DaylightTime(**transition_kwargs)
continue
- raise ValueError(f'Unknown transition: {transition}')
+ raise ValueError(f"Unknown transition: {transition}")
return standard_time, daylight_time, standard_period
@@ -1944,9 +2022,9 @@ Classes
class AbsoluteDateTransition(BaseTransition):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/absolutedatetransition"""
- ELEMENT_NAME = 'AbsoluteDateTransition'
+ ELEMENT_NAME = "AbsoluteDateTransition"
- date = DateTimeBackedDateField(field_uri='DateTime')
+ date = DateTimeBackedDateField(field_uri="DateTime")
Ancestors
@@ -1996,9 +2074,9 @@ Inherited members
class AcceptSharingInvitation(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/acceptsharinginvitation"""
- ELEMENT_NAME = 'AcceptSharingInvitation'
+ ELEMENT_NAME = "AcceptSharingInvitation"
- reference_item_id = ReferenceItemIdField(field_uri='item:ReferenceItemId')
+ reference_item_id = ReferenceItemIdField(field_uri="item:ReferenceItemId")
class AlternateId(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/alternateid"""
- ELEMENT_NAME = 'AlternateId'
+ ELEMENT_NAME = "AlternateId"
- id = CharField(field_uri='Id', is_required=True, is_attribute=True)
- format = ChoiceField(field_uri='Format', is_required=True, is_attribute=True,
- choices={Choice(c) for c in ID_FORMATS})
- mailbox = EmailAddressField(field_uri='Mailbox', is_required=True, is_attribute=True)
- is_archive = BooleanField(field_uri='IsArchive', is_required=False, is_attribute=True)
+ id = CharField(field_uri="Id", is_required=True, is_attribute=True)
+ format = ChoiceField(
+ field_uri="Format", is_required=True, is_attribute=True, choices={Choice(c) for c in ID_FORMATS}
+ )
+ mailbox = EmailAddressField(field_uri="Mailbox", is_required=True, is_attribute=True)
+ is_archive = BooleanField(field_uri="IsArchive", is_required=False, is_attribute=True)
@classmethod
def response_tag(cls):
# This element is in TNS in the request and MNS in the response...
- return f'{{{MNS}}}{cls.ELEMENT_NAME}'
+ return f"{{{MNS}}}{cls.ELEMENT_NAME}"
@classmethod
def response_tag(cls):
# This element is in TNS in the request and MNS in the response...
- return f'{{{MNS}}}{cls.ELEMENT_NAME}'
+ return f"{{{MNS}}}{cls.ELEMENT_NAME}"
@@ -2180,11 +2259,12 @@ class AlternatePublicFolderId(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/alternatepublicfolderid"""
- ELEMENT_NAME = 'AlternatePublicFolderId'
+ ELEMENT_NAME = "AlternatePublicFolderId"
- folder_id = CharField(field_uri='FolderId', is_required=True, is_attribute=True)
- format = ChoiceField(field_uri='Format', is_required=True, is_attribute=True,
- choices={Choice(c) for c in ID_FORMATS})
+ folder_id = CharField(field_uri="FolderId", is_required=True, is_attribute=True)
+ format = ChoiceField(
+ field_uri="Format", is_required=True, is_attribute=True, choices={Choice(c) for c in ID_FORMATS}
+ )
class Attendee(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/attendee"""
- ELEMENT_NAME = 'Attendee'
- RESPONSE_TYPES = {'Unknown', 'Organizer', 'Tentative', 'Accept', 'Decline', 'NoResponseReceived'}
+ ELEMENT_NAME = "Attendee"
+ RESPONSE_TYPES = {"Unknown", "Organizer", "Tentative", "Accept", "Decline", "NoResponseReceived"}
mailbox = MailboxField(is_required=True)
- response_type = ChoiceField(field_uri='ResponseType', choices={Choice(c) for c in RESPONSE_TYPES},
- default='Unknown')
- last_response_time = DateTimeField(field_uri='LastResponseTime')
+ response_type = ChoiceField(
+ field_uri="ResponseType", choices={Choice(c) for c in RESPONSE_TYPES}, default="Unknown"
+ )
+ last_response_time = DateTimeField(field_uri="LastResponseTime")
def __hash__(self):
return hash(self.mailbox)
@@ -2415,15 +2497,15 @@ class Attribution(IdChangeKeyMixIn):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/phonenumber"""
- ELEMENT_NAME = 'Attribution'
+ ELEMENT_NAME = "Attribution"
ID_ELEMENT_CLS = SourceId
- ID = CharField(field_uri='Id')
- _id = IdElementField(field_uri='SourceId', value_cls=ID_ELEMENT_CLS)
- display_name = CharField(field_uri='DisplayName')
- is_writable = BooleanField(field_uri='IsWritable')
- is_quick_contact = BooleanField(field_uri='IsQuickContact')
- is_hidden = BooleanField(field_uri='IsHidden')
+ ID = CharField(field_uri="Id")
+ _id = IdElementField(field_uri="SourceId", value_cls=ID_ELEMENT_CLS)
+ display_name = CharField(field_uri="DisplayName")
+ is_writable = BooleanField(field_uri="IsWritable")
+ is_quick_contact = BooleanField(field_uri="IsQuickContact")
+ is_hidden = BooleanField(field_uri="IsHidden")
folder_id = EWSElementField(value_cls=FolderId)
@classmethod
def from_mailbox(cls, mailbox):
if not isinstance(mailbox, Mailbox):
- raise InvalidTypeError('mailbox', mailbox, Mailbox)
+ raise InvalidTypeError("mailbox", mailbox, Mailbox)
return cls(name=mailbox.name, email_address=mailbox.email_address, routing_type=mailbox.routing_type)
@@ -2656,16 +2738,16 @@ class BasePermission(EWSElement, metaclass=EWSMeta):
"""Base class for the Permission and CalendarPermission classes"""
- PERMISSION_ENUM = {Choice('None'), Choice('Owned'), Choice('All')}
+ PERMISSION_ENUM = {Choice("None"), Choice("Owned"), Choice("All")}
- can_create_items = BooleanField(field_uri='CanCreateItems', default=False)
- can_create_subfolders = BooleanField(field_uri='CanCreateSubfolders', default=False)
- is_folder_owner = BooleanField(field_uri='IsFolderOwner', default=False)
- is_folder_visible = BooleanField(field_uri='IsFolderVisible', default=False)
- is_folder_contact = BooleanField(field_uri='IsFolderContact', default=False)
- edit_items = ChoiceField(field_uri='EditItems', choices=PERMISSION_ENUM, default='None')
- delete_items = ChoiceField(field_uri='DeleteItems', choices=PERMISSION_ENUM, default='None')
- read_items = ChoiceField(field_uri='ReadItems', choices={Choice('None'), Choice('FullDetails')}, default='None')
+ can_create_items = BooleanField(field_uri="CanCreateItems", default=False)
+ can_create_subfolders = BooleanField(field_uri="CanCreateSubfolders", default=False)
+ is_folder_owner = BooleanField(field_uri="IsFolderOwner", default=False)
+ is_folder_visible = BooleanField(field_uri="IsFolderVisible", default=False)
+ is_folder_contact = BooleanField(field_uri="IsFolderContact", default=False)
+ edit_items = ChoiceField(field_uri="EditItems", choices=PERMISSION_ENUM, default="None")
+ delete_items = ChoiceField(field_uri="DeleteItems", choices=PERMISSION_ENUM, default="None")
+ read_items = ChoiceField(field_uri="ReadItems", choices={Choice("None"), Choice("FullDetails")}, default="None")
user_id = EWSElementField(value_cls=UserId, is_required=True)
class BaseTransition(EWSElement, metaclass=EWSMeta):
"""Base class for all other transition classes"""
- to = CharField(field_uri='To')
- kind = CharField(field_uri='Kind', is_attribute=True) # An attribute on the 'To' element
+ to = CharField(field_uri="To")
+ kind = CharField(field_uri="Kind", is_attribute=True) # An attribute on the 'To' element
@staticmethod
def transition_model_from_tag(tag):
- return {cls.response_tag(): cls for cls in (
- Transition, AbsoluteDateTransition, RecurringDateTransition, RecurringDayTransition
- )}[tag]
+ return {
+ cls.response_tag(): cls
+ for cls in (Transition, AbsoluteDateTransition, RecurringDateTransition, RecurringDayTransition)
+ }[tag]
@classmethod
def from_xml(cls, elem, account):
- kind = elem.find(cls.get_field_by_fieldname('to').response_tag()).get('Kind')
+ kind = elem.find(cls.get_field_by_fieldname("to").response_tag()).get("Kind")
res = super().from_xml(elem=elem, account=account)
res.kind = kind
return res
@@ -2799,7 +2882,7 @@ @classmethod
def from_xml(cls, elem, account):
- kind = elem.find(cls.get_field_by_fieldname('to').response_tag()).get('Kind')
+ kind = elem.find(cls.get_field_by_fieldname("to").response_tag()).get("Kind")
res = super().from_xml(elem=elem, account=account)
res.kind = kind
return res
@@ -2816,9 +2899,10 @@ @staticmethod
def transition_model_from_tag(tag):
- return {cls.response_tag(): cls for cls in (
- Transition, AbsoluteDateTransition, RecurringDateTransition, RecurringDayTransition
- )}[tag]
+ return {
+ cls.response_tag(): cls
+ for cls in (Transition, AbsoluteDateTransition, RecurringDateTransition, RecurringDayTransition)
+ }[tag]
@@ -2862,7 +2946,7 @@ class CalendarEvent(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/calendarevent"""
- ELEMENT_NAME = 'CalendarEvent'
+ ELEMENT_NAME = "CalendarEvent"
- start = DateTimeField(field_uri='StartTime')
- end = DateTimeField(field_uri='EndTime')
- busy_type = FreeBusyStatusField(field_uri='BusyType', is_required=True, default='Busy')
+ start = DateTimeField(field_uri="StartTime")
+ end = DateTimeField(field_uri="EndTime")
+ busy_type = FreeBusyStatusField(field_uri="BusyType", is_required=True, default="Busy")
details = EWSElementField(value_cls=CalendarEventDetails)
class CalendarEventDetails(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/calendareventdetails"""
- ELEMENT_NAME = 'CalendarEventDetails'
+ ELEMENT_NAME = "CalendarEventDetails"
- id = CharField(field_uri='ID')
- subject = CharField(field_uri='Subject')
- location = CharField(field_uri='Location')
- is_meeting = BooleanField(field_uri='IsMeeting')
- is_recurring = BooleanField(field_uri='IsRecurring')
- is_exception = BooleanField(field_uri='IsException')
- is_reminder_set = BooleanField(field_uri='IsReminderSet')
- is_private = BooleanField(field_uri='IsPrivate')
+ id = CharField(field_uri="ID")
+ subject = CharField(field_uri="Subject")
+ location = CharField(field_uri="Location")
+ is_meeting = BooleanField(field_uri="IsMeeting")
+ is_recurring = BooleanField(field_uri="IsRecurring")
+ is_exception = BooleanField(field_uri="IsException")
+ is_reminder_set = BooleanField(field_uri="IsReminderSet")
+ is_private = BooleanField(field_uri="IsPrivate")
class CalendarPermission(BasePermission):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/calendarpermission"""
- ELEMENT_NAME = 'CalendarPermission'
+ ELEMENT_NAME = "CalendarPermission"
LEVEL_CHOICES = (
- 'None', 'Owner', 'PublishingEditor', 'Editor', 'PublishingAuthor', 'Author', 'NoneditingAuthor', 'Reviewer',
- 'Contributor', 'FreeBusyTimeOnly', 'FreeBusyTimeAndSubjectAndLocation', 'Custom',
+ "None",
+ "Owner",
+ "PublishingEditor",
+ "Editor",
+ "PublishingAuthor",
+ "Author",
+ "NoneditingAuthor",
+ "Reviewer",
+ "Contributor",
+ "FreeBusyTimeOnly",
+ "FreeBusyTimeAndSubjectAndLocation",
+ "Custom",
)
calendar_permission_level = ChoiceField(
- field_uri='CalendarPermissionLevel', choices={Choice(c) for c in LEVEL_CHOICES}, default=LEVEL_CHOICES[0]
+ field_uri="CalendarPermissionLevel", choices={Choice(c) for c in LEVEL_CHOICES}, default=LEVEL_CHOICES[0]
)
class CalendarView(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/calendarview"""
- ELEMENT_NAME = 'CalendarView'
+ ELEMENT_NAME = "CalendarView"
NAMESPACE = MNS
- start = DateTimeField(field_uri='StartDate', is_required=True, is_attribute=True)
- end = DateTimeField(field_uri='EndDate', is_required=True, is_attribute=True)
- max_items = IntegerField(field_uri='MaxEntriesReturned', min=1, is_attribute=True)
+ start = DateTimeField(field_uri="StartDate", is_required=True, is_attribute=True)
+ end = DateTimeField(field_uri="EndDate", is_required=True, is_attribute=True)
+ max_items = IntegerField(field_uri="MaxEntriesReturned", min=1, is_attribute=True)
def clean(self, version=None):
super().clean(version=version)
@@ -3345,18 +3439,18 @@ Inherited members
class CompleteName(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/completename"""
- ELEMENT_NAME = 'CompleteName'
+ ELEMENT_NAME = "CompleteName"
- title = CharField(field_uri='Title')
- first_name = CharField(field_uri='FirstName')
- middle_name = CharField(field_uri='MiddleName')
- last_name = CharField(field_uri='LastName')
- suffix = CharField(field_uri='Suffix')
- initials = CharField(field_uri='Initials')
- full_name = CharField(field_uri='FullName')
- nickname = CharField(field_uri='Nickname')
- yomi_first_name = CharField(field_uri='YomiFirstName')
- yomi_last_name = CharField(field_uri='YomiLastName')
+ title = CharField(field_uri="Title")
+ first_name = CharField(field_uri="FirstName")
+ middle_name = CharField(field_uri="MiddleName")
+ last_name = CharField(field_uri="LastName")
+ suffix = CharField(field_uri="Suffix")
+ initials = CharField(field_uri="Initials")
+ full_name = CharField(field_uri="FullName")
+ nickname = CharField(field_uri="Nickname")
+ yomi_first_name = CharField(field_uri="YomiFirstName")
+ yomi_last_name = CharField(field_uri="YomiLastName")
class ConversationId(ItemId):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/conversationid"""
- ELEMENT_NAME = 'ConversationId'
+ ELEMENT_NAME = "ConversationId"
class CopiedEvent(OldTimestampEvent):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/copiedevent"""
- ELEMENT_NAME = 'CopiedEvent'
+ ELEMENT_NAME = "CopiedEvent"
class CreatedEvent(TimestampEvent):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/createdevent"""
- ELEMENT_NAME = 'CreatedEvent'
+ ELEMENT_NAME = "CreatedEvent"
class DaylightTime(TimeZoneTransition):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/daylighttime"""
- ELEMENT_NAME = 'DaylightTime'
+ ELEMENT_NAME = "DaylightTime"
class DelegatePermissions(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/delegatepermissions"""
- ELEMENT_NAME = 'DelegatePermissions'
+ ELEMENT_NAME = "DelegatePermissions"
PERMISSION_LEVEL_CHOICES = {
- Choice('None'), Choice('Editor'), Choice('Reviewer'), Choice('Author'), Choice('Custom'),
- }
-
- calendar_folder_permission_level = ChoiceField(field_uri='CalendarFolderPermissionLevel',
- choices=PERMISSION_LEVEL_CHOICES, default='None')
- tasks_folder_permission_level = ChoiceField(field_uri='TasksFolderPermissionLevel',
- choices=PERMISSION_LEVEL_CHOICES, default='None')
- inbox_folder_permission_level = ChoiceField(field_uri='InboxFolderPermissionLevel',
- choices=PERMISSION_LEVEL_CHOICES, default='None')
- contacts_folder_permission_level = ChoiceField(field_uri='ContactsFolderPermissionLevel',
- choices=PERMISSION_LEVEL_CHOICES, default='None')
- notes_folder_permission_level = ChoiceField(field_uri='NotesFolderPermissionLevel',
- choices=PERMISSION_LEVEL_CHOICES, default='None')
- journal_folder_permission_level = ChoiceField(field_uri='JournalFolderPermissionLevel',
- choices=PERMISSION_LEVEL_CHOICES, default='None')
+ Choice("None"),
+ Choice("Editor"),
+ Choice("Reviewer"),
+ Choice("Author"),
+ Choice("Custom"),
+ }
+
+ calendar_folder_permission_level = ChoiceField(
+ field_uri="CalendarFolderPermissionLevel", choices=PERMISSION_LEVEL_CHOICES, default="None"
+ )
+ tasks_folder_permission_level = ChoiceField(
+ field_uri="TasksFolderPermissionLevel", choices=PERMISSION_LEVEL_CHOICES, default="None"
+ )
+ inbox_folder_permission_level = ChoiceField(
+ field_uri="InboxFolderPermissionLevel", choices=PERMISSION_LEVEL_CHOICES, default="None"
+ )
+ contacts_folder_permission_level = ChoiceField(
+ field_uri="ContactsFolderPermissionLevel", choices=PERMISSION_LEVEL_CHOICES, default="None"
+ )
+ notes_folder_permission_level = ChoiceField(
+ field_uri="NotesFolderPermissionLevel", choices=PERMISSION_LEVEL_CHOICES, default="None"
+ )
+ journal_folder_permission_level = ChoiceField(
+ field_uri="JournalFolderPermissionLevel", choices=PERMISSION_LEVEL_CHOICES, default="None"
+ )
class DelegateUser(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/delegateuser"""
- ELEMENT_NAME = 'DelegateUser'
+ ELEMENT_NAME = "DelegateUser"
NAMESPACE = MNS
user_id = EWSElementField(value_cls=UserId)
delegate_permissions = EWSElementField(value_cls=DelegatePermissions)
- receive_copies_of_meeting_messages = BooleanField(field_uri='ReceiveCopiesOfMeetingMessages', default=False)
- view_private_items = BooleanField(field_uri='ViewPrivateItems', default=False)
+ receive_copies_of_meeting_messages = BooleanField(field_uri="ReceiveCopiesOfMeetingMessages", default=False)
+ view_private_items = BooleanField(field_uri="ViewPrivateItems", default=False)
class DeletedEvent(TimestampEvent):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/deletedevent"""
- ELEMENT_NAME = 'DeletedEvent'
+ ELEMENT_NAME = "DeletedEvent"
class DictionaryEntry(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/dictionaryentry"""
- ELEMENT_NAME = 'DictionaryEntry'
+ ELEMENT_NAME = "DictionaryEntry"
- key = TypeValueField(field_uri='DictionaryKey')
- value = TypeValueField(field_uri='DictionaryValue')
+ key = TypeValueField(field_uri="DictionaryKey")
+ value = TypeValueField(field_uri="DictionaryValue")
class DistinguishedFolderId(FolderId):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/distinguishedfolderid"""
- ELEMENT_NAME = 'DistinguishedFolderId'
+ ELEMENT_NAME = "DistinguishedFolderId"
mailbox = MailboxField()
def clean(self, version=None):
from .folders import PublicFoldersRoot
+
super().clean(version=version)
if self.id == PublicFoldersRoot.DISTINGUISHED_FOLDER_ID:
# Avoid "ErrorInvalidOperation: It is not valid to specify a mailbox with the public folder root" from EWS
@@ -3945,6 +4050,7 @@ Methods
def clean(self, version=None):
from .folders import PublicFoldersRoot
+
super().clean(version=version)
if self.id == PublicFoldersRoot.DISTINGUISHED_FOLDER_ID:
# Avoid "ErrorInvalidOperation: It is not valid to specify a mailbox with the public folder root" from EWS
@@ -4001,7 +4107,7 @@ Inherited members
# Property setters
return super().__setattr__(key, value)
raise AttributeError(
- f'{key!r} is not a valid attribute. See {self.__class__.__name__}.FIELDS for valid field names'
+ f"{key!r} is not a valid attribute. See {self.__class__.__name__}.FIELDS for valid field names"
)
def clean(self, version=None):
@@ -4063,19 +4169,19 @@ Inherited members
@classmethod
def request_tag(cls):
if not cls.ELEMENT_NAME:
- raise ValueError(f'Class {cls} is missing the ELEMENT_NAME attribute')
+ raise ValueError(f"Class {cls} is missing the ELEMENT_NAME attribute")
return {
- TNS: f't:{cls.ELEMENT_NAME}',
- MNS: f'm:{cls.ELEMENT_NAME}',
+ TNS: f"t:{cls.ELEMENT_NAME}",
+ MNS: f"m:{cls.ELEMENT_NAME}",
}[cls.NAMESPACE]
@classmethod
def response_tag(cls):
if not cls.NAMESPACE:
- raise ValueError(f'Class {cls} is missing the NAMESPACE attribute')
+ raise ValueError(f"Class {cls} is missing the NAMESPACE attribute")
if not cls.ELEMENT_NAME:
- raise ValueError(f'Class {cls} is missing the ELEMENT_NAME attribute')
- return f'{{{cls.NAMESPACE}}}{cls.ELEMENT_NAME}'
+ raise ValueError(f"Class {cls} is missing the ELEMENT_NAME attribute")
+ return f"{{{cls.NAMESPACE}}}{cls.ELEMENT_NAME}"
@classmethod
def attribute_fields(cls):
@@ -4159,14 +4265,12 @@ Inherited members
return field_vals
def __str__(self):
- args_str = ', '.join(
- f'{name}={val!r}' for name, val in self._field_vals() if val is not None
- )
- return f'{self.__class__.__name__}({args_str})'
+ args_str = ", ".join(f"{name}={val!r}" for name, val in self._field_vals() if val is not None)
+ return f"{self.__class__.__name__}({args_str})"
def __repr__(self):
- args_str = ', '.join(f'{name}={val!r}' for name, val in self._field_vals())
- return f'{self.__class__.__name__}({args_str})'
+ args_str = ", ".join(f"{name}={val!r}" for name, val in self._field_vals())
+ return f"{self.__class__.__name__}({args_str})"
@classmethod
def request_tag(cls):
if not cls.ELEMENT_NAME:
- raise ValueError(f'Class {cls} is missing the ELEMENT_NAME attribute')
+ raise ValueError(f"Class {cls} is missing the ELEMENT_NAME attribute")
return {
- TNS: f't:{cls.ELEMENT_NAME}',
- MNS: f'm:{cls.ELEMENT_NAME}',
+ TNS: f"t:{cls.ELEMENT_NAME}",
+ MNS: f"m:{cls.ELEMENT_NAME}",
}[cls.NAMESPACE]
@@ -4385,10 +4489,10 @@ @classmethod
def response_tag(cls):
if not cls.NAMESPACE:
- raise ValueError(f'Class {cls} is missing the NAMESPACE attribute')
+ raise ValueError(f"Class {cls} is missing the NAMESPACE attribute")
if not cls.ELEMENT_NAME:
- raise ValueError(f'Class {cls} is missing the ELEMENT_NAME attribute')
- return f'{{{cls.NAMESPACE}}}{cls.ELEMENT_NAME}'
+ raise ValueError(f"Class {cls} is missing the ELEMENT_NAME attribute")
+ return f"{{{cls.NAMESPACE}}}{cls.ELEMENT_NAME}"
@@ -4532,23 +4636,23 @@ Methods
# Build a list of fields defined on this and all base classes
base_fields = Fields()
for base in bases:
- if hasattr(base, 'FIELDS'):
+ if hasattr(base, "FIELDS"):
base_fields += base.FIELDS
# FIELDS defined on a model overrides the base class fields
- fields = kwargs.get('FIELDS', base_fields) + local_fields
+ fields = kwargs.get("FIELDS", base_fields) + local_fields
# Include all fields as class attributes so we can use them as instance attributes
kwargs.update({_mangle(f.name): f for f in fields})
# Calculate __slots__ so we don't have to hard-code it on the model
- kwargs['__slots__'] = tuple(f.name for f in fields if f.name not in base_fields) + kwargs.get('__slots__', ())
+ kwargs["__slots__"] = tuple(f.name for f in fields if f.name not in base_fields) + kwargs.get("__slots__", ())
# FIELDS is mentioned in docs and expected by internal code. Add it here, but only if the class has its own
# fields. Otherwise, we want the implicit FIELDS from the base class (used for injecting custom fields on the
# Folder class, making the custom field available for subclasses).
if local_fields:
- kwargs['FIELDS'] = fields
+ kwargs["FIELDS"] = fields
cls = super().__new__(mcs, name, bases, kwargs)
cls._slots_keys = mcs._get_slots_keys(cls)
return cls
@@ -4558,7 +4662,7 @@ Methods
seen = set()
keys = []
for c in reversed(getmro(cls)):
- if not hasattr(c, '__slots__'):
+ if not hasattr(c, "__slots__"):
continue
for k in c.__slots__:
if k in seen:
@@ -4572,7 +4676,7 @@ Methods
def __getattribute__(cls, k):
"""Return Field instances via their mangled class attribute"""
try:
- return super().__getattribute__('__dict__')[_mangle(k)]
+ return super().__getattribute__("__dict__")[_mangle(k)]
except KeyError:
return super().__getattribute__(k)
@@ -4594,15 +4698,15 @@ class EffectiveRights(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/effectiverights"""
- ELEMENT_NAME = 'EffectiveRights'
+ ELEMENT_NAME = "EffectiveRights"
- create_associated = BooleanField(field_uri='CreateAssociated', default=False)
- create_contents = BooleanField(field_uri='CreateContents', default=False)
- create_hierarchy = BooleanField(field_uri='CreateHierarchy', default=False)
- delete = BooleanField(field_uri='Delete', default=False)
- modify = BooleanField(field_uri='Modify', default=False)
- read = BooleanField(field_uri='Read', default=False)
- view_private_items = BooleanField(field_uri='ViewPrivateItems', default=False)
+ create_associated = BooleanField(field_uri="CreateAssociated", default=False)
+ create_contents = BooleanField(field_uri="CreateContents", default=False)
+ create_hierarchy = BooleanField(field_uri="CreateHierarchy", default=False)
+ delete = BooleanField(field_uri="Delete", default=False)
+ modify = BooleanField(field_uri="Modify", default=False)
+ read = BooleanField(field_uri="Read", default=False)
+ view_private_items = BooleanField(field_uri="ViewPrivateItems", default=False)
def __contains__(self, item):
return getattr(self, item, False)
@@ -4681,7 +4785,7 @@ class Event(EWSElement, metaclass=EWSMeta):
"""Base class for all event types."""
- watermark = CharField(field_uri='Watermark')
+ watermark = CharField(field_uri="Watermark")
class ExceptionFieldURI(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/exceptionfielduri"""
- ELEMENT_NAME = 'ExceptionFieldURI'
+ ELEMENT_NAME = "ExceptionFieldURI"
- field_uri = CharField(field_uri='FieldURI', is_attribute=True, is_required=True)
+ field_uri = CharField(field_uri="FieldURI", is_attribute=True, is_required=True)
class ExtendedFieldURI(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/extendedfielduri"""
- ELEMENT_NAME = 'ExtendedFieldURI'
+ ELEMENT_NAME = "ExtendedFieldURI"
- distinguished_property_set_id = CharField(field_uri='DistinguishedPropertySetId', is_attribute=True)
- property_set_id = CharField(field_uri='PropertySetId', is_attribute=True)
- property_tag = CharField(field_uri='PropertyTag', is_attribute=True)
- property_name = CharField(field_uri='PropertyName', is_attribute=True)
- property_id = CharField(field_uri='PropertyId', is_attribute=True)
- property_type = CharField(field_uri='PropertyType', is_attribute=True)
+ distinguished_property_set_id = CharField(field_uri="DistinguishedPropertySetId", is_attribute=True)
+ property_set_id = CharField(field_uri="PropertySetId", is_attribute=True)
+ property_tag = CharField(field_uri="PropertyTag", is_attribute=True)
+ property_name = CharField(field_uri="PropertyName", is_attribute=True)
+ property_id = CharField(field_uri="PropertyId", is_attribute=True)
+ property_type = CharField(field_uri="PropertyType", is_attribute=True)
class FailedMailbox(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/failedmailbox"""
- ELEMENT_NAME = 'FailedMailbox'
+ ELEMENT_NAME = "FailedMailbox"
- mailbox = CharField(field_uri='Mailbox')
- error_code = IntegerField(field_uri='ErrorCode')
- error_message = CharField(field_uri='ErrorMessage')
- is_archive = BooleanField(field_uri='IsArchive')
+ mailbox = CharField(field_uri="Mailbox")
+ error_code = IntegerField(field_uri="ErrorCode")
+ error_message = CharField(field_uri="ErrorMessage")
+ is_archive = BooleanField(field_uri="IsArchive")
class FieldURI(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/fielduri"""
- ELEMENT_NAME = 'FieldURI'
+ ELEMENT_NAME = "FieldURI"
- field_uri = CharField(field_uri='FieldURI', is_attribute=True, is_required=True)
+ field_uri = CharField(field_uri="FieldURI", is_attribute=True, is_required=True)
@@ -5285,7 +5389,7 @@ Methods
def insert(self, index, field):
if field.name in self._dict:
- raise ValueError(f'Field {field!r} is a duplicate')
+ raise ValueError(f"Field {field!r} is a duplicate")
super().insert(index, field)
self._dict[field.name] = field
@@ -5320,7 +5424,7 @@ Methods
class FolderId(ItemId):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/folderid"""
- ELEMENT_NAME = 'FolderId'
+ ELEMENT_NAME = "FolderId"
class FreeBusyChangedEvent(TimestampEvent):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/freebusychangedevent"""
- ELEMENT_NAME = 'FreeBusyChangedEvent'
+ ELEMENT_NAME = "FreeBusyChangedEvent"
class FreeBusyView(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/freebusyview"""
- ELEMENT_NAME = 'FreeBusyView'
+ ELEMENT_NAME = "FreeBusyView"
NAMESPACE = MNS
- view_type = ChoiceField(field_uri='FreeBusyViewType', choices={
- Choice('None'), Choice('MergedOnly'), Choice('FreeBusy'), Choice('FreeBusyMerged'), Choice('Detailed'),
- Choice('DetailedMerged'),
- }, is_required=True)
+ view_type = ChoiceField(
+ field_uri="FreeBusyViewType",
+ choices={
+ Choice("None"),
+ Choice("MergedOnly"),
+ Choice("FreeBusy"),
+ Choice("FreeBusyMerged"),
+ Choice("Detailed"),
+ Choice("DetailedMerged"),
+ },
+ is_required=True,
+ )
# A string of digits. Each digit points to a position in .fields.FREE_BUSY_CHOICES
- merged = CharField(field_uri='MergedFreeBusy')
- calendar_events = EWSElementListField(field_uri='CalendarEventArray', value_cls=CalendarEvent)
+ merged = CharField(field_uri="MergedFreeBusy")
+ calendar_events = EWSElementListField(field_uri="CalendarEventArray", value_cls=CalendarEvent)
# WorkingPeriod is located inside the WorkingPeriodArray element which is inside the WorkingHours element
- working_hours = EWSElementListField(field_uri='WorkingPeriodArray', value_cls=WorkingPeriod)
+ working_hours = EWSElementListField(field_uri="WorkingPeriodArray", value_cls=WorkingPeriod)
# TimeZone is also inside the WorkingHours element. It contains information about the timezone which the
# account is located in.
working_hours_timezone = EWSElementField(value_cls=TimeZone)
@@ -5422,9 +5534,9 @@ Inherited members
@classmethod
def from_xml(cls, elem, account):
kwargs = {}
- working_hours_elem = elem.find(f'{{{TNS}}}WorkingHours')
+ working_hours_elem = elem.find(f"{{{TNS}}}WorkingHours")
for f in cls.FIELDS:
- if f.name in ['working_hours', 'working_hours_timezone']:
+ if f.name in ["working_hours", "working_hours_timezone"]:
if working_hours_elem is None:
continue
kwargs[f.name] = f.from_xml(elem=working_hours_elem, account=account)
@@ -5466,9 +5578,9 @@ Static methods
@classmethod
def from_xml(cls, elem, account):
kwargs = {}
- working_hours_elem = elem.find(f'{{{TNS}}}WorkingHours')
+ working_hours_elem = elem.find(f"{{{TNS}}}WorkingHours")
for f in cls.FIELDS:
- if f.name in ['working_hours', 'working_hours_timezone']:
+ if f.name in ["working_hours", "working_hours_timezone"]:
if working_hours_elem is None:
continue
kwargs[f.name] = f.from_xml(elem=working_hours_elem, account=account)
@@ -5527,15 +5639,17 @@ Inherited members
class FreeBusyViewOptions(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/freebusyviewoptions"""
- ELEMENT_NAME = 'FreeBusyViewOptions'
- REQUESTED_VIEWS = {'MergedOnly', 'FreeBusy', 'FreeBusyMerged', 'Detailed', 'DetailedMerged'}
+ ELEMENT_NAME = "FreeBusyViewOptions"
+ REQUESTED_VIEWS = {"MergedOnly", "FreeBusy", "FreeBusyMerged", "Detailed", "DetailedMerged"}
time_window = EWSElementField(value_cls=TimeWindow, is_required=True)
# Interval value is in minutes
- merged_free_busy_interval = IntegerField(field_uri='MergedFreeBusyIntervalInMinutes', min=5, max=1440, default=30,
- is_required=True)
- requested_view = ChoiceField(field_uri='RequestedView', choices={Choice(c) for c in REQUESTED_VIEWS},
- is_required=True) # Choice('None') is also valid, but only for responses
+ merged_free_busy_interval = IntegerField(
+ field_uri="MergedFreeBusyIntervalInMinutes", min=5, max=1440, default=30, is_required=True
+ )
+ requested_view = ChoiceField(
+ field_uri="RequestedView", choices={Choice(c) for c in REQUESTED_VIEWS}, is_required=True
+ ) # Choice('None') is also valid, but only for responses
Ancestors
@@ -5600,7 +5714,7 @@ Inherited members
MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/body
"""
- body_type = 'HTML'
+ body_type = "HTML"
@classmethod
def get_field_by_fieldname(cls, fieldname):
- if fieldname in ('id', 'changekey'):
+ if fieldname in ("id", "changekey"):
return cls.ID_ELEMENT_CLS.get_field_by_fieldname(fieldname=fieldname)
return super().get_field_by_fieldname(fieldname=fieldname)
@@ -5801,7 +5915,7 @@ def to_id(self):
if self._id is None:
- raise ValueError('Must have an ID')
+ raise ValueError("Must have an ID")
return self._id
@@ -5831,10 +5945,10 @@ class IndexedFieldURI(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/indexedfielduri"""
- ELEMENT_NAME = 'IndexedFieldURI'
+ ELEMENT_NAME = "IndexedFieldURI"
- field_uri = CharField(field_uri='FieldURI', is_attribute=True, is_required=True)
- field_index = CharField(field_uri='FieldIndex', is_attribute=True, is_required=True)
+ field_uri = CharField(field_uri="FieldURI", is_attribute=True, is_required=True)
+ field_index = CharField(field_uri="FieldIndex", is_attribute=True, is_required=True)
class MailTips(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/mailtips"""
- ELEMENT_NAME = 'MailTips'
+ ELEMENT_NAME = "MailTips"
NAMESPACE = MNS
recipient_address = RecipientAddressField()
- pending_mail_tips = ChoiceField(field_uri='PendingMailTips', choices={Choice(c) for c in MAIL_TIPS_TYPES})
+ pending_mail_tips = ChoiceField(field_uri="PendingMailTips", choices={Choice(c) for c in MAIL_TIPS_TYPES})
out_of_office = EWSElementField(value_cls=OutOfOffice)
- mailbox_full = BooleanField(field_uri='MailboxFull')
- custom_mail_tip = TextField(field_uri='CustomMailTip')
- total_member_count = IntegerField(field_uri='TotalMemberCount')
- external_member_count = IntegerField(field_uri='ExternalMemberCount')
- max_message_size = IntegerField(field_uri='MaxMessageSize')
- delivery_restricted = BooleanField(field_uri='DeliveryRestricted')
- is_moderated = BooleanField(field_uri='IsModerated')
- invalid_recipient = BooleanField(field_uri='InvalidRecipient')
+ mailbox_full = BooleanField(field_uri="MailboxFull")
+ custom_mail_tip = TextField(field_uri="CustomMailTip")
+ total_member_count = IntegerField(field_uri="TotalMemberCount")
+ external_member_count = IntegerField(field_uri="ExternalMemberCount")
+ max_message_size = IntegerField(field_uri="MaxMessageSize")
+ delivery_restricted = BooleanField(field_uri="DeliveryRestricted")
+ is_moderated = BooleanField(field_uri="IsModerated")
+ invalid_recipient = BooleanField(field_uri="InvalidRecipient")
class Mailbox(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/mailbox"""
- ELEMENT_NAME = 'Mailbox'
- MAILBOX = 'Mailbox'
- ONE_OFF = 'OneOff'
+ ELEMENT_NAME = "Mailbox"
+ MAILBOX = "Mailbox"
+ ONE_OFF = "OneOff"
MAILBOX_TYPE_CHOICES = {
- Choice(MAILBOX), Choice('PublicDL'), Choice('PrivateDL'), Choice('Contact'), Choice('PublicFolder'),
- Choice('Unknown'), Choice(ONE_OFF), Choice('GroupMailbox', supported_from=EXCHANGE_2013)
- }
-
- name = TextField(field_uri='Name')
- email_address = EmailAddressField(field_uri='EmailAddress')
+ Choice(MAILBOX),
+ Choice("PublicDL"),
+ Choice("PrivateDL"),
+ Choice("Contact"),
+ Choice("PublicFolder"),
+ Choice("Unknown"),
+ Choice(ONE_OFF),
+ Choice("GroupMailbox", supported_from=EXCHANGE_2013),
+ }
+
+ name = TextField(field_uri="Name")
+ email_address = EmailAddressField(field_uri="EmailAddress")
# RoutingType values are not restricted:
# https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/routingtype-emailaddresstype
- routing_type = TextField(field_uri='RoutingType', default='SMTP')
- mailbox_type = ChoiceField(field_uri='MailboxType', choices=MAILBOX_TYPE_CHOICES, default=MAILBOX)
+ routing_type = TextField(field_uri="RoutingType", default="SMTP")
+ mailbox_type = ChoiceField(field_uri="MailboxType", choices=MAILBOX_TYPE_CHOICES, default=MAILBOX)
item_id = EWSElementField(value_cls=ItemId, is_read_only=True)
def clean(self, version=None):
@@ -6218,12 +6338,12 @@ Inherited members
class MailboxData(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/mailboxdata"""
- ELEMENT_NAME = 'MailboxData'
- ATTENDEE_TYPES = {'Optional', 'Organizer', 'Required', 'Resource', 'Room'}
+ ELEMENT_NAME = "MailboxData"
+ ATTENDEE_TYPES = {"Optional", "Organizer", "Required", "Resource", "Room"}
email = EmailField()
- attendee_type = ChoiceField(field_uri='AttendeeType', choices={Choice(c) for c in ATTENDEE_TYPES})
- exclude_conflicts = BooleanField(field_uri='ExcludeConflicts')
+ attendee_type = ChoiceField(field_uri="AttendeeType", choices={Choice(c) for c in ATTENDEE_TYPES})
+ exclude_conflicts = BooleanField(field_uri="ExcludeConflicts")
class MessageHeader(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/internetmessageheader"""
- ELEMENT_NAME = 'InternetMessageHeader'
+ ELEMENT_NAME = "InternetMessageHeader"
- name = TextField(field_uri='HeaderName', is_attribute=True)
+ name = TextField(field_uri="HeaderName", is_attribute=True)
value = SubField()
class ModifiedEvent(TimestampEvent):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/modifiedevent"""
- ELEMENT_NAME = 'ModifiedEvent'
+ ELEMENT_NAME = "ModifiedEvent"
- unread_count = IntegerField(field_uri='UnreadCount')
+ unread_count = IntegerField(field_uri="UnreadCount")
class MovedEvent(OldTimestampEvent):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/movedevent"""
- ELEMENT_NAME = 'MovedEvent'
+ ELEMENT_NAME = "MovedEvent"
class MovedItemId(ItemId):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/moveditemid"""
- ELEMENT_NAME = 'MovedItemId'
+ ELEMENT_NAME = "MovedItemId"
NAMESPACE = MNS
@classmethod
@@ -6566,7 +6686,7 @@ Inherited members
class NewMailEvent(TimestampEvent):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/newmailevent"""
- ELEMENT_NAME = 'NewMailEvent'
+ ELEMENT_NAME = "NewMailEvent"
class OccurrenceItemId(BaseItemId):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/occurrenceitemid"""
- ELEMENT_NAME = 'OccurrenceItemId'
- ID_ATTR = 'RecurringMasterId'
- CHANGEKEY_ATTR = 'ChangeKey'
+ ELEMENT_NAME = "OccurrenceItemId"
+ ID_ATTR = "RecurringMasterId"
+ CHANGEKEY_ATTR = "ChangeKey"
id = IdField(field_uri=ID_ATTR, is_required=True)
changekey = IdField(field_uri=CHANGEKEY_ATTR, is_required=False)
- instance_index = IntegerField(field_uri='InstanceIndex', is_attribute=True, is_required=True, min=1)
+ instance_index = IntegerField(field_uri="InstanceIndex", is_attribute=True, is_required=True, min=1)
class OldTimestampEvent(TimestampEvent, metaclass=EWSMeta):
"""Base class for both item and folder copy/move events."""
- old_item_id = EWSElementField(field_uri='OldItemId', value_cls=ItemId)
- old_folder_id = EWSElementField(field_uri='OldFolderId', value_cls=FolderId)
- old_parent_folder_id = EWSElementField(field_uri='OldParentFolderId', value_cls=ParentFolderId)
+ old_item_id = EWSElementField(field_uri="OldItemId", value_cls=ItemId)
+ old_folder_id = EWSElementField(field_uri="OldFolderId", value_cls=FolderId)
+ old_parent_folder_id = EWSElementField(field_uri="OldParentFolderId", value_cls=ParentFolderId)
class OutOfOffice(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/outofoffice"""
- ELEMENT_NAME = 'OutOfOffice'
+ ELEMENT_NAME = "OutOfOffice"
- reply_body = MessageField(field_uri='ReplyBody')
- start = DateTimeField(field_uri='StartTime', is_required=False)
- end = DateTimeField(field_uri='EndTime', is_required=False)
+ reply_body = MessageField(field_uri="ReplyBody")
+ start = DateTimeField(field_uri="StartTime", is_required=False)
+ end = DateTimeField(field_uri="EndTime", is_required=False)
@classmethod
def duration_to_start_end(cls, elem, account):
kwargs = {}
- duration = elem.find(f'{{{TNS}}}Duration')
+ duration = elem.find(f"{{{TNS}}}Duration")
if duration is not None:
- for attr in ('start', 'end'):
+ for attr in ("start", "end"):
f = cls.get_field_by_fieldname(attr)
kwargs[attr] = f.from_xml(elem=duration, account=account)
return kwargs
@@ -6833,7 +6953,7 @@ Inherited members
@classmethod
def from_xml(cls, elem, account):
kwargs = {}
- for attr in ('reply_body',):
+ for attr in ("reply_body",):
f = cls.get_field_by_fieldname(attr)
kwargs[attr] = f.from_xml(elem=elem, account=account)
kwargs.update(cls.duration_to_start_end(elem=elem, account=account))
@@ -6869,9 +6989,9 @@ Static methods
@classmethod
def duration_to_start_end(cls, elem, account):
kwargs = {}
- duration = elem.find(f'{{{TNS}}}Duration')
+ duration = elem.find(f"{{{TNS}}}Duration")
if duration is not None:
- for attr in ('start', 'end'):
+ for attr in ("start", "end"):
f = cls.get_field_by_fieldname(attr)
kwargs[attr] = f.from_xml(elem=duration, account=account)
return kwargs
@@ -6889,7 +7009,7 @@ Static methods
@classmethod
def from_xml(cls, elem, account):
kwargs = {}
- for attr in ('reply_body',):
+ for attr in ("reply_body",):
f = cls.get_field_by_fieldname(attr)
kwargs[attr] = f.from_xml(elem=elem, account=account)
kwargs.update(cls.duration_to_start_end(elem=elem, account=account))
@@ -6938,7 +7058,7 @@ Inherited members
class ParentFolderId(ItemId):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/parentfolderid"""
- ELEMENT_NAME = 'ParentFolderId'
+ ELEMENT_NAME = "ParentFolderId"
Ancestors
@@ -6978,7 +7098,7 @@ Inherited members
class ParentItemId(ItemId):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/parentitemid"""
- ELEMENT_NAME = 'ParentItemId'
+ ELEMENT_NAME = "ParentItemId"
NAMESPACE = MNS
Ancestors
@@ -7023,14 +7143,14 @@ Inherited members
class Period(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/period"""
- ELEMENT_NAME = 'Period'
+ ELEMENT_NAME = "Period"
- id = CharField(field_uri='Id', is_attribute=True)
- name = CharField(field_uri='Name', is_attribute=True)
- bias = TimeDeltaField(field_uri='Bias', is_attribute=True)
+ id = CharField(field_uri="Id", is_attribute=True)
+ name = CharField(field_uri="Name", is_attribute=True)
+ bias = TimeDeltaField(field_uri="Bias", is_attribute=True)
def _split_id(self):
- to_year, to_type = self.id.rsplit('/', 1)[1].split('-')
+ to_year, to_type = self.id.rsplit("/", 1)[1].split("-")
return int(to_year), to_type
@property
@@ -7136,14 +7256,22 @@ Inherited members
class Permission(BasePermission):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/permission"""
- ELEMENT_NAME = 'Permission'
+ ELEMENT_NAME = "Permission"
LEVEL_CHOICES = (
- 'None', 'Owner', 'PublishingEditor', 'Editor', 'PublishingAuthor', 'Author', 'NoneditingAuthor', 'Reviewer',
- 'Contributor', 'Custom',
+ "None",
+ "Owner",
+ "PublishingEditor",
+ "Editor",
+ "PublishingAuthor",
+ "Author",
+ "NoneditingAuthor",
+ "Reviewer",
+ "Contributor",
+ "Custom",
)
permission_level = ChoiceField(
- field_uri='CalendarPermissionLevel', choices={Choice(c) for c in LEVEL_CHOICES}, default=LEVEL_CHOICES[0]
+ field_uri="CalendarPermissionLevel", choices={Choice(c) for c in LEVEL_CHOICES}, default=LEVEL_CHOICES[0]
)
Ancestors
@@ -7206,11 +7334,11 @@ Inherited members
"""
# For simplicity, we implement the two distinct but equally names elements as one class.
- ELEMENT_NAME = 'PermissionSet'
+ ELEMENT_NAME = "PermissionSet"
- permissions = EWSElementListField(field_uri='Permissions', value_cls=Permission)
- calendar_permissions = EWSElementListField(field_uri='CalendarPermissions', value_cls=CalendarPermission)
- unknown_entries = UnknownEntriesField(field_uri='UnknownEntries')
+ permissions = EWSElementListField(field_uri="Permissions", value_cls=Permission)
+ calendar_permissions = EWSElementListField(field_uri="CalendarPermissions", value_cls=CalendarPermission)
+ unknown_entries = UnknownEntriesField(field_uri="UnknownEntries")
class PersonaId(ItemId):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/personaid"""
- ELEMENT_NAME = 'PersonaId'
+ ELEMENT_NAME = "PersonaId"
NAMESPACE = MNS
@classmethod
def response_tag(cls):
# This element is in MNS in the request and TNS in the response...
- return f'{{{TNS}}}{cls.ELEMENT_NAME}'
+ return f"{{{TNS}}}{cls.ELEMENT_NAME}"
@classmethod
def response_tag(cls):
# This element is in MNS in the request and TNS in the response...
- return f'{{{TNS}}}{cls.ELEMENT_NAME}'
+ return f"{{{TNS}}}{cls.ELEMENT_NAME}"
@@ -7338,10 +7466,10 @@ class PhoneNumber(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/phonenumber"""
- ELEMENT_NAME = 'PhoneNumber'
+ ELEMENT_NAME = "PhoneNumber"
- number = CharField(field_uri='Number')
- type = CharField(field_uri='Type')
+ number = CharField(field_uri="Number")
+ type = CharField(field_uri="Type")
class RecurringDateTransition(BaseTransition):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/recurringdatetransition"""
- ELEMENT_NAME = 'RecurringDateTransition'
+ ELEMENT_NAME = "RecurringDateTransition"
- offset = TimeDeltaField(field_uri='TimeOffset')
- month = IntegerField(field_uri='Month')
- day = IntegerField(field_uri='Day') # Day of month
+ offset = TimeDeltaField(field_uri="TimeOffset")
+ month = IntegerField(field_uri="Month")
+ day = IntegerField(field_uri="Day") # Day of month
class RecurringDayTransition(BaseTransition):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/recurringdaytransition"""
- ELEMENT_NAME = 'RecurringDayTransition'
+ ELEMENT_NAME = "RecurringDayTransition"
- offset = TimeDeltaField(field_uri='TimeOffset')
- month = IntegerField(field_uri='Month')
+ offset = TimeDeltaField(field_uri="TimeOffset")
+ month = IntegerField(field_uri="Month")
# Valid ISO 8601 weekday, as a number in range 1 -> 7 (1 being Monday)
- day_of_week = EnumField(field_uri='DayOfWeek', enum=WEEKDAY_NAMES)
- occurrence = IntegerField(field_uri='Occurrence')
+ day_of_week = EnumField(field_uri="DayOfWeek", enum=WEEKDAY_NAMES)
+ occurrence = IntegerField(field_uri="Occurrence")
@classmethod
def from_xml(cls, elem, account):
@@ -7895,9 +8023,9 @@ Inherited members
class RecurringMasterItemId(BaseItemId):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/recurringmasteritemid"""
- ELEMENT_NAME = 'RecurringMasterItemId'
- ID_ATTR = 'OccurrenceId'
- CHANGEKEY_ATTR = 'ChangeKey'
+ ELEMENT_NAME = "RecurringMasterItemId"
+ ID_ATTR = "OccurrenceId"
+ CHANGEKEY_ATTR = "ChangeKey"
id = IdField(field_uri=ID_ATTR, is_required=True)
changekey = IdField(field_uri=CHANGEKEY_ATTR, is_required=False)
@@ -7962,7 +8090,7 @@ Inherited members
class ReferenceItemId(ItemId):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/referenceitemid"""
- ELEMENT_NAME = 'ReferenceItemId'
+ ELEMENT_NAME = "ReferenceItemId"
class ReminderMessageData(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/remindermessagedata"""
- ELEMENT_NAME = 'ReminderMessageData'
+ ELEMENT_NAME = "ReminderMessageData"
- reminder_text = CharField(field_uri='ReminderText')
- location = CharField(field_uri='Location')
- start_time = TimeField(field_uri='StartTime')
- end_time = TimeField(field_uri='EndTime')
- associated_calendar_item_id = AssociatedCalendarItemIdField(field_uri='AssociatedCalendarItemId',
- supported_from=Build(15, 0, 913, 9))
+ reminder_text = CharField(field_uri="ReminderText")
+ location = CharField(field_uri="Location")
+ start_time = TimeField(field_uri="StartTime")
+ end_time = TimeField(field_uri="EndTime")
+ associated_calendar_item_id = AssociatedCalendarItemIdField(
+ field_uri="AssociatedCalendarItemId", supported_from=Build(15, 0, 913, 9)
+ )
class RemoveItem(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/removeitem"""
- ELEMENT_NAME = 'RemoveItem'
+ ELEMENT_NAME = "RemoveItem"
- reference_item_id = ReferenceItemIdField(field_uri='item:ReferenceItemId')
+ reference_item_id = ReferenceItemIdField(field_uri="item:ReferenceItemId")
class ResponseObjects(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/responseobjects"""
- ELEMENT_NAME = 'ResponseObjects'
+ ELEMENT_NAME = "ResponseObjects"
NAMESPACE = EWSElement.NAMESPACE
- accept_item = EWSElementField(field_uri='AcceptItem', value_cls='AcceptItem', namespace=NAMESPACE)
- tentatively_accept_item = EWSElementField(field_uri='TentativelyAcceptItem', value_cls='TentativelyAcceptItem',
- namespace=NAMESPACE)
- decline_item = EWSElementField(field_uri='DeclineItem', value_cls='DeclineItem', namespace=NAMESPACE)
- reply_to_item = EWSElementField(field_uri='ReplyToItem', value_cls='ReplyToItem', namespace=NAMESPACE)
- forward_item = EWSElementField(field_uri='ForwardItem', value_cls='ForwardItem', namespace=NAMESPACE)
- reply_all_to_item = EWSElementField(field_uri='ReplyAllToItem', value_cls='ReplyAllToItem', namespace=NAMESPACE)
- cancel_calendar_item = EWSElementField(field_uri='CancelCalendarItem', value_cls='CancelCalendarItem',
- namespace=NAMESPACE)
- remove_item = EWSElementField(field_uri='RemoveItem', value_cls=RemoveItem)
- post_reply_item = EWSElementField(field_uri='PostReplyItem', value_cls='PostReplyItem',
- namespace=EWSElement.NAMESPACE)
- success_read_receipt = EWSElementField(field_uri='SuppressReadReceipt', value_cls=SuppressReadReceipt)
- accept_sharing_invitation = EWSElementField(field_uri='AcceptSharingInvitation',
- value_cls=AcceptSharingInvitation)
+ accept_item = EWSElementField(field_uri="AcceptItem", value_cls="AcceptItem", namespace=NAMESPACE)
+ tentatively_accept_item = EWSElementField(
+ field_uri="TentativelyAcceptItem", value_cls="TentativelyAcceptItem", namespace=NAMESPACE
+ )
+ decline_item = EWSElementField(field_uri="DeclineItem", value_cls="DeclineItem", namespace=NAMESPACE)
+ reply_to_item = EWSElementField(field_uri="ReplyToItem", value_cls="ReplyToItem", namespace=NAMESPACE)
+ forward_item = EWSElementField(field_uri="ForwardItem", value_cls="ForwardItem", namespace=NAMESPACE)
+ reply_all_to_item = EWSElementField(field_uri="ReplyAllToItem", value_cls="ReplyAllToItem", namespace=NAMESPACE)
+ cancel_calendar_item = EWSElementField(
+ field_uri="CancelCalendarItem", value_cls="CancelCalendarItem", namespace=NAMESPACE
+ )
+ remove_item = EWSElementField(field_uri="RemoveItem", value_cls=RemoveItem)
+ post_reply_item = EWSElementField(
+ field_uri="PostReplyItem", value_cls="PostReplyItem", namespace=EWSElement.NAMESPACE
+ )
+ success_read_receipt = EWSElementField(field_uri="SuppressReadReceipt", value_cls=SuppressReadReceipt)
+ accept_sharing_invitation = EWSElementField(field_uri="AcceptSharingInvitation", value_cls=AcceptSharingInvitation)
class Room(Mailbox):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/room"""
- ELEMENT_NAME = 'Room'
+ ELEMENT_NAME = "Room"
@classmethod
def from_xml(cls, elem, account):
- id_elem = elem.find(f'{{{TNS}}}Id')
+ id_elem = elem.find(f"{{{TNS}}}Id")
item_id_elem = id_elem.find(ItemId.response_tag())
kwargs = dict(
- name=get_xml_attr(id_elem, f'{{{TNS}}}Name'),
- email_address=get_xml_attr(id_elem, f'{{{TNS}}}EmailAddress'),
- mailbox_type=get_xml_attr(id_elem, f'{{{TNS}}}MailboxType'),
+ name=get_xml_attr(id_elem, f"{{{TNS}}}Name"),
+ email_address=get_xml_attr(id_elem, f"{{{TNS}}}EmailAddress"),
+ mailbox_type=get_xml_attr(id_elem, f"{{{TNS}}}MailboxType"),
item_id=ItemId.from_xml(elem=item_id_elem, account=account) if item_id_elem else None,
)
cls._clear(elem)
@@ -8275,12 +8406,12 @@ Static methods
@classmethod
def from_xml(cls, elem, account):
- id_elem = elem.find(f'{{{TNS}}}Id')
+ id_elem = elem.find(f"{{{TNS}}}Id")
item_id_elem = id_elem.find(ItemId.response_tag())
kwargs = dict(
- name=get_xml_attr(id_elem, f'{{{TNS}}}Name'),
- email_address=get_xml_attr(id_elem, f'{{{TNS}}}EmailAddress'),
- mailbox_type=get_xml_attr(id_elem, f'{{{TNS}}}MailboxType'),
+ name=get_xml_attr(id_elem, f"{{{TNS}}}Name"),
+ email_address=get_xml_attr(id_elem, f"{{{TNS}}}EmailAddress"),
+ mailbox_type=get_xml_attr(id_elem, f"{{{TNS}}}MailboxType"),
item_id=ItemId.from_xml(elem=item_id_elem, account=account) if item_id_elem else None,
)
cls._clear(elem)
@@ -8313,14 +8444,14 @@ Inherited members
class RoomList(Mailbox):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/roomlist"""
- ELEMENT_NAME = 'RoomList'
+ ELEMENT_NAME = "RoomList"
NAMESPACE = MNS
@classmethod
def response_tag(cls):
# In a GetRoomLists response, room lists are delivered as Address elements. See
# https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/address-emailaddresstype
- return f'{{{TNS}}}Address'
+ return f"{{{TNS}}}Address"
Ancestors
@@ -8353,7 +8484,7 @@ Static methods
def response_tag(cls):
# In a GetRoomLists response, room lists are delivered as Address elements. See
# https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/address-emailaddresstype
- return f'{{{TNS}}}Address'
+ return f"{{{TNS}}}Address"
@@ -8382,10 +8513,10 @@ class RootItemId(BaseItemId):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/rootitemid"""
- ELEMENT_NAME = 'RootItemId'
+ ELEMENT_NAME = "RootItemId"
NAMESPACE = MNS
- ID_ATTR = 'RootItemId'
- CHANGEKEY_ATTR = 'RootItemChangeKey'
+ ID_ATTR = "RootItemId"
+ CHANGEKEY_ATTR = "RootItemChangeKey"
id = IdField(field_uri=ID_ATTR, is_required=True)
changekey = IdField(field_uri=CHANGEKEY_ATTR, is_required=True)
@@ -8454,15 +8585,15 @@ class SearchableMailbox(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/searchablemailbox"""
- ELEMENT_NAME = 'SearchableMailbox'
+ ELEMENT_NAME = "SearchableMailbox"
- guid = CharField(field_uri='Guid')
- primary_smtp_address = EmailAddressField(field_uri='PrimarySmtpAddress')
- is_external = BooleanField(field_uri='IsExternalMailbox')
- external_email = EmailAddressField(field_uri='ExternalEmailAddress')
- display_name = CharField(field_uri='DisplayName')
- is_membership_group = BooleanField(field_uri='IsMembershipGroup')
- reference_id = CharField(field_uri='ReferenceId')
+ guid = CharField(field_uri="Guid")
+ primary_smtp_address = EmailAddressField(field_uri="PrimarySmtpAddress")
+ is_external = BooleanField(field_uri="IsExternalMailbox")
+ external_email = EmailAddressField(field_uri="ExternalEmailAddress")
+ display_name = CharField(field_uri="DisplayName")
+ is_membership_group = BooleanField(field_uri="IsMembershipGroup")
+ reference_id = CharField(field_uri="ReferenceId")
class SourceId(ItemId):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/sourceid"""
- ELEMENT_NAME = 'SourceId'
+ ELEMENT_NAME = "SourceId"
class StandardTime(TimeZoneTransition):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/standardtime"""
- ELEMENT_NAME = 'StandardTime'
+ ELEMENT_NAME = "StandardTime"
class StatusEvent(Event):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/statusevent"""
- ELEMENT_NAME = 'StatusEvent'
+ ELEMENT_NAME = "StatusEvent"
class SuppressReadReceipt(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/suppressreadreceipt"""
- ELEMENT_NAME = 'SuppressReadReceipt'
+ ELEMENT_NAME = "SuppressReadReceipt"
- reference_item_id = ReferenceItemIdField(field_uri='item:ReferenceItemId')
+ reference_item_id = ReferenceItemIdField(field_uri="item:ReferenceItemId")
class TimeWindow(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/timewindow"""
- ELEMENT_NAME = 'TimeWindow'
+ ELEMENT_NAME = "TimeWindow"
- start = DateTimeField(field_uri='StartTime', is_required=True)
- end = DateTimeField(field_uri='EndTime', is_required=True)
+ start = DateTimeField(field_uri="StartTime", is_required=True)
+ end = DateTimeField(field_uri="EndTime", is_required=True)
def clean(self, version=None):
if self.start >= self.end:
@@ -8890,9 +9021,9 @@ Inherited members
class TimeZone(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/timezone-availability"""
- ELEMENT_NAME = 'TimeZone'
+ ELEMENT_NAME = "TimeZone"
- bias = IntegerField(field_uri='Bias', is_required=True) # Standard (non-DST) offset from UTC, in minutes
+ bias = IntegerField(field_uri="Bias", is_required=True) # Standard (non-DST) offset from UTC, in minutes
standard_time = EWSElementField(value_cls=StandardTime)
daylight_time = EWSElementField(value_cls=DaylightTime)
@@ -8913,7 +9044,7 @@ Inherited members
for_year=for_year,
)
if candidate == self:
- log.debug('Found exact candidate: %s (%s)', tz_definition.id, tz_definition.name)
+ log.debug("Found exact candidate: %s (%s)", tz_definition.id, tz_definition.name)
# We prefer this timezone over anything else. Return immediately.
return tz_definition.id
# Reduce list based on base bias and standard / daylight bias values
@@ -8935,14 +9066,14 @@ Inherited members
continue
if candidate.daylight_time.bias != self.daylight_time.bias:
continue
- log.debug('Found candidate with matching biases: %s (%s)', tz_definition.id, tz_definition.name)
+ log.debug("Found candidate with matching biases: %s (%s)", tz_definition.id, tz_definition.name)
candidates.add(tz_definition.id)
if not candidates:
- raise ValueError('No server timezones match this timezone definition')
+ raise ValueError("No server timezones match this timezone definition")
if len(candidates) == 1:
- log.info('Could not find an exact timezone match for %s. Selecting the best candidate', self)
+ log.info("Could not find an exact timezone match for %s. Selecting the best candidate", self)
else:
- log.warning('Could not find an exact timezone match for %s. Selecting a random candidate', self)
+ log.warning("Could not find an exact timezone match for %s. Selecting a random candidate", self)
return candidates.pop()
@classmethod
@@ -9033,7 +9164,7 @@ Methods
for_year=for_year,
)
if candidate == self:
- log.debug('Found exact candidate: %s (%s)', tz_definition.id, tz_definition.name)
+ log.debug("Found exact candidate: %s (%s)", tz_definition.id, tz_definition.name)
# We prefer this timezone over anything else. Return immediately.
return tz_definition.id
# Reduce list based on base bias and standard / daylight bias values
@@ -9055,14 +9186,14 @@ Methods
continue
if candidate.daylight_time.bias != self.daylight_time.bias:
continue
- log.debug('Found candidate with matching biases: %s (%s)', tz_definition.id, tz_definition.name)
+ log.debug("Found candidate with matching biases: %s (%s)", tz_definition.id, tz_definition.name)
candidates.add(tz_definition.id)
if not candidates:
- raise ValueError('No server timezones match this timezone definition')
+ raise ValueError("No server timezones match this timezone definition")
if len(candidates) == 1:
- log.info('Could not find an exact timezone match for %s. Selecting the best candidate', self)
+ log.info("Could not find an exact timezone match for %s. Selecting the best candidate", self)
else:
- log.warning('Could not find an exact timezone match for %s. Selecting a random candidate', self)
+ log.warning("Could not find an exact timezone match for %s. Selecting a random candidate", self)
return candidates.pop()
@@ -9092,14 +9223,14 @@ Inherited members
class TimeZoneDefinition(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/timezonedefinition"""
- ELEMENT_NAME = 'TimeZoneDefinition'
+ ELEMENT_NAME = "TimeZoneDefinition"
- id = CharField(field_uri='Id', is_attribute=True)
- name = CharField(field_uri='Name', is_attribute=True)
+ id = CharField(field_uri="Id", is_attribute=True)
+ name = CharField(field_uri="Name", is_attribute=True)
- periods = EWSElementListField(field_uri='Periods', value_cls=Period)
- transitions_groups = EWSElementListField(field_uri='TransitionsGroups', value_cls=TransitionsGroup)
- transitions = TransitionListField(field_uri='Transitions', value_cls=BaseTransition)
+ periods = EWSElementListField(field_uri="Periods", value_cls=Period)
+ transitions_groups = EWSElementListField(field_uri="TransitionsGroups", value_cls=TransitionsGroup)
+ transitions = TransitionListField(field_uri="Transitions", value_cls=BaseTransition)
@classmethod
def from_xml(cls, elem, account):
@@ -9111,11 +9242,11 @@ Inherited members
for period in sorted(self.periods, key=lambda p: (p.year, p.type)):
if period.year > for_year:
break
- if period.type != 'Standard':
+ if period.type != "Standard":
continue
valid_period = period
if valid_period is None:
- raise TimezoneDefinitionInvalidForYear(f'Year {for_year} not included in periods {self.periods}')
+ raise TimezoneDefinitionInvalidForYear(f"Year {for_year} not included in periods {self.periods}")
return valid_period
def _get_transitions_group(self, for_year):
@@ -9123,20 +9254,20 @@ Inherited members
transitions_group = None
transitions_groups_map = {tg.id: tg for tg in self.transitions_groups}
for transition in sorted(self.transitions, key=lambda t: t.to):
- if transition.kind != 'Group':
+ if transition.kind != "Group":
continue
if isinstance(transition, AbsoluteDateTransition) and transition.date.year > for_year:
break
transitions_group = transitions_groups_map[transition.to]
if transitions_group is None:
- raise ValueError(f'No valid transition group for year {for_year}: {self.transitions}')
+ raise ValueError(f"No valid transition group for year {for_year}: {self.transitions}")
return transitions_group
def get_std_and_dst(self, for_year):
# Return 'standard_time' and 'daylight_time' objects. We do unnecessary work here, but it keeps code simple.
transitions_group = self._get_transitions_group(for_year)
if not 0 <= len(transitions_group.transitions) <= 2:
- raise ValueError(f'Expected 0-2 transitions in transitions group {transitions_group}')
+ raise ValueError(f"Expected 0-2 transitions in transitions group {transitions_group}")
standard_period = self._get_standard_period(for_year)
periods_map = {p.id: p for p in self.periods}
@@ -9159,15 +9290,15 @@ Inherited members
weekday=transition.day_of_week,
)
period = periods_map[transition.to]
- if period.name == 'Standard':
- transition_kwargs['bias'] = 0
+ if period.name == "Standard":
+ transition_kwargs["bias"] = 0
standard_time = StandardTime(**transition_kwargs)
continue
- if period.name == 'Daylight':
- transition_kwargs['bias'] = period.bias_in_minutes - standard_period.bias_in_minutes
+ if period.name == "Daylight":
+ transition_kwargs["bias"] = period.bias_in_minutes - standard_period.bias_in_minutes
daylight_time = DaylightTime(**transition_kwargs)
continue
- raise ValueError(f'Unknown transition: {transition}')
+ raise ValueError(f"Unknown transition: {transition}")
return standard_time, daylight_time, standard_period
Ancestors
@@ -9240,7 +9371,7 @@ Methods
# Return 'standard_time' and 'daylight_time' objects. We do unnecessary work here, but it keeps code simple.
transitions_group = self._get_transitions_group(for_year)
if not 0 <= len(transitions_group.transitions) <= 2:
- raise ValueError(f'Expected 0-2 transitions in transitions group {transitions_group}')
+ raise ValueError(f"Expected 0-2 transitions in transitions group {transitions_group}")
standard_period = self._get_standard_period(for_year)
periods_map = {p.id: p for p in self.periods}
@@ -9263,15 +9394,15 @@ Methods
weekday=transition.day_of_week,
)
period = periods_map[transition.to]
- if period.name == 'Standard':
- transition_kwargs['bias'] = 0
+ if period.name == "Standard":
+ transition_kwargs["bias"] = 0
standard_time = StandardTime(**transition_kwargs)
continue
- if period.name == 'Daylight':
- transition_kwargs['bias'] = period.bias_in_minutes - standard_period.bias_in_minutes
+ if period.name == "Daylight":
+ transition_kwargs["bias"] = period.bias_in_minutes - standard_period.bias_in_minutes
daylight_time = DaylightTime(**transition_kwargs)
continue
- raise ValueError(f'Unknown transition: {transition}')
+ raise ValueError(f"Unknown transition: {transition}")
return standard_time, daylight_time, standard_period
@@ -9301,11 +9432,11 @@ class TimeZoneTransition(EWSElement, metaclass=EWSMeta):
"""Base class for StandardTime and DaylightTime classes."""
- bias = IntegerField(field_uri='Bias', is_required=True) # Offset from the default bias, in minutes
- time = TimeField(field_uri='Time', is_required=True)
- occurrence = IntegerField(field_uri='DayOrder', is_required=True) # n'th occurrence of weekday in iso_month
- iso_month = IntegerField(field_uri='Month', is_required=True)
- weekday = EnumField(field_uri='DayOfWeek', enum=WEEKDAY_NAMES, is_required=True)
+ bias = IntegerField(field_uri="Bias", is_required=True) # Offset from the default bias, in minutes
+ time = TimeField(field_uri="Time", is_required=True)
+ occurrence = IntegerField(field_uri="DayOrder", is_required=True) # n'th occurrence of weekday in iso_month
+ iso_month = IntegerField(field_uri="Month", is_required=True)
+ weekday = EnumField(field_uri="DayOfWeek", enum=WEEKDAY_NAMES, is_required=True)
# 'Year' is not implemented yet
@classmethod
@@ -9428,13 +9559,13 @@ Inherited members
class TimestampEvent(Event, metaclass=EWSMeta):
"""Base class for both item and folder events with a timestamp."""
- FOLDER = 'folder'
- ITEM = 'item'
+ FOLDER = "folder"
+ ITEM = "item"
- timestamp = DateTimeField(field_uri='TimeStamp')
- item_id = EWSElementField(field_uri='ItemId', value_cls=ItemId)
- folder_id = EWSElementField(field_uri='FolderId', value_cls=FolderId)
- parent_folder_id = EWSElementField(field_uri='ParentFolderId', value_cls=ParentFolderId)
+ timestamp = DateTimeField(field_uri="TimeStamp")
+ item_id = EWSElementField(field_uri="ItemId", value_cls=ItemId)
+ folder_id = EWSElementField(field_uri="FolderId", value_cls=FolderId)
+ parent_folder_id = EWSElementField(field_uri="ParentFolderId", value_cls=ParentFolderId)
@property
def event_type(self):
@@ -9533,7 +9664,7 @@ Inherited members
class Transition(BaseTransition):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/transition"""
- ELEMENT_NAME = 'Transition'
+ ELEMENT_NAME = "Transition"
Ancestors
@@ -9572,9 +9703,9 @@ Inherited members
class TransitionsGroup(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/transitionsgroup"""
- ELEMENT_NAME = 'TransitionsGroup'
+ ELEMENT_NAME = "TransitionsGroup"
- id = CharField(field_uri='Id', is_attribute=True)
+ id = CharField(field_uri="Id", is_attribute=True)
transitions = TransitionListField(value_cls=BaseTransition)
Ancestors
@@ -9643,22 +9774,15 @@ Inherited members
account.calendar.filter(global_object_id=UID('261cbc18-1f65-5a0a-bd11-23b1e224cc2f'))
"""
- _HEADER = binascii.hexlify(bytearray((
- 0x04, 0x00, 0x00, 0x00,
- 0x82, 0x00, 0xE0, 0x00,
- 0x74, 0xC5, 0xB7, 0x10,
- 0x1A, 0x82, 0xE0, 0x08)))
+ _HEADER = binascii.hexlify(
+ bytearray((0x04, 0x00, 0x00, 0x00, 0x82, 0x00, 0xE0, 0x00, 0x74, 0xC5, 0xB7, 0x10, 0x1A, 0x82, 0xE0, 0x08))
+ )
- _EXCEPTION_REPLACEMENT_TIME = binascii.hexlify(bytearray((
- 0, 0, 0, 0)))
+ _EXCEPTION_REPLACEMENT_TIME = binascii.hexlify(bytearray((0, 0, 0, 0)))
- _CREATION_TIME = binascii.hexlify(bytearray((
- 0, 0, 0, 0,
- 0, 0, 0, 0)))
+ _CREATION_TIME = binascii.hexlify(bytearray((0, 0, 0, 0, 0, 0, 0, 0)))
- _RESERVED = binascii.hexlify(bytearray((
- 0, 0, 0, 0,
- 0, 0, 0, 0)))
+ _RESERVED = binascii.hexlify(bytearray((0, 0, 0, 0, 0, 0, 0, 0)))
# https://docs.microsoft.com/en-us/openspecs/exchange_server_protocols/ms-oxocal/1d3aac05-a7b9-45cc-a213-47f0a0a2c5c1
# https://docs.microsoft.com/en-us/openspecs/exchange_server_protocols/ms-asemail/e7424ddc-dd10-431e-a0b7-5c794863370e
@@ -9666,12 +9790,12 @@ Inherited members
# https://stackoverflow.com/questions/33757805
def __new__(cls, uid):
- payload = binascii.hexlify(bytearray(f'vCal-Uid\x01\x00\x00\x00{uid}\x00'.encode('ascii')))
- length = binascii.hexlify(bytearray(struct.pack('<I', int(len(payload)/2))))
- encoding = b''.join([
- cls._HEADER, cls._EXCEPTION_REPLACEMENT_TIME, cls._CREATION_TIME, cls._RESERVED, length, payload
- ])
- return super().__new__(cls, codecs.decode(encoding, 'hex'))
+ payload = binascii.hexlify(bytearray(f"vCal-Uid\x01\x00\x00\x00{uid}\x00".encode("ascii")))
+ length = binascii.hexlify(bytearray(struct.pack("<I", int(len(payload) / 2))))
+ encoding = b"".join(
+ [cls._HEADER, cls._EXCEPTION_REPLACEMENT_TIME, cls._CREATION_TIME, cls._RESERVED, length, payload]
+ )
+ return super().__new__(cls, codecs.decode(encoding, "hex"))
@classmethod
def to_global_object_id(cls, uid):
@@ -9714,15 +9838,15 @@ Static methods
class UserConfiguration(IdChangeKeyMixIn):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/userconfiguration"""
- ELEMENT_NAME = 'UserConfiguration'
+ ELEMENT_NAME = "UserConfiguration"
NAMESPACE = MNS
ID_ELEMENT_CLS = ItemId
- _id = IdElementField(field_uri='ItemId', value_cls=ID_ELEMENT_CLS)
+ _id = IdElementField(field_uri="ItemId", value_cls=ID_ELEMENT_CLS)
user_configuration_name = EWSElementField(value_cls=UserConfigurationName)
- dictionary = DictionaryField(field_uri='Dictionary')
- xml_data = Base64Field(field_uri='XmlData')
- binary_data = Base64Field(field_uri='BinaryData')
+ dictionary = DictionaryField(field_uri="Dictionary")
+ xml_data = Base64Field(field_uri="XmlData")
+ binary_data = Base64Field(field_uri="BinaryData")
class UserConfigurationName(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/userconfigurationname"""
- ELEMENT_NAME = 'UserConfigurationName'
+ ELEMENT_NAME = "UserConfigurationName"
NAMESPACE = TNS
- name = CharField(field_uri='Name', is_attribute=True)
+ name = CharField(field_uri="Name", is_attribute=True)
folder = EWSElementField(value_cls=FolderId)
def clean(self, version=None):
from .folders import BaseFolder
+
if isinstance(self.folder, BaseFolder):
self.folder = self.folder.to_id()
super().clean(version=version)
@@ -9885,6 +10010,7 @@ Methods
def clean(self, version=None):
from .folders import BaseFolder
+
if isinstance(self.folder, BaseFolder):
self.folder = self.folder.to_id()
super().clean(version=version)
@@ -9959,15 +10085,13 @@ Inherited members
class UserId(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/userid"""
- ELEMENT_NAME = 'UserId'
+ ELEMENT_NAME = "UserId"
- sid = CharField(field_uri='SID')
- primary_smtp_address = EmailAddressField(field_uri='PrimarySmtpAddress')
- display_name = CharField(field_uri='DisplayName')
- distinguished_user = ChoiceField(field_uri='DistinguishedUser', choices={
- Choice('Default'), Choice('Anonymous')
- })
- external_user_identity = CharField(field_uri='ExternalUserIdentity')
+ sid = CharField(field_uri="SID")
+ primary_smtp_address = EmailAddressField(field_uri="PrimarySmtpAddress")
+ display_name = CharField(field_uri="DisplayName")
+ distinguished_user = ChoiceField(field_uri="DistinguishedUser", choices={Choice("Default"), Choice("Anonymous")})
+ external_user_identity = CharField(field_uri="ExternalUserIdentity")
class WorkingPeriod(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/workingperiod"""
- ELEMENT_NAME = 'WorkingPeriod'
+ ELEMENT_NAME = "WorkingPeriod"
- weekdays = EnumListField(field_uri='DayOfWeek', enum=WEEKDAY_NAMES, is_required=True)
- start = TimeField(field_uri='StartTimeInMinutes', is_required=True)
- end = TimeField(field_uri='EndTimeInMinutes', is_required=True)
+ weekdays = EnumListField(field_uri="DayOfWeek", enum=WEEKDAY_NAMES, is_required=True)
+ start = TimeField(field_uri="StartTimeInMinutes", is_required=True)
+ end = TimeField(field_uri="EndTimeInMinutes", is_required=True)
exchangelib.protocol
exchangelib.protocol
exchangelib.protocol
exchangelib.protocol
exchangelib.protocol
exchangelib.protocol
exchangelib.protocol
exchangelib.protocol
exchangelib.protocol
exchangelib.protocol
exchangelib.protocol
exchangelib.protocol
exchangelib.protocol
exchangelib.protocol
exchangelib.protocol
exchangelib.protocol
exchangelib.protocol
exchangelib.protocol
exchangelib.protocol
exchangelib.protocol
exchangelib.protocol
exchangelib.protocol
exchangelib.protocol
exchangelib.protocol
exchangelib.protocol
exchangelib.protocol
exchangelib.protocol
exchangelib.protocol
exchangelib.protocol
exchangelib.protocol
exchangelib.protocol
def close(self):
- log.debug('Server %s: Closing sessions', self.server)
+ log.debug("Server %s: Closing sessions", self.server)
while True:
try:
session = self._session_pool.get(block=False)
@@ -1384,27 +1445,27 @@ Methods
def create_oauth2_session(self):
has_token = False
- scope = ['https://outlook.office365.com/.default']
+ scope = ["https://outlook.office365.com/.default"]
session_params = {}
token_params = {}
if isinstance(self.credentials, OAuth2AuthorizationCodeCredentials):
# Ask for a refresh token
- scope.append('offline_access')
+ scope.append("offline_access")
# We don't know (or need) the Microsoft tenant ID. Use
# common/ to let Microsoft select the appropriate tenant
# for the provided authorization code or refresh token.
#
# Suppress looks-like-password warning from Bandit.
- token_url = 'https://login.microsoftonline.com/common/oauth2/v2.0/token' # nosec
+ token_url = "https://login.microsoftonline.com/common/oauth2/v2.0/token" # nosec
client_params = {}
has_token = self.credentials.access_token is not None
if has_token:
- session_params['token'] = self.credentials.access_token
+ session_params["token"] = self.credentials.access_token
elif self.credentials.authorization_code is not None:
- token_params['code'] = self.credentials.authorization_code
+ token_params["code"] = self.credentials.authorization_code
self.credentials.authorization_code = None
if self.credentials.client_id is not None and self.credentials.client_secret is not None:
@@ -1415,25 +1476,32 @@ Methods
# covers cases where the caller doesn't have access to
# the client secret but is working with a service that
# can provide it refreshed tokens on a limited basis).
- session_params.update({
- 'auto_refresh_kwargs': {
- 'client_id': self.credentials.client_id,
- 'client_secret': self.credentials.client_secret,
- },
- 'auto_refresh_url': token_url,
- 'token_updater': self.credentials.on_token_auto_refreshed,
- })
+ session_params.update(
+ {
+ "auto_refresh_kwargs": {
+ "client_id": self.credentials.client_id,
+ "client_secret": self.credentials.client_secret,
+ },
+ "auto_refresh_url": token_url,
+ "token_updater": self.credentials.on_token_auto_refreshed,
+ }
+ )
client = WebApplicationClient(self.credentials.client_id, **client_params)
else:
- token_url = f'https://login.microsoftonline.com/{self.credentials.tenant_id}/oauth2/v2.0/token'
+ token_url = f"https://login.microsoftonline.com/{self.credentials.tenant_id}/oauth2/v2.0/token"
client = BackendApplicationClient(client_id=self.credentials.client_id)
session = self.raw_session(self.service_endpoint, oauth2_client=client, oauth2_session_params=session_params)
if not has_token:
# Fetch the token explicitly -- it doesn't occur implicitly
- token = session.fetch_token(token_url=token_url, client_id=self.credentials.client_id,
- client_secret=self.credentials.client_secret, scope=scope,
- timeout=self.TIMEOUT, **token_params)
+ token = session.fetch_token(
+ token_url=token_url,
+ client_id=self.credentials.client_id,
+ client_secret=self.credentials.client_secret,
+ scope=scope,
+ timeout=self.TIMEOUT,
+ **token_params,
+ )
# Allow the credentials object to update its copy of the new
# token, and give the application an opportunity to cache it
self.credentials.on_token_auto_refreshed(token)
@@ -1454,7 +1522,7 @@ Methods
def create_session(self):
if self.credentials is None:
if self.auth_type in CREDENTIALS_REQUIRED:
- raise ValueError(f'Auth type {self.auth_type!r} requires credentials')
+ raise ValueError(f"Auth type {self.auth_type!r} requires credentials")
session = self.raw_session(self.service_endpoint)
session.auth = get_auth_instance(auth_type=self.auth_type)
else:
@@ -1469,18 +1537,18 @@ Methods
session.credentials_sig = self.credentials.sig()
else:
if self.auth_type == NTLM and self.credentials.type == self.credentials.EMAIL:
- username = '\\' + self.credentials.username
+ username = "\\" + self.credentials.username
else:
username = self.credentials.username
session = self.raw_session(self.service_endpoint)
- session.auth = get_auth_instance(auth_type=self.auth_type, username=username,
- password=self.credentials.password)
+ session.auth = get_auth_instance(
+ auth_type=self.auth_type, username=username, password=self.credentials.password
+ )
# Add some extra info
- session.session_id = sum(map(ord, str(os.urandom(100)))) # Used for debugging messages in services
+ session.session_id = random.randint(10000, 99999) # Used for debugging messages in services
session.usage_count = 0
- session.protocol = self
- log.debug('Server %s: Created session %s', self.server, session.session_id)
+ log.debug("Server %s: Created session %s", self.server, session.session_id)
return session
@@ -1501,13 +1569,17 @@ Methods
# Take a single session from the pool and discard it. We need to protect this with a lock while we are changing
# the pool size variable, to avoid race conditions. We must keep at least one session in the pool.
if self._session_pool_size <= 1:
- raise SessionPoolMinSizeReached('Session pool size cannot be decreased further')
+ raise SessionPoolMinSizeReached("Session pool size cannot be decreased further")
with self._session_pool_lock:
if self._session_pool_size <= 1:
- log.debug('Session pool size was decreased in another thread')
+ log.debug("Session pool size was decreased in another thread")
return
- log.warning('Server %s: Decreasing session pool size from %s to %s', self.server, self._session_pool_size,
- self._session_pool_size - 1)
+ log.warning(
+ "Server %s: Decreasing session pool size from %s to %s",
+ self.server,
+ self._session_pool_size,
+ self._session_pool_size - 1,
+ )
session = self.get_session()
self.close_session(session)
self._session_pool_size -= 1
@@ -1524,7 +1596,7 @@ Methods
def get_auth_type(self):
# Autodetect authentication type. We also set version hint here.
- name = str(self.credentials) if self.credentials and str(self.credentials) else 'DUMMY'
+ name = str(self.credentials) if self.credentials and str(self.credentials) else "DUMMY"
auth_type, api_version_hint = get_service_authtype(
service_endpoint=self.service_endpoint, retry_policy=self.retry_policy, api_versions=API_VERSIONS, name=name
)
@@ -1547,7 +1619,7 @@ Methods
_timeout = 60 # Rate-limit messages about session starvation
try:
session = self._session_pool.get(block=False)
- log.debug('Server %s: Got session immediately', self.server)
+ log.debug("Server %s: Got session immediately", self.server)
except Empty:
try:
self.increase_poolsize()
@@ -1555,13 +1627,13 @@ Methods
pass
while True:
try:
- log.debug('Server %s: Waiting for session', self.server)
+ log.debug("Server %s: Waiting for session", self.server)
session = self._session_pool.get(timeout=_timeout)
break
except Empty:
# This is normal when we have many worker threads starving for available sessions
- log.debug('Server %s: No sessions available for %s seconds', self.server, _timeout)
- log.debug('Server %s: Got session %s', self.server, session.session_id)
+ log.debug("Server %s: No sessions available for %s seconds", self.server, _timeout)
+ log.debug("Server %s: Got session %s", self.server, session.session_id)
session.usage_count += 1
return session
@@ -1580,13 +1652,17 @@ Methods
# Create a single session and insert it into the pool. We need to protect this with a lock while we are changing
# the pool size variable, to avoid race conditions. We must not exceed the pool size limit.
if self._session_pool_size >= self._session_pool_maxsize:
- raise SessionPoolMaxSizeReached('Session pool size cannot be increased further')
+ raise SessionPoolMaxSizeReached("Session pool size cannot be increased further")
with self._session_pool_lock:
if self._session_pool_size >= self._session_pool_maxsize:
- log.debug('Session pool size was increased in another thread')
+ log.debug("Session pool size was increased in another thread")
return
- log.debug('Server %s: Increasing session pool size from %s to %s', self.server, self._session_pool_size,
- self._session_pool_size + 1)
+ log.debug(
+ "Server %s: Increasing session pool size from %s to %s",
+ self.server,
+ self._session_pool_size,
+ self._session_pool_size + 1,
+ )
self._session_pool.put(self.create_session(), block=False)
self._session_pool_size += 1
@@ -1626,9 +1702,9 @@ def release_session(self, session):
# This should never fail, as we don't have more sessions than the queue contains
- log.debug('Server %s: Releasing session %s', self.server, session.session_id)
+ log.debug("Server %s: Releasing session %s", self.server, session.session_id)
if self.MAX_SESSION_USAGE_COUNT and session.usage_count >= self.MAX_SESSION_USAGE_COUNT:
- log.debug('Server %s: session %s usage exceeded limit. Discarding', self.server, session.session_id)
+ log.debug("Server %s: session %s usage exceeded limit. Discarding", self.server, session.session_id)
session = self.renew_session(session)
self._session_pool.put(session, block=False)
@@ -1644,7 +1720,7 @@ def renew_session(self, session):
# The session is useless. Close it completely and place a fresh session in the pool
- log.debug('Server %s: Renewing session %s', self.server, session.session_id)
+ log.debug("Server %s: Renewing session %s", self.server, session.session_id)
self.close_session(session)
return self.create_session()
@@ -1660,7 +1736,7 @@ def retire_session(self, session):
# The session is useless. Close it completely and place a fresh session in the pool
- log.debug('Server %s: Retiring session %s', self.server, session.session_id)
+ log.debug("Server %s: Retiring session %s", self.server, session.session_id)
self.close_session(session)
self.release_session(self.create_session())
@@ -1690,10 +1766,11 @@ def get_free_busy_info(self, accounts, start, end, merged_free_busy_interval=30, requested_view='DetailedMerged'):
+def get_free_busy_info(self, accounts, start, end, merged_free_busy_interval=30, requested_view="DetailedMerged"):
"""Return free/busy information for a list of accounts.
:param accounts: A list of (account, attendee_type, exclude_conflicts) tuples, where account is either an
@@ -2291,22 +2379,23 @@ Methods
:return: A generator of FreeBusyView objects
"""
from .account import Account
- tz_definition = list(self.get_timezones(
- timezones=[start.tzinfo],
- return_full_timezone_data=True
- ))[0]
+
+ tz_definition = list(self.get_timezones(timezones=[start.tzinfo], return_full_timezone_data=True))[0]
return GetUserAvailability(self).call(
- timezone=TimeZone.from_server_timezone(tz_definition=tz_definition, for_year=start.year),
- mailbox_data=[MailboxData(
+ timezone=TimeZone.from_server_timezone(tz_definition=tz_definition, for_year=start.year),
+ mailbox_data=[
+ MailboxData(
email=account.primary_smtp_address if isinstance(account, Account) else account,
attendee_type=attendee_type,
- exclude_conflicts=exclude_conflicts
- ) for account, attendee_type, exclude_conflicts in accounts],
- free_busy_view_options=FreeBusyViewOptions(
- time_window=TimeWindow(start=start, end=end),
- merged_free_busy_interval=merged_free_busy_interval,
- requested_view=requested_view,
- ),
+ exclude_conflicts=exclude_conflicts,
+ )
+ for account, attendee_type, exclude_conflicts in accounts
+ ],
+ free_busy_view_options=FreeBusyViewOptions(
+ time_window=TimeWindow(start=start, end=end),
+ merged_free_busy_interval=merged_free_busy_interval,
+ requested_view=requested_view,
+ ),
)
@@ -2361,10 +2450,12 @@ Methods
:return: a list of SearchableMailbox, FailedMailbox or Exception instances
"""
- return list(GetSearchableMailboxes(protocol=self).call(
- search_filter=search_filter,
- expand_group_membership=expand_group_membership,
- ))
+ return list(
+ GetSearchableMailboxes(protocol=self).call(
+ search_filter=search_filter,
+ expand_group_membership=expand_group_membership,
+ )
+ )
@@ -2409,8 +2500,7 @@ Methods
Expand source code
-def resolve_names(self, names, parent_folders=None, return_full_contact_data=False, search_scope=None,
- shape=None):
+def resolve_names(self, names, parent_folders=None, return_full_contact_data=False, search_scope=None, shape=None):
"""Resolve accounts on the server using partial account data, e.g. an email address or initials.
:param names: A list of identifiers to query
@@ -2421,10 +2511,15 @@ Methods
:return: A list of Mailbox items or, if return_full_contact_data is True, tuples of (Mailbox, Contact) items
"""
- return list(ResolveNames(protocol=self).call(
- unresolved_entries=names, parent_folders=parent_folders, return_full_contact_data=return_full_contact_data,
- search_scope=search_scope, contact_data_shape=shape,
- ))
+ return list(
+ ResolveNames(protocol=self).call(
+ unresolved_entries=names,
+ parent_folders=parent_folders,
+ return_full_contact_data=return_full_contact_data,
+ search_scope=search_scope,
+ contact_data_shape=shape,
+ )
+ )
@@ -2476,28 +2571,30 @@ Inherited members
"""Return whether retries should still be attempted"""
def raise_response_errors(self, response):
- cas_error = response.headers.get('X-CasErrorCode')
+ cas_error = response.headers.get("X-CasErrorCode")
if cas_error:
- if cas_error.startswith('CAS error:'):
+ if cas_error.startswith("CAS error:"):
# Remove unnecessary text
- cas_error = cas_error.split(':', 1)[1].strip()
+ cas_error = cas_error.split(":", 1)[1].strip()
raise CASError(cas_error=cas_error, response=response)
- if response.status_code == 500 and (b'The specified server version is invalid' in response.content or
- b'ErrorInvalidSchemaVersionForMailboxVersion' in response.content):
+ if response.status_code == 500 and (
+ b"The specified server version is invalid" in response.content
+ or b"ErrorInvalidSchemaVersionForMailboxVersion" in response.content
+ ):
# Another way of communicating invalid schema versions
- raise ErrorInvalidSchemaVersionForMailboxVersion('Invalid server version')
- if b'The referenced account is currently locked out' in response.content:
- raise UnauthorizedError('The referenced account is currently locked out')
+ raise ErrorInvalidSchemaVersionForMailboxVersion("Invalid server version")
+ if b"The referenced account is currently locked out" in response.content:
+ raise UnauthorizedError("The referenced account is currently locked out")
if response.status_code == 401 and self.fail_fast:
# This is a login failure
- raise UnauthorizedError(f'Invalid credentials for {response.url}')
- if 'TimeoutException' in response.headers:
+ raise UnauthorizedError(f"Invalid credentials for {response.url}")
+ if "TimeoutException" in response.headers:
# A header set by us on CONNECTION_ERRORS
- raise response.headers['TimeoutException']
+ raise response.headers["TimeoutException"]
# This could be anything. Let higher layers handle this
raise MalformedResponseError(
- f'Unknown failure in response. Code: {response.status_code} headers: {response.headers} '
- f'content: {response.text}'
+ f"Unknown failure in response. Code: {response.status_code} headers: {response.headers} "
+ f"content: {response.text}"
)
def raise_response_errors(self, response):
- cas_error = response.headers.get('X-CasErrorCode')
+ cas_error = response.headers.get("X-CasErrorCode")
if cas_error:
- if cas_error.startswith('CAS error:'):
+ if cas_error.startswith("CAS error:"):
# Remove unnecessary text
- cas_error = cas_error.split(':', 1)[1].strip()
+ cas_error = cas_error.split(":", 1)[1].strip()
raise CASError(cas_error=cas_error, response=response)
- if response.status_code == 500 and (b'The specified server version is invalid' in response.content or
- b'ErrorInvalidSchemaVersionForMailboxVersion' in response.content):
+ if response.status_code == 500 and (
+ b"The specified server version is invalid" in response.content
+ or b"ErrorInvalidSchemaVersionForMailboxVersion" in response.content
+ ):
# Another way of communicating invalid schema versions
- raise ErrorInvalidSchemaVersionForMailboxVersion('Invalid server version')
- if b'The referenced account is currently locked out' in response.content:
- raise UnauthorizedError('The referenced account is currently locked out')
+ raise ErrorInvalidSchemaVersionForMailboxVersion("Invalid server version")
+ if b"The referenced account is currently locked out" in response.content:
+ raise UnauthorizedError("The referenced account is currently locked out")
if response.status_code == 401 and self.fail_fast:
# This is a login failure
- raise UnauthorizedError(f'Invalid credentials for {response.url}')
- if 'TimeoutException' in response.headers:
+ raise UnauthorizedError(f"Invalid credentials for {response.url}")
+ if "TimeoutException" in response.headers:
# A header set by us on CONNECTION_ERRORS
- raise response.headers['TimeoutException']
+ raise response.headers["TimeoutException"]
# This could be anything. Let higher layers handle this
raise MalformedResponseError(
- f'Unknown failure in response. Code: {response.status_code} headers: {response.headers} '
- f'content: {response.text}'
+ f"Unknown failure in response. Code: {response.status_code} headers: {response.headers} "
+ f"content: {response.text}"
)
@@ -2619,7 +2718,7 @@ def init_poolmanager(self, *args, **kwargs):
- kwargs['cert_file'] = self.cert_file
+ kwargs["cert_file"] = self.cert_file
return super().init_poolmanager(*args, **kwargs)
diff --git a/docs/exchangelib/queryset.html b/docs/exchangelib/queryset.html
index 9205d88d..cf3f0e0b 100644
--- a/docs/exchangelib/queryset.html
+++ b/docs/exchangelib/queryset.html
@@ -31,9 +31,9 @@ exchangelib.queryset
exchangelib.queryset
exchangelib.queryset
exchangelib.queryset
exchangelib.queryset
exchangelib.queryset
exchangelib.queryset
exchangelib.queryset
exchangelib.queryset
exchangelib.queryset
exchangelib.queryset
exchangelib.queryset
exchangelib.queryset
exchangelib.queryset
exchangelib.queryset
exchangelib.queryset
exchangelib.queryset
exchangelib.queryset
exchangelib.queryset
exchangelib.queryset
exchangelib.queryset
@@ -1570,12 +1541,12 @@ Methods
def get(self, *args, **kwargs):
"""Assume the query will return exactly one item. Return that item."""
- if not args and set(kwargs) in ({'id'}, {'id', 'changekey'}):
+ if not args and set(kwargs) in ({"id"}, {"id", "changekey"}):
# We allow calling get(id=..., changekey=...) to get a single item, but only if exactly these two
# kwargs are present.
account = self.folder_collection.account
- item_id = self._id_field.field.clean(kwargs['id'], version=account.version)
- changekey = self._changekey_field.field.clean(kwargs.get('changekey'), version=account.version)
+ item_id = self._id_field.field.clean(kwargs["id"], version=account.version)
+ changekey = self._changekey_field.field.clean(kwargs.get("changekey"), version=account.version)
items = list(account.fetch(ids=[(item_id, changekey)], only_fields=self.only_fields))
else:
new_qs = self.filter(*args, **kwargs)
@@ -1612,11 +1583,7 @@ Methods
"""
ids = self._id_only_copy_self()
ids.page_size = page_size
- return self.folder_collection.account.bulk_mark_as_junk(
- ids=ids,
- chunk_size=chunk_size,
- **mark_as_junk_kwargs
- )
+ return self.folder_collection.account.bulk_mark_as_junk(ids=ids, chunk_size=chunk_size, **mark_as_junk_kwargs)
@@ -1724,7 +1691,7 @@ Methods
def reverse(self):
"""Reverses the ordering of the queryset."""
if not self.order_fields:
- raise ValueError('Reversing only makes sense if there are order_by fields')
+ raise ValueError("Reversing only makes sense if there are order_by fields")
new_qs = self._copy_self()
for f in new_qs.order_fields:
f.reverse = not f.reverse
@@ -1754,11 +1721,7 @@ Methods
"""
ids = self._id_only_copy_self()
ids.page_size = page_size
- return self.folder_collection.account.bulk_send(
- ids=ids,
- chunk_size=chunk_size,
- **send_kwargs
- )
+ return self.folder_collection.account.bulk_send(ids=ids, chunk_size=chunk_size, **send_kwargs)
@@ -1795,11 +1758,11 @@ Methods
"""Return the values of the specified field names as a list of lists. If called with flat=True and only one
field name, returns a list of values.
"""
- flat = kwargs.pop('flat', False)
+ flat = kwargs.pop("flat", False)
if kwargs:
- raise AttributeError(f'Unknown kwargs: {kwargs}')
+ raise AttributeError(f"Unknown kwargs: {kwargs}")
if flat and len(args) != 1:
- raise ValueError('flat=True requires exactly one field name')
+ raise ValueError("flat=True requires exactly one field name")
try:
only_fields = tuple(self._get_field_path(arg) for arg in args)
except ValueError as e:
diff --git a/docs/exchangelib/recurrence.html b/docs/exchangelib/recurrence.html
index b769ddf6..1f9717d6 100644
--- a/docs/exchangelib/recurrence.html
+++ b/docs/exchangelib/recurrence.html
@@ -28,15 +28,26 @@ Module exchangelib.recurrence
import logging
-from .fields import IntegerField, EnumField, WeekdaysField, DateOrDateTimeField, DateTimeField, EWSElementField, \
- IdElementField, MONTHS, WEEK_NUMBERS, WEEKDAYS, WEEKDAY_NAMES
-from .properties import EWSElement, IdChangeKeyMixIn, ItemId, EWSMeta
+from .fields import (
+ MONTHS,
+ WEEK_NUMBERS,
+ WEEKDAY_NAMES,
+ WEEKDAYS,
+ DateOrDateTimeField,
+ DateTimeField,
+ EnumField,
+ EWSElementField,
+ IdElementField,
+ IntegerField,
+ WeekdaysField,
+)
+from .properties import EWSElement, EWSMeta, IdChangeKeyMixIn, ItemId
log = logging.getLogger(__name__)
def _month_to_str(month):
- return MONTHS[month-1] if isinstance(month, int) else month
+ return MONTHS[month - 1] if isinstance(month, int) else month
def _weekday_to_str(weekday):
@@ -60,16 +71,16 @@ Module exchangelib.recurrence
https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/absoluteyearlyrecurrence
"""
- ELEMENT_NAME = 'AbsoluteYearlyRecurrence'
+ ELEMENT_NAME = "AbsoluteYearlyRecurrence"
# The day of month of an occurrence, in range 1 -> 31. If a particular month has less days than the day_of_month
# value, the last day in the month is assumed
- day_of_month = IntegerField(field_uri='DayOfMonth', min=1, max=31, is_required=True)
+ day_of_month = IntegerField(field_uri="DayOfMonth", min=1, max=31, is_required=True)
# The month of the year, from 1 - 12
- month = EnumField(field_uri='Month', enum=MONTHS, is_required=True)
+ month = EnumField(field_uri="Month", enum=MONTHS, is_required=True)
def __str__(self):
- return f'Occurs on day {self.day_of_month} of {_month_to_str(self.month)}'
+ return f"Occurs on day {self.day_of_month} of {_month_to_str(self.month)}"
class RelativeYearlyPattern(Pattern):
@@ -77,21 +88,23 @@ Module exchangelib.recurrence
https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/relativeyearlyrecurrence
"""
- ELEMENT_NAME = 'RelativeYearlyRecurrence'
+ ELEMENT_NAME = "RelativeYearlyRecurrence"
# Valid ISO 8601 weekday, as a number in range 1 -> 7 (1 being Monday). The value can also be one of the DAY
# (or 8), WEEK_DAY (or 9) or WEEKEND_DAY (or 10) consts which is interpreted as the first day, weekday, or weekend
# day of the year. Despite the field name in EWS, this is not a list.
- weekday = EnumField(field_uri='DaysOfWeek', enum=WEEKDAYS, is_required=True)
+ weekday = EnumField(field_uri="DaysOfWeek", enum=WEEKDAYS, is_required=True)
# Week number of the month, in range 1 -> 5. If 5 is specified, this assumes the last week of the month for
# months that have only 4 weeks
- week_number = EnumField(field_uri='DayOfWeekIndex', enum=WEEK_NUMBERS, is_required=True)
+ week_number = EnumField(field_uri="DayOfWeekIndex", enum=WEEK_NUMBERS, is_required=True)
# The month of the year, from 1 - 12
- month = EnumField(field_uri='Month', enum=MONTHS, is_required=True)
+ month = EnumField(field_uri="Month", enum=MONTHS, is_required=True)
def __str__(self):
- return f'Occurs on weekday {_weekday_to_str(self.weekday)} in the {_week_number_to_str(self.week_number)} ' \
- f'week of {_month_to_str(self.month)}'
+ return (
+ f"Occurs on weekday {_weekday_to_str(self.weekday)} in the {_week_number_to_str(self.week_number)} "
+ f"week of {_month_to_str(self.month)}"
+ )
class AbsoluteMonthlyPattern(Pattern):
@@ -99,16 +112,16 @@ Module exchangelib.recurrence
https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/absolutemonthlyrecurrence
"""
- ELEMENT_NAME = 'AbsoluteMonthlyRecurrence'
+ ELEMENT_NAME = "AbsoluteMonthlyRecurrence"
# Interval, in months, in range 1 -> 99
- interval = IntegerField(field_uri='Interval', min=1, max=99, is_required=True)
+ interval = IntegerField(field_uri="Interval", min=1, max=99, is_required=True)
# The day of month of an occurrence, in range 1 -> 31. If a particular month has less days than the day_of_month
# value, the last day in the month is assumed
- day_of_month = IntegerField(field_uri='DayOfMonth', min=1, max=31, is_required=True)
+ day_of_month = IntegerField(field_uri="DayOfMonth", min=1, max=31, is_required=True)
def __str__(self):
- return f'Occurs on day {self.day_of_month} of every {self.interval} month(s)'
+ return f"Occurs on day {self.day_of_month} of every {self.interval} month(s)"
class RelativeMonthlyPattern(Pattern):
@@ -116,99 +129,103 @@ Module exchangelib.recurrence
https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/relativemonthlyrecurrence
"""
- ELEMENT_NAME = 'RelativeMonthlyRecurrence'
+ ELEMENT_NAME = "RelativeMonthlyRecurrence"
# Interval, in months, in range 1 -> 99
- interval = IntegerField(field_uri='Interval', min=1, max=99, is_required=True)
+ interval = IntegerField(field_uri="Interval", min=1, max=99, is_required=True)
# Valid ISO 8601 weekday, as a number in range 1 -> 7 (1 being Monday). The value can also be one of the DAY
# (or 8), WEEK_DAY (or 9) or WEEKEND_DAY (or 10) consts which is interpreted as the first day, weekday, or weekend
# day of the month. Despite the field name in EWS, this is not a list.
- weekday = EnumField(field_uri='DaysOfWeek', enum=WEEKDAYS, is_required=True)
+ weekday = EnumField(field_uri="DaysOfWeek", enum=WEEKDAYS, is_required=True)
# Week number of the month, in range 1 -> 5. If 5 is specified, this assumes the last week of the month for
# months that have only 4 weeks.
- week_number = EnumField(field_uri='DayOfWeekIndex', enum=WEEK_NUMBERS, is_required=True)
+ week_number = EnumField(field_uri="DayOfWeekIndex", enum=WEEK_NUMBERS, is_required=True)
def __str__(self):
- return f'Occurs on weekday {_weekday_to_str(self.weekday)} in the {_week_number_to_str(self.week_number)} ' \
- f'week of every {self.interval} month(s)'
+ return (
+ f"Occurs on weekday {_weekday_to_str(self.weekday)} in the {_week_number_to_str(self.week_number)} "
+ f"week of every {self.interval} month(s)"
+ )
class WeeklyPattern(Pattern):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/weeklyrecurrence"""
- ELEMENT_NAME = 'WeeklyRecurrence'
+ ELEMENT_NAME = "WeeklyRecurrence"
# Interval, in weeks, in range 1 -> 99
- interval = IntegerField(field_uri='Interval', min=1, max=99, is_required=True)
+ interval = IntegerField(field_uri="Interval", min=1, max=99, is_required=True)
# List of valid ISO 8601 weekdays, as list of numbers in range 1 -> 7 (1 being Monday)
- weekdays = WeekdaysField(field_uri='DaysOfWeek', enum=WEEKDAY_NAMES, is_required=True)
+ weekdays = WeekdaysField(field_uri="DaysOfWeek", enum=WEEKDAY_NAMES, is_required=True)
# The first day of the week. Defaults to Monday
- first_day_of_week = EnumField(field_uri='FirstDayOfWeek', enum=WEEKDAY_NAMES, default=1, is_required=True)
+ first_day_of_week = EnumField(field_uri="FirstDayOfWeek", enum=WEEKDAY_NAMES, default=1, is_required=True)
def __str__(self):
- weekdays = [_weekday_to_str(i) for i in self.get_field_by_fieldname('weekdays').clean(self.weekdays)]
- return f'Occurs on weekdays {", ".join(weekdays)} of every {self.interval} week(s) where the first day of ' \
- f'the week is {_weekday_to_str(self.first_day_of_week)}'
+ weekdays = [_weekday_to_str(i) for i in self.get_field_by_fieldname("weekdays").clean(self.weekdays)]
+ return (
+ f'Occurs on weekdays {", ".join(weekdays)} of every {self.interval} week(s) where the first day of '
+ f"the week is {_weekday_to_str(self.first_day_of_week)}"
+ )
class DailyPattern(Pattern):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/dailyrecurrence"""
- ELEMENT_NAME = 'DailyRecurrence'
+ ELEMENT_NAME = "DailyRecurrence"
# Interval, in days, in range 1 -> 999
- interval = IntegerField(field_uri='Interval', min=1, max=999, is_required=True)
+ interval = IntegerField(field_uri="Interval", min=1, max=999, is_required=True)
def __str__(self):
- return f'Occurs every {self.interval} day(s)'
+ return f"Occurs every {self.interval} day(s)"
class YearlyRegeneration(Regeneration):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/yearlyregeneration"""
- ELEMENT_NAME = 'YearlyRegeneration'
+ ELEMENT_NAME = "YearlyRegeneration"
# Interval, in years
- interval = IntegerField(field_uri='Interval', min=1, is_required=True)
+ interval = IntegerField(field_uri="Interval", min=1, is_required=True)
def __str__(self):
- return f'Regenerates every {self.interval} year(s)'
+ return f"Regenerates every {self.interval} year(s)"
class MonthlyRegeneration(Regeneration):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/monthlyregeneration"""
- ELEMENT_NAME = 'MonthlyRegeneration'
+ ELEMENT_NAME = "MonthlyRegeneration"
# Interval, in months
- interval = IntegerField(field_uri='Interval', min=1, is_required=True)
+ interval = IntegerField(field_uri="Interval", min=1, is_required=True)
def __str__(self):
- return f'Regenerates every {self.interval} month(s)'
+ return f"Regenerates every {self.interval} month(s)"
class WeeklyRegeneration(Regeneration):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/weeklyregeneration"""
- ELEMENT_NAME = 'WeeklyRegeneration'
+ ELEMENT_NAME = "WeeklyRegeneration"
# Interval, in weeks
- interval = IntegerField(field_uri='Interval', min=1, is_required=True)
+ interval = IntegerField(field_uri="Interval", min=1, is_required=True)
def __str__(self):
- return f'Regenerates every {self.interval} week(s)'
+ return f"Regenerates every {self.interval} week(s)"
class DailyRegeneration(Regeneration):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/dailyregeneration"""
- ELEMENT_NAME = 'DailyRegeneration'
+ ELEMENT_NAME = "DailyRegeneration"
# Interval, in days
- interval = IntegerField(field_uri='Interval', min=1, is_required=True)
+ interval = IntegerField(field_uri="Interval", min=1, is_required=True)
def __str__(self):
- return f'Regenerates every {self.interval} day(s)'
+ return f"Regenerates every {self.interval} day(s)"
class Boundary(EWSElement, metaclass=EWSMeta):
@@ -218,56 +235,56 @@ Module exchangelib.recurrence
class NoEndPattern(Boundary):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/noendrecurrence"""
- ELEMENT_NAME = 'NoEndRecurrence'
+ ELEMENT_NAME = "NoEndRecurrence"
# Start date, as EWSDate or EWSDateTime
- start = DateOrDateTimeField(field_uri='StartDate', is_required=True)
+ start = DateOrDateTimeField(field_uri="StartDate", is_required=True)
def __str__(self):
- return f'Starts on {self.start}'
+ return f"Starts on {self.start}"
class EndDatePattern(Boundary):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/enddaterecurrence"""
- ELEMENT_NAME = 'EndDateRecurrence'
+ ELEMENT_NAME = "EndDateRecurrence"
# Start date, as EWSDate or EWSDateTime
- start = DateOrDateTimeField(field_uri='StartDate', is_required=True)
+ start = DateOrDateTimeField(field_uri="StartDate", is_required=True)
# End date, as EWSDate
- end = DateOrDateTimeField(field_uri='EndDate', is_required=True)
+ end = DateOrDateTimeField(field_uri="EndDate", is_required=True)
def __str__(self):
- return f'Starts on {self.start}, ends on {self.end}'
+ return f"Starts on {self.start}, ends on {self.end}"
class NumberedPattern(Boundary):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/numberedrecurrence"""
- ELEMENT_NAME = 'NumberedRecurrence'
+ ELEMENT_NAME = "NumberedRecurrence"
# Start date, as EWSDate or EWSDateTime
- start = DateOrDateTimeField(field_uri='StartDate', is_required=True)
+ start = DateOrDateTimeField(field_uri="StartDate", is_required=True)
# The number of occurrences in this pattern, in range 1 -> 999
- number = IntegerField(field_uri='NumberOfOccurrences', min=1, max=999, is_required=True)
+ number = IntegerField(field_uri="NumberOfOccurrences", min=1, max=999, is_required=True)
def __str__(self):
- return f'Starts on {self.start} and occurs {self.number} time(s)'
+ return f"Starts on {self.start} and occurs {self.number} time(s)"
class Occurrence(IdChangeKeyMixIn):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/occurrence"""
- ELEMENT_NAME = 'Occurrence'
+ ELEMENT_NAME = "Occurrence"
ID_ELEMENT_CLS = ItemId
- _id = IdElementField(field_uri='ItemId', value_cls=ID_ELEMENT_CLS)
+ _id = IdElementField(field_uri="ItemId", value_cls=ID_ELEMENT_CLS)
# The modified start time of the item, as EWSDateTime
- start = DateTimeField(field_uri='Start')
+ start = DateTimeField(field_uri="Start")
# The modified end time of the item, as EWSDateTime
- end = DateTimeField(field_uri='End')
+ end = DateTimeField(field_uri="End")
# The original start time of the item, as EWSDateTime
- original_start = DateTimeField(field_uri='OriginalStart')
+ original_start = DateTimeField(field_uri="OriginalStart")
# Container elements:
@@ -278,26 +295,32 @@ Module exchangelib.recurrence
class FirstOccurrence(Occurrence):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/firstoccurrence"""
- ELEMENT_NAME = 'FirstOccurrence'
+ ELEMENT_NAME = "FirstOccurrence"
class LastOccurrence(Occurrence):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/lastoccurrence"""
- ELEMENT_NAME = 'LastOccurrence'
+ ELEMENT_NAME = "LastOccurrence"
class DeletedOccurrence(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/deletedoccurrence"""
- ELEMENT_NAME = 'DeletedOccurrence'
+ ELEMENT_NAME = "DeletedOccurrence"
# The modified start time of the item, as EWSDateTime
- start = DateTimeField(field_uri='Start')
+ start = DateTimeField(field_uri="Start")
-PATTERN_CLASSES = AbsoluteYearlyPattern, RelativeYearlyPattern, AbsoluteMonthlyPattern, RelativeMonthlyPattern, \
- WeeklyPattern, DailyPattern
+PATTERN_CLASSES = (
+ AbsoluteYearlyPattern,
+ RelativeYearlyPattern,
+ AbsoluteMonthlyPattern,
+ RelativeMonthlyPattern,
+ WeeklyPattern,
+ DailyPattern,
+)
REGENERATION_CLASSES = YearlyRegeneration, MonthlyRegeneration, WeeklyRegeneration, DailyRegeneration
BOUNDARY_CLASSES = NoEndPattern, EndDatePattern, NumberedPattern
@@ -307,7 +330,7 @@ Module exchangelib.recurrence
https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/recurrence-recurrencetype
"""
- ELEMENT_NAME = 'Recurrence'
+ ELEMENT_NAME = "Recurrence"
PATTERN_CLASS_MAP = {cls.response_tag(): cls for cls in PATTERN_CLASSES}
BOUNDARY_CLASS_MAP = {cls.response_tag(): cls for cls in BOUNDARY_CLASSES}
@@ -316,18 +339,18 @@ Module exchangelib.recurrence
def __init__(self, **kwargs):
# Allow specifying a start, end and/or number as a shortcut to creating a boundary
- start = kwargs.pop('start', None)
- end = kwargs.pop('end', None)
- number = kwargs.pop('number', None)
+ start = kwargs.pop("start", None)
+ end = kwargs.pop("end", None)
+ number = kwargs.pop("number", None)
if any([start, end, number]):
- if 'boundary' in kwargs:
+ if "boundary" in kwargs:
raise ValueError("'boundary' is not allowed in combination with 'start', 'end' or 'number'")
if start and not end and not number:
- kwargs['boundary'] = NoEndPattern(start=start)
+ kwargs["boundary"] = NoEndPattern(start=start)
elif start and end and not number:
- kwargs['boundary'] = EndDatePattern(start=start, end=end)
+ kwargs["boundary"] = EndDatePattern(start=start, end=end)
elif start and number and not end:
- kwargs['boundary'] = NumberedPattern(start=start, number=number)
+ kwargs["boundary"] = NumberedPattern(start=start, number=number)
else:
raise ValueError("Unsupported 'start', 'end', 'number' combination")
super().__init__(**kwargs)
@@ -343,7 +366,7 @@ Module exchangelib.recurrence
return cls(pattern=pattern, boundary=boundary)
def __str__(self):
- return f'Pattern: {self.pattern}, Boundary: {self.boundary}'
+ return f"Pattern: {self.pattern}, Boundary: {self.boundary}"
class TaskRecurrence(Recurrence):
@@ -379,16 +402,16 @@ Classes
https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/absolutemonthlyrecurrence
"""
- ELEMENT_NAME = 'AbsoluteMonthlyRecurrence'
+ ELEMENT_NAME = "AbsoluteMonthlyRecurrence"
# Interval, in months, in range 1 -> 99
- interval = IntegerField(field_uri='Interval', min=1, max=99, is_required=True)
+ interval = IntegerField(field_uri="Interval", min=1, max=99, is_required=True)
# The day of month of an occurrence, in range 1 -> 31. If a particular month has less days than the day_of_month
# value, the last day in the month is assumed
- day_of_month = IntegerField(field_uri='DayOfMonth', min=1, max=31, is_required=True)
+ day_of_month = IntegerField(field_uri="DayOfMonth", min=1, max=31, is_required=True)
def __str__(self):
- return f'Occurs on day {self.day_of_month} of every {self.interval} month(s)'
+ return f"Occurs on day {self.day_of_month} of every {self.interval} month(s)"
class DailyPattern(Pattern):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/dailyrecurrence"""
- ELEMENT_NAME = 'DailyRecurrence'
+ ELEMENT_NAME = "DailyRecurrence"
# Interval, in days, in range 1 -> 999
- interval = IntegerField(field_uri='Interval', min=1, max=999, is_required=True)
+ interval = IntegerField(field_uri="Interval", min=1, max=999, is_required=True)
def __str__(self):
- return f'Occurs every {self.interval} day(s)'
+ return f"Occurs every {self.interval} day(s)"
class DailyRegeneration(Regeneration):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/dailyregeneration"""
- ELEMENT_NAME = 'DailyRegeneration'
+ ELEMENT_NAME = "DailyRegeneration"
# Interval, in days
- interval = IntegerField(field_uri='Interval', min=1, is_required=True)
+ interval = IntegerField(field_uri="Interval", min=1, is_required=True)
def __str__(self):
- return f'Regenerates every {self.interval} day(s)'
+ return f"Regenerates every {self.interval} day(s)"
class DeletedOccurrence(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/deletedoccurrence"""
- ELEMENT_NAME = 'DeletedOccurrence'
+ ELEMENT_NAME = "DeletedOccurrence"
# The modified start time of the item, as EWSDateTime
- start = DateTimeField(field_uri='Start')
+ start = DateTimeField(field_uri="Start")
class EndDatePattern(Boundary):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/enddaterecurrence"""
- ELEMENT_NAME = 'EndDateRecurrence'
+ ELEMENT_NAME = "EndDateRecurrence"
# Start date, as EWSDate or EWSDateTime
- start = DateOrDateTimeField(field_uri='StartDate', is_required=True)
+ start = DateOrDateTimeField(field_uri="StartDate", is_required=True)
# End date, as EWSDate
- end = DateOrDateTimeField(field_uri='EndDate', is_required=True)
+ end = DateOrDateTimeField(field_uri="EndDate", is_required=True)
def __str__(self):
- return f'Starts on {self.start}, ends on {self.end}'
+ return f"Starts on {self.start}, ends on {self.end}"
class FirstOccurrence(Occurrence):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/firstoccurrence"""
- ELEMENT_NAME = 'FirstOccurrence'
+ ELEMENT_NAME = "FirstOccurrence"
class LastOccurrence(Occurrence):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/lastoccurrence"""
- ELEMENT_NAME = 'LastOccurrence'
+ ELEMENT_NAME = "LastOccurrence"
class MonthlyRegeneration(Regeneration):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/monthlyregeneration"""
- ELEMENT_NAME = 'MonthlyRegeneration'
+ ELEMENT_NAME = "MonthlyRegeneration"
# Interval, in months
- interval = IntegerField(field_uri='Interval', min=1, is_required=True)
+ interval = IntegerField(field_uri="Interval", min=1, is_required=True)
def __str__(self):
- return f'Regenerates every {self.interval} month(s)'
+ return f"Regenerates every {self.interval} month(s)"
class NoEndPattern(Boundary):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/noendrecurrence"""
- ELEMENT_NAME = 'NoEndRecurrence'
+ ELEMENT_NAME = "NoEndRecurrence"
# Start date, as EWSDate or EWSDateTime
- start = DateOrDateTimeField(field_uri='StartDate', is_required=True)
+ start = DateOrDateTimeField(field_uri="StartDate", is_required=True)
def __str__(self):
- return f'Starts on {self.start}'
+ return f"Starts on {self.start}"
class NumberedPattern(Boundary):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/numberedrecurrence"""
- ELEMENT_NAME = 'NumberedRecurrence'
+ ELEMENT_NAME = "NumberedRecurrence"
# Start date, as EWSDate or EWSDateTime
- start = DateOrDateTimeField(field_uri='StartDate', is_required=True)
+ start = DateOrDateTimeField(field_uri="StartDate", is_required=True)
# The number of occurrences in this pattern, in range 1 -> 999
- number = IntegerField(field_uri='NumberOfOccurrences', min=1, max=999, is_required=True)
+ number = IntegerField(field_uri="NumberOfOccurrences", min=1, max=999, is_required=True)
def __str__(self):
- return f'Starts on {self.start} and occurs {self.number} time(s)'
+ return f"Starts on {self.start} and occurs {self.number} time(s)"
class Occurrence(IdChangeKeyMixIn):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/occurrence"""
- ELEMENT_NAME = 'Occurrence'
+ ELEMENT_NAME = "Occurrence"
ID_ELEMENT_CLS = ItemId
- _id = IdElementField(field_uri='ItemId', value_cls=ID_ELEMENT_CLS)
+ _id = IdElementField(field_uri="ItemId", value_cls=ID_ELEMENT_CLS)
# The modified start time of the item, as EWSDateTime
- start = DateTimeField(field_uri='Start')
+ start = DateTimeField(field_uri="Start")
# The modified end time of the item, as EWSDateTime
- end = DateTimeField(field_uri='End')
+ end = DateTimeField(field_uri="End")
# The original start time of the item, as EWSDateTime
- original_start = DateTimeField(field_uri='OriginalStart')
+ original_start = DateTimeField(field_uri="OriginalStart")
class WeeklyPattern(Pattern):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/weeklyrecurrence"""
- ELEMENT_NAME = 'WeeklyRecurrence'
+ ELEMENT_NAME = "WeeklyRecurrence"
# Interval, in weeks, in range 1 -> 99
- interval = IntegerField(field_uri='Interval', min=1, max=99, is_required=True)
+ interval = IntegerField(field_uri="Interval", min=1, max=99, is_required=True)
# List of valid ISO 8601 weekdays, as list of numbers in range 1 -> 7 (1 being Monday)
- weekdays = WeekdaysField(field_uri='DaysOfWeek', enum=WEEKDAY_NAMES, is_required=True)
+ weekdays = WeekdaysField(field_uri="DaysOfWeek", enum=WEEKDAY_NAMES, is_required=True)
# The first day of the week. Defaults to Monday
- first_day_of_week = EnumField(field_uri='FirstDayOfWeek', enum=WEEKDAY_NAMES, default=1, is_required=True)
+ first_day_of_week = EnumField(field_uri="FirstDayOfWeek", enum=WEEKDAY_NAMES, default=1, is_required=True)
def __str__(self):
- weekdays = [_weekday_to_str(i) for i in self.get_field_by_fieldname('weekdays').clean(self.weekdays)]
- return f'Occurs on weekdays {", ".join(weekdays)} of every {self.interval} week(s) where the first day of ' \
- f'the week is {_weekday_to_str(self.first_day_of_week)}'
+ weekdays = [_weekday_to_str(i) for i in self.get_field_by_fieldname("weekdays").clean(self.weekdays)]
+ return (
+ f'Occurs on weekdays {", ".join(weekdays)} of every {self.interval} week(s) where the first day of '
+ f"the week is {_weekday_to_str(self.first_day_of_week)}"
+ )
class WeeklyRegeneration(Regeneration):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/weeklyregeneration"""
- ELEMENT_NAME = 'WeeklyRegeneration'
+ ELEMENT_NAME = "WeeklyRegeneration"
# Interval, in weeks
- interval = IntegerField(field_uri='Interval', min=1, is_required=True)
+ interval = IntegerField(field_uri="Interval", min=1, is_required=True)
def __str__(self):
- return f'Regenerates every {self.interval} week(s)'
+ return f"Regenerates every {self.interval} week(s)"
class YearlyRegeneration(Regeneration):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/yearlyregeneration"""
- ELEMENT_NAME = 'YearlyRegeneration'
+ ELEMENT_NAME = "YearlyRegeneration"
# Interval, in years
- interval = IntegerField(field_uri='Interval', min=1, is_required=True)
+ interval = IntegerField(field_uri="Interval", min=1, is_required=True)
def __str__(self):
- return f'Regenerates every {self.interval} year(s)'
+ return f"Regenerates every {self.interval} year(s)"
exchangelib.restriction
exchangelib.restriction
exchangelib.restriction
exchangelib.restriction
exchangelib.restriction
exchangelib.restriction
exchangelib.restriction
exchangelib.restriction
exchangelib.restriction
exchangelib.restriction
exchangelib.restriction
exchangelib.restriction
exchangelib.restriction
exchangelib.restriction
exchangelib.restriction
exchangelib.services.archive_item
from .common import EWSAccountService, folder_ids_element, item_ids_element
-from ..items import Item
-from ..util import create_element, MNS
+from ..items import Item
+from ..util import MNS, create_element
from ..version import EXCHANGE_2013
+from .common import EWSAccountService, folder_ids_element, item_ids_element
class ArchiveItem(EWSAccountService):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/archiveitem-operation"""
- SERVICE_NAME = 'ArchiveItem'
- element_container_name = f'{{{MNS}}}Items'
+ SERVICE_NAME = "ArchiveItem"
+ element_container_name = f"{{{MNS}}}Items"
supported_from = EXCHANGE_2013
def call(self, items, to_folder):
@@ -53,9 +53,9 @@ Module exchangelib.services.archive_item
return Item.id_from_xml(elem)
def get_payload(self, items, to_folder):
- payload = create_element(f'm:{self.SERVICE_NAME}')
+ payload = create_element(f"m:{self.SERVICE_NAME}")
payload.append(
- folder_ids_element(folders=[to_folder], version=self.account.version, tag='m:ArchiveSourceFolderId')
+ folder_ids_element(folders=[to_folder], version=self.account.version, tag="m:ArchiveSourceFolderId")
)
payload.append(item_ids_element(items=items, version=self.account.version))
return payload
@@ -83,8 +83,8 @@ Classes
class ArchiveItem(EWSAccountService):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/archiveitem-operation"""
- SERVICE_NAME = 'ArchiveItem'
- element_container_name = f'{{{MNS}}}Items'
+ SERVICE_NAME = "ArchiveItem"
+ element_container_name = f"{{{MNS}}}Items"
supported_from = EXCHANGE_2013
def call(self, items, to_folder):
@@ -101,9 +101,9 @@ Classes
return Item.id_from_xml(elem)
def get_payload(self, items, to_folder):
- payload = create_element(f'm:{self.SERVICE_NAME}')
+ payload = create_element(f"m:{self.SERVICE_NAME}")
payload.append(
- folder_ids_element(folders=[to_folder], version=self.account.version, tag='m:ArchiveSourceFolderId')
+ folder_ids_element(folders=[to_folder], version=self.account.version, tag="m:ArchiveSourceFolderId")
)
payload.append(item_ids_element(items=items, version=self.account.version))
return payload
@@ -163,9 +163,9 @@ Methods
Expand source code
def get_payload(self, items, to_folder):
- payload = create_element(f'm:{self.SERVICE_NAME}')
+ payload = create_element(f"m:{self.SERVICE_NAME}")
payload.append(
- folder_ids_element(folders=[to_folder], version=self.account.version, tag='m:ArchiveSourceFolderId')
+ folder_ids_element(folders=[to_folder], version=self.account.version, tag="m:ArchiveSourceFolderId")
)
payload.append(item_ids_element(items=items, version=self.account.version))
return payload
diff --git a/docs/exchangelib/services/common.html b/docs/exchangelib/services/common.html
index c7a83634..a4ee88eb 100644
--- a/docs/exchangelib/services/common.html
+++ b/docs/exchangelib/services/common.html
@@ -34,27 +34,91 @@ Module exchangelib.services.common
from .. import errors
from ..attachments import AttachmentId
from ..credentials import IMPERSONATION, OAuth2Credentials
-from ..errors import EWSWarning, TransportError, SOAPError, ErrorTimeoutExpired, ErrorBatchProcessingStopped, \
- ErrorQuotaExceeded, ErrorCannotDeleteObject, ErrorCreateItemAccessDenied, ErrorFolderNotFound, \
- ErrorNonExistentMailbox, ErrorMailboxStoreUnavailable, ErrorImpersonateUserDenied, ErrorInternalServerError, \
- ErrorInternalServerTransientError, ErrorNoRespondingCASInDestinationSite, ErrorImpersonationFailed, \
- ErrorMailboxMoveInProgress, ErrorAccessDenied, ErrorConnectionFailed, RateLimitError, ErrorServerBusy, \
- ErrorTooManyObjectsOpened, ErrorInvalidLicense, ErrorInvalidSchemaVersionForMailboxVersion, \
- ErrorInvalidServerVersion, ErrorItemNotFound, ErrorADUnavailable, ErrorInvalidChangeKey, \
- ErrorItemSave, ErrorInvalidIdMalformed, ErrorMessageSizeExceeded, UnauthorizedError, \
- ErrorCannotDeleteTaskOccurrence, ErrorMimeContentConversionFailed, ErrorRecurrenceHasNoOccurrence, \
- ErrorNoPublicFolderReplicaAvailable, MalformedResponseError, ErrorExceededConnectionCount, \
- SessionPoolMinSizeReached, ErrorIncorrectSchemaVersion, ErrorInvalidRequest, ErrorCorruptData, \
- ErrorCannotEmptyFolder, ErrorDeleteDistinguishedFolder, ErrorInvalidSubscription, ErrorInvalidWatermark, \
- ErrorInvalidSyncStateData, ErrorNameResolutionNoResults, ErrorNameResolutionMultipleResults, \
- ErrorConnectionFailedTransientError, ErrorDelegateNoUser, ErrorNotDelegate, InvalidTypeError
+from ..errors import (
+ ErrorAccessDenied,
+ ErrorADUnavailable,
+ ErrorBatchProcessingStopped,
+ ErrorCannotDeleteObject,
+ ErrorCannotDeleteTaskOccurrence,
+ ErrorCannotEmptyFolder,
+ ErrorConnectionFailed,
+ ErrorConnectionFailedTransientError,
+ ErrorCorruptData,
+ ErrorCreateItemAccessDenied,
+ ErrorDelegateNoUser,
+ ErrorDeleteDistinguishedFolder,
+ ErrorExceededConnectionCount,
+ ErrorFolderNotFound,
+ ErrorImpersonateUserDenied,
+ ErrorImpersonationFailed,
+ ErrorIncorrectSchemaVersion,
+ ErrorInternalServerError,
+ ErrorInternalServerTransientError,
+ ErrorInvalidChangeKey,
+ ErrorInvalidIdMalformed,
+ ErrorInvalidLicense,
+ ErrorInvalidRequest,
+ ErrorInvalidSchemaVersionForMailboxVersion,
+ ErrorInvalidServerVersion,
+ ErrorInvalidSubscription,
+ ErrorInvalidSyncStateData,
+ ErrorInvalidWatermark,
+ ErrorItemCorrupt,
+ ErrorItemNotFound,
+ ErrorItemSave,
+ ErrorMailboxMoveInProgress,
+ ErrorMailboxStoreUnavailable,
+ ErrorMessageSizeExceeded,
+ ErrorMimeContentConversionFailed,
+ ErrorNameResolutionMultipleResults,
+ ErrorNameResolutionNoResults,
+ ErrorNonExistentMailbox,
+ ErrorNoPublicFolderReplicaAvailable,
+ ErrorNoRespondingCASInDestinationSite,
+ ErrorNotDelegate,
+ ErrorQuotaExceeded,
+ ErrorRecurrenceHasNoOccurrence,
+ ErrorServerBusy,
+ ErrorTimeoutExpired,
+ ErrorTooManyObjectsOpened,
+ EWSWarning,
+ InvalidTypeError,
+ MalformedResponseError,
+ RateLimitError,
+ SessionPoolMinSizeReached,
+ SOAPError,
+ TransportError,
+ UnauthorizedError,
+)
from ..folders import BaseFolder, Folder, RootOfHierarchy
from ..items import BaseItem
-from ..properties import FieldURI, IndexedFieldURI, ExtendedFieldURI, ExceptionFieldURI, ItemId, FolderId, \
- DistinguishedFolderId, BaseItemId
+from ..properties import (
+ BaseItemId,
+ DistinguishedFolderId,
+ ExceptionFieldURI,
+ ExtendedFieldURI,
+ FieldURI,
+ FolderId,
+ IndexedFieldURI,
+ ItemId,
+)
from ..transport import wrap
-from ..util import chunkify, create_element, add_xml_child, get_xml_attr, to_xml, post_ratelimited, \
- xml_to_str, set_xml_value, SOAPNS, TNS, MNS, ENS, ParseError, DummyResponse
+from ..util import (
+ ENS,
+ MNS,
+ SOAPNS,
+ TNS,
+ DummyResponse,
+ ParseError,
+ add_xml_child,
+ chunkify,
+ create_element,
+ get_xml_attr,
+ post_ratelimited,
+ set_xml_value,
+ to_xml,
+ xml_to_str,
+)
from ..version import API_VERSIONS, Version
log = logging.getLogger(__name__)
@@ -84,6 +148,7 @@ Module exchangelib.services.common
ErrorInvalidSubscription,
ErrorInvalidSyncStateData,
ErrorInvalidWatermark,
+ ErrorItemCorrupt,
ErrorItemNotFound,
ErrorMailboxMoveInProgress,
ErrorMailboxStoreUnavailable,
@@ -109,9 +174,18 @@ Module exchangelib.services.common
returns_elements = True # If False, the service does not return response elements, just the ResponseCode status
# Return exception instance instead of raising exceptions for the following errors when contained in an element
ERRORS_TO_CATCH_IN_RESPONSE = (
- EWSWarning, ErrorCannotDeleteObject, ErrorInvalidChangeKey, ErrorItemNotFound, ErrorItemSave,
- ErrorInvalidIdMalformed, ErrorMessageSizeExceeded, ErrorCannotDeleteTaskOccurrence,
- ErrorMimeContentConversionFailed, ErrorRecurrenceHasNoOccurrence, ErrorCorruptData
+ EWSWarning,
+ ErrorCannotDeleteObject,
+ ErrorInvalidChangeKey,
+ ErrorItemNotFound,
+ ErrorItemSave,
+ ErrorInvalidIdMalformed,
+ ErrorMessageSizeExceeded,
+ ErrorCannotDeleteTaskOccurrence,
+ ErrorMimeContentConversionFailed,
+ ErrorRecurrenceHasNoOccurrence,
+ ErrorCorruptData,
+ ErrorItemCorrupt,
)
# Similarly, define the warnings we want to return unraised
WARNINGS_TO_CATCH_IN_RESPONSE = ErrorBatchProcessingStopped
@@ -127,13 +201,13 @@ Module exchangelib.services.common
def __init__(self, protocol, chunk_size=None, timeout=None):
self.chunk_size = chunk_size or CHUNK_SIZE
if not isinstance(self.chunk_size, int):
- raise InvalidTypeError('chunk_size', chunk_size, int)
+ raise InvalidTypeError("chunk_size", chunk_size, int)
if self.chunk_size < 1:
raise ValueError(f"'chunk_size' {self.chunk_size} must be a positive number")
if self.supported_from and protocol.version.build < self.supported_from:
raise NotImplementedError(
- f'{self.SERVICE_NAME!r} is only supported on {self.supported_from.fullname()!r} and later. '
- f'Your current version is {protocol.version.build.fullname()!r}.'
+ f"{self.SERVICE_NAME!r} is only supported on {self.supported_from.fullname()!r} and later. "
+ f"Your current version is {protocol.version.build.fullname()!r}."
)
self.protocol = protocol
# Allow a service to override the default protocol timeout. Useful for streaming services
@@ -144,6 +218,16 @@ Module exchangelib.services.common
self._streaming_session = None
self._streaming_response = None
+ def __del__(self):
+ # pylint: disable=bare-except
+ try:
+ if self.streaming:
+ # Make sure to clean up lingering resources
+ self.stop_streaming()
+ except Exception: # nosec
+ # __del__ should never fail
+ pass
+
# The following two methods are the minimum required to be implemented by subclasses, but the name and number of
# kwargs differs between services. Therefore, we cannot make these methods abstract.
@@ -179,10 +263,10 @@ Module exchangelib.services.common
return None
if expect_result is False:
if res:
- raise ValueError(f'Expected result length 0, but got {res}')
+ raise ValueError(f"Expected result length 0, but got {res}")
return None
if len(res) != 1:
- raise ValueError(f'Expected result length 1, but got {res}')
+ raise ValueError(f"Expected result length 1, but got {res}")
return res[0]
def parse(self, xml):
@@ -250,12 +334,12 @@ Module exchangelib.services.common
# If the input for a service is a QuerySet, it can be difficult to remove exceptions before now
filtered_items = filter(lambda i: not isinstance(i, Exception), items)
for i, chunk in enumerate(chunkify(filtered_items, self.chunk_size), start=1):
- log.debug('Processing chunk %s containing %s items', i, len(chunk))
+ log.debug("Processing chunk %s containing %s items", i, len(chunk))
yield from self._get_elements(payload=payload_func(chunk, **kwargs))
def stop_streaming(self):
if not self.streaming:
- raise RuntimeError('Attempt to stop a non-streaming service')
+ raise RuntimeError("Attempt to stop a non-streaming service")
if self._streaming_response:
self._streaming_response.close() # Release memory
self._streaming_response = None
@@ -292,11 +376,11 @@ Module exchangelib.services.common
raise e
# Re-raise as an ErrorServerBusy with a default delay of 5 minutes
- raise ErrorServerBusy(f'Reraised from {e.__class__.__name__}({e})')
+ raise ErrorServerBusy(f"Reraised from {e.__class__.__name__}({e})")
except Exception:
# This may run in a thread, which obfuscates the stack trace. Print trace immediately.
account = self.account if isinstance(self, EWSAccountService) else None
- log.warning('Account %s: Exception in _get_elements: %s', account, traceback.format_exc(20))
+ log.warning("Account %s: Exception in _get_elements: %s", account, traceback.format_exc(20))
raise
finally:
if self.streaming:
@@ -307,10 +391,10 @@ Module exchangelib.services.common
def _get_response(self, payload, api_version):
"""Send the actual HTTP request and get the response."""
- session = self.protocol.get_session()
if self.streaming:
# Make sure to clean up lingering resources
self.stop_streaming()
+ session = self.protocol.get_session()
r, session = post_ratelimited(
protocol=self.protocol,
session=session,
@@ -354,9 +438,9 @@ Module exchangelib.services.common
# Microsoft really doesn't want to make our lives easy. The server may report one version in our initial version
# guessing tango, but then the server may decide that any arbitrary legacy backend server may actually process
# the request for an account. Prepare to handle version-related errors and set the server version per-account.
- log.debug('Calling service %s', self.SERVICE_NAME)
+ log.debug("Calling service %s", self.SERVICE_NAME)
for api_version in self._api_versions_to_try:
- log.debug('Trying API version %s', api_version)
+ log.debug("Trying API version %s", api_version)
r = self._get_response(payload=payload, api_version=api_version)
if self.streaming:
# Let 'requests' decode raw data automatically
@@ -371,10 +455,14 @@ Module exchangelib.services.common
self._update_api_version(api_version=api_version, header=header, **parse_opts)
try:
return self._get_soap_messages(body=body, **parse_opts)
- except (ErrorInvalidServerVersion, ErrorIncorrectSchemaVersion, ErrorInvalidRequest,
- ErrorInvalidSchemaVersionForMailboxVersion):
+ except (
+ ErrorInvalidServerVersion,
+ ErrorIncorrectSchemaVersion,
+ ErrorInvalidRequest,
+ ErrorInvalidSchemaVersionForMailboxVersion,
+ ):
# The guessed server version is wrong. Try the next version
- log.debug('API version %s was invalid', api_version)
+ log.debug("API version %s was invalid", api_version)
continue
except ErrorExceededConnectionCount as e:
# This indicates that the connecting user has too many open TCP connections to the server. Decrease
@@ -390,7 +478,7 @@ Module exchangelib.services.common
# In streaming mode, we may not have accessed the raw stream yet. Caller must handle this.
r.close() # Release memory
- raise self.NO_VALID_SERVER_VERSIONS(f'Tried versions {self._api_versions_to_try} but all were invalid')
+ raise self.NO_VALID_SERVER_VERSIONS(f"Tried versions {self._api_versions_to_try} but all were invalid")
def _handle_backoff(self, e):
"""Take a request from the server to back off and checks the retry policy for what to do. Re-raise the
@@ -399,7 +487,7 @@ Module exchangelib.services.common
:param e: An ErrorServerBusy instance
:return:
"""
- log.debug('Got ErrorServerBusy (back off %s seconds)', e.back_off)
+ log.debug("Got ErrorServerBusy (back off %s seconds)", e.back_off)
# ErrorServerBusy is very often a symptom of sending too many requests. Scale back connections if possible.
try:
self.protocol.decrease_poolsize()
@@ -417,12 +505,12 @@ Module exchangelib.services.common
try:
head_version = Version.from_soap_header(requested_api_version=api_version, header=header)
except TransportError as te:
- log.debug('Failed to update version info (%s)', te)
+ log.debug("Failed to update version info (%s)", te)
return
if self._version_hint == head_version:
# Nothing to do
return
- log.debug('Found new version (%s -> %s)', self._version_hint, head_version)
+ log.debug("Found new version (%s -> %s)", self._version_hint, head_version)
# The api_version that worked was different than our hint, or we never got a build version. Store the working
# version.
self._version_hint = head_version
@@ -430,17 +518,17 @@ Module exchangelib.services.common
@classmethod
def _response_tag(cls):
"""Return the name of the element containing the service response."""
- return f'{{{MNS}}}{cls.SERVICE_NAME}Response'
+ return f"{{{MNS}}}{cls.SERVICE_NAME}Response"
@staticmethod
def _response_messages_tag():
"""Return the name of the element containing service response messages."""
- return f'{{{MNS}}}ResponseMessages'
+ return f"{{{MNS}}}ResponseMessages"
@classmethod
def _response_message_tag(cls):
"""Return the name of the element of a single response message."""
- return f'{{{MNS}}}{cls.SERVICE_NAME}ResponseMessage'
+ return f"{{{MNS}}}{cls.SERVICE_NAME}ResponseMessage"
@classmethod
def _get_soap_parts(cls, response, **parse_opts):
@@ -448,23 +536,23 @@ Module exchangelib.services.common
try:
root = to_xml(response.iter_content())
except ParseError as e:
- raise SOAPError(f'Bad SOAP response: {e}')
- header = root.find(f'{{{SOAPNS}}}Header')
+ raise SOAPError(f"Bad SOAP response: {e}")
+ header = root.find(f"{{{SOAPNS}}}Header")
if header is None:
# This is normal when the response contains SOAP-level errors
- log.debug('No header in XML response')
- body = root.find(f'{{{SOAPNS}}}Body')
+ log.debug("No header in XML response")
+ body = root.find(f"{{{SOAPNS}}}Body")
if body is None:
- raise MalformedResponseError('No Body element in SOAP response')
+ raise MalformedResponseError("No Body element in SOAP response")
return header, body
def _get_soap_messages(self, body, **parse_opts):
"""Return the elements in the response containing the response messages. Raises any SOAP exceptions."""
response = body.find(self._response_tag())
if response is None:
- fault = body.find(f'{{{SOAPNS}}}Fault')
+ fault = body.find(f"{{{SOAPNS}}}Fault")
if fault is None:
- raise SOAPError(f'Unknown SOAP response (expected {self._response_tag()} or Fault): {xml_to_str(body)}')
+ raise SOAPError(f"Unknown SOAP response (expected {self._response_tag()} or Fault): {xml_to_str(body)}")
self._raise_soap_errors(fault=fault) # Will throw SOAPError or custom EWS error
response_messages = response.find(self._response_messages_tag())
if response_messages is None:
@@ -477,43 +565,43 @@ Module exchangelib.services.common
def _raise_soap_errors(cls, fault):
"""Parse error messages contained in SOAP headers and raise as exceptions defined in this package."""
# Fault: See http://www.w3.org/TR/2000/NOTE-SOAP-20000508/#_Toc478383507
- fault_code = get_xml_attr(fault, 'faultcode')
- fault_string = get_xml_attr(fault, 'faultstring')
- fault_actor = get_xml_attr(fault, 'faultactor')
- detail = fault.find('detail')
+ fault_code = get_xml_attr(fault, "faultcode")
+ fault_string = get_xml_attr(fault, "faultstring")
+ fault_actor = get_xml_attr(fault, "faultactor")
+ detail = fault.find("detail")
if detail is not None:
- code, msg = None, ''
- if detail.find(f'{{{ENS}}}ResponseCode') is not None:
- code = get_xml_attr(detail, f'{{{ENS}}}ResponseCode').strip()
- if detail.find(f'{{{ENS}}}Message') is not None:
- msg = get_xml_attr(detail, f'{{{ENS}}}Message').strip()
- msg_xml = detail.find(f'{{{TNS}}}MessageXml') # Crazy. Here, it's in the TNS namespace
- if code == 'ErrorServerBusy':
+ code, msg = None, ""
+ if detail.find(f"{{{ENS}}}ResponseCode") is not None:
+ code = get_xml_attr(detail, f"{{{ENS}}}ResponseCode").strip()
+ if detail.find(f"{{{ENS}}}Message") is not None:
+ msg = get_xml_attr(detail, f"{{{ENS}}}Message").strip()
+ msg_xml = detail.find(f"{{{TNS}}}MessageXml") # Crazy. Here, it's in the TNS namespace
+ if code == "ErrorServerBusy":
back_off = None
try:
- value = msg_xml.find(f'{{{TNS}}}Value')
- if value.get('Name') == 'BackOffMilliseconds':
+ value = msg_xml.find(f"{{{TNS}}}Value")
+ if value.get("Name") == "BackOffMilliseconds":
back_off = int(value.text) / 1000.0 # Convert to seconds
except (TypeError, AttributeError):
pass
raise ErrorServerBusy(msg, back_off=back_off)
- if code == 'ErrorSchemaValidation' and msg_xml is not None:
- line_number = get_xml_attr(msg_xml, f'{{{TNS}}}LineNumber')
- line_position = get_xml_attr(msg_xml, f'{{{TNS}}}LinePosition')
- violation = get_xml_attr(msg_xml, f'{{{TNS}}}Violation')
+ if code == "ErrorSchemaValidation" and msg_xml is not None:
+ line_number = get_xml_attr(msg_xml, f"{{{TNS}}}LineNumber")
+ line_position = get_xml_attr(msg_xml, f"{{{TNS}}}LinePosition")
+ violation = get_xml_attr(msg_xml, f"{{{TNS}}}Violation")
if violation:
- msg = f'{msg} {violation}'
+ msg = f"{msg} {violation}"
if line_number or line_position:
- msg = f'{msg} (line: {line_number} position: {line_position})'
+ msg = f"{msg} (line: {line_number} position: {line_position})"
try:
raise vars(errors)[code](msg)
except KeyError:
- detail = f'{cls.SERVICE_NAME}: code: {code} msg: {msg} ({xml_to_str(detail)})'
+ detail = f"{cls.SERVICE_NAME}: code: {code} msg: {msg} ({xml_to_str(detail)})"
try:
raise vars(errors)[fault_code](fault_string)
except KeyError:
pass
- raise SOAPError(f'SOAP error code: {fault_code} string: {fault_string} actor: {fault_actor} detail: {detail}')
+ raise SOAPError(f"SOAP error code: {fault_code} string: {fault_string} actor: {fault_actor} detail: {detail}")
def _get_element_container(self, message, name=None):
"""Return the XML element in a response element that contains the elements we want the service to return. For
@@ -540,23 +628,23 @@ Module exchangelib.services.common
# ResponseClass is an XML attribute of various SomeServiceResponseMessage elements: Possible values are:
# Success, Warning, Error. See e.g.
# https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/finditemresponsemessage
- response_class = message.get('ResponseClass')
+ response_class = message.get("ResponseClass")
# ResponseCode, MessageText: See
# https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/responsecode
- response_code = get_xml_attr(message, f'{{{MNS}}}ResponseCode')
- if response_class == 'Success' and response_code == 'NoError':
+ response_code = get_xml_attr(message, f"{{{MNS}}}ResponseCode")
+ if response_class == "Success" and response_code == "NoError":
if not name:
return message
container = message.find(name)
if container is None:
- raise MalformedResponseError(f'No {name} elements in ResponseMessage ({xml_to_str(message)})')
+ raise MalformedResponseError(f"No {name} elements in ResponseMessage ({xml_to_str(message)})")
return container
- if response_code == 'NoError':
+ if response_code == "NoError":
return True
# Raise any non-acceptable errors in the container, or return the container or the acceptable exception instance
- msg_text = get_xml_attr(message, f'{{{MNS}}}MessageText')
- msg_xml = message.find(f'{{{MNS}}}MessageXml')
- if response_class == 'Warning':
+ msg_text = get_xml_attr(message, f"{{{MNS}}}MessageText")
+ msg_xml = message.find(f"{{{MNS}}}MessageXml")
+ if response_class == "Warning":
try:
raise self._get_exception(code=response_code, text=msg_text, msg_xml=msg_xml)
except self.WARNINGS_TO_CATCH_IN_RESPONSE as e:
@@ -565,7 +653,7 @@ Module exchangelib.services.common
log.warning(str(e))
container = message.find(name)
if container is None:
- raise MalformedResponseError(f'No {name} elements in ResponseMessage ({xml_to_str(message)})')
+ raise MalformedResponseError(f"No {name} elements in ResponseMessage ({xml_to_str(message)})")
return container
# rspclass == 'Error', or 'Success' and not 'NoError'
try:
@@ -577,21 +665,21 @@ Module exchangelib.services.common
def _get_exception(code, text, msg_xml):
"""Parse error messages contained in EWS responses and raise as exceptions defined in this package."""
if not code:
- return TransportError(f'Empty ResponseCode in ResponseMessage (MessageText: {text}, MessageXml: {msg_xml})')
+ return TransportError(f"Empty ResponseCode in ResponseMessage (MessageText: {text}, MessageXml: {msg_xml})")
if msg_xml is not None:
# If this is an ErrorInvalidPropertyRequest error, the xml may contain a specific FieldURI
for elem_cls in (FieldURI, IndexedFieldURI, ExtendedFieldURI, ExceptionFieldURI):
elem = msg_xml.find(elem_cls.response_tag())
if elem is not None:
field_uri = elem_cls.from_xml(elem, account=None)
- text += f' (field: {field_uri})'
+ text += f" (field: {field_uri})"
break
# If this is an ErrorInvalidValueForProperty error, the xml may contain the name and value of the property
- if code == 'ErrorInvalidValueForProperty':
+ if code == "ErrorInvalidValueForProperty":
msg_parts = {}
- for elem in msg_xml.findall(f'{{{TNS}}}Value'):
- key, val = elem.get('Name'), elem.text
+ for elem in msg_xml.findall(f"{{{TNS}}}Value"):
+ key, val = elem.get("Name"), elem.text
if key:
msg_parts[key] = val
if msg_parts:
@@ -599,26 +687,26 @@ Module exchangelib.services.common
# If this is an ErrorInternalServerError error, the xml may contain a more specific error code
inner_code, inner_text = None, None
- for value_elem in msg_xml.findall(f'{{{TNS}}}Value'):
- name = value_elem.get('Name')
- if name == 'InnerErrorResponseCode':
+ for value_elem in msg_xml.findall(f"{{{TNS}}}Value"):
+ name = value_elem.get("Name")
+ if name == "InnerErrorResponseCode":
inner_code = value_elem.text
- elif name == 'InnerErrorMessageText':
+ elif name == "InnerErrorMessageText":
inner_text = value_elem.text
if inner_code:
try:
# Raise the error as the inner error code
- return vars(errors)[inner_code](f'{inner_text} (raised from: {code}({text!r}))')
+ return vars(errors)[inner_code](f"{inner_text} (raised from: {code}({text!r}))")
except KeyError:
# Inner code is unknown to us. Just append to the original text
- text += f' (inner error: {inner_code}({inner_text!r}))'
+ text += f" (inner error: {inner_code}({inner_text!r}))"
try:
# Raise the error corresponding to the ResponseCode
return vars(errors)[code](text)
except KeyError:
# Should not happen
return TransportError(
- f'Unknown ResponseCode in ResponseMessage: {code} (MessageText: {text}, MessageXml: {msg_xml})'
+ f"Unknown ResponseCode in ResponseMessage: {code} (MessageText: {text}, MessageXml: {msg_xml})"
)
def _get_elements_in_response(self, response):
@@ -681,8 +769,8 @@ Module exchangelib.services.common
prefer_affinity = False
def __init__(self, *args, **kwargs):
- self.account = kwargs.pop('account')
- kwargs['protocol'] = self.account.protocol
+ self.account = kwargs.pop("account")
+ kwargs["protocol"] = self.account.protocol
super().__init__(*args, **kwargs)
@property
@@ -699,7 +787,7 @@ Module exchangelib.services.common
# See self._extra_headers() for documentation on affinity
if self.prefer_affinity:
for cookie in session.cookies:
- if cookie.name == 'X-BackEndOverrideCookie':
+ if cookie.name == "X-BackEndOverrideCookie":
self.account.affinity_cookie = cookie.value
break
@@ -707,14 +795,14 @@ Module exchangelib.services.common
headers = super()._extra_headers(session=session)
# See
# https://blogs.msdn.microsoft.com/webdav_101/2015/05/11/best-practices-ews-authentication-and-access-issues/
- headers['X-AnchorMailbox'] = self.account.primary_smtp_address
+ headers["X-AnchorMailbox"] = self.account.primary_smtp_address
# See
# https://docs.microsoft.com/en-us/exchange/client-developer/exchange-web-services/how-to-maintain-affinity-between-group-of-subscriptions-and-mailbox-server
if self.prefer_affinity:
- headers['X-PreferServerAffinity'] = 'True'
+ headers["X-PreferServerAffinity"] = "True"
if self.account.affinity_cookie:
- headers['X-BackEndOverrideCookie'] = self.account.affinity_cookie
+ headers["X-BackEndOverrideCookie"] = self.account.affinity_cookie
return headers
@property
@@ -730,9 +818,9 @@ Module exchangelib.services.common
class EWSPagingService(EWSAccountService):
def __init__(self, *args, **kwargs):
- self.page_size = kwargs.pop('page_size', None) or PAGE_SIZE
+ self.page_size = kwargs.pop("page_size", None) or PAGE_SIZE
if not isinstance(self.page_size, int):
- raise InvalidTypeError('page_size', self.page_size, int)
+ raise InvalidTypeError("page_size", self.page_size, int)
if self.page_size < 1:
raise ValueError(f"'page_size' {self.page_size} must be a positive number")
super().__init__(*args, **kwargs)
@@ -742,48 +830,51 @@ Module exchangelib.services.common
all paging-related counters.
"""
paging_infos = {f: dict(item_count=0, next_offset=None) for f in folders}
- common_next_offset = kwargs['offset']
+ common_next_offset = kwargs["offset"]
total_item_count = 0
while True:
if not paging_infos:
# Paging is done for all folders
break
- log.debug('Getting page at offset %s (max_items %s)', common_next_offset, max_items)
- kwargs['offset'] = common_next_offset
- kwargs['folders'] = paging_infos.keys() # Only request the paging of the remaining folders.
+ log.debug("Getting page at offset %s (max_items %s)", common_next_offset, max_items)
+ kwargs["offset"] = common_next_offset
+ kwargs["folders"] = paging_infos.keys() # Only request the paging of the remaining folders.
pages = self._get_pages(payload_func, kwargs, len(paging_infos))
for (page, next_offset), (f, paging_info) in zip(pages, list(paging_infos.items())):
- paging_info['next_offset'] = next_offset
+ paging_info["next_offset"] = next_offset
if isinstance(page, Exception):
# Assume this folder no longer works. Don't attempt to page it again.
- log.debug('Exception occurred for folder %s. Removing.', f)
+ log.debug("Exception occurred for folder %s. Removing.", f)
del paging_infos[f]
yield page
continue
if page is not None:
for elem in self._get_elems_from_page(page, max_items, total_item_count):
- paging_info['item_count'] += 1
+ paging_info["item_count"] += 1
total_item_count += 1
yield elem
if max_items and total_item_count >= max_items:
# No need to continue. Break out of inner loop
log.debug("'max_items' count reached (inner)")
break
- if not paging_info['next_offset']:
+ if not paging_info["next_offset"]:
# Paging is done for this folder. Don't attempt to page it again.
- log.debug('Paging has completed for folder %s. Removing.', f)
+ log.debug("Paging has completed for folder %s. Removing.", f)
del paging_infos[f]
continue
- log.debug('Folder %s still has items', f)
+ log.debug("Folder %s still has items", f)
# Check sanity of paging offsets, but don't fail. When we are iterating huge collections that take a
# long time to complete, the collection may change while we are iterating. This can affect the
# 'next_offset' value and make it inconsistent with the number of already collected items.
# We may have a mismatch if we stopped early due to reaching 'max_items'.
- if paging_info['next_offset'] != paging_info['item_count'] and (
+ if paging_info["next_offset"] != paging_info["item_count"] and (
not max_items or total_item_count < max_items
):
- log.warning('Unexpected next offset: %s -> %s. Maybe the server-side collection has changed?',
- paging_info['item_count'], paging_info['next_offset'])
+ log.warning(
+ "Unexpected next offset: %s -> %s. Maybe the server-side collection has changed?",
+ paging_info["item_count"],
+ paging_info["next_offset"],
+ )
# Also break out of outer loop
if max_items and total_item_count >= max_items:
log.debug("'max_items' count reached (outer)")
@@ -796,11 +887,11 @@ Module exchangelib.services.common
@staticmethod
def _get_paging_values(elem):
"""Read paging information from the paging container element."""
- offset_attr = elem.get('IndexedPagingOffset')
+ offset_attr = elem.get("IndexedPagingOffset")
next_offset = None if offset_attr is None else int(offset_attr)
- item_count = int(elem.get('TotalItemsInView'))
- is_last_page = elem.get('IncludesLastItemInRange').lower() in ('true', '0')
- log.debug('Got page with offset %s, item_count %s, last_page %s', next_offset, item_count, is_last_page)
+ item_count = int(elem.get("TotalItemsInView"))
+ is_last_page = elem.get("IncludesLastItemInRange").lower() in ("true", "0")
+ log.debug("Got page with offset %s, item_count %s, last_page %s", next_offset, item_count, is_last_page)
# Clean up contradictory paging values
if next_offset is None and not is_last_page:
log.debug("Not last page in range, but server didn't send a page offset. Assuming first page")
@@ -831,7 +922,7 @@ Module exchangelib.services.common
container = elem.find(self.element_container_name)
if container is None:
raise MalformedResponseError(
- f'No {self.element_container_name} elements in ResponseMessage ({xml_to_str(elem)})'
+ f"No {self.element_container_name} elements in ResponseMessage ({xml_to_str(elem)})"
)
for e in self._get_elements_in_container(container=container):
if max_items and total_item_count >= max_items:
@@ -854,7 +945,7 @@ Module exchangelib.services.common
@staticmethod
def _get_next_offset(paging_infos):
- next_offsets = {p['next_offset'] for p in paging_infos if p['next_offset'] is not None}
+ next_offsets = {p["next_offset"] for p in paging_infos if p["next_offset"] is not None}
if not next_offsets:
# Paging is done for all messages
return None
@@ -866,7 +957,7 @@ Module exchangelib.services.common
# choose something that is most likely to work. Select the lowest of all the values to at least make sure
# we don't miss any items, although we may then get duplicates ¯\_(ツ)_/¯
if len(next_offsets) > 1:
- log.warning('Inconsistent next_offset values: %r. Using lowest value', next_offsets)
+ log.warning("Inconsistent next_offset values: %r. Using lowest value", next_offsets)
return min(next_offsets)
@@ -888,17 +979,18 @@ Module exchangelib.services.common
def shape_element(tag, shape, additional_fields, version):
shape_elem = create_element(tag)
- add_xml_child(shape_elem, 't:BaseShape', shape)
+ add_xml_child(shape_elem, "t:BaseShape", shape)
if additional_fields:
- additional_properties = create_element('t:AdditionalProperties')
+ additional_properties = create_element("t:AdditionalProperties")
expanded_fields = chain(*(f.expand(version=version) for f in additional_fields))
# 'path' is insufficient to consistently sort additional properties. For example, we have both
# 'contacts:Companies' and 'task:Companies' with path 'companies'. Sort by both 'field_uri' and 'path'.
# Extended properties do not have a 'field_uri' value.
- set_xml_value(additional_properties, sorted(
- expanded_fields,
- key=lambda f: (getattr(f.field, 'field_uri', ''), f.path)
- ), version=version)
+ set_xml_value(
+ additional_properties,
+ sorted(expanded_fields, key=lambda f: (getattr(f.field, "field_uri", ""), f.path)),
+ version=version,
+ )
shape_elem.append(additional_properties)
return shape_elem
@@ -910,15 +1002,15 @@ Module exchangelib.services.common
return item_ids
-def folder_ids_element(folders, version, tag='m:FolderIds'):
+def folder_ids_element(folders, version, tag="m:FolderIds"):
return _ids_element(folders, FolderId, version, tag)
-def item_ids_element(items, version, tag='m:ItemIds'):
+def item_ids_element(items, version, tag="m:ItemIds"):
return _ids_element(items, ItemId, version, tag)
-def attachment_ids_element(items, version, tag='m:AttachmentIds'):
+def attachment_ids_element(items, version, tag="m:AttachmentIds"):
return _ids_element(items, AttachmentId, version, tag)
@@ -934,7 +1026,7 @@ Module exchangelib.services.common
folder_cls = cls
break
else:
- raise ValueError(f'Unknown distinguished folder ID: {folder.id}')
+ raise ValueError(f"Unknown distinguished folder ID: {folder.id}")
f = folder_cls.from_xml_with_root(elem=elem, root=account.root)
else:
# 'folder' is a generic FolderId instance. We don't know the root so assume account.root.
@@ -962,7 +1054,7 @@ Functions
Expand source code
-def attachment_ids_element(items, version, tag='m:AttachmentIds'):
+def attachment_ids_element(items, version, tag="m:AttachmentIds"):
return _ids_element(items, AttachmentId, version, tag)
@@ -975,7 +1067,7 @@ Functions
Expand source code
-def folder_ids_element(folders, version, tag='m:FolderIds'):
+def folder_ids_element(folders, version, tag="m:FolderIds"):
return _ids_element(folders, FolderId, version, tag)
@@ -988,7 +1080,7 @@ Functions
Expand source code
-def item_ids_element(items, version, tag='m:ItemIds'):
+def item_ids_element(items, version, tag="m:ItemIds"):
return _ids_element(items, ItemId, version, tag)
@@ -1013,7 +1105,7 @@ Functions
folder_cls = cls
break
else:
- raise ValueError(f'Unknown distinguished folder ID: {folder.id}')
+ raise ValueError(f"Unknown distinguished folder ID: {folder.id}")
f = folder_cls.from_xml_with_root(elem=elem, root=account.root)
else:
# 'folder' is a generic FolderId instance. We don't know the root so assume account.root.
@@ -1036,17 +1128,18 @@ Functions
def shape_element(tag, shape, additional_fields, version):
shape_elem = create_element(tag)
- add_xml_child(shape_elem, 't:BaseShape', shape)
+ add_xml_child(shape_elem, "t:BaseShape", shape)
if additional_fields:
- additional_properties = create_element('t:AdditionalProperties')
+ additional_properties = create_element("t:AdditionalProperties")
expanded_fields = chain(*(f.expand(version=version) for f in additional_fields))
# 'path' is insufficient to consistently sort additional properties. For example, we have both
# 'contacts:Companies' and 'task:Companies' with path 'companies'. Sort by both 'field_uri' and 'path'.
# Extended properties do not have a 'field_uri' value.
- set_xml_value(additional_properties, sorted(
- expanded_fields,
- key=lambda f: (getattr(f.field, 'field_uri', ''), f.path)
- ), version=version)
+ set_xml_value(
+ additional_properties,
+ sorted(expanded_fields, key=lambda f: (getattr(f.field, "field_uri", ""), f.path)),
+ version=version,
+ )
shape_elem.append(additional_properties)
return shape_elem
@@ -1099,8 +1192,8 @@ Classes
prefer_affinity = False
def __init__(self, *args, **kwargs):
- self.account = kwargs.pop('account')
- kwargs['protocol'] = self.account.protocol
+ self.account = kwargs.pop("account")
+ kwargs["protocol"] = self.account.protocol
super().__init__(*args, **kwargs)
@property
@@ -1117,7 +1210,7 @@ Classes
# See self._extra_headers() for documentation on affinity
if self.prefer_affinity:
for cookie in session.cookies:
- if cookie.name == 'X-BackEndOverrideCookie':
+ if cookie.name == "X-BackEndOverrideCookie":
self.account.affinity_cookie = cookie.value
break
@@ -1125,14 +1218,14 @@ Classes
headers = super()._extra_headers(session=session)
# See
# https://blogs.msdn.microsoft.com/webdav_101/2015/05/11/best-practices-ews-authentication-and-access-issues/
- headers['X-AnchorMailbox'] = self.account.primary_smtp_address
+ headers["X-AnchorMailbox"] = self.account.primary_smtp_address
# See
# https://docs.microsoft.com/en-us/exchange/client-developer/exchange-web-services/how-to-maintain-affinity-between-group-of-subscriptions-and-mailbox-server
if self.prefer_affinity:
- headers['X-PreferServerAffinity'] = 'True'
+ headers["X-PreferServerAffinity"] = "True"
if self.account.affinity_cookie:
- headers['X-BackEndOverrideCookie'] = self.account.affinity_cookie
+ headers["X-BackEndOverrideCookie"] = self.account.affinity_cookie
return headers
@property
@@ -1214,9 +1307,9 @@ Inherited members
class EWSPagingService(EWSAccountService):
def __init__(self, *args, **kwargs):
- self.page_size = kwargs.pop('page_size', None) or PAGE_SIZE
+ self.page_size = kwargs.pop("page_size", None) or PAGE_SIZE
if not isinstance(self.page_size, int):
- raise InvalidTypeError('page_size', self.page_size, int)
+ raise InvalidTypeError("page_size", self.page_size, int)
if self.page_size < 1:
raise ValueError(f"'page_size' {self.page_size} must be a positive number")
super().__init__(*args, **kwargs)
@@ -1226,48 +1319,51 @@ Inherited members
all paging-related counters.
"""
paging_infos = {f: dict(item_count=0, next_offset=None) for f in folders}
- common_next_offset = kwargs['offset']
+ common_next_offset = kwargs["offset"]
total_item_count = 0
while True:
if not paging_infos:
# Paging is done for all folders
break
- log.debug('Getting page at offset %s (max_items %s)', common_next_offset, max_items)
- kwargs['offset'] = common_next_offset
- kwargs['folders'] = paging_infos.keys() # Only request the paging of the remaining folders.
+ log.debug("Getting page at offset %s (max_items %s)", common_next_offset, max_items)
+ kwargs["offset"] = common_next_offset
+ kwargs["folders"] = paging_infos.keys() # Only request the paging of the remaining folders.
pages = self._get_pages(payload_func, kwargs, len(paging_infos))
for (page, next_offset), (f, paging_info) in zip(pages, list(paging_infos.items())):
- paging_info['next_offset'] = next_offset
+ paging_info["next_offset"] = next_offset
if isinstance(page, Exception):
# Assume this folder no longer works. Don't attempt to page it again.
- log.debug('Exception occurred for folder %s. Removing.', f)
+ log.debug("Exception occurred for folder %s. Removing.", f)
del paging_infos[f]
yield page
continue
if page is not None:
for elem in self._get_elems_from_page(page, max_items, total_item_count):
- paging_info['item_count'] += 1
+ paging_info["item_count"] += 1
total_item_count += 1
yield elem
if max_items and total_item_count >= max_items:
# No need to continue. Break out of inner loop
log.debug("'max_items' count reached (inner)")
break
- if not paging_info['next_offset']:
+ if not paging_info["next_offset"]:
# Paging is done for this folder. Don't attempt to page it again.
- log.debug('Paging has completed for folder %s. Removing.', f)
+ log.debug("Paging has completed for folder %s. Removing.", f)
del paging_infos[f]
continue
- log.debug('Folder %s still has items', f)
+ log.debug("Folder %s still has items", f)
# Check sanity of paging offsets, but don't fail. When we are iterating huge collections that take a
# long time to complete, the collection may change while we are iterating. This can affect the
# 'next_offset' value and make it inconsistent with the number of already collected items.
# We may have a mismatch if we stopped early due to reaching 'max_items'.
- if paging_info['next_offset'] != paging_info['item_count'] and (
+ if paging_info["next_offset"] != paging_info["item_count"] and (
not max_items or total_item_count < max_items
):
- log.warning('Unexpected next offset: %s -> %s. Maybe the server-side collection has changed?',
- paging_info['item_count'], paging_info['next_offset'])
+ log.warning(
+ "Unexpected next offset: %s -> %s. Maybe the server-side collection has changed?",
+ paging_info["item_count"],
+ paging_info["next_offset"],
+ )
# Also break out of outer loop
if max_items and total_item_count >= max_items:
log.debug("'max_items' count reached (outer)")
@@ -1280,11 +1376,11 @@ Inherited members
@staticmethod
def _get_paging_values(elem):
"""Read paging information from the paging container element."""
- offset_attr = elem.get('IndexedPagingOffset')
+ offset_attr = elem.get("IndexedPagingOffset")
next_offset = None if offset_attr is None else int(offset_attr)
- item_count = int(elem.get('TotalItemsInView'))
- is_last_page = elem.get('IncludesLastItemInRange').lower() in ('true', '0')
- log.debug('Got page with offset %s, item_count %s, last_page %s', next_offset, item_count, is_last_page)
+ item_count = int(elem.get("TotalItemsInView"))
+ is_last_page = elem.get("IncludesLastItemInRange").lower() in ("true", "0")
+ log.debug("Got page with offset %s, item_count %s, last_page %s", next_offset, item_count, is_last_page)
# Clean up contradictory paging values
if next_offset is None and not is_last_page:
log.debug("Not last page in range, but server didn't send a page offset. Assuming first page")
@@ -1315,7 +1411,7 @@ Inherited members
container = elem.find(self.element_container_name)
if container is None:
raise MalformedResponseError(
- f'No {self.element_container_name} elements in ResponseMessage ({xml_to_str(elem)})'
+ f"No {self.element_container_name} elements in ResponseMessage ({xml_to_str(elem)})"
)
for e in self._get_elements_in_container(container=container):
if max_items and total_item_count >= max_items:
@@ -1338,7 +1434,7 @@ Inherited members
@staticmethod
def _get_next_offset(paging_infos):
- next_offsets = {p['next_offset'] for p in paging_infos if p['next_offset'] is not None}
+ next_offsets = {p["next_offset"] for p in paging_infos if p["next_offset"] is not None}
if not next_offsets:
# Paging is done for all messages
return None
@@ -1350,7 +1446,7 @@ Inherited members
# choose something that is most likely to work. Select the lowest of all the values to at least make sure
# we don't miss any items, although we may then get duplicates ¯\_(ツ)_/¯
if len(next_offsets) > 1:
- log.warning('Inconsistent next_offset values: %r. Using lowest value', next_offsets)
+ log.warning("Inconsistent next_offset values: %r. Using lowest value", next_offsets)
return min(next_offsets)
Ancestors
@@ -1396,9 +1492,18 @@ Inherited members
returns_elements = True # If False, the service does not return response elements, just the ResponseCode status
# Return exception instance instead of raising exceptions for the following errors when contained in an element
ERRORS_TO_CATCH_IN_RESPONSE = (
- EWSWarning, ErrorCannotDeleteObject, ErrorInvalidChangeKey, ErrorItemNotFound, ErrorItemSave,
- ErrorInvalidIdMalformed, ErrorMessageSizeExceeded, ErrorCannotDeleteTaskOccurrence,
- ErrorMimeContentConversionFailed, ErrorRecurrenceHasNoOccurrence, ErrorCorruptData
+ EWSWarning,
+ ErrorCannotDeleteObject,
+ ErrorInvalidChangeKey,
+ ErrorItemNotFound,
+ ErrorItemSave,
+ ErrorInvalidIdMalformed,
+ ErrorMessageSizeExceeded,
+ ErrorCannotDeleteTaskOccurrence,
+ ErrorMimeContentConversionFailed,
+ ErrorRecurrenceHasNoOccurrence,
+ ErrorCorruptData,
+ ErrorItemCorrupt,
)
# Similarly, define the warnings we want to return unraised
WARNINGS_TO_CATCH_IN_RESPONSE = ErrorBatchProcessingStopped
@@ -1414,13 +1519,13 @@ Inherited members
def __init__(self, protocol, chunk_size=None, timeout=None):
self.chunk_size = chunk_size or CHUNK_SIZE
if not isinstance(self.chunk_size, int):
- raise InvalidTypeError('chunk_size', chunk_size, int)
+ raise InvalidTypeError("chunk_size", chunk_size, int)
if self.chunk_size < 1:
raise ValueError(f"'chunk_size' {self.chunk_size} must be a positive number")
if self.supported_from and protocol.version.build < self.supported_from:
raise NotImplementedError(
- f'{self.SERVICE_NAME!r} is only supported on {self.supported_from.fullname()!r} and later. '
- f'Your current version is {protocol.version.build.fullname()!r}.'
+ f"{self.SERVICE_NAME!r} is only supported on {self.supported_from.fullname()!r} and later. "
+ f"Your current version is {protocol.version.build.fullname()!r}."
)
self.protocol = protocol
# Allow a service to override the default protocol timeout. Useful for streaming services
@@ -1431,6 +1536,16 @@ Inherited members
self._streaming_session = None
self._streaming_response = None
+ def __del__(self):
+ # pylint: disable=bare-except
+ try:
+ if self.streaming:
+ # Make sure to clean up lingering resources
+ self.stop_streaming()
+ except Exception: # nosec
+ # __del__ should never fail
+ pass
+
# The following two methods are the minimum required to be implemented by subclasses, but the name and number of
# kwargs differs between services. Therefore, we cannot make these methods abstract.
@@ -1466,10 +1581,10 @@ Inherited members
return None
if expect_result is False:
if res:
- raise ValueError(f'Expected result length 0, but got {res}')
+ raise ValueError(f"Expected result length 0, but got {res}")
return None
if len(res) != 1:
- raise ValueError(f'Expected result length 1, but got {res}')
+ raise ValueError(f"Expected result length 1, but got {res}")
return res[0]
def parse(self, xml):
@@ -1537,12 +1652,12 @@ Inherited members
# If the input for a service is a QuerySet, it can be difficult to remove exceptions before now
filtered_items = filter(lambda i: not isinstance(i, Exception), items)
for i, chunk in enumerate(chunkify(filtered_items, self.chunk_size), start=1):
- log.debug('Processing chunk %s containing %s items', i, len(chunk))
+ log.debug("Processing chunk %s containing %s items", i, len(chunk))
yield from self._get_elements(payload=payload_func(chunk, **kwargs))
def stop_streaming(self):
if not self.streaming:
- raise RuntimeError('Attempt to stop a non-streaming service')
+ raise RuntimeError("Attempt to stop a non-streaming service")
if self._streaming_response:
self._streaming_response.close() # Release memory
self._streaming_response = None
@@ -1579,11 +1694,11 @@ Inherited members
raise e
# Re-raise as an ErrorServerBusy with a default delay of 5 minutes
- raise ErrorServerBusy(f'Reraised from {e.__class__.__name__}({e})')
+ raise ErrorServerBusy(f"Reraised from {e.__class__.__name__}({e})")
except Exception:
# This may run in a thread, which obfuscates the stack trace. Print trace immediately.
account = self.account if isinstance(self, EWSAccountService) else None
- log.warning('Account %s: Exception in _get_elements: %s', account, traceback.format_exc(20))
+ log.warning("Account %s: Exception in _get_elements: %s", account, traceback.format_exc(20))
raise
finally:
if self.streaming:
@@ -1594,10 +1709,10 @@ Inherited members
def _get_response(self, payload, api_version):
"""Send the actual HTTP request and get the response."""
- session = self.protocol.get_session()
if self.streaming:
# Make sure to clean up lingering resources
self.stop_streaming()
+ session = self.protocol.get_session()
r, session = post_ratelimited(
protocol=self.protocol,
session=session,
@@ -1641,9 +1756,9 @@ Inherited members
# Microsoft really doesn't want to make our lives easy. The server may report one version in our initial version
# guessing tango, but then the server may decide that any arbitrary legacy backend server may actually process
# the request for an account. Prepare to handle version-related errors and set the server version per-account.
- log.debug('Calling service %s', self.SERVICE_NAME)
+ log.debug("Calling service %s", self.SERVICE_NAME)
for api_version in self._api_versions_to_try:
- log.debug('Trying API version %s', api_version)
+ log.debug("Trying API version %s", api_version)
r = self._get_response(payload=payload, api_version=api_version)
if self.streaming:
# Let 'requests' decode raw data automatically
@@ -1658,10 +1773,14 @@ Inherited members
self._update_api_version(api_version=api_version, header=header, **parse_opts)
try:
return self._get_soap_messages(body=body, **parse_opts)
- except (ErrorInvalidServerVersion, ErrorIncorrectSchemaVersion, ErrorInvalidRequest,
- ErrorInvalidSchemaVersionForMailboxVersion):
+ except (
+ ErrorInvalidServerVersion,
+ ErrorIncorrectSchemaVersion,
+ ErrorInvalidRequest,
+ ErrorInvalidSchemaVersionForMailboxVersion,
+ ):
# The guessed server version is wrong. Try the next version
- log.debug('API version %s was invalid', api_version)
+ log.debug("API version %s was invalid", api_version)
continue
except ErrorExceededConnectionCount as e:
# This indicates that the connecting user has too many open TCP connections to the server. Decrease
@@ -1677,7 +1796,7 @@ Inherited members
# In streaming mode, we may not have accessed the raw stream yet. Caller must handle this.
r.close() # Release memory
- raise self.NO_VALID_SERVER_VERSIONS(f'Tried versions {self._api_versions_to_try} but all were invalid')
+ raise self.NO_VALID_SERVER_VERSIONS(f"Tried versions {self._api_versions_to_try} but all were invalid")
def _handle_backoff(self, e):
"""Take a request from the server to back off and checks the retry policy for what to do. Re-raise the
@@ -1686,7 +1805,7 @@ Inherited members
:param e: An ErrorServerBusy instance
:return:
"""
- log.debug('Got ErrorServerBusy (back off %s seconds)', e.back_off)
+ log.debug("Got ErrorServerBusy (back off %s seconds)", e.back_off)
# ErrorServerBusy is very often a symptom of sending too many requests. Scale back connections if possible.
try:
self.protocol.decrease_poolsize()
@@ -1704,12 +1823,12 @@ Inherited members
try:
head_version = Version.from_soap_header(requested_api_version=api_version, header=header)
except TransportError as te:
- log.debug('Failed to update version info (%s)', te)
+ log.debug("Failed to update version info (%s)", te)
return
if self._version_hint == head_version:
# Nothing to do
return
- log.debug('Found new version (%s -> %s)', self._version_hint, head_version)
+ log.debug("Found new version (%s -> %s)", self._version_hint, head_version)
# The api_version that worked was different than our hint, or we never got a build version. Store the working
# version.
self._version_hint = head_version
@@ -1717,17 +1836,17 @@ Inherited members
@classmethod
def _response_tag(cls):
"""Return the name of the element containing the service response."""
- return f'{{{MNS}}}{cls.SERVICE_NAME}Response'
+ return f"{{{MNS}}}{cls.SERVICE_NAME}Response"
@staticmethod
def _response_messages_tag():
"""Return the name of the element containing service response messages."""
- return f'{{{MNS}}}ResponseMessages'
+ return f"{{{MNS}}}ResponseMessages"
@classmethod
def _response_message_tag(cls):
"""Return the name of the element of a single response message."""
- return f'{{{MNS}}}{cls.SERVICE_NAME}ResponseMessage'
+ return f"{{{MNS}}}{cls.SERVICE_NAME}ResponseMessage"
@classmethod
def _get_soap_parts(cls, response, **parse_opts):
@@ -1735,23 +1854,23 @@ Inherited members
try:
root = to_xml(response.iter_content())
except ParseError as e:
- raise SOAPError(f'Bad SOAP response: {e}')
- header = root.find(f'{{{SOAPNS}}}Header')
+ raise SOAPError(f"Bad SOAP response: {e}")
+ header = root.find(f"{{{SOAPNS}}}Header")
if header is None:
# This is normal when the response contains SOAP-level errors
- log.debug('No header in XML response')
- body = root.find(f'{{{SOAPNS}}}Body')
+ log.debug("No header in XML response")
+ body = root.find(f"{{{SOAPNS}}}Body")
if body is None:
- raise MalformedResponseError('No Body element in SOAP response')
+ raise MalformedResponseError("No Body element in SOAP response")
return header, body
def _get_soap_messages(self, body, **parse_opts):
"""Return the elements in the response containing the response messages. Raises any SOAP exceptions."""
response = body.find(self._response_tag())
if response is None:
- fault = body.find(f'{{{SOAPNS}}}Fault')
+ fault = body.find(f"{{{SOAPNS}}}Fault")
if fault is None:
- raise SOAPError(f'Unknown SOAP response (expected {self._response_tag()} or Fault): {xml_to_str(body)}')
+ raise SOAPError(f"Unknown SOAP response (expected {self._response_tag()} or Fault): {xml_to_str(body)}")
self._raise_soap_errors(fault=fault) # Will throw SOAPError or custom EWS error
response_messages = response.find(self._response_messages_tag())
if response_messages is None:
@@ -1764,43 +1883,43 @@ Inherited members
def _raise_soap_errors(cls, fault):
"""Parse error messages contained in SOAP headers and raise as exceptions defined in this package."""
# Fault: See http://www.w3.org/TR/2000/NOTE-SOAP-20000508/#_Toc478383507
- fault_code = get_xml_attr(fault, 'faultcode')
- fault_string = get_xml_attr(fault, 'faultstring')
- fault_actor = get_xml_attr(fault, 'faultactor')
- detail = fault.find('detail')
+ fault_code = get_xml_attr(fault, "faultcode")
+ fault_string = get_xml_attr(fault, "faultstring")
+ fault_actor = get_xml_attr(fault, "faultactor")
+ detail = fault.find("detail")
if detail is not None:
- code, msg = None, ''
- if detail.find(f'{{{ENS}}}ResponseCode') is not None:
- code = get_xml_attr(detail, f'{{{ENS}}}ResponseCode').strip()
- if detail.find(f'{{{ENS}}}Message') is not None:
- msg = get_xml_attr(detail, f'{{{ENS}}}Message').strip()
- msg_xml = detail.find(f'{{{TNS}}}MessageXml') # Crazy. Here, it's in the TNS namespace
- if code == 'ErrorServerBusy':
+ code, msg = None, ""
+ if detail.find(f"{{{ENS}}}ResponseCode") is not None:
+ code = get_xml_attr(detail, f"{{{ENS}}}ResponseCode").strip()
+ if detail.find(f"{{{ENS}}}Message") is not None:
+ msg = get_xml_attr(detail, f"{{{ENS}}}Message").strip()
+ msg_xml = detail.find(f"{{{TNS}}}MessageXml") # Crazy. Here, it's in the TNS namespace
+ if code == "ErrorServerBusy":
back_off = None
try:
- value = msg_xml.find(f'{{{TNS}}}Value')
- if value.get('Name') == 'BackOffMilliseconds':
+ value = msg_xml.find(f"{{{TNS}}}Value")
+ if value.get("Name") == "BackOffMilliseconds":
back_off = int(value.text) / 1000.0 # Convert to seconds
except (TypeError, AttributeError):
pass
raise ErrorServerBusy(msg, back_off=back_off)
- if code == 'ErrorSchemaValidation' and msg_xml is not None:
- line_number = get_xml_attr(msg_xml, f'{{{TNS}}}LineNumber')
- line_position = get_xml_attr(msg_xml, f'{{{TNS}}}LinePosition')
- violation = get_xml_attr(msg_xml, f'{{{TNS}}}Violation')
+ if code == "ErrorSchemaValidation" and msg_xml is not None:
+ line_number = get_xml_attr(msg_xml, f"{{{TNS}}}LineNumber")
+ line_position = get_xml_attr(msg_xml, f"{{{TNS}}}LinePosition")
+ violation = get_xml_attr(msg_xml, f"{{{TNS}}}Violation")
if violation:
- msg = f'{msg} {violation}'
+ msg = f"{msg} {violation}"
if line_number or line_position:
- msg = f'{msg} (line: {line_number} position: {line_position})'
+ msg = f"{msg} (line: {line_number} position: {line_position})"
try:
raise vars(errors)[code](msg)
except KeyError:
- detail = f'{cls.SERVICE_NAME}: code: {code} msg: {msg} ({xml_to_str(detail)})'
+ detail = f"{cls.SERVICE_NAME}: code: {code} msg: {msg} ({xml_to_str(detail)})"
try:
raise vars(errors)[fault_code](fault_string)
except KeyError:
pass
- raise SOAPError(f'SOAP error code: {fault_code} string: {fault_string} actor: {fault_actor} detail: {detail}')
+ raise SOAPError(f"SOAP error code: {fault_code} string: {fault_string} actor: {fault_actor} detail: {detail}")
def _get_element_container(self, message, name=None):
"""Return the XML element in a response element that contains the elements we want the service to return. For
@@ -1827,23 +1946,23 @@ Inherited members
# ResponseClass is an XML attribute of various SomeServiceResponseMessage elements: Possible values are:
# Success, Warning, Error. See e.g.
# https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/finditemresponsemessage
- response_class = message.get('ResponseClass')
+ response_class = message.get("ResponseClass")
# ResponseCode, MessageText: See
# https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/responsecode
- response_code = get_xml_attr(message, f'{{{MNS}}}ResponseCode')
- if response_class == 'Success' and response_code == 'NoError':
+ response_code = get_xml_attr(message, f"{{{MNS}}}ResponseCode")
+ if response_class == "Success" and response_code == "NoError":
if not name:
return message
container = message.find(name)
if container is None:
- raise MalformedResponseError(f'No {name} elements in ResponseMessage ({xml_to_str(message)})')
+ raise MalformedResponseError(f"No {name} elements in ResponseMessage ({xml_to_str(message)})")
return container
- if response_code == 'NoError':
+ if response_code == "NoError":
return True
# Raise any non-acceptable errors in the container, or return the container or the acceptable exception instance
- msg_text = get_xml_attr(message, f'{{{MNS}}}MessageText')
- msg_xml = message.find(f'{{{MNS}}}MessageXml')
- if response_class == 'Warning':
+ msg_text = get_xml_attr(message, f"{{{MNS}}}MessageText")
+ msg_xml = message.find(f"{{{MNS}}}MessageXml")
+ if response_class == "Warning":
try:
raise self._get_exception(code=response_code, text=msg_text, msg_xml=msg_xml)
except self.WARNINGS_TO_CATCH_IN_RESPONSE as e:
@@ -1852,7 +1971,7 @@ Inherited members
log.warning(str(e))
container = message.find(name)
if container is None:
- raise MalformedResponseError(f'No {name} elements in ResponseMessage ({xml_to_str(message)})')
+ raise MalformedResponseError(f"No {name} elements in ResponseMessage ({xml_to_str(message)})")
return container
# rspclass == 'Error', or 'Success' and not 'NoError'
try:
@@ -1864,21 +1983,21 @@ Inherited members
def _get_exception(code, text, msg_xml):
"""Parse error messages contained in EWS responses and raise as exceptions defined in this package."""
if not code:
- return TransportError(f'Empty ResponseCode in ResponseMessage (MessageText: {text}, MessageXml: {msg_xml})')
+ return TransportError(f"Empty ResponseCode in ResponseMessage (MessageText: {text}, MessageXml: {msg_xml})")
if msg_xml is not None:
# If this is an ErrorInvalidPropertyRequest error, the xml may contain a specific FieldURI
for elem_cls in (FieldURI, IndexedFieldURI, ExtendedFieldURI, ExceptionFieldURI):
elem = msg_xml.find(elem_cls.response_tag())
if elem is not None:
field_uri = elem_cls.from_xml(elem, account=None)
- text += f' (field: {field_uri})'
+ text += f" (field: {field_uri})"
break
# If this is an ErrorInvalidValueForProperty error, the xml may contain the name and value of the property
- if code == 'ErrorInvalidValueForProperty':
+ if code == "ErrorInvalidValueForProperty":
msg_parts = {}
- for elem in msg_xml.findall(f'{{{TNS}}}Value'):
- key, val = elem.get('Name'), elem.text
+ for elem in msg_xml.findall(f"{{{TNS}}}Value"):
+ key, val = elem.get("Name"), elem.text
if key:
msg_parts[key] = val
if msg_parts:
@@ -1886,26 +2005,26 @@ Inherited members
# If this is an ErrorInternalServerError error, the xml may contain a more specific error code
inner_code, inner_text = None, None
- for value_elem in msg_xml.findall(f'{{{TNS}}}Value'):
- name = value_elem.get('Name')
- if name == 'InnerErrorResponseCode':
+ for value_elem in msg_xml.findall(f"{{{TNS}}}Value"):
+ name = value_elem.get("Name")
+ if name == "InnerErrorResponseCode":
inner_code = value_elem.text
- elif name == 'InnerErrorMessageText':
+ elif name == "InnerErrorMessageText":
inner_text = value_elem.text
if inner_code:
try:
# Raise the error as the inner error code
- return vars(errors)[inner_code](f'{inner_text} (raised from: {code}({text!r}))')
+ return vars(errors)[inner_code](f"{inner_text} (raised from: {code}({text!r}))")
except KeyError:
# Inner code is unknown to us. Just append to the original text
- text += f' (inner error: {inner_code}({inner_text!r}))'
+ text += f" (inner error: {inner_code}({inner_text!r}))"
try:
# Raise the error corresponding to the ResponseCode
return vars(errors)[code](text)
except KeyError:
# Should not happen
return TransportError(
- f'Unknown ResponseCode in ResponseMessage: {code} (MessageText: {text}, MessageXml: {msg_xml})'
+ f"Unknown ResponseCode in ResponseMessage: {code} (MessageText: {text}, MessageXml: {msg_xml})"
)
def _get_elements_in_response(self, response):
@@ -2049,10 +2168,10 @@ Methods
return None
if expect_result is False:
if res:
- raise ValueError(f'Expected result length 0, but got {res}')
+ raise ValueError(f"Expected result length 0, but got {res}")
return None
if len(res) != 1:
- raise ValueError(f'Expected result length 1, but got {res}')
+ raise ValueError(f"Expected result length 1, but got {res}")
return res[0]
@@ -2083,7 +2202,7 @@ Methods
def stop_streaming(self):
if not self.streaming:
- raise RuntimeError('Attempt to stop a non-streaming service')
+ raise RuntimeError("Attempt to stop a non-streaming service")
if self._streaming_response:
self._streaming_response.close() # Release memory
self._streaming_response = None
diff --git a/docs/exchangelib/services/convert_id.html b/docs/exchangelib/services/convert_id.html
index 392fb764..12f2f4bd 100644
--- a/docs/exchangelib/services/convert_id.html
+++ b/docs/exchangelib/services/convert_id.html
@@ -26,11 +26,11 @@ Module exchangelib.services.convert_id
Expand source code
-from .common import EWSService
-from ..errors import InvalidEnumValue, InvalidTypeError
-from ..properties import AlternateId, AlternatePublicFolderId, AlternatePublicFolderItemId, ID_FORMATS
+from ..errors import InvalidEnumValue, InvalidTypeError
+from ..properties import ID_FORMATS, AlternateId, AlternatePublicFolderId, AlternatePublicFolderItemId
from ..util import create_element, set_xml_value
from ..version import EXCHANGE_2007_SP1
+from .common import EWSService
class ConvertId(EWSService):
@@ -40,15 +40,13 @@ Module exchangelib.services.convert_id
MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/convertid-operation
"""
- SERVICE_NAME = 'ConvertId'
+ SERVICE_NAME = "ConvertId"
supported_from = EXCHANGE_2007_SP1
- cls_map = {cls.response_tag(): cls for cls in (
- AlternateId, AlternatePublicFolderId, AlternatePublicFolderItemId
- )}
+ cls_map = {cls.response_tag(): cls for cls in (AlternateId, AlternatePublicFolderId, AlternatePublicFolderItemId)}
def call(self, items, destination_format):
if destination_format not in ID_FORMATS:
- raise InvalidEnumValue('destination_format', destination_format, ID_FORMATS)
+ raise InvalidEnumValue("destination_format", destination_format, ID_FORMATS)
return self._elems_to_objs(
self._chunked_get_elements(self.get_payload, items=items, destination_format=destination_format)
)
@@ -58,11 +56,11 @@ Module exchangelib.services.convert_id
def get_payload(self, items, destination_format):
supported_item_classes = AlternateId, AlternatePublicFolderId, AlternatePublicFolderItemId
- payload = create_element(f'm:{self.SERVICE_NAME}', attrs=dict(DestinationFormat=destination_format))
- item_ids = create_element('m:SourceIds')
+ payload = create_element(f"m:{self.SERVICE_NAME}", attrs=dict(DestinationFormat=destination_format))
+ item_ids = create_element("m:SourceIds")
for item in items:
if not isinstance(item, supported_item_classes):
- raise InvalidTypeError('item', item, supported_item_classes)
+ raise InvalidTypeError("item", item, supported_item_classes)
set_xml_value(item_ids, item, version=self.protocol.version)
payload.append(item_ids)
return payload
@@ -70,9 +68,11 @@ Module exchangelib.services.convert_id
@classmethod
def _get_elements_in_container(cls, container):
# We may have other elements in here, e.g. 'ResponseCode'. Filter away those.
- return container.findall(AlternateId.response_tag()) \
- + container.findall(AlternatePublicFolderId.response_tag()) \
- + container.findall(AlternatePublicFolderItemId.response_tag())
+ return (
+ container.findall(AlternateId.response_tag())
+ + container.findall(AlternatePublicFolderId.response_tag())
+ + container.findall(AlternatePublicFolderItemId.response_tag())
+ )
@@ -103,15 +103,13 @@ Classes
MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/convertid-operation
"""
- SERVICE_NAME = 'ConvertId'
+ SERVICE_NAME = "ConvertId"
supported_from = EXCHANGE_2007_SP1
- cls_map = {cls.response_tag(): cls for cls in (
- AlternateId, AlternatePublicFolderId, AlternatePublicFolderItemId
- )}
+ cls_map = {cls.response_tag(): cls for cls in (AlternateId, AlternatePublicFolderId, AlternatePublicFolderItemId)}
def call(self, items, destination_format):
if destination_format not in ID_FORMATS:
- raise InvalidEnumValue('destination_format', destination_format, ID_FORMATS)
+ raise InvalidEnumValue("destination_format", destination_format, ID_FORMATS)
return self._elems_to_objs(
self._chunked_get_elements(self.get_payload, items=items, destination_format=destination_format)
)
@@ -121,11 +119,11 @@ Classes
def get_payload(self, items, destination_format):
supported_item_classes = AlternateId, AlternatePublicFolderId, AlternatePublicFolderItemId
- payload = create_element(f'm:{self.SERVICE_NAME}', attrs=dict(DestinationFormat=destination_format))
- item_ids = create_element('m:SourceIds')
+ payload = create_element(f"m:{self.SERVICE_NAME}", attrs=dict(DestinationFormat=destination_format))
+ item_ids = create_element("m:SourceIds")
for item in items:
if not isinstance(item, supported_item_classes):
- raise InvalidTypeError('item', item, supported_item_classes)
+ raise InvalidTypeError("item", item, supported_item_classes)
set_xml_value(item_ids, item, version=self.protocol.version)
payload.append(item_ids)
return payload
@@ -133,9 +131,11 @@ Classes
@classmethod
def _get_elements_in_container(cls, container):
# We may have other elements in here, e.g. 'ResponseCode'. Filter away those.
- return container.findall(AlternateId.response_tag()) \
- + container.findall(AlternatePublicFolderId.response_tag()) \
- + container.findall(AlternatePublicFolderItemId.response_tag())
+ return (
+ container.findall(AlternateId.response_tag())
+ + container.findall(AlternatePublicFolderId.response_tag())
+ + container.findall(AlternatePublicFolderItemId.response_tag())
+ )
Ancestors
@@ -169,7 +169,7 @@ Methods
def call(self, items, destination_format):
if destination_format not in ID_FORMATS:
- raise InvalidEnumValue('destination_format', destination_format, ID_FORMATS)
+ raise InvalidEnumValue("destination_format", destination_format, ID_FORMATS)
return self._elems_to_objs(
self._chunked_get_elements(self.get_payload, items=items, destination_format=destination_format)
)
@@ -186,11 +186,11 @@ Methods
def get_payload(self, items, destination_format):
supported_item_classes = AlternateId, AlternatePublicFolderId, AlternatePublicFolderItemId
- payload = create_element(f'm:{self.SERVICE_NAME}', attrs=dict(DestinationFormat=destination_format))
- item_ids = create_element('m:SourceIds')
+ payload = create_element(f"m:{self.SERVICE_NAME}", attrs=dict(DestinationFormat=destination_format))
+ item_ids = create_element("m:SourceIds")
for item in items:
if not isinstance(item, supported_item_classes):
- raise InvalidTypeError('item', item, supported_item_classes)
+ raise InvalidTypeError("item", item, supported_item_classes)
set_xml_value(item_ids, item, version=self.protocol.version)
payload.append(item_ids)
return payload
diff --git a/docs/exchangelib/services/copy_item.html b/docs/exchangelib/services/copy_item.html
index 903219c7..8dcad32e 100644
--- a/docs/exchangelib/services/copy_item.html
+++ b/docs/exchangelib/services/copy_item.html
@@ -32,7 +32,7 @@ Module exchangelib.services.copy_item
class CopyItem(move_item.MoveItem):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/copyitem-operation"""
- SERVICE_NAME = 'CopyItem'
+ SERVICE_NAME = "CopyItem"
class CopyItem(move_item.MoveItem):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/copyitem-operation"""
- SERVICE_NAME = 'CopyItem'
+ SERVICE_NAME = "CopyItem"
exchangelib.services.create_attachment
from .common import EWSAccountService, to_item_id
-from ..attachments import FileAttachment, ItemAttachment
+from ..attachments import FileAttachment, ItemAttachment
from ..items import BaseItem
from ..properties import ParentItemId
-from ..util import create_element, set_xml_value, MNS
+from ..util import MNS, create_element, set_xml_value
+from .common import EWSAccountService, to_item_id
class CreateAttachment(EWSAccountService):
@@ -38,8 +38,8 @@ Module exchangelib.services.create_attachment
Module exchangelib.services.create_attachment
Classes
https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/createattachment-operation
"""
- SERVICE_NAME = 'CreateAttachment'
- element_container_name = f'{{{MNS}}}Attachments'
+ SERVICE_NAME = "CreateAttachment"
+ element_container_name = f"{{{MNS}}}Attachments"
cls_map = {cls.response_tag(): cls for cls in (FileAttachment, ItemAttachment)}
def call(self, parent_item, items):
@@ -98,13 +98,13 @@ Classes
return self.cls_map[elem.tag].from_xml(elem=elem, account=self.account)
def get_payload(self, items, parent_item):
- payload = create_element(f'm:{self.SERVICE_NAME}')
+ payload = create_element(f"m:{self.SERVICE_NAME}")
version = self.account.version
if isinstance(parent_item, BaseItem):
# to_item_id() would convert this to a normal ItemId, but the service wants a ParentItemId
parent_item = ParentItemId(parent_item.id, parent_item.changekey)
set_xml_value(payload, to_item_id(parent_item, ParentItemId), version=self.account.version)
- attachments = create_element('m:Attachments')
+ attachments = create_element("m:Attachments")
for item in items:
set_xml_value(attachments, item, version=version)
payload.append(attachments)
@@ -155,13 +155,13 @@ Methods
Expand source code
def get_payload(self, items, parent_item):
- payload = create_element(f'm:{self.SERVICE_NAME}')
+ payload = create_element(f"m:{self.SERVICE_NAME}")
version = self.account.version
if isinstance(parent_item, BaseItem):
# to_item_id() would convert this to a normal ItemId, but the service wants a ParentItemId
parent_item = ParentItemId(parent_item.id, parent_item.changekey)
set_xml_value(payload, to_item_id(parent_item, ParentItemId), version=self.account.version)
- attachments = create_element('m:Attachments')
+ attachments = create_element("m:Attachments")
for item in items:
set_xml_value(attachments, item, version=version)
payload.append(attachments)
diff --git a/docs/exchangelib/services/create_folder.html b/docs/exchangelib/services/create_folder.html
index 7122a1b9..23eb3d65 100644
--- a/docs/exchangelib/services/create_folder.html
+++ b/docs/exchangelib/services/create_folder.html
@@ -26,19 +26,17 @@ Module exchangelib.services.create_folder
Expand source code
-from .common import EWSAccountService, parse_folder_elem, folder_ids_element
-from ..errors import ErrorFolderExists
-from ..util import create_element, MNS
+from ..errors import ErrorFolderExists
+from ..util import MNS, create_element
+from .common import EWSAccountService, folder_ids_element, parse_folder_elem
class CreateFolder(EWSAccountService):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/createfolder-operation"""
- SERVICE_NAME = 'CreateFolder'
- element_container_name = f'{{{MNS}}}Folders'
- ERRORS_TO_CATCH_IN_RESPONSE = EWSAccountService.ERRORS_TO_CATCH_IN_RESPONSE + (
- ErrorFolderExists,
- )
+ SERVICE_NAME = "CreateFolder"
+ element_container_name = f"{{{MNS}}}Folders"
+ ERRORS_TO_CATCH_IN_RESPONSE = EWSAccountService.ERRORS_TO_CATCH_IN_RESPONSE + (ErrorFolderExists,)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
@@ -48,9 +46,13 @@ Module exchangelib.services.create_folder
# We can't easily find the correct folder class from the returned XML. Instead, return objects with the same
# class as the folder instance it was requested with.
self.folders = list(folders) # Convert to a list, in case 'folders' is a generator. We're iterating twice.
- return self._elems_to_objs(self._chunked_get_elements(
- self.get_payload, items=self.folders, parent_folder=parent_folder,
- ))
+ return self._elems_to_objs(
+ self._chunked_get_elements(
+ self.get_payload,
+ items=self.folders,
+ parent_folder=parent_folder,
+ )
+ )
def _elems_to_objs(self, elems):
for folder, elem in zip(self.folders, elems):
@@ -60,11 +62,11 @@ Module exchangelib.services.create_folder
yield parse_folder_elem(elem=elem, folder=folder, account=self.account)
def get_payload(self, folders, parent_folder):
- payload = create_element(f'm:{self.SERVICE_NAME}')
+ payload = create_element(f"m:{self.SERVICE_NAME}")
payload.append(
- folder_ids_element(folders=[parent_folder], version=self.account.version, tag='m:ParentFolderId')
+ folder_ids_element(folders=[parent_folder], version=self.account.version, tag="m:ParentFolderId")
)
- payload.append(folder_ids_element(folders=folders, version=self.account.version, tag='m:Folders'))
+ payload.append(folder_ids_element(folders=folders, version=self.account.version, tag="m:Folders"))
return payload
class CreateFolder(EWSAccountService):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/createfolder-operation"""
- SERVICE_NAME = 'CreateFolder'
- element_container_name = f'{{{MNS}}}Folders'
- ERRORS_TO_CATCH_IN_RESPONSE = EWSAccountService.ERRORS_TO_CATCH_IN_RESPONSE + (
- ErrorFolderExists,
- )
+ SERVICE_NAME = "CreateFolder"
+ element_container_name = f"{{{MNS}}}Folders"
+ ERRORS_TO_CATCH_IN_RESPONSE = EWSAccountService.ERRORS_TO_CATCH_IN_RESPONSE + (ErrorFolderExists,)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
@@ -104,9 +104,13 @@ Classes
# We can't easily find the correct folder class from the returned XML. Instead, return objects with the same
# class as the folder instance it was requested with.
self.folders = list(folders) # Convert to a list, in case 'folders' is a generator. We're iterating twice.
- return self._elems_to_objs(self._chunked_get_elements(
- self.get_payload, items=self.folders, parent_folder=parent_folder,
- ))
+ return self._elems_to_objs(
+ self._chunked_get_elements(
+ self.get_payload,
+ items=self.folders,
+ parent_folder=parent_folder,
+ )
+ )
def _elems_to_objs(self, elems):
for folder, elem in zip(self.folders, elems):
@@ -116,11 +120,11 @@ Classes
yield parse_folder_elem(elem=elem, folder=folder, account=self.account)
def get_payload(self, folders, parent_folder):
- payload = create_element(f'm:{self.SERVICE_NAME}')
+ payload = create_element(f"m:{self.SERVICE_NAME}")
payload.append(
- folder_ids_element(folders=[parent_folder], version=self.account.version, tag='m:ParentFolderId')
+ folder_ids_element(folders=[parent_folder], version=self.account.version, tag="m:ParentFolderId")
)
- payload.append(folder_ids_element(folders=folders, version=self.account.version, tag='m:Folders'))
+ payload.append(folder_ids_element(folders=folders, version=self.account.version, tag="m:Folders"))
return payload
@@ -173,11 +181,11 @@ Methods
Expand source code
def get_payload(self, folders, parent_folder):
- payload = create_element(f'm:{self.SERVICE_NAME}')
+ payload = create_element(f"m:{self.SERVICE_NAME}")
payload.append(
- folder_ids_element(folders=[parent_folder], version=self.account.version, tag='m:ParentFolderId')
+ folder_ids_element(folders=[parent_folder], version=self.account.version, tag="m:ParentFolderId")
)
- payload.append(folder_ids_element(folders=folders, version=self.account.version, tag='m:Folders'))
+ payload.append(folder_ids_element(folders=folders, version=self.account.version, tag="m:Folders"))
return payload
diff --git a/docs/exchangelib/services/create_item.html b/docs/exchangelib/services/create_item.html
index 88a944d0..09529f6e 100644
--- a/docs/exchangelib/services/create_item.html
+++ b/docs/exchangelib/services/create_item.html
@@ -26,13 +26,19 @@ Module exchangelib.services.create_item
Expand source code
-from .common import EWSAccountService, folder_ids_element
-from ..errors import InvalidEnumValue, InvalidTypeError
+from ..errors import InvalidEnumValue, InvalidTypeError
from ..folders import BaseFolder
-from ..items import SAVE_ONLY, SEND_AND_SAVE_COPY, SEND_ONLY, \
- SEND_MEETING_INVITATIONS_CHOICES, MESSAGE_DISPOSITION_CHOICES, BulkCreateResult
+from ..items import (
+ MESSAGE_DISPOSITION_CHOICES,
+ SAVE_ONLY,
+ SEND_AND_SAVE_COPY,
+ SEND_MEETING_INVITATIONS_CHOICES,
+ SEND_ONLY,
+ BulkCreateResult,
+)
from ..properties import FolderId
-from ..util import create_element, set_xml_value, MNS
+from ..util import MNS, create_element, set_xml_value
+from .common import EWSAccountService, folder_ids_element
class CreateItem(EWSAccountService):
@@ -42,34 +48,36 @@ Module exchangelib.services.create_item
MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/createitem-operation
"""
- SERVICE_NAME = 'CreateItem'
- element_container_name = f'{{{MNS}}}Items'
+ SERVICE_NAME = "CreateItem"
+ element_container_name = f"{{{MNS}}}Items"
def call(self, items, folder, message_disposition, send_meeting_invitations):
if message_disposition not in MESSAGE_DISPOSITION_CHOICES:
- raise InvalidEnumValue('message_disposition', message_disposition, MESSAGE_DISPOSITION_CHOICES)
+ raise InvalidEnumValue("message_disposition", message_disposition, MESSAGE_DISPOSITION_CHOICES)
if send_meeting_invitations not in SEND_MEETING_INVITATIONS_CHOICES:
raise InvalidEnumValue(
- 'send_meeting_invitations', send_meeting_invitations, SEND_MEETING_INVITATIONS_CHOICES
+ "send_meeting_invitations", send_meeting_invitations, SEND_MEETING_INVITATIONS_CHOICES
)
if folder is not None:
if not isinstance(folder, (BaseFolder, FolderId)):
- raise InvalidTypeError('folder', folder, (BaseFolder, FolderId))
+ raise InvalidTypeError("folder", folder, (BaseFolder, FolderId))
if folder.account != self.account:
- raise ValueError('Folder must belong to account')
+ raise ValueError("Folder must belong to account")
if message_disposition == SAVE_ONLY and folder is None:
raise AttributeError("Folder must be supplied when in save-only mode")
if message_disposition == SEND_AND_SAVE_COPY and folder is None:
folder = self.account.sent # 'Sent' is default EWS behaviour
if message_disposition == SEND_ONLY and folder is not None:
raise AttributeError("Folder must be None in send-ony mode")
- return self._elems_to_objs(self._chunked_get_elements(
- self.get_payload,
- items=items,
- folder=folder,
- message_disposition=message_disposition,
- send_meeting_invitations=send_meeting_invitations,
- ))
+ return self._elems_to_objs(
+ self._chunked_get_elements(
+ self.get_payload,
+ items=items,
+ folder=folder,
+ message_disposition=message_disposition,
+ send_meeting_invitations=send_meeting_invitations,
+ )
+ )
def _elem_to_obj(self, elem):
if isinstance(elem, bool):
@@ -101,14 +109,14 @@ Module exchangelib.services.create_item
:param send_meeting_invitations:
"""
payload = create_element(
- f'm:{self.SERVICE_NAME}',
- attrs=dict(MessageDisposition=message_disposition, SendMeetingInvitations=send_meeting_invitations)
+ f"m:{self.SERVICE_NAME}",
+ attrs=dict(MessageDisposition=message_disposition, SendMeetingInvitations=send_meeting_invitations),
)
if folder:
- payload.append(folder_ids_element(
- folders=[folder], version=self.account.version, tag='m:SavedItemFolderId'
- ))
- item_elems = create_element('m:Items')
+ payload.append(
+ folder_ids_element(folders=[folder], version=self.account.version, tag="m:SavedItemFolderId")
+ )
+ item_elems = create_element("m:Items")
for item in items:
if not item.account:
item.account = self.account
@@ -145,34 +153,36 @@ Classes
MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/createitem-operation
"""
- SERVICE_NAME = 'CreateItem'
- element_container_name = f'{{{MNS}}}Items'
+ SERVICE_NAME = "CreateItem"
+ element_container_name = f"{{{MNS}}}Items"
def call(self, items, folder, message_disposition, send_meeting_invitations):
if message_disposition not in MESSAGE_DISPOSITION_CHOICES:
- raise InvalidEnumValue('message_disposition', message_disposition, MESSAGE_DISPOSITION_CHOICES)
+ raise InvalidEnumValue("message_disposition", message_disposition, MESSAGE_DISPOSITION_CHOICES)
if send_meeting_invitations not in SEND_MEETING_INVITATIONS_CHOICES:
raise InvalidEnumValue(
- 'send_meeting_invitations', send_meeting_invitations, SEND_MEETING_INVITATIONS_CHOICES
+ "send_meeting_invitations", send_meeting_invitations, SEND_MEETING_INVITATIONS_CHOICES
)
if folder is not None:
if not isinstance(folder, (BaseFolder, FolderId)):
- raise InvalidTypeError('folder', folder, (BaseFolder, FolderId))
+ raise InvalidTypeError("folder", folder, (BaseFolder, FolderId))
if folder.account != self.account:
- raise ValueError('Folder must belong to account')
+ raise ValueError("Folder must belong to account")
if message_disposition == SAVE_ONLY and folder is None:
raise AttributeError("Folder must be supplied when in save-only mode")
if message_disposition == SEND_AND_SAVE_COPY and folder is None:
folder = self.account.sent # 'Sent' is default EWS behaviour
if message_disposition == SEND_ONLY and folder is not None:
raise AttributeError("Folder must be None in send-ony mode")
- return self._elems_to_objs(self._chunked_get_elements(
- self.get_payload,
- items=items,
- folder=folder,
- message_disposition=message_disposition,
- send_meeting_invitations=send_meeting_invitations,
- ))
+ return self._elems_to_objs(
+ self._chunked_get_elements(
+ self.get_payload,
+ items=items,
+ folder=folder,
+ message_disposition=message_disposition,
+ send_meeting_invitations=send_meeting_invitations,
+ )
+ )
def _elem_to_obj(self, elem):
if isinstance(elem, bool):
@@ -204,14 +214,14 @@ Classes
:param send_meeting_invitations:
"""
payload = create_element(
- f'm:{self.SERVICE_NAME}',
- attrs=dict(MessageDisposition=message_disposition, SendMeetingInvitations=send_meeting_invitations)
+ f"m:{self.SERVICE_NAME}",
+ attrs=dict(MessageDisposition=message_disposition, SendMeetingInvitations=send_meeting_invitations),
)
if folder:
- payload.append(folder_ids_element(
- folders=[folder], version=self.account.version, tag='m:SavedItemFolderId'
- ))
- item_elems = create_element('m:Items')
+ payload.append(
+ folder_ids_element(folders=[folder], version=self.account.version, tag="m:SavedItemFolderId")
+ )
+ item_elems = create_element("m:Items")
for item in items:
if not item.account:
item.account = self.account
@@ -248,29 +258,31 @@ Methods
def call(self, items, folder, message_disposition, send_meeting_invitations):
if message_disposition not in MESSAGE_DISPOSITION_CHOICES:
- raise InvalidEnumValue('message_disposition', message_disposition, MESSAGE_DISPOSITION_CHOICES)
+ raise InvalidEnumValue("message_disposition", message_disposition, MESSAGE_DISPOSITION_CHOICES)
if send_meeting_invitations not in SEND_MEETING_INVITATIONS_CHOICES:
raise InvalidEnumValue(
- 'send_meeting_invitations', send_meeting_invitations, SEND_MEETING_INVITATIONS_CHOICES
+ "send_meeting_invitations", send_meeting_invitations, SEND_MEETING_INVITATIONS_CHOICES
)
if folder is not None:
if not isinstance(folder, (BaseFolder, FolderId)):
- raise InvalidTypeError('folder', folder, (BaseFolder, FolderId))
+ raise InvalidTypeError("folder", folder, (BaseFolder, FolderId))
if folder.account != self.account:
- raise ValueError('Folder must belong to account')
+ raise ValueError("Folder must belong to account")
if message_disposition == SAVE_ONLY and folder is None:
raise AttributeError("Folder must be supplied when in save-only mode")
if message_disposition == SEND_AND_SAVE_COPY and folder is None:
folder = self.account.sent # 'Sent' is default EWS behaviour
if message_disposition == SEND_ONLY and folder is not None:
raise AttributeError("Folder must be None in send-ony mode")
- return self._elems_to_objs(self._chunked_get_elements(
- self.get_payload,
- items=items,
- folder=folder,
- message_disposition=message_disposition,
- send_meeting_invitations=send_meeting_invitations,
- ))
+ return self._elems_to_objs(
+ self._chunked_get_elements(
+ self.get_payload,
+ items=items,
+ folder=folder,
+ message_disposition=message_disposition,
+ send_meeting_invitations=send_meeting_invitations,
+ )
+ )
@@ -315,14 +327,14 @@ Methods
:param send_meeting_invitations:
"""
payload = create_element(
- f'm:{self.SERVICE_NAME}',
- attrs=dict(MessageDisposition=message_disposition, SendMeetingInvitations=send_meeting_invitations)
+ f"m:{self.SERVICE_NAME}",
+ attrs=dict(MessageDisposition=message_disposition, SendMeetingInvitations=send_meeting_invitations),
)
if folder:
- payload.append(folder_ids_element(
- folders=[folder], version=self.account.version, tag='m:SavedItemFolderId'
- ))
- item_elems = create_element('m:Items')
+ payload.append(
+ folder_ids_element(folders=[folder], version=self.account.version, tag="m:SavedItemFolderId")
+ )
+ item_elems = create_element("m:Items")
for item in items:
if not item.account:
item.account = self.account
diff --git a/docs/exchangelib/services/create_user_configuration.html b/docs/exchangelib/services/create_user_configuration.html
index 81b66f16..5db8b917 100644
--- a/docs/exchangelib/services/create_user_configuration.html
+++ b/docs/exchangelib/services/create_user_configuration.html
@@ -26,8 +26,8 @@ Module exchangelib.services.create_user_configuration
Expand source code
-from .common import EWSAccountService
-from ..util import create_element, set_xml_value
+from ..util import create_element, set_xml_value
+from .common import EWSAccountService
class CreateUserConfiguration(EWSAccountService):
@@ -35,7 +35,7 @@ Module exchangelib.services.create_user_configurationModule exchangelib.services.create_user_configuration
@@ -72,7 +72,7 @@ Classes
https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/createuserconfiguration-operation
"""
- SERVICE_NAME = 'CreateUserConfiguration'
+ SERVICE_NAME = "CreateUserConfiguration"
returns_elements = False
def call(self, user_configuration):
@@ -80,7 +80,7 @@ Classes
def get_payload(self, user_configuration):
return set_xml_value(
- create_element(f'm:{self.SERVICE_NAME}'), user_configuration, version=self.protocol.version
+ create_element(f"m:{self.SERVICE_NAME}"), user_configuration, version=self.protocol.version
)
Ancestors
@@ -125,7 +125,7 @@ Methods
def get_payload(self, user_configuration):
return set_xml_value(
- create_element(f'm:{self.SERVICE_NAME}'), user_configuration, version=self.protocol.version
+ create_element(f"m:{self.SERVICE_NAME}"), user_configuration, version=self.protocol.version
)
diff --git a/docs/exchangelib/services/delete_attachment.html b/docs/exchangelib/services/delete_attachment.html
index 093df9cb..9585face 100644
--- a/docs/exchangelib/services/delete_attachment.html
+++ b/docs/exchangelib/services/delete_attachment.html
@@ -26,9 +26,9 @@ Module exchangelib.services.delete_attachment
Expand source code
-from .common import EWSAccountService, attachment_ids_element
-from ..properties import RootItemId
+from ..properties import RootItemId
from ..util import create_element, set_xml_value
+from .common import EWSAccountService, attachment_ids_element
class DeleteAttachment(EWSAccountService):
@@ -36,7 +36,7 @@ Module exchangelib.services.delete_attachment
Module exchangelib.services.delete_attachment
@@ -81,7 +81,7 @@ Classes
https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/deleteattachment-operation
"""
- SERVICE_NAME = 'DeleteAttachment'
+ SERVICE_NAME = "DeleteAttachment"
def call(self, items):
return self._elems_to_objs(self._chunked_get_elements(self.get_payload, items=items))
@@ -95,9 +95,9 @@ Classes
def get_payload(self, items):
return set_xml_value(
- create_element(f'm:{self.SERVICE_NAME}'),
+ create_element(f"m:{self.SERVICE_NAME}"),
attachment_ids_element(items=items, version=self.account.version),
- version=self.account.version
+ version=self.account.version,
)
def get_payload(self, items):
return set_xml_value(
- create_element(f'm:{self.SERVICE_NAME}'),
+ create_element(f"m:{self.SERVICE_NAME}"),
attachment_ids_element(items=items, version=self.account.version),
- version=self.account.version
+ version=self.account.version,
)
diff --git a/docs/exchangelib/services/delete_folder.html b/docs/exchangelib/services/delete_folder.html
index 50875946..1df70f09 100644
--- a/docs/exchangelib/services/delete_folder.html
+++ b/docs/exchangelib/services/delete_folder.html
@@ -26,25 +26,25 @@ exchangelib.services.delete_folder
from .common import EWSAccountService, folder_ids_element
-from ..errors import InvalidEnumValue
+from ..errors import InvalidEnumValue
from ..items import DELETE_TYPE_CHOICES
from ..util import create_element
+from .common import EWSAccountService, folder_ids_element
class DeleteFolder(EWSAccountService):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/deletefolder-operation"""
- SERVICE_NAME = 'DeleteFolder'
+ SERVICE_NAME = "DeleteFolder"
returns_elements = False
def call(self, folders, delete_type):
if delete_type not in DELETE_TYPE_CHOICES:
- raise InvalidEnumValue('delete_type', delete_type, DELETE_TYPE_CHOICES)
+ raise InvalidEnumValue("delete_type", delete_type, DELETE_TYPE_CHOICES)
return self._chunked_get_elements(self.get_payload, items=folders, delete_type=delete_type)
def get_payload(self, folders, delete_type):
- payload = create_element(f'm:{self.SERVICE_NAME}', attrs=dict(DeleteType=delete_type))
+ payload = create_element(f"m:{self.SERVICE_NAME}", attrs=dict(DeleteType=delete_type))
payload.append(folder_ids_element(folders=folders, version=self.account.version))
return payload
@@ -71,16 +71,16 @@ Classes
class DeleteFolder(EWSAccountService):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/deletefolder-operation"""
- SERVICE_NAME = 'DeleteFolder'
+ SERVICE_NAME = "DeleteFolder"
returns_elements = False
def call(self, folders, delete_type):
if delete_type not in DELETE_TYPE_CHOICES:
- raise InvalidEnumValue('delete_type', delete_type, DELETE_TYPE_CHOICES)
+ raise InvalidEnumValue("delete_type", delete_type, DELETE_TYPE_CHOICES)
return self._chunked_get_elements(self.get_payload, items=folders, delete_type=delete_type)
def get_payload(self, folders, delete_type):
- payload = create_element(f'm:{self.SERVICE_NAME}', attrs=dict(DeleteType=delete_type))
+ payload = create_element(f"m:{self.SERVICE_NAME}", attrs=dict(DeleteType=delete_type))
payload.append(folder_ids_element(folders=folders, version=self.account.version))
return payload
@@ -113,7 +113,7 @@ Methods
def call(self, folders, delete_type):
if delete_type not in DELETE_TYPE_CHOICES:
- raise InvalidEnumValue('delete_type', delete_type, DELETE_TYPE_CHOICES)
+ raise InvalidEnumValue("delete_type", delete_type, DELETE_TYPE_CHOICES)
return self._chunked_get_elements(self.get_payload, items=folders, delete_type=delete_type)
@@ -127,7 +127,7 @@ Methods
Expand source code
def get_payload(self, folders, delete_type):
- payload = create_element(f'm:{self.SERVICE_NAME}', attrs=dict(DeleteType=delete_type))
+ payload = create_element(f"m:{self.SERVICE_NAME}", attrs=dict(DeleteType=delete_type))
payload.append(folder_ids_element(folders=folders, version=self.account.version))
return payload
diff --git a/docs/exchangelib/services/delete_item.html b/docs/exchangelib/services/delete_item.html
index c5e1af14..6cc6ebb3 100644
--- a/docs/exchangelib/services/delete_item.html
+++ b/docs/exchangelib/services/delete_item.html
@@ -26,11 +26,11 @@ Module exchangelib.services.delete_item
Expand source code
-from .common import EWSAccountService, item_ids_element
-from ..errors import InvalidEnumValue
-from ..items import DELETE_TYPE_CHOICES, SEND_MEETING_CANCELLATIONS_CHOICES, AFFECTED_TASK_OCCURRENCES_CHOICES
+from ..errors import InvalidEnumValue
+from ..items import AFFECTED_TASK_OCCURRENCES_CHOICES, DELETE_TYPE_CHOICES, SEND_MEETING_CANCELLATIONS_CHOICES
from ..util import create_element
from ..version import EXCHANGE_2013_SP1
+from .common import EWSAccountService, item_ids_element
class DeleteItem(EWSAccountService):
@@ -40,19 +40,19 @@ Module exchangelib.services.delete_item
MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/deleteitem-operation
"""
- SERVICE_NAME = 'DeleteItem'
+ SERVICE_NAME = "DeleteItem"
returns_elements = False
def call(self, items, delete_type, send_meeting_cancellations, affected_task_occurrences, suppress_read_receipts):
if delete_type not in DELETE_TYPE_CHOICES:
- raise InvalidEnumValue('delete_type', delete_type, DELETE_TYPE_CHOICES)
+ raise InvalidEnumValue("delete_type", delete_type, DELETE_TYPE_CHOICES)
if send_meeting_cancellations not in SEND_MEETING_CANCELLATIONS_CHOICES:
raise InvalidEnumValue(
- 'send_meeting_cancellations', send_meeting_cancellations, SEND_MEETING_CANCELLATIONS_CHOICES
+ "send_meeting_cancellations", send_meeting_cancellations, SEND_MEETING_CANCELLATIONS_CHOICES
)
if affected_task_occurrences not in AFFECTED_TASK_OCCURRENCES_CHOICES:
raise InvalidEnumValue(
- 'affected_task_occurrences', affected_task_occurrences, AFFECTED_TASK_OCCURRENCES_CHOICES
+ "affected_task_occurrences", affected_task_occurrences, AFFECTED_TASK_OCCURRENCES_CHOICES
)
return self._chunked_get_elements(
self.get_payload,
@@ -63,8 +63,9 @@ Module exchangelib.services.delete_item
suppress_read_receipts=suppress_read_receipts,
)
- def get_payload(self, items, delete_type, send_meeting_cancellations, affected_task_occurrences,
- suppress_read_receipts):
+ def get_payload(
+ self, items, delete_type, send_meeting_cancellations, affected_task_occurrences, suppress_read_receipts
+ ):
# Takes a list of (id, changekey) tuples or Item objects and returns the XML for a DeleteItem request.
attrs = dict(
DeleteType=delete_type,
@@ -72,8 +73,8 @@ Module exchangelib.services.delete_item
AffectedTaskOccurrences=affected_task_occurrences,
)
if self.account.version.build >= EXCHANGE_2013_SP1:
- attrs['SuppressReadReceipts'] = suppress_read_receipts
- payload = create_element(f'm:{self.SERVICE_NAME}', attrs=attrs)
+ attrs["SuppressReadReceipts"] = suppress_read_receipts
+ payload = create_element(f"m:{self.SERVICE_NAME}", attrs=attrs)
payload.append(item_ids_element(items=items, version=self.account.version))
return payload
@@ -106,19 +107,19 @@ Classes
MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/deleteitem-operation
"""
- SERVICE_NAME = 'DeleteItem'
+ SERVICE_NAME = "DeleteItem"
returns_elements = False
def call(self, items, delete_type, send_meeting_cancellations, affected_task_occurrences, suppress_read_receipts):
if delete_type not in DELETE_TYPE_CHOICES:
- raise InvalidEnumValue('delete_type', delete_type, DELETE_TYPE_CHOICES)
+ raise InvalidEnumValue("delete_type", delete_type, DELETE_TYPE_CHOICES)
if send_meeting_cancellations not in SEND_MEETING_CANCELLATIONS_CHOICES:
raise InvalidEnumValue(
- 'send_meeting_cancellations', send_meeting_cancellations, SEND_MEETING_CANCELLATIONS_CHOICES
+ "send_meeting_cancellations", send_meeting_cancellations, SEND_MEETING_CANCELLATIONS_CHOICES
)
if affected_task_occurrences not in AFFECTED_TASK_OCCURRENCES_CHOICES:
raise InvalidEnumValue(
- 'affected_task_occurrences', affected_task_occurrences, AFFECTED_TASK_OCCURRENCES_CHOICES
+ "affected_task_occurrences", affected_task_occurrences, AFFECTED_TASK_OCCURRENCES_CHOICES
)
return self._chunked_get_elements(
self.get_payload,
@@ -129,8 +130,9 @@ Classes
suppress_read_receipts=suppress_read_receipts,
)
- def get_payload(self, items, delete_type, send_meeting_cancellations, affected_task_occurrences,
- suppress_read_receipts):
+ def get_payload(
+ self, items, delete_type, send_meeting_cancellations, affected_task_occurrences, suppress_read_receipts
+ ):
# Takes a list of (id, changekey) tuples or Item objects and returns the XML for a DeleteItem request.
attrs = dict(
DeleteType=delete_type,
@@ -138,8 +140,8 @@ Classes
AffectedTaskOccurrences=affected_task_occurrences,
)
if self.account.version.build >= EXCHANGE_2013_SP1:
- attrs['SuppressReadReceipts'] = suppress_read_receipts
- payload = create_element(f'm:{self.SERVICE_NAME}', attrs=attrs)
+ attrs["SuppressReadReceipts"] = suppress_read_receipts
+ payload = create_element(f"m:{self.SERVICE_NAME}", attrs=attrs)
payload.append(item_ids_element(items=items, version=self.account.version))
return payload
@@ -172,14 +174,14 @@ Methods
def call(self, items, delete_type, send_meeting_cancellations, affected_task_occurrences, suppress_read_receipts):
if delete_type not in DELETE_TYPE_CHOICES:
- raise InvalidEnumValue('delete_type', delete_type, DELETE_TYPE_CHOICES)
+ raise InvalidEnumValue("delete_type", delete_type, DELETE_TYPE_CHOICES)
if send_meeting_cancellations not in SEND_MEETING_CANCELLATIONS_CHOICES:
raise InvalidEnumValue(
- 'send_meeting_cancellations', send_meeting_cancellations, SEND_MEETING_CANCELLATIONS_CHOICES
+ "send_meeting_cancellations", send_meeting_cancellations, SEND_MEETING_CANCELLATIONS_CHOICES
)
if affected_task_occurrences not in AFFECTED_TASK_OCCURRENCES_CHOICES:
raise InvalidEnumValue(
- 'affected_task_occurrences', affected_task_occurrences, AFFECTED_TASK_OCCURRENCES_CHOICES
+ "affected_task_occurrences", affected_task_occurrences, AFFECTED_TASK_OCCURRENCES_CHOICES
)
return self._chunked_get_elements(
self.get_payload,
@@ -200,8 +202,9 @@ Methods
Expand source code
-def get_payload(self, items, delete_type, send_meeting_cancellations, affected_task_occurrences,
- suppress_read_receipts):
+def get_payload(
+ self, items, delete_type, send_meeting_cancellations, affected_task_occurrences, suppress_read_receipts
+):
# Takes a list of (id, changekey) tuples or Item objects and returns the XML for a DeleteItem request.
attrs = dict(
DeleteType=delete_type,
@@ -209,8 +212,8 @@ Methods
AffectedTaskOccurrences=affected_task_occurrences,
)
if self.account.version.build >= EXCHANGE_2013_SP1:
- attrs['SuppressReadReceipts'] = suppress_read_receipts
- payload = create_element(f'm:{self.SERVICE_NAME}', attrs=attrs)
+ attrs["SuppressReadReceipts"] = suppress_read_receipts
+ payload = create_element(f"m:{self.SERVICE_NAME}", attrs=attrs)
payload.append(item_ids_element(items=items, version=self.account.version))
return payload
diff --git a/docs/exchangelib/services/delete_user_configuration.html b/docs/exchangelib/services/delete_user_configuration.html
index 33ed2fe1..176ffd43 100644
--- a/docs/exchangelib/services/delete_user_configuration.html
+++ b/docs/exchangelib/services/delete_user_configuration.html
@@ -26,8 +26,8 @@ Module exchangelib.services.delete_user_configuration
Expand source code
-from .common import EWSAccountService
-from ..util import create_element, set_xml_value
+from ..util import create_element, set_xml_value
+from .common import EWSAccountService
class DeleteUserConfiguration(EWSAccountService):
@@ -35,7 +35,7 @@ Module exchangelib.services.delete_user_configurationModule exchangelib.services.delete_user_configuration
@@ -72,7 +72,7 @@ Classes
https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/deleteuserconfiguration-operation
"""
- SERVICE_NAME = 'DeleteUserConfiguration'
+ SERVICE_NAME = "DeleteUserConfiguration"
returns_elements = False
def call(self, user_configuration_name):
@@ -80,7 +80,7 @@ Classes
def get_payload(self, user_configuration_name):
return set_xml_value(
- create_element(f'm:{self.SERVICE_NAME}'), user_configuration_name, version=self.account.version
+ create_element(f"m:{self.SERVICE_NAME}"), user_configuration_name, version=self.account.version
)
Ancestors
@@ -125,7 +125,7 @@ Methods
def get_payload(self, user_configuration_name):
return set_xml_value(
- create_element(f'm:{self.SERVICE_NAME}'), user_configuration_name, version=self.account.version
+ create_element(f"m:{self.SERVICE_NAME}"), user_configuration_name, version=self.account.version
)
diff --git a/docs/exchangelib/services/empty_folder.html b/docs/exchangelib/services/empty_folder.html
index b52a63cb..caf06dc0 100644
--- a/docs/exchangelib/services/empty_folder.html
+++ b/docs/exchangelib/services/empty_folder.html
@@ -26,29 +26,28 @@ Module exchangelib.services.empty_folder
Expand source code
-from .common import EWSAccountService, folder_ids_element
-from ..errors import InvalidEnumValue
+from ..errors import InvalidEnumValue
from ..items import DELETE_TYPE_CHOICES
from ..util import create_element
+from .common import EWSAccountService, folder_ids_element
class EmptyFolder(EWSAccountService):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/emptyfolder-operation"""
- SERVICE_NAME = 'EmptyFolder'
+ SERVICE_NAME = "EmptyFolder"
returns_elements = False
def call(self, folders, delete_type, delete_sub_folders):
if delete_type not in DELETE_TYPE_CHOICES:
- raise InvalidEnumValue('delete_type', delete_type, DELETE_TYPE_CHOICES)
+ raise InvalidEnumValue("delete_type", delete_type, DELETE_TYPE_CHOICES)
return self._chunked_get_elements(
self.get_payload, items=folders, delete_type=delete_type, delete_sub_folders=delete_sub_folders
)
def get_payload(self, folders, delete_type, delete_sub_folders):
payload = create_element(
- f'm:{self.SERVICE_NAME}',
- attrs=dict(DeleteType=delete_type, DeleteSubFolders=delete_sub_folders)
+ f"m:{self.SERVICE_NAME}", attrs=dict(DeleteType=delete_type, DeleteSubFolders=delete_sub_folders)
)
payload.append(folder_ids_element(folders=folders, version=self.account.version))
return payload
@@ -76,20 +75,19 @@ Classes
class EmptyFolder(EWSAccountService):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/emptyfolder-operation"""
- SERVICE_NAME = 'EmptyFolder'
+ SERVICE_NAME = "EmptyFolder"
returns_elements = False
def call(self, folders, delete_type, delete_sub_folders):
if delete_type not in DELETE_TYPE_CHOICES:
- raise InvalidEnumValue('delete_type', delete_type, DELETE_TYPE_CHOICES)
+ raise InvalidEnumValue("delete_type", delete_type, DELETE_TYPE_CHOICES)
return self._chunked_get_elements(
self.get_payload, items=folders, delete_type=delete_type, delete_sub_folders=delete_sub_folders
)
def get_payload(self, folders, delete_type, delete_sub_folders):
payload = create_element(
- f'm:{self.SERVICE_NAME}',
- attrs=dict(DeleteType=delete_type, DeleteSubFolders=delete_sub_folders)
+ f"m:{self.SERVICE_NAME}", attrs=dict(DeleteType=delete_type, DeleteSubFolders=delete_sub_folders)
)
payload.append(folder_ids_element(folders=folders, version=self.account.version))
return payload
@@ -123,7 +121,7 @@ Methods
def call(self, folders, delete_type, delete_sub_folders):
if delete_type not in DELETE_TYPE_CHOICES:
- raise InvalidEnumValue('delete_type', delete_type, DELETE_TYPE_CHOICES)
+ raise InvalidEnumValue("delete_type", delete_type, DELETE_TYPE_CHOICES)
return self._chunked_get_elements(
self.get_payload, items=folders, delete_type=delete_type, delete_sub_folders=delete_sub_folders
)
@@ -140,8 +138,7 @@ Methods
def get_payload(self, folders, delete_type, delete_sub_folders):
payload = create_element(
- f'm:{self.SERVICE_NAME}',
- attrs=dict(DeleteType=delete_type, DeleteSubFolders=delete_sub_folders)
+ f"m:{self.SERVICE_NAME}", attrs=dict(DeleteType=delete_type, DeleteSubFolders=delete_sub_folders)
)
payload.append(folder_ids_element(folders=folders, version=self.account.version))
return payload
diff --git a/docs/exchangelib/services/expand_dl.html b/docs/exchangelib/services/expand_dl.html
index c0591b64..9aea3d8b 100644
--- a/docs/exchangelib/services/expand_dl.html
+++ b/docs/exchangelib/services/expand_dl.html
@@ -26,17 +26,17 @@ Module exchangelib.services.expand_dl
Expand source code
-from .common import EWSService
-from ..errors import ErrorNameResolutionMultipleResults
+from ..errors import ErrorNameResolutionMultipleResults
from ..properties import Mailbox
-from ..util import create_element, set_xml_value, MNS
+from ..util import MNS, create_element, set_xml_value
+from .common import EWSService
class ExpandDL(EWSService):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/expanddl-operation"""
- SERVICE_NAME = 'ExpandDL'
- element_container_name = f'{{{MNS}}}DLExpansion'
+ SERVICE_NAME = "ExpandDL"
+ element_container_name = f"{{{MNS}}}DLExpansion"
WARNINGS_TO_IGNORE_IN_RESPONSE = ErrorNameResolutionMultipleResults
def call(self, distribution_list):
@@ -46,7 +46,7 @@ Module exchangelib.services.expand_dl
return Mailbox.from_xml(elem, account=None)
def get_payload(self, distribution_list):
- return set_xml_value(create_element(f'm:{self.SERVICE_NAME}'), distribution_list, version=self.protocol.version)
+ return set_xml_value(create_element(f"m:{self.SERVICE_NAME}"), distribution_list, version=self.protocol.version)
@@ -71,8 +71,8 @@ Classes
class ExpandDL(EWSService):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/expanddl-operation"""
- SERVICE_NAME = 'ExpandDL'
- element_container_name = f'{{{MNS}}}DLExpansion'
+ SERVICE_NAME = "ExpandDL"
+ element_container_name = f"{{{MNS}}}DLExpansion"
WARNINGS_TO_IGNORE_IN_RESPONSE = ErrorNameResolutionMultipleResults
def call(self, distribution_list):
@@ -82,7 +82,7 @@ Classes
return Mailbox.from_xml(elem, account=None)
def get_payload(self, distribution_list):
- return set_xml_value(create_element(f'm:{self.SERVICE_NAME}'), distribution_list, version=self.protocol.version)
+ return set_xml_value(create_element(f"m:{self.SERVICE_NAME}"), distribution_list, version=self.protocol.version)
Ancestors
@@ -128,7 +128,7 @@ Methods
Expand source code
def get_payload(self, distribution_list):
- return set_xml_value(create_element(f'm:{self.SERVICE_NAME}'), distribution_list, version=self.protocol.version)
+ return set_xml_value(create_element(f"m:{self.SERVICE_NAME}"), distribution_list, version=self.protocol.version)
diff --git a/docs/exchangelib/services/export_items.html b/docs/exchangelib/services/export_items.html
index 9e93423b..1c36ae71 100644
--- a/docs/exchangelib/services/export_items.html
+++ b/docs/exchangelib/services/export_items.html
@@ -26,17 +26,17 @@ Module exchangelib.services.export_items
Expand source code
-from .common import EWSAccountService, item_ids_element
-from ..errors import ResponseMessageError
-from ..util import create_element, MNS
+from ..errors import ResponseMessageError
+from ..util import MNS, create_element
+from .common import EWSAccountService, item_ids_element
class ExportItems(EWSAccountService):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/exportitems-operation"""
ERRORS_TO_CATCH_IN_RESPONSE = ResponseMessageError
- SERVICE_NAME = 'ExportItems'
- element_container_name = f'{{{MNS}}}Data'
+ SERVICE_NAME = "ExportItems"
+ element_container_name = f"{{{MNS}}}Data"
def call(self, items):
return self._elems_to_objs(self._chunked_get_elements(self.get_payload, items=items))
@@ -45,7 +45,7 @@ Module exchangelib.services.export_items
return elem.text # All we want is the 64bit string in the 'Data' tag
def get_payload(self, items):
- payload = create_element(f'm:{self.SERVICE_NAME}')
+ payload = create_element(f"m:{self.SERVICE_NAME}")
payload.append(item_ids_element(items=items, version=self.account.version))
return payload
@@ -79,8 +79,8 @@ Classes
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/exportitems-operation"""
ERRORS_TO_CATCH_IN_RESPONSE = ResponseMessageError
- SERVICE_NAME = 'ExportItems'
- element_container_name = f'{{{MNS}}}Data'
+ SERVICE_NAME = "ExportItems"
+ element_container_name = f"{{{MNS}}}Data"
def call(self, items):
return self._elems_to_objs(self._chunked_get_elements(self.get_payload, items=items))
@@ -89,7 +89,7 @@ Classes
return elem.text # All we want is the 64bit string in the 'Data' tag
def get_payload(self, items):
- payload = create_element(f'm:{self.SERVICE_NAME}')
+ payload = create_element(f"m:{self.SERVICE_NAME}")
payload.append(item_ids_element(items=items, version=self.account.version))
return payload
@@ -144,7 +144,7 @@ Methods
Expand source code
def get_payload(self, items):
- payload = create_element(f'm:{self.SERVICE_NAME}')
+ payload = create_element(f"m:{self.SERVICE_NAME}")
payload.append(item_ids_element(items=items, version=self.account.version))
return payload
diff --git a/docs/exchangelib/services/find_folder.html b/docs/exchangelib/services/find_folder.html
index 24912407..0f728f8e 100644
--- a/docs/exchangelib/services/find_folder.html
+++ b/docs/exchangelib/services/find_folder.html
@@ -26,21 +26,21 @@ Module exchangelib.services.find_folder
Expand source code
-from .common import EWSPagingService, shape_element, folder_ids_element
-from ..errors import InvalidEnumValue
+from ..errors import InvalidEnumValue
from ..folders import Folder
from ..folders.queryset import FOLDER_TRAVERSAL_CHOICES
from ..items import SHAPE_CHOICES
-from ..util import create_element, TNS, MNS
+from ..util import MNS, TNS, create_element
from ..version import EXCHANGE_2010
+from .common import EWSPagingService, folder_ids_element, shape_element
class FindFolder(EWSPagingService):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/findfolder-operation"""
- SERVICE_NAME = 'FindFolder'
- element_container_name = f'{{{TNS}}}Folders'
- paging_container_name = f'{{{MNS}}}RootFolder'
+ SERVICE_NAME = "FindFolder"
+ element_container_name = f"{{{TNS}}}Folders"
+ paging_container_name = f"{{{MNS}}}RootFolder"
supports_paging = True
def __init__(self, *args, **kwargs):
@@ -61,14 +61,15 @@ Module exchangelib.services.find_folder
:return: XML elements for the matching folders
"""
if shape not in SHAPE_CHOICES:
- raise InvalidEnumValue('shape', shape, SHAPE_CHOICES)
+ raise InvalidEnumValue("shape", shape, SHAPE_CHOICES)
if depth not in FOLDER_TRAVERSAL_CHOICES:
- raise InvalidEnumValue('depth', depth, FOLDER_TRAVERSAL_CHOICES)
+ raise InvalidEnumValue("depth", depth, FOLDER_TRAVERSAL_CHOICES)
roots = {f.root for f in folders}
if len(roots) != 1:
raise ValueError(f"All folders in 'roots' must have the same root hierarchy ({roots})")
self.root = roots.pop()
- return self._elems_to_objs(self._paged_call(
+ return self._elems_to_objs(
+ self._paged_call(
payload_func=self.get_payload,
max_items=max_items,
folders=folders,
@@ -79,21 +80,24 @@ Module exchangelib.services.find_folder
depth=depth,
page_size=self.page_size,
offset=offset,
- )
- ))
+ ),
+ )
+ )
def _elem_to_obj(self, elem):
return Folder.from_xml_with_root(elem=elem, root=self.root)
def get_payload(self, folders, additional_fields, restriction, shape, depth, page_size, offset=0):
- payload = create_element(f'm:{self.SERVICE_NAME}', attrs=dict(Traversal=depth))
- payload.append(shape_element(
- tag='m:FolderShape', shape=shape, additional_fields=additional_fields, version=self.account.version
- ))
+ payload = create_element(f"m:{self.SERVICE_NAME}", attrs=dict(Traversal=depth))
+ payload.append(
+ shape_element(
+ tag="m:FolderShape", shape=shape, additional_fields=additional_fields, version=self.account.version
+ )
+ )
if self.account.version.build >= EXCHANGE_2010:
indexed_page_folder_view = create_element(
- 'm:IndexedPageFolderView',
- attrs=dict(MaxEntriesReturned=page_size, Offset=offset, BasePoint='Beginning')
+ "m:IndexedPageFolderView",
+ attrs=dict(MaxEntriesReturned=page_size, Offset=offset, BasePoint="Beginning"),
)
payload.append(indexed_page_folder_view)
else:
@@ -101,7 +105,7 @@ Module exchangelib.services.find_folder
raise NotImplementedError("'offset' is only supported for Exchange 2010 servers and later")
if restriction:
payload.append(restriction.to_xml(version=self.account.version))
- payload.append(folder_ids_element(folders=folders, version=self.protocol.version, tag='m:ParentFolderIds'))
+ payload.append(folder_ids_element(folders=folders, version=self.protocol.version, tag="m:ParentFolderIds"))
return payload
@@ -127,9 +131,9 @@ Classes
class FindFolder(EWSPagingService):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/findfolder-operation"""
- SERVICE_NAME = 'FindFolder'
- element_container_name = f'{{{TNS}}}Folders'
- paging_container_name = f'{{{MNS}}}RootFolder'
+ SERVICE_NAME = "FindFolder"
+ element_container_name = f"{{{TNS}}}Folders"
+ paging_container_name = f"{{{MNS}}}RootFolder"
supports_paging = True
def __init__(self, *args, **kwargs):
@@ -150,14 +154,15 @@ Classes
:return: XML elements for the matching folders
"""
if shape not in SHAPE_CHOICES:
- raise InvalidEnumValue('shape', shape, SHAPE_CHOICES)
+ raise InvalidEnumValue("shape", shape, SHAPE_CHOICES)
if depth not in FOLDER_TRAVERSAL_CHOICES:
- raise InvalidEnumValue('depth', depth, FOLDER_TRAVERSAL_CHOICES)
+ raise InvalidEnumValue("depth", depth, FOLDER_TRAVERSAL_CHOICES)
roots = {f.root for f in folders}
if len(roots) != 1:
raise ValueError(f"All folders in 'roots' must have the same root hierarchy ({roots})")
self.root = roots.pop()
- return self._elems_to_objs(self._paged_call(
+ return self._elems_to_objs(
+ self._paged_call(
payload_func=self.get_payload,
max_items=max_items,
folders=folders,
@@ -168,21 +173,24 @@ Classes
depth=depth,
page_size=self.page_size,
offset=offset,
- )
- ))
+ ),
+ )
+ )
def _elem_to_obj(self, elem):
return Folder.from_xml_with_root(elem=elem, root=self.root)
def get_payload(self, folders, additional_fields, restriction, shape, depth, page_size, offset=0):
- payload = create_element(f'm:{self.SERVICE_NAME}', attrs=dict(Traversal=depth))
- payload.append(shape_element(
- tag='m:FolderShape', shape=shape, additional_fields=additional_fields, version=self.account.version
- ))
+ payload = create_element(f"m:{self.SERVICE_NAME}", attrs=dict(Traversal=depth))
+ payload.append(
+ shape_element(
+ tag="m:FolderShape", shape=shape, additional_fields=additional_fields, version=self.account.version
+ )
+ )
if self.account.version.build >= EXCHANGE_2010:
indexed_page_folder_view = create_element(
- 'm:IndexedPageFolderView',
- attrs=dict(MaxEntriesReturned=page_size, Offset=offset, BasePoint='Beginning')
+ "m:IndexedPageFolderView",
+ attrs=dict(MaxEntriesReturned=page_size, Offset=offset, BasePoint="Beginning"),
)
payload.append(indexed_page_folder_view)
else:
@@ -190,7 +198,7 @@ Classes
raise NotImplementedError("'offset' is only supported for Exchange 2010 servers and later")
if restriction:
payload.append(restriction.to_xml(version=self.account.version))
- payload.append(folder_ids_element(folders=folders, version=self.protocol.version, tag='m:ParentFolderIds'))
+ payload.append(folder_ids_element(folders=folders, version=self.protocol.version, tag="m:ParentFolderIds"))
return payload
Ancestors
@@ -251,14 +259,15 @@ Methods
:return: XML elements for the matching folders
"""
if shape not in SHAPE_CHOICES:
- raise InvalidEnumValue('shape', shape, SHAPE_CHOICES)
+ raise InvalidEnumValue("shape", shape, SHAPE_CHOICES)
if depth not in FOLDER_TRAVERSAL_CHOICES:
- raise InvalidEnumValue('depth', depth, FOLDER_TRAVERSAL_CHOICES)
+ raise InvalidEnumValue("depth", depth, FOLDER_TRAVERSAL_CHOICES)
roots = {f.root for f in folders}
if len(roots) != 1:
raise ValueError(f"All folders in 'roots' must have the same root hierarchy ({roots})")
self.root = roots.pop()
- return self._elems_to_objs(self._paged_call(
+ return self._elems_to_objs(
+ self._paged_call(
payload_func=self.get_payload,
max_items=max_items,
folders=folders,
@@ -269,8 +278,9 @@ Methods
depth=depth,
page_size=self.page_size,
offset=offset,
- )
- ))
+ ),
+ )
+ )
@@ -283,14 +293,16 @@ Methods
Expand source code
def get_payload(self, folders, additional_fields, restriction, shape, depth, page_size, offset=0):
- payload = create_element(f'm:{self.SERVICE_NAME}', attrs=dict(Traversal=depth))
- payload.append(shape_element(
- tag='m:FolderShape', shape=shape, additional_fields=additional_fields, version=self.account.version
- ))
+ payload = create_element(f"m:{self.SERVICE_NAME}", attrs=dict(Traversal=depth))
+ payload.append(
+ shape_element(
+ tag="m:FolderShape", shape=shape, additional_fields=additional_fields, version=self.account.version
+ )
+ )
if self.account.version.build >= EXCHANGE_2010:
indexed_page_folder_view = create_element(
- 'm:IndexedPageFolderView',
- attrs=dict(MaxEntriesReturned=page_size, Offset=offset, BasePoint='Beginning')
+ "m:IndexedPageFolderView",
+ attrs=dict(MaxEntriesReturned=page_size, Offset=offset, BasePoint="Beginning"),
)
payload.append(indexed_page_folder_view)
else:
@@ -298,7 +310,7 @@ Methods
raise NotImplementedError("'offset' is only supported for Exchange 2010 servers and later")
if restriction:
payload.append(restriction.to_xml(version=self.account.version))
- payload.append(folder_ids_element(folders=folders, version=self.protocol.version, tag='m:ParentFolderIds'))
+ payload.append(folder_ids_element(folders=folders, version=self.protocol.version, tag="m:ParentFolderIds"))
return payload
diff --git a/docs/exchangelib/services/find_item.html b/docs/exchangelib/services/find_item.html
index d0701e68..ea5dd93a 100644
--- a/docs/exchangelib/services/find_item.html
+++ b/docs/exchangelib/services/find_item.html
@@ -26,19 +26,19 @@ Module exchangelib.services.find_item
Expand source code
-from .common import EWSPagingService, shape_element, folder_ids_element
-from ..errors import InvalidEnumValue
+from ..errors import InvalidEnumValue
from ..folders.base import BaseFolder
-from ..items import Item, ID_ONLY, SHAPE_CHOICES, ITEM_TRAVERSAL_CHOICES
-from ..util import create_element, set_xml_value, TNS, MNS
+from ..items import ID_ONLY, ITEM_TRAVERSAL_CHOICES, SHAPE_CHOICES, Item
+from ..util import MNS, TNS, create_element, set_xml_value
+from .common import EWSPagingService, folder_ids_element, shape_element
class FindItem(EWSPagingService):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/finditem-operation"""
- SERVICE_NAME = 'FindItem'
- element_container_name = f'{{{TNS}}}Items'
- paging_container_name = f'{{{MNS}}}RootFolder'
+ SERVICE_NAME = "FindItem"
+ element_container_name = f"{{{TNS}}}Items"
+ paging_container_name = f"{{{MNS}}}RootFolder"
supports_paging = True
def __init__(self, *args, **kwargs):
@@ -47,8 +47,19 @@ Module exchangelib.services.find_item
self.additional_fields = None
self.shape = None
- def call(self, folders, additional_fields, restriction, order_fields, shape, query_string, depth, calendar_view,
- max_items, offset):
+ def call(
+ self,
+ folders,
+ additional_fields,
+ restriction,
+ order_fields,
+ shape,
+ query_string,
+ depth,
+ calendar_view,
+ max_items,
+ offset,
+ ):
"""Find items in an account.
:param folders: the folders to act on
@@ -65,43 +76,57 @@ Module exchangelib.services.find_item
:return: XML elements for the matching items
"""
if shape not in SHAPE_CHOICES:
- raise InvalidEnumValue('shape', shape, SHAPE_CHOICES)
+ raise InvalidEnumValue("shape", shape, SHAPE_CHOICES)
if depth not in ITEM_TRAVERSAL_CHOICES:
- raise InvalidEnumValue('depth', depth, ITEM_TRAVERSAL_CHOICES)
+ raise InvalidEnumValue("depth", depth, ITEM_TRAVERSAL_CHOICES)
self.additional_fields = additional_fields
self.shape = shape
- return self._elems_to_objs(self._paged_call(
- payload_func=self.get_payload,
- max_items=max_items,
- folders=folders,
- **dict(
- additional_fields=additional_fields,
- restriction=restriction,
- order_fields=order_fields,
- query_string=query_string,
- shape=shape,
- depth=depth,
- calendar_view=calendar_view,
- page_size=self.page_size,
- offset=offset,
+ return self._elems_to_objs(
+ self._paged_call(
+ payload_func=self.get_payload,
+ max_items=max_items,
+ folders=folders,
+ **dict(
+ additional_fields=additional_fields,
+ restriction=restriction,
+ order_fields=order_fields,
+ query_string=query_string,
+ shape=shape,
+ depth=depth,
+ calendar_view=calendar_view,
+ page_size=self.page_size,
+ offset=offset,
+ ),
)
- ))
+ )
def _elem_to_obj(self, elem):
if self.shape == ID_ONLY and self.additional_fields is None:
return Item.id_from_xml(elem)
return BaseFolder.item_model_from_tag(elem.tag).from_xml(elem=elem, account=self.account)
- def get_payload(self, folders, additional_fields, restriction, order_fields, query_string, shape, depth,
- calendar_view, page_size, offset=0):
- payload = create_element(f'm:{self.SERVICE_NAME}', attrs=dict(Traversal=depth))
- payload.append(shape_element(
- tag='m:ItemShape', shape=shape, additional_fields=additional_fields, version=self.account.version
- ))
+ def get_payload(
+ self,
+ folders,
+ additional_fields,
+ restriction,
+ order_fields,
+ query_string,
+ shape,
+ depth,
+ calendar_view,
+ page_size,
+ offset=0,
+ ):
+ payload = create_element(f"m:{self.SERVICE_NAME}", attrs=dict(Traversal=depth))
+ payload.append(
+ shape_element(
+ tag="m:ItemShape", shape=shape, additional_fields=additional_fields, version=self.account.version
+ )
+ )
if calendar_view is None:
view_type = create_element(
- 'm:IndexedPageItemView',
- attrs=dict(MaxEntriesReturned=page_size, Offset=offset, BasePoint='Beginning')
+ "m:IndexedPageItemView", attrs=dict(MaxEntriesReturned=page_size, Offset=offset, BasePoint="Beginning")
)
else:
view_type = calendar_view.to_xml(version=self.account.version)
@@ -109,12 +134,8 @@ Module exchangelib.services.find_item
if restriction:
payload.append(restriction.to_xml(version=self.account.version))
if order_fields:
- payload.append(set_xml_value(
- create_element('m:SortOrder'),
- order_fields,
- version=self.account.version
- ))
- payload.append(folder_ids_element(folders=folders, version=self.protocol.version, tag='m:ParentFolderIds'))
+ payload.append(set_xml_value(create_element("m:SortOrder"), order_fields, version=self.account.version))
+ payload.append(folder_ids_element(folders=folders, version=self.protocol.version, tag="m:ParentFolderIds"))
if query_string:
payload.append(query_string.to_xml(version=self.account.version))
return payload
@@ -142,9 +163,9 @@ Classes
class FindItem(EWSPagingService):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/finditem-operation"""
- SERVICE_NAME = 'FindItem'
- element_container_name = f'{{{TNS}}}Items'
- paging_container_name = f'{{{MNS}}}RootFolder'
+ SERVICE_NAME = "FindItem"
+ element_container_name = f"{{{TNS}}}Items"
+ paging_container_name = f"{{{MNS}}}RootFolder"
supports_paging = True
def __init__(self, *args, **kwargs):
@@ -153,8 +174,19 @@ Classes
self.additional_fields = None
self.shape = None
- def call(self, folders, additional_fields, restriction, order_fields, shape, query_string, depth, calendar_view,
- max_items, offset):
+ def call(
+ self,
+ folders,
+ additional_fields,
+ restriction,
+ order_fields,
+ shape,
+ query_string,
+ depth,
+ calendar_view,
+ max_items,
+ offset,
+ ):
"""Find items in an account.
:param folders: the folders to act on
@@ -171,43 +203,57 @@ Classes
:return: XML elements for the matching items
"""
if shape not in SHAPE_CHOICES:
- raise InvalidEnumValue('shape', shape, SHAPE_CHOICES)
+ raise InvalidEnumValue("shape", shape, SHAPE_CHOICES)
if depth not in ITEM_TRAVERSAL_CHOICES:
- raise InvalidEnumValue('depth', depth, ITEM_TRAVERSAL_CHOICES)
+ raise InvalidEnumValue("depth", depth, ITEM_TRAVERSAL_CHOICES)
self.additional_fields = additional_fields
self.shape = shape
- return self._elems_to_objs(self._paged_call(
- payload_func=self.get_payload,
- max_items=max_items,
- folders=folders,
- **dict(
- additional_fields=additional_fields,
- restriction=restriction,
- order_fields=order_fields,
- query_string=query_string,
- shape=shape,
- depth=depth,
- calendar_view=calendar_view,
- page_size=self.page_size,
- offset=offset,
+ return self._elems_to_objs(
+ self._paged_call(
+ payload_func=self.get_payload,
+ max_items=max_items,
+ folders=folders,
+ **dict(
+ additional_fields=additional_fields,
+ restriction=restriction,
+ order_fields=order_fields,
+ query_string=query_string,
+ shape=shape,
+ depth=depth,
+ calendar_view=calendar_view,
+ page_size=self.page_size,
+ offset=offset,
+ ),
)
- ))
+ )
def _elem_to_obj(self, elem):
if self.shape == ID_ONLY and self.additional_fields is None:
return Item.id_from_xml(elem)
return BaseFolder.item_model_from_tag(elem.tag).from_xml(elem=elem, account=self.account)
- def get_payload(self, folders, additional_fields, restriction, order_fields, query_string, shape, depth,
- calendar_view, page_size, offset=0):
- payload = create_element(f'm:{self.SERVICE_NAME}', attrs=dict(Traversal=depth))
- payload.append(shape_element(
- tag='m:ItemShape', shape=shape, additional_fields=additional_fields, version=self.account.version
- ))
+ def get_payload(
+ self,
+ folders,
+ additional_fields,
+ restriction,
+ order_fields,
+ query_string,
+ shape,
+ depth,
+ calendar_view,
+ page_size,
+ offset=0,
+ ):
+ payload = create_element(f"m:{self.SERVICE_NAME}", attrs=dict(Traversal=depth))
+ payload.append(
+ shape_element(
+ tag="m:ItemShape", shape=shape, additional_fields=additional_fields, version=self.account.version
+ )
+ )
if calendar_view is None:
view_type = create_element(
- 'm:IndexedPageItemView',
- attrs=dict(MaxEntriesReturned=page_size, Offset=offset, BasePoint='Beginning')
+ "m:IndexedPageItemView", attrs=dict(MaxEntriesReturned=page_size, Offset=offset, BasePoint="Beginning")
)
else:
view_type = calendar_view.to_xml(version=self.account.version)
@@ -215,12 +261,8 @@ Classes
if restriction:
payload.append(restriction.to_xml(version=self.account.version))
if order_fields:
- payload.append(set_xml_value(
- create_element('m:SortOrder'),
- order_fields,
- version=self.account.version
- ))
- payload.append(folder_ids_element(folders=folders, version=self.protocol.version, tag='m:ParentFolderIds'))
+ payload.append(set_xml_value(create_element("m:SortOrder"), order_fields, version=self.account.version))
+ payload.append(folder_ids_element(folders=folders, version=self.protocol.version, tag="m:ParentFolderIds"))
if query_string:
payload.append(query_string.to_xml(version=self.account.version))
return payload
@@ -272,8 +314,19 @@ Methods
Expand source code
-def call(self, folders, additional_fields, restriction, order_fields, shape, query_string, depth, calendar_view,
- max_items, offset):
+def call(
+ self,
+ folders,
+ additional_fields,
+ restriction,
+ order_fields,
+ shape,
+ query_string,
+ depth,
+ calendar_view,
+ max_items,
+ offset,
+):
"""Find items in an account.
:param folders: the folders to act on
@@ -290,27 +343,29 @@ Methods
:return: XML elements for the matching items
"""
if shape not in SHAPE_CHOICES:
- raise InvalidEnumValue('shape', shape, SHAPE_CHOICES)
+ raise InvalidEnumValue("shape", shape, SHAPE_CHOICES)
if depth not in ITEM_TRAVERSAL_CHOICES:
- raise InvalidEnumValue('depth', depth, ITEM_TRAVERSAL_CHOICES)
+ raise InvalidEnumValue("depth", depth, ITEM_TRAVERSAL_CHOICES)
self.additional_fields = additional_fields
self.shape = shape
- return self._elems_to_objs(self._paged_call(
- payload_func=self.get_payload,
- max_items=max_items,
- folders=folders,
- **dict(
- additional_fields=additional_fields,
- restriction=restriction,
- order_fields=order_fields,
- query_string=query_string,
- shape=shape,
- depth=depth,
- calendar_view=calendar_view,
- page_size=self.page_size,
- offset=offset,
+ return self._elems_to_objs(
+ self._paged_call(
+ payload_func=self.get_payload,
+ max_items=max_items,
+ folders=folders,
+ **dict(
+ additional_fields=additional_fields,
+ restriction=restriction,
+ order_fields=order_fields,
+ query_string=query_string,
+ shape=shape,
+ depth=depth,
+ calendar_view=calendar_view,
+ page_size=self.page_size,
+ offset=offset,
+ ),
)
- ))
+ )
@@ -322,16 +377,28 @@ Methods
Expand source code
-def get_payload(self, folders, additional_fields, restriction, order_fields, query_string, shape, depth,
- calendar_view, page_size, offset=0):
- payload = create_element(f'm:{self.SERVICE_NAME}', attrs=dict(Traversal=depth))
- payload.append(shape_element(
- tag='m:ItemShape', shape=shape, additional_fields=additional_fields, version=self.account.version
- ))
+def get_payload(
+ self,
+ folders,
+ additional_fields,
+ restriction,
+ order_fields,
+ query_string,
+ shape,
+ depth,
+ calendar_view,
+ page_size,
+ offset=0,
+):
+ payload = create_element(f"m:{self.SERVICE_NAME}", attrs=dict(Traversal=depth))
+ payload.append(
+ shape_element(
+ tag="m:ItemShape", shape=shape, additional_fields=additional_fields, version=self.account.version
+ )
+ )
if calendar_view is None:
view_type = create_element(
- 'm:IndexedPageItemView',
- attrs=dict(MaxEntriesReturned=page_size, Offset=offset, BasePoint='Beginning')
+ "m:IndexedPageItemView", attrs=dict(MaxEntriesReturned=page_size, Offset=offset, BasePoint="Beginning")
)
else:
view_type = calendar_view.to_xml(version=self.account.version)
@@ -339,12 +406,8 @@ Methods
if restriction:
payload.append(restriction.to_xml(version=self.account.version))
if order_fields:
- payload.append(set_xml_value(
- create_element('m:SortOrder'),
- order_fields,
- version=self.account.version
- ))
- payload.append(folder_ids_element(folders=folders, version=self.protocol.version, tag='m:ParentFolderIds'))
+ payload.append(set_xml_value(create_element("m:SortOrder"), order_fields, version=self.account.version))
+ payload.append(folder_ids_element(folders=folders, version=self.protocol.version, tag="m:ParentFolderIds"))
if query_string:
payload.append(query_string.to_xml(version=self.account.version))
return payload
diff --git a/docs/exchangelib/services/find_people.html b/docs/exchangelib/services/find_people.html
index db96c304..acd0c50c 100644
--- a/docs/exchangelib/services/find_people.html
+++ b/docs/exchangelib/services/find_people.html
@@ -27,11 +27,12 @@ Module exchangelib.services.find_people
Expand source code
import logging
-from .common import EWSPagingService, shape_element, folder_ids_element
+
from ..errors import InvalidEnumValue
-from ..items import Persona, ID_ONLY, SHAPE_CHOICES, ITEM_TRAVERSAL_CHOICES
-from ..util import create_element, set_xml_value, MNS
+from ..items import ID_ONLY, ITEM_TRAVERSAL_CHOICES, SHAPE_CHOICES, Persona
+from ..util import MNS, create_element, set_xml_value
from ..version import EXCHANGE_2013
+from .common import EWSPagingService, folder_ids_element, shape_element
log = logging.getLogger(__name__)
@@ -39,8 +40,8 @@ Module exchangelib.services.find_people
class FindPeople(EWSPagingService):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/findpeople-operation"""
- SERVICE_NAME = 'FindPeople'
- element_container_name = f'{{{MNS}}}People'
+ SERVICE_NAME = "FindPeople"
+ element_container_name = f"{{{MNS}}}People"
supported_from = EXCHANGE_2013
supports_paging = True
@@ -66,52 +67,54 @@ Module exchangelib.services.find_people
:return: XML elements for the matching items
"""
if shape not in SHAPE_CHOICES:
- raise InvalidEnumValue('shape', shape, SHAPE_CHOICES)
+ raise InvalidEnumValue("shape", shape, SHAPE_CHOICES)
if depth not in ITEM_TRAVERSAL_CHOICES:
- raise InvalidEnumValue('depth', depth, ITEM_TRAVERSAL_CHOICES)
+ raise InvalidEnumValue("depth", depth, ITEM_TRAVERSAL_CHOICES)
self.additional_fields = additional_fields
self.shape = shape
- return self._elems_to_objs(self._paged_call(
- payload_func=self.get_payload,
- max_items=max_items,
- folders=[folder], # We just need the list to satisfy self._paged_call()
- **dict(
- additional_fields=additional_fields,
- restriction=restriction,
- order_fields=order_fields,
- query_string=query_string,
- shape=shape,
- depth=depth,
- page_size=self.page_size,
- offset=offset,
+ return self._elems_to_objs(
+ self._paged_call(
+ payload_func=self.get_payload,
+ max_items=max_items,
+ folders=[folder], # We just need the list to satisfy self._paged_call()
+ **dict(
+ additional_fields=additional_fields,
+ restriction=restriction,
+ order_fields=order_fields,
+ query_string=query_string,
+ shape=shape,
+ depth=depth,
+ page_size=self.page_size,
+ offset=offset,
+ ),
)
- ))
+ )
def _elem_to_obj(self, elem):
if self.shape == ID_ONLY and self.additional_fields is None:
return Persona.id_from_xml(elem)
return Persona.from_xml(elem, account=self.account)
- def get_payload(self, folders, additional_fields, restriction, order_fields, query_string, shape, depth, page_size,
- offset=0):
+ def get_payload(
+ self, folders, additional_fields, restriction, order_fields, query_string, shape, depth, page_size, offset=0
+ ):
# We actually only support a single folder, but self._paged_call() sends us a list
- payload = create_element(f'm:{self.SERVICE_NAME}', attrs=dict(Traversal=depth))
- payload.append(shape_element(
- tag='m:PersonaShape', shape=shape, additional_fields=additional_fields, version=self.account.version
- ))
- payload.append(create_element(
- 'm:IndexedPageItemView',
- attrs=dict(MaxEntriesReturned=page_size, Offset=offset, BasePoint='Beginning')
- ))
+ payload = create_element(f"m:{self.SERVICE_NAME}", attrs=dict(Traversal=depth))
+ payload.append(
+ shape_element(
+ tag="m:PersonaShape", shape=shape, additional_fields=additional_fields, version=self.account.version
+ )
+ )
+ payload.append(
+ create_element(
+ "m:IndexedPageItemView", attrs=dict(MaxEntriesReturned=page_size, Offset=offset, BasePoint="Beginning")
+ )
+ )
if restriction:
payload.append(restriction.to_xml(version=self.account.version))
if order_fields:
- payload.append(set_xml_value(
- create_element('m:SortOrder'),
- order_fields,
- version=self.account.version
- ))
- payload.append(folder_ids_element(folders=folders, version=self.account.version, tag='m:ParentFolderId'))
+ payload.append(set_xml_value(create_element("m:SortOrder"), order_fields, version=self.account.version))
+ payload.append(folder_ids_element(folders=folders, version=self.account.version, tag="m:ParentFolderId"))
if query_string:
payload.append(query_string.to_xml(version=self.account.version))
return payload
@@ -119,11 +122,15 @@ Module exchangelib.services.find_people
@staticmethod
def _get_paging_values(elem):
"""Find paging values. The paging element from FindPeople is different from other paging containers."""
- item_count = int(elem.find(f'{{{MNS}}}TotalNumberOfPeopleInView').text)
- first_matching = int(elem.find(f'{{{MNS}}}FirstMatchingRowIndex').text)
- first_loaded = int(elem.find(f'{{{MNS}}}FirstLoadedRowIndex').text)
- log.debug('Got page with total items %s, first matching %s, first loaded %s ', item_count, first_matching,
- first_loaded)
+ item_count = int(elem.find(f"{{{MNS}}}TotalNumberOfPeopleInView").text)
+ first_matching = int(elem.find(f"{{{MNS}}}FirstMatchingRowIndex").text)
+ first_loaded = int(elem.find(f"{{{MNS}}}FirstLoadedRowIndex").text)
+ log.debug(
+ "Got page with total items %s, first matching %s, first loaded %s ",
+ item_count,
+ first_matching,
+ first_loaded,
+ )
next_offset = None # GetPersona does not support fetching more pages
return item_count, next_offset
@@ -150,8 +157,8 @@ Classes
class FindPeople(EWSPagingService):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/findpeople-operation"""
- SERVICE_NAME = 'FindPeople'
- element_container_name = f'{{{MNS}}}People'
+ SERVICE_NAME = "FindPeople"
+ element_container_name = f"{{{MNS}}}People"
supported_from = EXCHANGE_2013
supports_paging = True
@@ -177,52 +184,54 @@ Classes
:return: XML elements for the matching items
"""
if shape not in SHAPE_CHOICES:
- raise InvalidEnumValue('shape', shape, SHAPE_CHOICES)
+ raise InvalidEnumValue("shape", shape, SHAPE_CHOICES)
if depth not in ITEM_TRAVERSAL_CHOICES:
- raise InvalidEnumValue('depth', depth, ITEM_TRAVERSAL_CHOICES)
+ raise InvalidEnumValue("depth", depth, ITEM_TRAVERSAL_CHOICES)
self.additional_fields = additional_fields
self.shape = shape
- return self._elems_to_objs(self._paged_call(
- payload_func=self.get_payload,
- max_items=max_items,
- folders=[folder], # We just need the list to satisfy self._paged_call()
- **dict(
- additional_fields=additional_fields,
- restriction=restriction,
- order_fields=order_fields,
- query_string=query_string,
- shape=shape,
- depth=depth,
- page_size=self.page_size,
- offset=offset,
+ return self._elems_to_objs(
+ self._paged_call(
+ payload_func=self.get_payload,
+ max_items=max_items,
+ folders=[folder], # We just need the list to satisfy self._paged_call()
+ **dict(
+ additional_fields=additional_fields,
+ restriction=restriction,
+ order_fields=order_fields,
+ query_string=query_string,
+ shape=shape,
+ depth=depth,
+ page_size=self.page_size,
+ offset=offset,
+ ),
)
- ))
+ )
def _elem_to_obj(self, elem):
if self.shape == ID_ONLY and self.additional_fields is None:
return Persona.id_from_xml(elem)
return Persona.from_xml(elem, account=self.account)
- def get_payload(self, folders, additional_fields, restriction, order_fields, query_string, shape, depth, page_size,
- offset=0):
+ def get_payload(
+ self, folders, additional_fields, restriction, order_fields, query_string, shape, depth, page_size, offset=0
+ ):
# We actually only support a single folder, but self._paged_call() sends us a list
- payload = create_element(f'm:{self.SERVICE_NAME}', attrs=dict(Traversal=depth))
- payload.append(shape_element(
- tag='m:PersonaShape', shape=shape, additional_fields=additional_fields, version=self.account.version
- ))
- payload.append(create_element(
- 'm:IndexedPageItemView',
- attrs=dict(MaxEntriesReturned=page_size, Offset=offset, BasePoint='Beginning')
- ))
+ payload = create_element(f"m:{self.SERVICE_NAME}", attrs=dict(Traversal=depth))
+ payload.append(
+ shape_element(
+ tag="m:PersonaShape", shape=shape, additional_fields=additional_fields, version=self.account.version
+ )
+ )
+ payload.append(
+ create_element(
+ "m:IndexedPageItemView", attrs=dict(MaxEntriesReturned=page_size, Offset=offset, BasePoint="Beginning")
+ )
+ )
if restriction:
payload.append(restriction.to_xml(version=self.account.version))
if order_fields:
- payload.append(set_xml_value(
- create_element('m:SortOrder'),
- order_fields,
- version=self.account.version
- ))
- payload.append(folder_ids_element(folders=folders, version=self.account.version, tag='m:ParentFolderId'))
+ payload.append(set_xml_value(create_element("m:SortOrder"), order_fields, version=self.account.version))
+ payload.append(folder_ids_element(folders=folders, version=self.account.version, tag="m:ParentFolderId"))
if query_string:
payload.append(query_string.to_xml(version=self.account.version))
return payload
@@ -230,11 +239,15 @@ Classes
@staticmethod
def _get_paging_values(elem):
"""Find paging values. The paging element from FindPeople is different from other paging containers."""
- item_count = int(elem.find(f'{{{MNS}}}TotalNumberOfPeopleInView').text)
- first_matching = int(elem.find(f'{{{MNS}}}FirstMatchingRowIndex').text)
- first_loaded = int(elem.find(f'{{{MNS}}}FirstLoadedRowIndex').text)
- log.debug('Got page with total items %s, first matching %s, first loaded %s ', item_count, first_matching,
- first_loaded)
+ item_count = int(elem.find(f"{{{MNS}}}TotalNumberOfPeopleInView").text)
+ first_matching = int(elem.find(f"{{{MNS}}}FirstMatchingRowIndex").text)
+ first_loaded = int(elem.find(f"{{{MNS}}}FirstLoadedRowIndex").text)
+ log.debug(
+ "Got page with total items %s, first matching %s, first loaded %s ",
+ item_count,
+ first_matching,
+ first_loaded,
+ )
next_offset = None # GetPersona does not support fetching more pages
return item_count, next_offset
@@ -300,26 +313,28 @@ Methods
:return: XML elements for the matching items
"""
if shape not in SHAPE_CHOICES:
- raise InvalidEnumValue('shape', shape, SHAPE_CHOICES)
+ raise InvalidEnumValue("shape", shape, SHAPE_CHOICES)
if depth not in ITEM_TRAVERSAL_CHOICES:
- raise InvalidEnumValue('depth', depth, ITEM_TRAVERSAL_CHOICES)
+ raise InvalidEnumValue("depth", depth, ITEM_TRAVERSAL_CHOICES)
self.additional_fields = additional_fields
self.shape = shape
- return self._elems_to_objs(self._paged_call(
- payload_func=self.get_payload,
- max_items=max_items,
- folders=[folder], # We just need the list to satisfy self._paged_call()
- **dict(
- additional_fields=additional_fields,
- restriction=restriction,
- order_fields=order_fields,
- query_string=query_string,
- shape=shape,
- depth=depth,
- page_size=self.page_size,
- offset=offset,
+ return self._elems_to_objs(
+ self._paged_call(
+ payload_func=self.get_payload,
+ max_items=max_items,
+ folders=[folder], # We just need the list to satisfy self._paged_call()
+ **dict(
+ additional_fields=additional_fields,
+ restriction=restriction,
+ order_fields=order_fields,
+ query_string=query_string,
+ shape=shape,
+ depth=depth,
+ page_size=self.page_size,
+ offset=offset,
+ ),
)
- ))
+ )
@@ -331,26 +346,26 @@ Methods
Expand source code
-def get_payload(self, folders, additional_fields, restriction, order_fields, query_string, shape, depth, page_size,
- offset=0):
+def get_payload(
+ self, folders, additional_fields, restriction, order_fields, query_string, shape, depth, page_size, offset=0
+):
# We actually only support a single folder, but self._paged_call() sends us a list
- payload = create_element(f'm:{self.SERVICE_NAME}', attrs=dict(Traversal=depth))
- payload.append(shape_element(
- tag='m:PersonaShape', shape=shape, additional_fields=additional_fields, version=self.account.version
- ))
- payload.append(create_element(
- 'm:IndexedPageItemView',
- attrs=dict(MaxEntriesReturned=page_size, Offset=offset, BasePoint='Beginning')
- ))
+ payload = create_element(f"m:{self.SERVICE_NAME}", attrs=dict(Traversal=depth))
+ payload.append(
+ shape_element(
+ tag="m:PersonaShape", shape=shape, additional_fields=additional_fields, version=self.account.version
+ )
+ )
+ payload.append(
+ create_element(
+ "m:IndexedPageItemView", attrs=dict(MaxEntriesReturned=page_size, Offset=offset, BasePoint="Beginning")
+ )
+ )
if restriction:
payload.append(restriction.to_xml(version=self.account.version))
if order_fields:
- payload.append(set_xml_value(
- create_element('m:SortOrder'),
- order_fields,
- version=self.account.version
- ))
- payload.append(folder_ids_element(folders=folders, version=self.account.version, tag='m:ParentFolderId'))
+ payload.append(set_xml_value(create_element("m:SortOrder"), order_fields, version=self.account.version))
+ payload.append(folder_ids_element(folders=folders, version=self.account.version, tag="m:ParentFolderId"))
if query_string:
payload.append(query_string.to_xml(version=self.account.version))
return payload
diff --git a/docs/exchangelib/services/get_attachment.html b/docs/exchangelib/services/get_attachment.html
index e635ab7e..39c2401c 100644
--- a/docs/exchangelib/services/get_attachment.html
+++ b/docs/exchangelib/services/get_attachment.html
@@ -28,50 +28,65 @@ Module exchangelib.services.get_attachment
from itertools import chain
-from .common import EWSAccountService, attachment_ids_element
from ..attachments import FileAttachment, ItemAttachment
from ..errors import InvalidEnumValue
-from ..util import create_element, add_xml_child, set_xml_value, DummyResponse, StreamingBase64Parser,\
- StreamingContentHandler, ElementNotFound, MNS
+from ..util import (
+ MNS,
+ DummyResponse,
+ ElementNotFound,
+ StreamingBase64Parser,
+ StreamingContentHandler,
+ add_xml_child,
+ create_element,
+ set_xml_value,
+)
+from .common import EWSAccountService, attachment_ids_element
# https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/bodytype
-BODY_TYPE_CHOICES = ('Best', 'HTML', 'Text')
+BODY_TYPE_CHOICES = ("Best", "HTML", "Text")
class GetAttachment(EWSAccountService):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/getattachment-operation"""
- SERVICE_NAME = 'GetAttachment'
- element_container_name = f'{{{MNS}}}Attachments'
+ SERVICE_NAME = "GetAttachment"
+ element_container_name = f"{{{MNS}}}Attachments"
cls_map = {cls.response_tag(): cls for cls in (FileAttachment, ItemAttachment)}
def call(self, items, include_mime_content, body_type, filter_html_content, additional_fields):
if body_type and body_type not in BODY_TYPE_CHOICES:
- raise InvalidEnumValue('body_type', body_type, BODY_TYPE_CHOICES)
- return self._elems_to_objs(self._chunked_get_elements(
- self.get_payload, items=items, include_mime_content=include_mime_content,
- body_type=body_type, filter_html_content=filter_html_content, additional_fields=additional_fields,
- ))
+ raise InvalidEnumValue("body_type", body_type, BODY_TYPE_CHOICES)
+ return self._elems_to_objs(
+ self._chunked_get_elements(
+ self.get_payload,
+ items=items,
+ include_mime_content=include_mime_content,
+ body_type=body_type,
+ filter_html_content=filter_html_content,
+ additional_fields=additional_fields,
+ )
+ )
def _elem_to_obj(self, elem):
return self.cls_map[elem.tag].from_xml(elem=elem, account=self.account)
def get_payload(self, items, include_mime_content, body_type, filter_html_content, additional_fields):
- payload = create_element(f'm:{self.SERVICE_NAME}')
- shape_elem = create_element('m:AttachmentShape')
+ payload = create_element(f"m:{self.SERVICE_NAME}")
+ shape_elem = create_element("m:AttachmentShape")
if include_mime_content:
- add_xml_child(shape_elem, 't:IncludeMimeContent', 'true')
+ add_xml_child(shape_elem, "t:IncludeMimeContent", "true")
if body_type:
- add_xml_child(shape_elem, 't:BodyType', body_type)
+ add_xml_child(shape_elem, "t:BodyType", body_type)
if filter_html_content is not None:
- add_xml_child(shape_elem, 't:FilterHtmlContent', 'true' if filter_html_content else 'false')
+ add_xml_child(shape_elem, "t:FilterHtmlContent", "true" if filter_html_content else "false")
if additional_fields:
- additional_properties = create_element('t:AdditionalProperties')
+ additional_properties = create_element("t:AdditionalProperties")
expanded_fields = chain(*(f.expand(version=self.account.version) for f in additional_fields))
- set_xml_value(additional_properties, sorted(
- expanded_fields,
- key=lambda f: (getattr(f.field, 'field_uri', ''), f.path)
- ), version=self.account.version)
+ set_xml_value(
+ additional_properties,
+ sorted(expanded_fields, key=lambda f: (getattr(f.field, "field_uri", ""), f.path)),
+ version=self.account.version,
+ )
shape_elem.append(additional_properties)
if len(shape_elem):
payload.append(shape_elem)
@@ -79,26 +94,26 @@ Module exchangelib.services.get_attachment
return payload
def _update_api_version(self, api_version, header, **parse_opts):
- if not parse_opts.get('stream_file_content', False):
+ if not parse_opts.get("stream_file_content", False):
super()._update_api_version(api_version, header, **parse_opts)
# TODO: We're skipping this part in streaming mode because StreamingBase64Parser cannot parse the SOAP header
@classmethod
def _get_soap_parts(cls, response, **parse_opts):
- if not parse_opts.get('stream_file_content', False):
+ if not parse_opts.get("stream_file_content", False):
return super()._get_soap_parts(response, **parse_opts)
# Pass the response unaltered. We want to use our custom streaming parser
return None, response
def _get_soap_messages(self, body, **parse_opts):
- if not parse_opts.get('stream_file_content', False):
+ if not parse_opts.get("stream_file_content", False):
return super()._get_soap_messages(body, **parse_opts)
# 'body' is actually the raw response passed on by '_get_soap_parts'
r = body
parser = StreamingBase64Parser()
- field = FileAttachment.get_field_by_fieldname('_content')
+ field = FileAttachment.get_field_by_fieldname("_content")
handler = StreamingContentHandler(parser=parser, ns=field.namespace, element_name=field.field_uri)
parser.setContentHandler(handler)
return parser.parse(r)
@@ -106,7 +121,10 @@ Module exchangelib.services.get_attachment
def stream_file_content(self, attachment_id):
# The streaming XML parser can only stream content of one attachment
payload = self.get_payload(
- items=[attachment_id], include_mime_content=False, body_type=None, filter_html_content=None,
+ items=[attachment_id],
+ include_mime_content=False,
+ body_type=None,
+ filter_html_content=None,
additional_fields=None,
)
self.streaming = True
@@ -151,37 +169,44 @@ Classes
class GetAttachment(EWSAccountService):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/getattachment-operation"""
- SERVICE_NAME = 'GetAttachment'
- element_container_name = f'{{{MNS}}}Attachments'
+ SERVICE_NAME = "GetAttachment"
+ element_container_name = f"{{{MNS}}}Attachments"
cls_map = {cls.response_tag(): cls for cls in (FileAttachment, ItemAttachment)}
def call(self, items, include_mime_content, body_type, filter_html_content, additional_fields):
if body_type and body_type not in BODY_TYPE_CHOICES:
- raise InvalidEnumValue('body_type', body_type, BODY_TYPE_CHOICES)
- return self._elems_to_objs(self._chunked_get_elements(
- self.get_payload, items=items, include_mime_content=include_mime_content,
- body_type=body_type, filter_html_content=filter_html_content, additional_fields=additional_fields,
- ))
+ raise InvalidEnumValue("body_type", body_type, BODY_TYPE_CHOICES)
+ return self._elems_to_objs(
+ self._chunked_get_elements(
+ self.get_payload,
+ items=items,
+ include_mime_content=include_mime_content,
+ body_type=body_type,
+ filter_html_content=filter_html_content,
+ additional_fields=additional_fields,
+ )
+ )
def _elem_to_obj(self, elem):
return self.cls_map[elem.tag].from_xml(elem=elem, account=self.account)
def get_payload(self, items, include_mime_content, body_type, filter_html_content, additional_fields):
- payload = create_element(f'm:{self.SERVICE_NAME}')
- shape_elem = create_element('m:AttachmentShape')
+ payload = create_element(f"m:{self.SERVICE_NAME}")
+ shape_elem = create_element("m:AttachmentShape")
if include_mime_content:
- add_xml_child(shape_elem, 't:IncludeMimeContent', 'true')
+ add_xml_child(shape_elem, "t:IncludeMimeContent", "true")
if body_type:
- add_xml_child(shape_elem, 't:BodyType', body_type)
+ add_xml_child(shape_elem, "t:BodyType", body_type)
if filter_html_content is not None:
- add_xml_child(shape_elem, 't:FilterHtmlContent', 'true' if filter_html_content else 'false')
+ add_xml_child(shape_elem, "t:FilterHtmlContent", "true" if filter_html_content else "false")
if additional_fields:
- additional_properties = create_element('t:AdditionalProperties')
+ additional_properties = create_element("t:AdditionalProperties")
expanded_fields = chain(*(f.expand(version=self.account.version) for f in additional_fields))
- set_xml_value(additional_properties, sorted(
- expanded_fields,
- key=lambda f: (getattr(f.field, 'field_uri', ''), f.path)
- ), version=self.account.version)
+ set_xml_value(
+ additional_properties,
+ sorted(expanded_fields, key=lambda f: (getattr(f.field, "field_uri", ""), f.path)),
+ version=self.account.version,
+ )
shape_elem.append(additional_properties)
if len(shape_elem):
payload.append(shape_elem)
@@ -189,26 +214,26 @@ Classes
return payload
def _update_api_version(self, api_version, header, **parse_opts):
- if not parse_opts.get('stream_file_content', False):
+ if not parse_opts.get("stream_file_content", False):
super()._update_api_version(api_version, header, **parse_opts)
# TODO: We're skipping this part in streaming mode because StreamingBase64Parser cannot parse the SOAP header
@classmethod
def _get_soap_parts(cls, response, **parse_opts):
- if not parse_opts.get('stream_file_content', False):
+ if not parse_opts.get("stream_file_content", False):
return super()._get_soap_parts(response, **parse_opts)
# Pass the response unaltered. We want to use our custom streaming parser
return None, response
def _get_soap_messages(self, body, **parse_opts):
- if not parse_opts.get('stream_file_content', False):
+ if not parse_opts.get("stream_file_content", False):
return super()._get_soap_messages(body, **parse_opts)
# 'body' is actually the raw response passed on by '_get_soap_parts'
r = body
parser = StreamingBase64Parser()
- field = FileAttachment.get_field_by_fieldname('_content')
+ field = FileAttachment.get_field_by_fieldname("_content")
handler = StreamingContentHandler(parser=parser, ns=field.namespace, element_name=field.field_uri)
parser.setContentHandler(handler)
return parser.parse(r)
@@ -216,7 +241,10 @@ Classes
def stream_file_content(self, attachment_id):
# The streaming XML parser can only stream content of one attachment
payload = self.get_payload(
- items=[attachment_id], include_mime_content=False, body_type=None, filter_html_content=None,
+ items=[attachment_id],
+ include_mime_content=False,
+ body_type=None,
+ filter_html_content=None,
additional_fields=None,
)
self.streaming = True
@@ -271,11 +299,17 @@ Methods
def call(self, items, include_mime_content, body_type, filter_html_content, additional_fields):
if body_type and body_type not in BODY_TYPE_CHOICES:
- raise InvalidEnumValue('body_type', body_type, BODY_TYPE_CHOICES)
- return self._elems_to_objs(self._chunked_get_elements(
- self.get_payload, items=items, include_mime_content=include_mime_content,
- body_type=body_type, filter_html_content=filter_html_content, additional_fields=additional_fields,
- ))
+ raise InvalidEnumValue("body_type", body_type, BODY_TYPE_CHOICES)
+ return self._elems_to_objs(
+ self._chunked_get_elements(
+ self.get_payload,
+ items=items,
+ include_mime_content=include_mime_content,
+ body_type=body_type,
+ filter_html_content=filter_html_content,
+ additional_fields=additional_fields,
+ )
+ )
@@ -288,21 +322,22 @@ Methods
Expand source code
def get_payload(self, items, include_mime_content, body_type, filter_html_content, additional_fields):
- payload = create_element(f'm:{self.SERVICE_NAME}')
- shape_elem = create_element('m:AttachmentShape')
+ payload = create_element(f"m:{self.SERVICE_NAME}")
+ shape_elem = create_element("m:AttachmentShape")
if include_mime_content:
- add_xml_child(shape_elem, 't:IncludeMimeContent', 'true')
+ add_xml_child(shape_elem, "t:IncludeMimeContent", "true")
if body_type:
- add_xml_child(shape_elem, 't:BodyType', body_type)
+ add_xml_child(shape_elem, "t:BodyType", body_type)
if filter_html_content is not None:
- add_xml_child(shape_elem, 't:FilterHtmlContent', 'true' if filter_html_content else 'false')
+ add_xml_child(shape_elem, "t:FilterHtmlContent", "true" if filter_html_content else "false")
if additional_fields:
- additional_properties = create_element('t:AdditionalProperties')
+ additional_properties = create_element("t:AdditionalProperties")
expanded_fields = chain(*(f.expand(version=self.account.version) for f in additional_fields))
- set_xml_value(additional_properties, sorted(
- expanded_fields,
- key=lambda f: (getattr(f.field, 'field_uri', ''), f.path)
- ), version=self.account.version)
+ set_xml_value(
+ additional_properties,
+ sorted(expanded_fields, key=lambda f: (getattr(f.field, "field_uri", ""), f.path)),
+ version=self.account.version,
+ )
shape_elem.append(additional_properties)
if len(shape_elem):
payload.append(shape_elem)
@@ -322,7 +357,10 @@ Methods
def stream_file_content(self, attachment_id):
# The streaming XML parser can only stream content of one attachment
payload = self.get_payload(
- items=[attachment_id], include_mime_content=False, body_type=None, filter_html_content=None,
+ items=[attachment_id],
+ include_mime_content=False,
+ body_type=None,
+ filter_html_content=None,
additional_fields=None,
)
self.streaming = True
diff --git a/docs/exchangelib/services/get_delegate.html b/docs/exchangelib/services/get_delegate.html
index c8c3ec03..93085f09 100644
--- a/docs/exchangelib/services/get_delegate.html
+++ b/docs/exchangelib/services/get_delegate.html
@@ -26,35 +26,37 @@ Module exchangelib.services.get_delegate
Expand source code
-from .common import EWSAccountService
-from ..properties import DLMailbox, DelegateUser, UserId # The service expects a Mailbox element in the MNS namespace
-from ..util import create_element, set_xml_value, MNS
+from ..properties import DelegateUser, DLMailbox, UserId # The service expects a Mailbox element in the MNS namespace
+from ..util import MNS, create_element, set_xml_value
from ..version import EXCHANGE_2007_SP1
+from .common import EWSAccountService
class GetDelegate(EWSAccountService):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/getdelegate-operation"""
- SERVICE_NAME = 'GetDelegate'
+ SERVICE_NAME = "GetDelegate"
ERRORS_TO_CATCH_IN_RESPONSE = ()
supported_from = EXCHANGE_2007_SP1
def call(self, user_ids, include_permissions):
- return self._elems_to_objs(self._chunked_get_elements(
- self.get_payload,
- items=user_ids or [None],
- mailbox=DLMailbox(email_address=self.account.primary_smtp_address),
- include_permissions=include_permissions,
- ))
+ return self._elems_to_objs(
+ self._chunked_get_elements(
+ self.get_payload,
+ items=user_ids or [None],
+ mailbox=DLMailbox(email_address=self.account.primary_smtp_address),
+ include_permissions=include_permissions,
+ )
+ )
def _elem_to_obj(self, elem):
return DelegateUser.from_xml(elem=elem, account=self.account)
def get_payload(self, user_ids, mailbox, include_permissions):
- payload = create_element(f'm:{self.SERVICE_NAME}', attrs=dict(IncludePermissions=include_permissions))
+ payload = create_element(f"m:{self.SERVICE_NAME}", attrs=dict(IncludePermissions=include_permissions))
set_xml_value(payload, mailbox, version=self.protocol.version)
if user_ids != [None]:
- user_ids_elem = create_element('m:UserIds')
+ user_ids_elem = create_element("m:UserIds")
for user_id in user_ids:
if isinstance(user_id, str):
user_id = UserId(primary_smtp_address=user_id)
@@ -68,7 +70,7 @@ Module exchangelib.services.get_delegate
@classmethod
def _response_message_tag(cls):
- return f'{{{MNS}}}DelegateUserResponseMessageType'
+ return f"{{{MNS}}}DelegateUserResponseMessageType"
@@ -93,26 +95,28 @@ Classes
class GetDelegate(EWSAccountService):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/getdelegate-operation"""
- SERVICE_NAME = 'GetDelegate'
+ SERVICE_NAME = "GetDelegate"
ERRORS_TO_CATCH_IN_RESPONSE = ()
supported_from = EXCHANGE_2007_SP1
def call(self, user_ids, include_permissions):
- return self._elems_to_objs(self._chunked_get_elements(
- self.get_payload,
- items=user_ids or [None],
- mailbox=DLMailbox(email_address=self.account.primary_smtp_address),
- include_permissions=include_permissions,
- ))
+ return self._elems_to_objs(
+ self._chunked_get_elements(
+ self.get_payload,
+ items=user_ids or [None],
+ mailbox=DLMailbox(email_address=self.account.primary_smtp_address),
+ include_permissions=include_permissions,
+ )
+ )
def _elem_to_obj(self, elem):
return DelegateUser.from_xml(elem=elem, account=self.account)
def get_payload(self, user_ids, mailbox, include_permissions):
- payload = create_element(f'm:{self.SERVICE_NAME}', attrs=dict(IncludePermissions=include_permissions))
+ payload = create_element(f"m:{self.SERVICE_NAME}", attrs=dict(IncludePermissions=include_permissions))
set_xml_value(payload, mailbox, version=self.protocol.version)
if user_ids != [None]:
- user_ids_elem = create_element('m:UserIds')
+ user_ids_elem = create_element("m:UserIds")
for user_id in user_ids:
if isinstance(user_id, str):
user_id = UserId(primary_smtp_address=user_id)
@@ -126,7 +130,7 @@ Classes
@classmethod
def _response_message_tag(cls):
- return f'{{{MNS}}}DelegateUserResponseMessageType'
+ return f"{{{MNS}}}DelegateUserResponseMessageType"
Ancestors
@@ -160,12 +164,14 @@ Methods
Expand source code
def call(self, user_ids, include_permissions):
- return self._elems_to_objs(self._chunked_get_elements(
- self.get_payload,
- items=user_ids or [None],
- mailbox=DLMailbox(email_address=self.account.primary_smtp_address),
- include_permissions=include_permissions,
- ))
+ return self._elems_to_objs(
+ self._chunked_get_elements(
+ self.get_payload,
+ items=user_ids or [None],
+ mailbox=DLMailbox(email_address=self.account.primary_smtp_address),
+ include_permissions=include_permissions,
+ )
+ )
@@ -178,10 +184,10 @@ Methods
Expand source code
def get_payload(self, user_ids, mailbox, include_permissions):
- payload = create_element(f'm:{self.SERVICE_NAME}', attrs=dict(IncludePermissions=include_permissions))
+ payload = create_element(f"m:{self.SERVICE_NAME}", attrs=dict(IncludePermissions=include_permissions))
set_xml_value(payload, mailbox, version=self.protocol.version)
if user_ids != [None]:
- user_ids_elem = create_element('m:UserIds')
+ user_ids_elem = create_element("m:UserIds")
for user_id in user_ids:
if isinstance(user_id, str):
user_id = UserId(primary_smtp_address=user_id)
diff --git a/docs/exchangelib/services/get_events.html b/docs/exchangelib/services/get_events.html
index daf07773..d60e781d 100644
--- a/docs/exchangelib/services/get_events.html
+++ b/docs/exchangelib/services/get_events.html
@@ -28,9 +28,9 @@ Module exchangelib.services.get_events
import logging
-from .common import EWSAccountService, add_xml_child
from ..properties import Notification
from ..util import create_element
+from .common import EWSAccountService, add_xml_child
log = logging.getLogger(__name__)
@@ -40,13 +40,18 @@ Module exchangelib.services.get_events
https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/getevents-operation
"""
- SERVICE_NAME = 'GetEvents'
+ SERVICE_NAME = "GetEvents"
prefer_affinity = True
def call(self, subscription_id, watermark):
- return self._elems_to_objs(self._get_elements(payload=self.get_payload(
- subscription_id=subscription_id, watermark=watermark,
- )))
+ return self._elems_to_objs(
+ self._get_elements(
+ payload=self.get_payload(
+ subscription_id=subscription_id,
+ watermark=watermark,
+ )
+ )
+ )
def _elem_to_obj(self, elem):
return Notification.from_xml(elem=elem, account=None)
@@ -56,9 +61,9 @@ Module exchangelib.services.get_events
return container.findall(Notification.response_tag())
def get_payload(self, subscription_id, watermark):
- payload = create_element(f'm:{self.SERVICE_NAME}')
- add_xml_child(payload, 'm:SubscriptionId', subscription_id)
- add_xml_child(payload, 'm:Watermark', watermark)
+ payload = create_element(f"m:{self.SERVICE_NAME}")
+ add_xml_child(payload, "m:SubscriptionId", subscription_id)
+ add_xml_child(payload, "m:Watermark", watermark)
return payload
@@ -87,13 +92,18 @@ Classes
https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/getevents-operation
"""
- SERVICE_NAME = 'GetEvents'
+ SERVICE_NAME = "GetEvents"
prefer_affinity = True
def call(self, subscription_id, watermark):
- return self._elems_to_objs(self._get_elements(payload=self.get_payload(
- subscription_id=subscription_id, watermark=watermark,
- )))
+ return self._elems_to_objs(
+ self._get_elements(
+ payload=self.get_payload(
+ subscription_id=subscription_id,
+ watermark=watermark,
+ )
+ )
+ )
def _elem_to_obj(self, elem):
return Notification.from_xml(elem=elem, account=None)
@@ -103,9 +113,9 @@ Classes
return container.findall(Notification.response_tag())
def get_payload(self, subscription_id, watermark):
- payload = create_element(f'm:{self.SERVICE_NAME}')
- add_xml_child(payload, 'm:SubscriptionId', subscription_id)
- add_xml_child(payload, 'm:Watermark', watermark)
+ payload = create_element(f"m:{self.SERVICE_NAME}")
+ add_xml_child(payload, "m:SubscriptionId", subscription_id)
+ add_xml_child(payload, "m:Watermark", watermark)
return payload
Ancestors
@@ -136,9 +146,14 @@ Methods
Expand source code
def call(self, subscription_id, watermark):
- return self._elems_to_objs(self._get_elements(payload=self.get_payload(
- subscription_id=subscription_id, watermark=watermark,
- )))
+ return self._elems_to_objs(
+ self._get_elements(
+ payload=self.get_payload(
+ subscription_id=subscription_id,
+ watermark=watermark,
+ )
+ )
+ )
@@ -151,9 +166,9 @@ Methods
Expand source code
def get_payload(self, subscription_id, watermark):
- payload = create_element(f'm:{self.SERVICE_NAME}')
- add_xml_child(payload, 'm:SubscriptionId', subscription_id)
- add_xml_child(payload, 'm:Watermark', watermark)
+ payload = create_element(f"m:{self.SERVICE_NAME}")
+ add_xml_child(payload, "m:SubscriptionId", subscription_id)
+ add_xml_child(payload, "m:Watermark", watermark)
return payload
diff --git a/docs/exchangelib/services/get_folder.html b/docs/exchangelib/services/get_folder.html
index 39013eb3..2f47a12f 100644
--- a/docs/exchangelib/services/get_folder.html
+++ b/docs/exchangelib/services/get_folder.html
@@ -26,18 +26,20 @@ Module exchangelib.services.get_folder
Expand source code
-from .common import EWSAccountService, parse_folder_elem, folder_ids_element, shape_element
-from ..errors import ErrorFolderNotFound, ErrorNoPublicFolderReplicaAvailable, ErrorInvalidOperation
-from ..util import create_element, MNS
+from ..errors import ErrorFolderNotFound, ErrorInvalidOperation, ErrorNoPublicFolderReplicaAvailable
+from ..util import MNS, create_element
+from .common import EWSAccountService, folder_ids_element, parse_folder_elem, shape_element
class GetFolder(EWSAccountService):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/getfolder-operation"""
- SERVICE_NAME = 'GetFolder'
- element_container_name = f'{{{MNS}}}Folders'
+ SERVICE_NAME = "GetFolder"
+ element_container_name = f"{{{MNS}}}Folders"
ERRORS_TO_CATCH_IN_RESPONSE = EWSAccountService.ERRORS_TO_CATCH_IN_RESPONSE + (
- ErrorFolderNotFound, ErrorNoPublicFolderReplicaAvailable, ErrorInvalidOperation,
+ ErrorFolderNotFound,
+ ErrorNoPublicFolderReplicaAvailable,
+ ErrorInvalidOperation,
)
def __init__(self, *args, **kwargs):
@@ -56,12 +58,14 @@ Module exchangelib.services.get_folder
# We can't easily find the correct folder class from the returned XML. Instead, return objects with the same
# class as the folder instance it was requested with.
self.folders = list(folders) # Convert to a list, in case 'folders' is a generator. We're iterating twice.
- return self._elems_to_objs(self._chunked_get_elements(
- self.get_payload,
- items=self.folders,
- additional_fields=additional_fields,
- shape=shape,
- ))
+ return self._elems_to_objs(
+ self._chunked_get_elements(
+ self.get_payload,
+ items=self.folders,
+ additional_fields=additional_fields,
+ shape=shape,
+ )
+ )
def _elems_to_objs(self, elems):
for folder, elem in zip(self.folders, elems):
@@ -71,10 +75,12 @@ Module exchangelib.services.get_folder
yield parse_folder_elem(elem=elem, folder=folder, account=self.account)
def get_payload(self, folders, additional_fields, shape):
- payload = create_element(f'm:{self.SERVICE_NAME}')
- payload.append(shape_element(
- tag='m:FolderShape', shape=shape, additional_fields=additional_fields, version=self.account.version
- ))
+ payload = create_element(f"m:{self.SERVICE_NAME}")
+ payload.append(
+ shape_element(
+ tag="m:FolderShape", shape=shape, additional_fields=additional_fields, version=self.account.version
+ )
+ )
payload.append(folder_ids_element(folders=folders, version=self.account.version))
return payload
@@ -101,10 +107,12 @@ Classes
class GetFolder(EWSAccountService):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/getfolder-operation"""
- SERVICE_NAME = 'GetFolder'
- element_container_name = f'{{{MNS}}}Folders'
+ SERVICE_NAME = "GetFolder"
+ element_container_name = f"{{{MNS}}}Folders"
ERRORS_TO_CATCH_IN_RESPONSE = EWSAccountService.ERRORS_TO_CATCH_IN_RESPONSE + (
- ErrorFolderNotFound, ErrorNoPublicFolderReplicaAvailable, ErrorInvalidOperation,
+ ErrorFolderNotFound,
+ ErrorNoPublicFolderReplicaAvailable,
+ ErrorInvalidOperation,
)
def __init__(self, *args, **kwargs):
@@ -123,12 +131,14 @@ Classes
# We can't easily find the correct folder class from the returned XML. Instead, return objects with the same
# class as the folder instance it was requested with.
self.folders = list(folders) # Convert to a list, in case 'folders' is a generator. We're iterating twice.
- return self._elems_to_objs(self._chunked_get_elements(
- self.get_payload,
- items=self.folders,
- additional_fields=additional_fields,
- shape=shape,
- ))
+ return self._elems_to_objs(
+ self._chunked_get_elements(
+ self.get_payload,
+ items=self.folders,
+ additional_fields=additional_fields,
+ shape=shape,
+ )
+ )
def _elems_to_objs(self, elems):
for folder, elem in zip(self.folders, elems):
@@ -138,10 +148,12 @@ Classes
yield parse_folder_elem(elem=elem, folder=folder, account=self.account)
def get_payload(self, folders, additional_fields, shape):
- payload = create_element(f'm:{self.SERVICE_NAME}')
- payload.append(shape_element(
- tag='m:FolderShape', shape=shape, additional_fields=additional_fields, version=self.account.version
- ))
+ payload = create_element(f"m:{self.SERVICE_NAME}")
+ payload.append(
+ shape_element(
+ tag="m:FolderShape", shape=shape, additional_fields=additional_fields, version=self.account.version
+ )
+ )
payload.append(folder_ids_element(folders=folders, version=self.account.version))
return payload
@@ -192,12 +204,14 @@ Methods
# We can't easily find the correct folder class from the returned XML. Instead, return objects with the same
# class as the folder instance it was requested with.
self.folders = list(folders) # Convert to a list, in case 'folders' is a generator. We're iterating twice.
- return self._elems_to_objs(self._chunked_get_elements(
- self.get_payload,
- items=self.folders,
- additional_fields=additional_fields,
- shape=shape,
- ))
+ return self._elems_to_objs(
+ self._chunked_get_elements(
+ self.get_payload,
+ items=self.folders,
+ additional_fields=additional_fields,
+ shape=shape,
+ )
+ )
@@ -210,10 +224,12 @@ Methods
Expand source code
def get_payload(self, folders, additional_fields, shape):
- payload = create_element(f'm:{self.SERVICE_NAME}')
- payload.append(shape_element(
- tag='m:FolderShape', shape=shape, additional_fields=additional_fields, version=self.account.version
- ))
+ payload = create_element(f"m:{self.SERVICE_NAME}")
+ payload.append(
+ shape_element(
+ tag="m:FolderShape", shape=shape, additional_fields=additional_fields, version=self.account.version
+ )
+ )
payload.append(folder_ids_element(folders=folders, version=self.account.version))
return payload
diff --git a/docs/exchangelib/services/get_item.html b/docs/exchangelib/services/get_item.html
index 7f96dc3a..92d00151 100644
--- a/docs/exchangelib/services/get_item.html
+++ b/docs/exchangelib/services/get_item.html
@@ -26,16 +26,16 @@ Module exchangelib.services.get_item
Expand source code
-from .common import EWSAccountService, item_ids_element, shape_element
-from ..folders.base import BaseFolder
-from ..util import create_element, MNS
+from ..folders.base import BaseFolder
+from ..util import MNS, create_element
+from .common import EWSAccountService, item_ids_element, shape_element
class GetItem(EWSAccountService):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/getitem-operation"""
- SERVICE_NAME = 'GetItem'
- element_container_name = f'{{{MNS}}}Items'
+ SERVICE_NAME = "GetItem"
+ element_container_name = f"{{{MNS}}}Items"
def call(self, items, additional_fields, shape):
"""Return all items in an account that correspond to a list of ID's, in stable order.
@@ -46,18 +46,25 @@ Module exchangelib.services.get_item
:return: XML elements for the items, in stable order
"""
- return self._elems_to_objs(self._chunked_get_elements(
- self.get_payload, items=items, additional_fields=additional_fields, shape=shape,
- ))
+ return self._elems_to_objs(
+ self._chunked_get_elements(
+ self.get_payload,
+ items=items,
+ additional_fields=additional_fields,
+ shape=shape,
+ )
+ )
def _elem_to_obj(self, elem):
return BaseFolder.item_model_from_tag(elem.tag).from_xml(elem=elem, account=self.account)
def get_payload(self, items, additional_fields, shape):
- payload = create_element(f'm:{self.SERVICE_NAME}')
- payload.append(shape_element(
- tag='m:ItemShape', shape=shape, additional_fields=additional_fields, version=self.account.version
- ))
+ payload = create_element(f"m:{self.SERVICE_NAME}")
+ payload.append(
+ shape_element(
+ tag="m:ItemShape", shape=shape, additional_fields=additional_fields, version=self.account.version
+ )
+ )
payload.append(item_ids_element(items=items, version=self.account.version))
return payload
@@ -84,8 +91,8 @@ Classes
class GetItem(EWSAccountService):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/getitem-operation"""
- SERVICE_NAME = 'GetItem'
- element_container_name = f'{{{MNS}}}Items'
+ SERVICE_NAME = "GetItem"
+ element_container_name = f"{{{MNS}}}Items"
def call(self, items, additional_fields, shape):
"""Return all items in an account that correspond to a list of ID's, in stable order.
@@ -96,18 +103,25 @@ Classes
:return: XML elements for the items, in stable order
"""
- return self._elems_to_objs(self._chunked_get_elements(
- self.get_payload, items=items, additional_fields=additional_fields, shape=shape,
- ))
+ return self._elems_to_objs(
+ self._chunked_get_elements(
+ self.get_payload,
+ items=items,
+ additional_fields=additional_fields,
+ shape=shape,
+ )
+ )
def _elem_to_obj(self, elem):
return BaseFolder.item_model_from_tag(elem.tag).from_xml(elem=elem, account=self.account)
def get_payload(self, items, additional_fields, shape):
- payload = create_element(f'm:{self.SERVICE_NAME}')
- payload.append(shape_element(
- tag='m:ItemShape', shape=shape, additional_fields=additional_fields, version=self.account.version
- ))
+ payload = create_element(f"m:{self.SERVICE_NAME}")
+ payload.append(
+ shape_element(
+ tag="m:ItemShape", shape=shape, additional_fields=additional_fields, version=self.account.version
+ )
+ )
payload.append(item_ids_element(items=items, version=self.account.version))
return payload
@@ -151,9 +165,14 @@ Methods
:return: XML elements for the items, in stable order
"""
- return self._elems_to_objs(self._chunked_get_elements(
- self.get_payload, items=items, additional_fields=additional_fields, shape=shape,
- ))
+ return self._elems_to_objs(
+ self._chunked_get_elements(
+ self.get_payload,
+ items=items,
+ additional_fields=additional_fields,
+ shape=shape,
+ )
+ )
@@ -166,10 +185,12 @@ Methods
Expand source code
def get_payload(self, items, additional_fields, shape):
- payload = create_element(f'm:{self.SERVICE_NAME}')
- payload.append(shape_element(
- tag='m:ItemShape', shape=shape, additional_fields=additional_fields, version=self.account.version
- ))
+ payload = create_element(f"m:{self.SERVICE_NAME}")
+ payload.append(
+ shape_element(
+ tag="m:ItemShape", shape=shape, additional_fields=additional_fields, version=self.account.version
+ )
+ )
payload.append(item_ids_element(items=items, version=self.account.version))
return payload
diff --git a/docs/exchangelib/services/get_mail_tips.html b/docs/exchangelib/services/get_mail_tips.html
index e81c5e98..4254efe0 100644
--- a/docs/exchangelib/services/get_mail_tips.html
+++ b/docs/exchangelib/services/get_mail_tips.html
@@ -26,32 +26,34 @@ Module exchangelib.services.get_mail_tips
Expand source code
-from .common import EWSService
-from ..properties import MailTips
-from ..util import create_element, set_xml_value, MNS
+from ..properties import MailTips
+from ..util import MNS, create_element, set_xml_value
+from .common import EWSService
class GetMailTips(EWSService):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/getmailtips-operation"""
- SERVICE_NAME = 'GetMailTips'
+ SERVICE_NAME = "GetMailTips"
def call(self, sending_as, recipients, mail_tips_requested):
- return self._elems_to_objs(self._chunked_get_elements(
- self.get_payload,
- items=recipients,
- sending_as=sending_as,
- mail_tips_requested=mail_tips_requested,
- ))
+ return self._elems_to_objs(
+ self._chunked_get_elements(
+ self.get_payload,
+ items=recipients,
+ sending_as=sending_as,
+ mail_tips_requested=mail_tips_requested,
+ )
+ )
def _elem_to_obj(self, elem):
return MailTips.from_xml(elem=elem, account=None)
- def get_payload(self, recipients, sending_as, mail_tips_requested):
- payload = create_element(f'm:{self.SERVICE_NAME}')
+ def get_payload(self, recipients, sending_as, mail_tips_requested):
+ payload = create_element(f"m:{self.SERVICE_NAME}")
set_xml_value(payload, sending_as, version=self.protocol.version)
- recipients_elem = create_element('m:Recipients')
+ recipients_elem = create_element("m:Recipients")
for recipient in recipients:
set_xml_value(recipients_elem, recipient, version=self.protocol.version)
payload.append(recipients_elem)
@@ -66,7 +68,7 @@ Module exchangelib.services.get_mail_tips
@classmethod
def _response_message_tag(cls):
- return f'{{{MNS}}}MailTipsResponseMessageType'
+ return f"{{{MNS}}}MailTipsResponseMessageType"
@@ -91,24 +93,26 @@ Classes
class GetMailTips(EWSService):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/getmailtips-operation"""
- SERVICE_NAME = 'GetMailTips'
+ SERVICE_NAME = "GetMailTips"
def call(self, sending_as, recipients, mail_tips_requested):
- return self._elems_to_objs(self._chunked_get_elements(
- self.get_payload,
- items=recipients,
- sending_as=sending_as,
- mail_tips_requested=mail_tips_requested,
- ))
+ return self._elems_to_objs(
+ self._chunked_get_elements(
+ self.get_payload,
+ items=recipients,
+ sending_as=sending_as,
+ mail_tips_requested=mail_tips_requested,
+ )
+ )
def _elem_to_obj(self, elem):
return MailTips.from_xml(elem=elem, account=None)
- def get_payload(self, recipients, sending_as, mail_tips_requested):
- payload = create_element(f'm:{self.SERVICE_NAME}')
+ def get_payload(self, recipients, sending_as, mail_tips_requested):
+ payload = create_element(f"m:{self.SERVICE_NAME}")
set_xml_value(payload, sending_as, version=self.protocol.version)
- recipients_elem = create_element('m:Recipients')
+ recipients_elem = create_element("m:Recipients")
for recipient in recipients:
set_xml_value(recipients_elem, recipient, version=self.protocol.version)
payload.append(recipients_elem)
@@ -123,7 +127,7 @@ Classes
@classmethod
def _response_message_tag(cls):
- return f'{{{MNS}}}MailTipsResponseMessageType'
+ return f"{{{MNS}}}MailTipsResponseMessageType"
Ancestors
@@ -148,12 +152,14 @@ Methods
Expand source code
def call(self, sending_as, recipients, mail_tips_requested):
- return self._elems_to_objs(self._chunked_get_elements(
- self.get_payload,
- items=recipients,
- sending_as=sending_as,
- mail_tips_requested=mail_tips_requested,
- ))
+ return self._elems_to_objs(
+ self._chunked_get_elements(
+ self.get_payload,
+ items=recipients,
+ sending_as=sending_as,
+ mail_tips_requested=mail_tips_requested,
+ )
+ )
@@ -165,11 +171,11 @@ Methods
Expand source code
-def get_payload(self, recipients, sending_as, mail_tips_requested):
- payload = create_element(f'm:{self.SERVICE_NAME}')
+def get_payload(self, recipients, sending_as, mail_tips_requested):
+ payload = create_element(f"m:{self.SERVICE_NAME}")
set_xml_value(payload, sending_as, version=self.protocol.version)
- recipients_elem = create_element('m:Recipients')
+ recipients_elem = create_element("m:Recipients")
for recipient in recipients:
set_xml_value(recipients_elem, recipient, version=self.protocol.version)
payload.append(recipients_elem)
diff --git a/docs/exchangelib/services/get_persona.html b/docs/exchangelib/services/get_persona.html
index a77d3294..303897e6 100644
--- a/docs/exchangelib/services/get_persona.html
+++ b/docs/exchangelib/services/get_persona.html
@@ -26,16 +26,16 @@ Module exchangelib.services.get_persona
Expand source code
-from .common import EWSAccountService, to_item_id
-from ..items import Persona
+from ..items import Persona
from ..properties import PersonaId
-from ..util import create_element, set_xml_value, MNS
+from ..util import MNS, create_element, set_xml_value
+from .common import EWSAccountService, to_item_id
class GetPersona(EWSAccountService):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/getpersona-operation"""
- SERVICE_NAME = 'GetPersona'
+ SERVICE_NAME = "GetPersona"
def call(self, personas):
# GetPersona only accepts one persona ID per request. Crazy.
@@ -47,18 +47,16 @@ Module exchangelib.services.get_persona
def get_payload(self, persona):
return set_xml_value(
- create_element(f'm:{self.SERVICE_NAME}'),
- to_item_id(persona, PersonaId),
- version=self.protocol.version
+ create_element(f"m:{self.SERVICE_NAME}"), to_item_id(persona, PersonaId), version=self.protocol.version
)
@classmethod
def _get_elements_in_container(cls, container):
- return container.findall(f'{{{MNS}}}{Persona.ELEMENT_NAME}')
+ return container.findall(f"{{{MNS}}}{Persona.ELEMENT_NAME}")
@classmethod
def _response_tag(cls):
- return f'{{{MNS}}}{cls.SERVICE_NAME}ResponseMessage'
+ return f"{{{MNS}}}{cls.SERVICE_NAME}ResponseMessage"
@@ -83,7 +81,7 @@ Classes
class GetPersona(EWSAccountService):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/getpersona-operation"""
- SERVICE_NAME = 'GetPersona'
+ SERVICE_NAME = "GetPersona"
def call(self, personas):
# GetPersona only accepts one persona ID per request. Crazy.
@@ -95,18 +93,16 @@ Classes
def get_payload(self, persona):
return set_xml_value(
- create_element(f'm:{self.SERVICE_NAME}'),
- to_item_id(persona, PersonaId),
- version=self.protocol.version
+ create_element(f"m:{self.SERVICE_NAME}"), to_item_id(persona, PersonaId), version=self.protocol.version
)
@classmethod
def _get_elements_in_container(cls, container):
- return container.findall(f'{{{MNS}}}{Persona.ELEMENT_NAME}')
+ return container.findall(f"{{{MNS}}}{Persona.ELEMENT_NAME}")
@classmethod
def _response_tag(cls):
- return f'{{{MNS}}}{cls.SERVICE_NAME}ResponseMessage'
+ return f"{{{MNS}}}{cls.SERVICE_NAME}ResponseMessage"
Ancestors
@@ -148,9 +144,7 @@ Methods
def get_payload(self, persona):
return set_xml_value(
- create_element(f'm:{self.SERVICE_NAME}'),
- to_item_id(persona, PersonaId),
- version=self.protocol.version
+ create_element(f"m:{self.SERVICE_NAME}"), to_item_id(persona, PersonaId), version=self.protocol.version
)
diff --git a/docs/exchangelib/services/get_room_lists.html b/docs/exchangelib/services/get_room_lists.html
index 98b58862..eb084e32 100644
--- a/docs/exchangelib/services/get_room_lists.html
+++ b/docs/exchangelib/services/get_room_lists.html
@@ -26,17 +26,17 @@ Module exchangelib.services.get_room_lists
Expand source code
-from .common import EWSService
-from ..properties import RoomList
-from ..util import create_element, MNS
+from ..properties import RoomList
+from ..util import MNS, create_element
from ..version import EXCHANGE_2010
+from .common import EWSService
class GetRoomLists(EWSService):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/getroomlists-operation"""
- SERVICE_NAME = 'GetRoomLists'
- element_container_name = f'{{{MNS}}}RoomLists'
+ SERVICE_NAME = "GetRoomLists"
+ element_container_name = f"{{{MNS}}}RoomLists"
supported_from = EXCHANGE_2010
def call(self):
@@ -46,7 +46,7 @@ Module exchangelib.services.get_room_lists
return RoomList.from_xml(elem=elem, account=None)
def get_payload(self):
- return create_element(f'm:{self.SERVICE_NAME}')
+ return create_element(f"m:{self.SERVICE_NAME}")
@@ -71,8 +71,8 @@ Classes
class GetRoomLists(EWSService):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/getroomlists-operation"""
- SERVICE_NAME = 'GetRoomLists'
- element_container_name = f'{{{MNS}}}RoomLists'
+ SERVICE_NAME = "GetRoomLists"
+ element_container_name = f"{{{MNS}}}RoomLists"
supported_from = EXCHANGE_2010
def call(self):
@@ -82,7 +82,7 @@ Classes
return RoomList.from_xml(elem=elem, account=None)
def get_payload(self):
- return create_element(f'm:{self.SERVICE_NAME}')
+ return create_element(f"m:{self.SERVICE_NAME}")
Ancestors
@@ -128,7 +128,7 @@ Methods
Expand source code
def get_payload(self):
- return create_element(f'm:{self.SERVICE_NAME}')
+ return create_element(f"m:{self.SERVICE_NAME}")
diff --git a/docs/exchangelib/services/get_rooms.html b/docs/exchangelib/services/get_rooms.html
index 45a79a64..ce91ce40 100644
--- a/docs/exchangelib/services/get_rooms.html
+++ b/docs/exchangelib/services/get_rooms.html
@@ -26,17 +26,17 @@ exchangelib.services.get_rooms
from .common import EWSService
-from ..properties import Room
-from ..util import create_element, set_xml_value, MNS
+from ..properties import Room
+from ..util import MNS, create_element, set_xml_value
from ..version import EXCHANGE_2010
+from .common import EWSService
class GetRooms(EWSService):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/getrooms-operation"""
- SERVICE_NAME = 'GetRooms'
- element_container_name = f'{{{MNS}}}Rooms'
+ SERVICE_NAME = "GetRooms"
+ element_container_name = f"{{{MNS}}}Rooms"
supported_from = EXCHANGE_2010
def call(self, room_list):
@@ -46,7 +46,7 @@ Module exchangelib.services.get_rooms
return Room.from_xml(elem=elem, account=None)
def get_payload(self, room_list):
- return set_xml_value(create_element(f'm:{self.SERVICE_NAME}'), room_list, version=self.protocol.version)
+ return set_xml_value(create_element(f"m:{self.SERVICE_NAME}"), room_list, version=self.protocol.version)
class GetRooms(EWSService):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/getrooms-operation"""
- SERVICE_NAME = 'GetRooms'
- element_container_name = f'{{{MNS}}}Rooms'
+ SERVICE_NAME = "GetRooms"
+ element_container_name = f"{{{MNS}}}Rooms"
supported_from = EXCHANGE_2010
def call(self, room_list):
@@ -82,7 +82,7 @@ Classes
return Room.from_xml(elem=elem, account=None)
def get_payload(self, room_list):
- return set_xml_value(create_element(f'm:{self.SERVICE_NAME}'), room_list, version=self.protocol.version)
+ return set_xml_value(create_element(f"m:{self.SERVICE_NAME}"), room_list, version=self.protocol.version)
def get_payload(self, room_list):
- return set_xml_value(create_element(f'm:{self.SERVICE_NAME}'), room_list, version=self.protocol.version)
+ return set_xml_value(create_element(f"m:{self.SERVICE_NAME}"), room_list, version=self.protocol.version)
diff --git a/docs/exchangelib/services/get_searchable_mailboxes.html b/docs/exchangelib/services/get_searchable_mailboxes.html
index b69e0382..f9ba8faa 100644
--- a/docs/exchangelib/services/get_searchable_mailboxes.html
+++ b/docs/exchangelib/services/get_searchable_mailboxes.html
@@ -26,11 +26,11 @@ exchangelib.services.get_searchable_mailboxes
Expand source code
-from .common import EWSService
-from ..errors import MalformedResponseError
-from ..properties import SearchableMailbox, FailedMailbox
-from ..util import create_element, add_xml_child, MNS
+from ..errors import MalformedResponseError
+from ..properties import FailedMailbox, SearchableMailbox
+from ..util import MNS, add_xml_child, create_element
from ..version import EXCHANGE_2013
+from .common import EWSService
class GetSearchableMailboxes(EWSService):
@@ -38,27 +38,31 @@ Module exchangelib.services.get_searchable_mailboxesClasses
https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/getsearchablemailboxes-operation
"""
- SERVICE_NAME = 'GetSearchableMailboxes'
- element_container_name = f'{{{MNS}}}SearchableMailboxes'
- failed_mailboxes_container_name = f'{{{MNS}}}FailedMailboxes'
+ SERVICE_NAME = "GetSearchableMailboxes"
+ element_container_name = f"{{{MNS}}}SearchableMailboxes"
+ failed_mailboxes_container_name = f"{{{MNS}}}FailedMailboxes"
supported_from = EXCHANGE_2013
cls_map = {cls.response_tag(): cls for cls in (SearchableMailbox, FailedMailbox)}
def call(self, search_filter, expand_group_membership):
- return self._elems_to_objs(self._get_elements(payload=self.get_payload(
- search_filter=search_filter,
- expand_group_membership=expand_group_membership,
- )))
+ return self._elems_to_objs(
+ self._get_elements(
+ payload=self.get_payload(
+ search_filter=search_filter,
+ expand_group_membership=expand_group_membership,
+ )
+ )
+ )
def _elem_to_obj(self, elem):
return self.cls_map[elem.tag].from_xml(elem=elem, account=None)
def get_payload(self, search_filter, expand_group_membership):
- payload = create_element(f'm:{self.SERVICE_NAME}')
+ payload = create_element(f"m:{self.SERVICE_NAME}")
if search_filter:
- add_xml_child(payload, 'm:SearchFilter', search_filter)
+ add_xml_child(payload, "m:SearchFilter", search_filter)
if expand_group_membership is not None:
- add_xml_child(payload, 'm:ExpandGroupMembership', 'true' if expand_group_membership else 'false')
+ add_xml_child(payload, "m:ExpandGroupMembership", "true" if expand_group_membership else "false")
return payload
def _get_elements_in_response(self, response):
@@ -169,10 +177,14 @@ Methods
Expand source code
def call(self, search_filter, expand_group_membership):
- return self._elems_to_objs(self._get_elements(payload=self.get_payload(
- search_filter=search_filter,
- expand_group_membership=expand_group_membership,
- )))
+ return self._elems_to_objs(
+ self._get_elements(
+ payload=self.get_payload(
+ search_filter=search_filter,
+ expand_group_membership=expand_group_membership,
+ )
+ )
+ )
@@ -185,11 +197,11 @@ Methods
Expand source code
def get_payload(self, search_filter, expand_group_membership):
- payload = create_element(f'm:{self.SERVICE_NAME}')
+ payload = create_element(f"m:{self.SERVICE_NAME}")
if search_filter:
- add_xml_child(payload, 'm:SearchFilter', search_filter)
+ add_xml_child(payload, "m:SearchFilter", search_filter)
if expand_group_membership is not None:
- add_xml_child(payload, 'm:ExpandGroupMembership', 'true' if expand_group_membership else 'false')
+ add_xml_child(payload, "m:ExpandGroupMembership", "true" if expand_group_membership else "false")
return payload
diff --git a/docs/exchangelib/services/get_server_time_zones.html b/docs/exchangelib/services/get_server_time_zones.html
index 9143769e..0c81a838 100644
--- a/docs/exchangelib/services/get_server_time_zones.html
+++ b/docs/exchangelib/services/get_server_time_zones.html
@@ -26,10 +26,10 @@ Module exchangelib.services.get_server_time_zones
Expand source code
-from .common import EWSService
-from ..properties import TimeZoneDefinition
-from ..util import create_element, set_xml_value, peek, MNS
+from ..properties import TimeZoneDefinition
+from ..util import MNS, create_element, peek, set_xml_value
from ..version import EXCHANGE_2010
+from .common import EWSService
class GetServerTimeZones(EWSService):
@@ -37,27 +37,28 @@ Module exchangelib.services.get_server_time_zones
https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/getservertimezones-operation
"""
- SERVICE_NAME = 'GetServerTimeZones'
- element_container_name = f'{{{MNS}}}TimeZoneDefinitions'
+ SERVICE_NAME = "GetServerTimeZones"
+ element_container_name = f"{{{MNS}}}TimeZoneDefinitions"
supported_from = EXCHANGE_2010
def call(self, timezones=None, return_full_timezone_data=False):
- return self._elems_to_objs(self._get_elements(payload=self.get_payload(
- timezones=timezones,
- return_full_timezone_data=return_full_timezone_data
- )))
+ return self._elems_to_objs(
+ self._get_elements(
+ payload=self.get_payload(timezones=timezones, return_full_timezone_data=return_full_timezone_data)
+ )
+ )
def get_payload(self, timezones, return_full_timezone_data):
payload = create_element(
- f'm:{self.SERVICE_NAME}',
+ f"m:{self.SERVICE_NAME}",
attrs=dict(ReturnFullTimeZoneData=return_full_timezone_data),
)
if timezones is not None:
is_empty, timezones = peek(timezones)
if not is_empty:
- tz_ids = create_element('m:Ids')
+ tz_ids = create_element("m:Ids")
for timezone in timezones:
- tz_id = set_xml_value(create_element('t:Id'), timezone.ms_id)
+ tz_id = set_xml_value(create_element("t:Id"), timezone.ms_id)
tz_ids.append(tz_id)
payload.append(tz_ids)
return payload
@@ -91,27 +92,28 @@ Classes
https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/getservertimezones-operation
"""
- SERVICE_NAME = 'GetServerTimeZones'
- element_container_name = f'{{{MNS}}}TimeZoneDefinitions'
+ SERVICE_NAME = "GetServerTimeZones"
+ element_container_name = f"{{{MNS}}}TimeZoneDefinitions"
supported_from = EXCHANGE_2010
def call(self, timezones=None, return_full_timezone_data=False):
- return self._elems_to_objs(self._get_elements(payload=self.get_payload(
- timezones=timezones,
- return_full_timezone_data=return_full_timezone_data
- )))
+ return self._elems_to_objs(
+ self._get_elements(
+ payload=self.get_payload(timezones=timezones, return_full_timezone_data=return_full_timezone_data)
+ )
+ )
def get_payload(self, timezones, return_full_timezone_data):
payload = create_element(
- f'm:{self.SERVICE_NAME}',
+ f"m:{self.SERVICE_NAME}",
attrs=dict(ReturnFullTimeZoneData=return_full_timezone_data),
)
if timezones is not None:
is_empty, timezones = peek(timezones)
if not is_empty:
- tz_ids = create_element('m:Ids')
+ tz_ids = create_element("m:Ids")
for timezone in timezones:
- tz_id = set_xml_value(create_element('t:Id'), timezone.ms_id)
+ tz_id = set_xml_value(create_element("t:Id"), timezone.ms_id)
tz_ids.append(tz_id)
payload.append(tz_ids)
return payload
@@ -150,10 +152,11 @@ Methods
Expand source code
def call(self, timezones=None, return_full_timezone_data=False):
- return self._elems_to_objs(self._get_elements(payload=self.get_payload(
- timezones=timezones,
- return_full_timezone_data=return_full_timezone_data
- )))
+ return self._elems_to_objs(
+ self._get_elements(
+ payload=self.get_payload(timezones=timezones, return_full_timezone_data=return_full_timezone_data)
+ )
+ )
@@ -167,15 +170,15 @@ Methods
def get_payload(self, timezones, return_full_timezone_data):
payload = create_element(
- f'm:{self.SERVICE_NAME}',
+ f"m:{self.SERVICE_NAME}",
attrs=dict(ReturnFullTimeZoneData=return_full_timezone_data),
)
if timezones is not None:
is_empty, timezones = peek(timezones)
if not is_empty:
- tz_ids = create_element('m:Ids')
+ tz_ids = create_element("m:Ids")
for timezone in timezones:
- tz_id = set_xml_value(create_element('t:Id'), timezone.ms_id)
+ tz_id = set_xml_value(create_element("t:Id"), timezone.ms_id)
tz_ids.append(tz_id)
payload.append(tz_ids)
return payload
diff --git a/docs/exchangelib/services/get_streaming_events.html b/docs/exchangelib/services/get_streaming_events.html
index d3b3aad1..7306c649 100644
--- a/docs/exchangelib/services/get_streaming_events.html
+++ b/docs/exchangelib/services/get_streaming_events.html
@@ -28,13 +28,13 @@ Module exchangelib.services.get_streaming_events
<
import logging
-from .common import EWSAccountService, add_xml_child
from ..errors import EWSError, InvalidTypeError
from ..properties import Notification
-from ..util import create_element, get_xml_attr, get_xml_attrs, MNS, DocumentYielder, DummyResponse
+from ..util import MNS, DocumentYielder, DummyResponse, create_element, get_xml_attr, get_xml_attrs
+from .common import EWSAccountService, add_xml_child
log = logging.getLogger(__name__)
-xml_log = logging.getLogger(f'{__name__}.xml')
+xml_log = logging.getLogger(f"{__name__}.xml")
class GetStreamingEvents(EWSAccountService):
@@ -42,13 +42,13 @@ Module exchangelib.services.get_streaming_events
<
https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/getstreamingevents-operation
"""
- SERVICE_NAME = 'GetStreamingEvents'
- element_container_name = f'{{{MNS}}}Notifications'
+ SERVICE_NAME = "GetStreamingEvents"
+ element_container_name = f"{{{MNS}}}Notifications"
prefer_affinity = True
# Connection status values
- OK = 'OK'
- CLOSED = 'Closed'
+ OK = "OK"
+ CLOSED = "Closed"
def __init__(self, *args, **kwargs):
# These values are set each time call() is consumed
@@ -58,14 +58,19 @@ Module exchangelib.services.get_streaming_events
<
def call(self, subscription_ids, connection_timeout):
if not isinstance(connection_timeout, int):
- raise InvalidTypeError('connection_timeout', connection_timeout, int)
+ raise InvalidTypeError("connection_timeout", connection_timeout, int)
if connection_timeout < 1:
raise ValueError(f"'connection_timeout' {connection_timeout} must be a positive integer")
# Add 60 seconds to the timeout, to allow us to always get the final message containing ConnectionStatus=Closed
self.timeout = connection_timeout * 60 + 60
- return self._elems_to_objs(self._get_elements(payload=self.get_payload(
- subscription_ids=subscription_ids, connection_timeout=connection_timeout,
- )))
+ return self._elems_to_objs(
+ self._get_elements(
+ payload=self.get_payload(
+ subscription_ids=subscription_ids,
+ connection_timeout=connection_timeout,
+ )
+ )
+ )
def _elem_to_obj(self, elem):
return Notification.from_xml(elem=elem, account=None)
@@ -81,7 +86,7 @@ Module exchangelib.services.get_streaming_events
<
# XML response.
r = body
for i, doc in enumerate(DocumentYielder(r.iter_content()), start=1):
- xml_log.debug('''Response XML (docs counter: %(i)s): %(xml_response)s''', dict(i=i, xml_response=doc))
+ xml_log.debug("Response XML (docs counter: %(i)s): %(xml_response)s", dict(i=i, xml_response=doc))
response = DummyResponse(content=doc)
try:
_, body = super()._get_soap_parts(response=response, **parse_opts)
@@ -96,10 +101,10 @@ Module exchangelib.services.get_streaming_events
<
break
def _get_element_container(self, message, name=None):
- error_ids_elem = message.find(f'{{{MNS}}}ErrorSubscriptionIds')
- error_ids = [] if error_ids_elem is None else get_xml_attrs(error_ids_elem, f'{{{MNS}}}SubscriptionId')
- self.connection_status = get_xml_attr(message, f'{{{MNS}}}ConnectionStatus') # Either 'OK' or 'Closed'
- log.debug('Connection status is: %s', self.connection_status)
+ error_ids_elem = message.find(f"{{{MNS}}}ErrorSubscriptionIds")
+ error_ids = [] if error_ids_elem is None else get_xml_attrs(error_ids_elem, f"{{{MNS}}}SubscriptionId")
+ self.connection_status = get_xml_attr(message, f"{{{MNS}}}ConnectionStatus") # Either 'OK' or 'Closed'
+ log.debug("Connection status is: %s", self.connection_status)
# Upstream normally expects to find a 'name' tag but our response does not always have it. We still want to
# call upstream, to have exceptions raised. Return an empty list if there is no 'name' tag and no errors.
if message.find(name) is None:
@@ -111,20 +116,20 @@ Module exchangelib.services.get_streaming_events
<
# subscriptions seem to never be returned even though the XML spec allows it. This means there's no point in
# trying to collect any notifications here and delivering a combination of errors and return values.
if error_ids:
- e.value += f' (subscription IDs: {error_ids})'
+ e.value += f" (subscription IDs: {error_ids})"
raise e
return [] if name is None else res
def get_payload(self, subscription_ids, connection_timeout):
- payload = create_element(f'm:{self.SERVICE_NAME}')
- subscriptions_elem = create_element('m:SubscriptionIds')
+ payload = create_element(f"m:{self.SERVICE_NAME}")
+ subscriptions_elem = create_element("m:SubscriptionIds")
for subscription_id in subscription_ids:
- add_xml_child(subscriptions_elem, 't:SubscriptionId', subscription_id)
+ add_xml_child(subscriptions_elem, "t:SubscriptionId", subscription_id)
if not len(subscriptions_elem):
raise ValueError("'subscription_ids' must not be empty")
payload.append(subscriptions_elem)
- add_xml_child(payload, 'm:ConnectionTimeout', connection_timeout)
+ add_xml_child(payload, "m:ConnectionTimeout", connection_timeout)
return payload
def call(self, subscription_ids, connection_timeout):
if not isinstance(connection_timeout, int):
- raise InvalidTypeError('connection_timeout', connection_timeout, int)
+ raise InvalidTypeError("connection_timeout", connection_timeout, int)
if connection_timeout < 1:
raise ValueError(f"'connection_timeout' {connection_timeout} must be a positive integer")
# Add 60 seconds to the timeout, to allow us to always get the final message containing ConnectionStatus=Closed
self.timeout = connection_timeout * 60 + 60
- return self._elems_to_objs(self._get_elements(payload=self.get_payload(
- subscription_ids=subscription_ids, connection_timeout=connection_timeout,
- )))
+ return self._elems_to_objs(
+ self._get_elements(
+ payload=self.get_payload(
+ subscription_ids=subscription_ids,
+ connection_timeout=connection_timeout,
+ )
+ )
+ )
@@ -299,15 +314,15 @@ Methods
Expand source code
def get_payload(self, subscription_ids, connection_timeout):
- payload = create_element(f'm:{self.SERVICE_NAME}')
- subscriptions_elem = create_element('m:SubscriptionIds')
+ payload = create_element(f"m:{self.SERVICE_NAME}")
+ subscriptions_elem = create_element("m:SubscriptionIds")
for subscription_id in subscription_ids:
- add_xml_child(subscriptions_elem, 't:SubscriptionId', subscription_id)
+ add_xml_child(subscriptions_elem, "t:SubscriptionId", subscription_id)
if not len(subscriptions_elem):
raise ValueError("'subscription_ids' must not be empty")
payload.append(subscriptions_elem)
- add_xml_child(payload, 'm:ConnectionTimeout', connection_timeout)
+ add_xml_child(payload, "m:ConnectionTimeout", connection_timeout)
return payload
diff --git a/docs/exchangelib/services/get_user_availability.html b/docs/exchangelib/services/get_user_availability.html
index 1e50527e..ba93a061 100644
--- a/docs/exchangelib/services/get_user_availability.html
+++ b/docs/exchangelib/services/get_user_availability.html
@@ -26,9 +26,9 @@ Module exchangelib.services.get_user_availability
Expand source code
-from .common import EWSService
-from ..properties import FreeBusyView
-from ..util import create_element, set_xml_value, MNS
+from ..properties import FreeBusyView
+from ..util import MNS, create_element, set_xml_value
+from .common import EWSService
class GetUserAvailability(EWSService):
@@ -37,45 +37,47 @@ Module exchangelib.services.get_user_availability
https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/getuseravailability-operation
"""
- SERVICE_NAME = 'GetUserAvailability'
+ SERVICE_NAME = "GetUserAvailability"
def call(self, timezone, mailbox_data, free_busy_view_options):
# TODO: Also supports SuggestionsViewOptions, see
# https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/suggestionsviewoptions
- return self._elems_to_objs(self._get_elements(payload=self.get_payload(
- timezone=timezone,
- mailbox_data=mailbox_data,
- free_busy_view_options=free_busy_view_options
- )))
+ return self._elems_to_objs(
+ self._get_elements(
+ payload=self.get_payload(
+ timezone=timezone, mailbox_data=mailbox_data, free_busy_view_options=free_busy_view_options
+ )
+ )
+ )
def _elem_to_obj(self, elem):
return FreeBusyView.from_xml(elem=elem, account=None)
def get_payload(self, timezone, mailbox_data, free_busy_view_options):
- payload = create_element(f'm:{self.SERVICE_NAME}Request')
+ payload = create_element(f"m:{self.SERVICE_NAME}Request")
set_xml_value(payload, timezone, version=self.protocol.version)
- mailbox_data_array = create_element('m:MailboxDataArray')
+ mailbox_data_array = create_element("m:MailboxDataArray")
set_xml_value(mailbox_data_array, mailbox_data, version=self.protocol.version)
payload.append(mailbox_data_array)
return set_xml_value(payload, free_busy_view_options, version=self.protocol.version)
@staticmethod
def _response_messages_tag():
- return f'{{{MNS}}}FreeBusyResponseArray'
+ return f"{{{MNS}}}FreeBusyResponseArray"
@classmethod
def _response_message_tag(cls):
- return f'{{{MNS}}}FreeBusyResponse'
+ return f"{{{MNS}}}FreeBusyResponse"
def _get_elements_in_response(self, response):
for msg in response:
# Just check the response code and raise errors
- self._get_element_container(message=msg.find(f'{{{MNS}}}ResponseMessage'))
+ self._get_element_container(message=msg.find(f"{{{MNS}}}ResponseMessage"))
yield from self._get_elements_in_container(container=msg)
@classmethod
def _get_elements_in_container(cls, container):
- return [container.find(f'{{{MNS}}}FreeBusyView')]
+ return [container.find(f"{{{MNS}}}FreeBusyView")]
@@ -105,45 +107,47 @@ Classes
https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/getuseravailability-operation
"""
- SERVICE_NAME = 'GetUserAvailability'
+ SERVICE_NAME = "GetUserAvailability"
def call(self, timezone, mailbox_data, free_busy_view_options):
# TODO: Also supports SuggestionsViewOptions, see
# https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/suggestionsviewoptions
- return self._elems_to_objs(self._get_elements(payload=self.get_payload(
- timezone=timezone,
- mailbox_data=mailbox_data,
- free_busy_view_options=free_busy_view_options
- )))
+ return self._elems_to_objs(
+ self._get_elements(
+ payload=self.get_payload(
+ timezone=timezone, mailbox_data=mailbox_data, free_busy_view_options=free_busy_view_options
+ )
+ )
+ )
def _elem_to_obj(self, elem):
return FreeBusyView.from_xml(elem=elem, account=None)
def get_payload(self, timezone, mailbox_data, free_busy_view_options):
- payload = create_element(f'm:{self.SERVICE_NAME}Request')
+ payload = create_element(f"m:{self.SERVICE_NAME}Request")
set_xml_value(payload, timezone, version=self.protocol.version)
- mailbox_data_array = create_element('m:MailboxDataArray')
+ mailbox_data_array = create_element("m:MailboxDataArray")
set_xml_value(mailbox_data_array, mailbox_data, version=self.protocol.version)
payload.append(mailbox_data_array)
return set_xml_value(payload, free_busy_view_options, version=self.protocol.version)
@staticmethod
def _response_messages_tag():
- return f'{{{MNS}}}FreeBusyResponseArray'
+ return f"{{{MNS}}}FreeBusyResponseArray"
@classmethod
def _response_message_tag(cls):
- return f'{{{MNS}}}FreeBusyResponse'
+ return f"{{{MNS}}}FreeBusyResponse"
def _get_elements_in_response(self, response):
for msg in response:
# Just check the response code and raise errors
- self._get_element_container(message=msg.find(f'{{{MNS}}}ResponseMessage'))
+ self._get_element_container(message=msg.find(f"{{{MNS}}}ResponseMessage"))
yield from self._get_elements_in_container(container=msg)
@classmethod
def _get_elements_in_container(cls, container):
- return [container.find(f'{{{MNS}}}FreeBusyView')]
+ return [container.find(f"{{{MNS}}}FreeBusyView")]
def call(self, timezone, mailbox_data, free_busy_view_options):
# TODO: Also supports SuggestionsViewOptions, see
# https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/suggestionsviewoptions
- return self._elems_to_objs(self._get_elements(payload=self.get_payload(
- timezone=timezone,
- mailbox_data=mailbox_data,
- free_busy_view_options=free_busy_view_options
- )))
+ return self._elems_to_objs(
+ self._get_elements(
+ payload=self.get_payload(
+ timezone=timezone, mailbox_data=mailbox_data, free_busy_view_options=free_busy_view_options
+ )
+ )
+ )
@@ -187,9 +193,9 @@ Methods
Expand source code
def get_payload(self, timezone, mailbox_data, free_busy_view_options):
- payload = create_element(f'm:{self.SERVICE_NAME}Request')
+ payload = create_element(f"m:{self.SERVICE_NAME}Request")
set_xml_value(payload, timezone, version=self.protocol.version)
- mailbox_data_array = create_element('m:MailboxDataArray')
+ mailbox_data_array = create_element("m:MailboxDataArray")
set_xml_value(mailbox_data_array, mailbox_data, version=self.protocol.version)
payload.append(mailbox_data_array)
return set_xml_value(payload, free_busy_view_options, version=self.protocol.version)
diff --git a/docs/exchangelib/services/get_user_configuration.html b/docs/exchangelib/services/get_user_configuration.html
index ce9e2a08..746b6d1e 100644
--- a/docs/exchangelib/services/get_user_configuration.html
+++ b/docs/exchangelib/services/get_user_configuration.html
@@ -26,16 +26,16 @@ Module exchangelib.services.get_user_configuration
Expand source code
-from .common import EWSAccountService
-from ..errors import InvalidEnumValue
+from ..errors import InvalidEnumValue
from ..properties import UserConfiguration
from ..util import create_element, set_xml_value
+from .common import EWSAccountService
-ID = 'Id'
-DICTIONARY = 'Dictionary'
-XML_DATA = 'XmlData'
-BINARY_DATA = 'BinaryData'
-ALL = 'All'
+ID = "Id"
+DICTIONARY = "Dictionary"
+XML_DATA = "XmlData"
+BINARY_DATA = "BinaryData"
+ALL = "All"
PROPERTIES_CHOICES = (ID, DICTIONARY, XML_DATA, BINARY_DATA, ALL)
@@ -44,14 +44,16 @@ Module exchangelib.services.get_user_configuration
Module exchangelib.services.get_user_configuration
@@ -94,14 +96,16 @@ Classes
https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/getuserconfiguration-operation
"""
- SERVICE_NAME = 'GetUserConfiguration'
+ SERVICE_NAME = "GetUserConfiguration"
def call(self, user_configuration_name, properties):
if properties not in PROPERTIES_CHOICES:
- raise InvalidEnumValue('properties', properties, PROPERTIES_CHOICES)
- return self._elems_to_objs(self._get_elements(payload=self.get_payload(
- user_configuration_name=user_configuration_name, properties=properties
- )))
+ raise InvalidEnumValue("properties", properties, PROPERTIES_CHOICES)
+ return self._elems_to_objs(
+ self._get_elements(
+ payload=self.get_payload(user_configuration_name=user_configuration_name, properties=properties)
+ )
+ )
def _elem_to_obj(self, elem):
return UserConfiguration.from_xml(elem=elem, account=self.account)
@@ -111,10 +115,10 @@ Classes
return container.findall(UserConfiguration.response_tag())
def get_payload(self, user_configuration_name, properties):
- payload = create_element(f'm:{self.SERVICE_NAME}')
+ payload = create_element(f"m:{self.SERVICE_NAME}")
set_xml_value(payload, user_configuration_name, version=self.account.version)
payload.append(
- set_xml_value(create_element('m:UserConfigurationProperties'), properties, version=self.account.version)
+ set_xml_value(create_element("m:UserConfigurationProperties"), properties, version=self.account.version)
)
return payload
@@ -143,10 +147,12 @@ Methods
def call(self, user_configuration_name, properties):
if properties not in PROPERTIES_CHOICES:
- raise InvalidEnumValue('properties', properties, PROPERTIES_CHOICES)
- return self._elems_to_objs(self._get_elements(payload=self.get_payload(
- user_configuration_name=user_configuration_name, properties=properties
- )))
+ raise InvalidEnumValue("properties", properties, PROPERTIES_CHOICES)
+ return self._elems_to_objs(
+ self._get_elements(
+ payload=self.get_payload(user_configuration_name=user_configuration_name, properties=properties)
+ )
+ )
@@ -159,10 +165,10 @@ Methods
Expand source code
def get_payload(self, user_configuration_name, properties):
- payload = create_element(f'm:{self.SERVICE_NAME}')
+ payload = create_element(f"m:{self.SERVICE_NAME}")
set_xml_value(payload, user_configuration_name, version=self.account.version)
payload.append(
- set_xml_value(create_element('m:UserConfigurationProperties'), properties, version=self.account.version)
+ set_xml_value(create_element("m:UserConfigurationProperties"), properties, version=self.account.version)
)
return payload
diff --git a/docs/exchangelib/services/get_user_oof_settings.html b/docs/exchangelib/services/get_user_oof_settings.html
index 84431936..84aa1ad4 100644
--- a/docs/exchangelib/services/get_user_oof_settings.html
+++ b/docs/exchangelib/services/get_user_oof_settings.html
@@ -26,10 +26,10 @@ Module exchangelib.services.get_user_oof_settings
Expand source code
-from .common import EWSAccountService
-from ..properties import AvailabilityMailbox
+from ..properties import AvailabilityMailbox
from ..settings import OofSettings
-from ..util import create_element, set_xml_value, MNS, TNS
+from ..util import MNS, TNS, create_element, set_xml_value
+from .common import EWSAccountService
class GetUserOofSettings(EWSAccountService):
@@ -37,8 +37,8 @@ Module exchangelib.services.get_user_oof_settings
MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/getuseroofsettings-operation
"""
- SERVICE_NAME = 'GetUserOofSettings'
- element_container_name = f'{{{TNS}}}OofSettings'
+ SERVICE_NAME = "GetUserOofSettings"
+ element_container_name = f"{{{TNS}}}OofSettings"
def call(self, mailbox):
return self._elems_to_objs(self._get_elements(payload=self.get_payload(mailbox=mailbox)))
@@ -48,9 +48,9 @@ Module exchangelib.services.get_user_oof_settings
def get_payload(self, mailbox):
return set_xml_value(
- create_element(f'm:{self.SERVICE_NAME}Request'),
+ create_element(f"m:{self.SERVICE_NAME}Request"),
AvailabilityMailbox.from_mailbox(mailbox),
- version=self.account.version
+ version=self.account.version,
)
@classmethod
@@ -65,7 +65,7 @@ Module exchangelib.services.get_user_oof_settings
@classmethod
def _response_message_tag(cls):
- return f'{{{MNS}}}ResponseMessage'
+ return f"{{{MNS}}}ResponseMessage"
@@ -93,8 +93,8 @@ Classes
MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/getuseroofsettings-operation
"""
- SERVICE_NAME = 'GetUserOofSettings'
- element_container_name = f'{{{TNS}}}OofSettings'
+ SERVICE_NAME = "GetUserOofSettings"
+ element_container_name = f"{{{TNS}}}OofSettings"
def call(self, mailbox):
return self._elems_to_objs(self._get_elements(payload=self.get_payload(mailbox=mailbox)))
@@ -104,9 +104,9 @@ Classes
def get_payload(self, mailbox):
return set_xml_value(
- create_element(f'm:{self.SERVICE_NAME}Request'),
+ create_element(f"m:{self.SERVICE_NAME}Request"),
AvailabilityMailbox.from_mailbox(mailbox),
- version=self.account.version
+ version=self.account.version,
)
@classmethod
@@ -121,7 +121,7 @@ Classes
@classmethod
def _response_message_tag(cls):
- return f'{{{MNS}}}ResponseMessage'
+ return f"{{{MNS}}}ResponseMessage"
def get_payload(self, mailbox):
return set_xml_value(
- create_element(f'm:{self.SERVICE_NAME}Request'),
+ create_element(f"m:{self.SERVICE_NAME}Request"),
AvailabilityMailbox.from_mailbox(mailbox),
- version=self.account.version
+ version=self.account.version,
)
diff --git a/docs/exchangelib/services/index.html b/docs/exchangelib/services/index.html
index b9eae536..b10f1196 100644
--- a/docs/exchangelib/services/index.html
+++ b/docs/exchangelib/services/index.html
@@ -40,8 +40,8 @@ exchangelib.services
exchangelib.services
exchangelib.services
class ArchiveItem(EWSAccountService):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/archiveitem-operation"""
- SERVICE_NAME = 'ArchiveItem'
- element_container_name = f'{{{MNS}}}Items'
+ SERVICE_NAME = "ArchiveItem"
+ element_container_name = f"{{{MNS}}}Items"
supported_from = EXCHANGE_2013
def call(self, items, to_folder):
@@ -380,9 +380,9 @@ Classes
return Item.id_from_xml(elem)
def get_payload(self, items, to_folder):
- payload = create_element(f'm:{self.SERVICE_NAME}')
+ payload = create_element(f"m:{self.SERVICE_NAME}")
payload.append(
- folder_ids_element(folders=[to_folder], version=self.account.version, tag='m:ArchiveSourceFolderId')
+ folder_ids_element(folders=[to_folder], version=self.account.version, tag="m:ArchiveSourceFolderId")
)
payload.append(item_ids_element(items=items, version=self.account.version))
return payload
@@ -442,9 +442,9 @@ def get_payload(self, items, to_folder):
- payload = create_element(f'm:{self.SERVICE_NAME}')
+ payload = create_element(f"m:{self.SERVICE_NAME}")
payload.append(
- folder_ids_element(folders=[to_folder], version=self.account.version, tag='m:ArchiveSourceFolderId')
+ folder_ids_element(folders=[to_folder], version=self.account.version, tag="m:ArchiveSourceFolderId")
)
payload.append(item_ids_element(items=items, version=self.account.version))
return payload
@@ -482,15 +482,13 @@ def call(self, items, destination_format):
if destination_format not in ID_FORMATS:
- raise InvalidEnumValue('destination_format', destination_format, ID_FORMATS)
+ raise InvalidEnumValue("destination_format", destination_format, ID_FORMATS)
return self._elems_to_objs(
self._chunked_get_elements(self.get_payload, items=items, destination_format=destination_format)
)
@@ -565,11 +565,11 @@ def get_payload(self, items, destination_format):
supported_item_classes = AlternateId, AlternatePublicFolderId, AlternatePublicFolderItemId
- payload = create_element(f'm:{self.SERVICE_NAME}', attrs=dict(DestinationFormat=destination_format))
- item_ids = create_element('m:SourceIds')
+ payload = create_element(f"m:{self.SERVICE_NAME}", attrs=dict(DestinationFormat=destination_format))
+ item_ids = create_element("m:SourceIds")
for item in items:
if not isinstance(item, supported_item_classes):
- raise InvalidTypeError('item', item, supported_item_classes)
+ raise InvalidTypeError("item", item, supported_item_classes)
set_xml_value(item_ids, item, version=self.protocol.version)
payload.append(item_ids)
return payload
@@ -601,7 +601,7 @@ class CopyItem(move_item.MoveItem):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/copyitem-operation"""
- SERVICE_NAME = 'CopyItem'
+ SERVICE_NAME = "CopyItem"
def get_payload(self, items, parent_item):
- payload = create_element(f'm:{self.SERVICE_NAME}')
+ payload = create_element(f"m:{self.SERVICE_NAME}")
version = self.account.version
if isinstance(parent_item, BaseItem):
# to_item_id() would convert this to a normal ItemId, but the service wants a ParentItemId
parent_item = ParentItemId(parent_item.id, parent_item.changekey)
set_xml_value(payload, to_item_id(parent_item, ParentItemId), version=self.account.version)
- attachments = create_element('m:Attachments')
+ attachments = create_element("m:Attachments")
for item in items:
set_xml_value(attachments, item, version=version)
payload.append(attachments)
@@ -751,11 +751,9 @@ Inherited members
class CreateFolder(EWSAccountService):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/createfolder-operation"""
- SERVICE_NAME = 'CreateFolder'
- element_container_name = f'{{{MNS}}}Folders'
- ERRORS_TO_CATCH_IN_RESPONSE = EWSAccountService.ERRORS_TO_CATCH_IN_RESPONSE + (
- ErrorFolderExists,
- )
+ SERVICE_NAME = "CreateFolder"
+ element_container_name = f"{{{MNS}}}Folders"
+ ERRORS_TO_CATCH_IN_RESPONSE = EWSAccountService.ERRORS_TO_CATCH_IN_RESPONSE + (ErrorFolderExists,)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
@@ -765,9 +763,13 @@ Inherited members
# We can't easily find the correct folder class from the returned XML. Instead, return objects with the same
# class as the folder instance it was requested with.
self.folders = list(folders) # Convert to a list, in case 'folders' is a generator. We're iterating twice.
- return self._elems_to_objs(self._chunked_get_elements(
- self.get_payload, items=self.folders, parent_folder=parent_folder,
- ))
+ return self._elems_to_objs(
+ self._chunked_get_elements(
+ self.get_payload,
+ items=self.folders,
+ parent_folder=parent_folder,
+ )
+ )
def _elems_to_objs(self, elems):
for folder, elem in zip(self.folders, elems):
@@ -777,11 +779,11 @@ Inherited members
yield parse_folder_elem(elem=elem, folder=folder, account=self.account)
def get_payload(self, folders, parent_folder):
- payload = create_element(f'm:{self.SERVICE_NAME}')
+ payload = create_element(f"m:{self.SERVICE_NAME}")
payload.append(
- folder_ids_element(folders=[parent_folder], version=self.account.version, tag='m:ParentFolderId')
+ folder_ids_element(folders=[parent_folder], version=self.account.version, tag="m:ParentFolderId")
)
- payload.append(folder_ids_element(folders=folders, version=self.account.version, tag='m:Folders'))
+ payload.append(folder_ids_element(folders=folders, version=self.account.version, tag="m:Folders"))
return payload
Ancestors
@@ -819,9 +821,13 @@ Methods
# We can't easily find the correct folder class from the returned XML. Instead, return objects with the same
# class as the folder instance it was requested with.
self.folders = list(folders) # Convert to a list, in case 'folders' is a generator. We're iterating twice.
- return self._elems_to_objs(self._chunked_get_elements(
- self.get_payload, items=self.folders, parent_folder=parent_folder,
- ))
+ return self._elems_to_objs(
+ self._chunked_get_elements(
+ self.get_payload,
+ items=self.folders,
+ parent_folder=parent_folder,
+ )
+ )
@@ -834,11 +840,11 @@ Methods
Expand source code
def get_payload(self, folders, parent_folder):
- payload = create_element(f'm:{self.SERVICE_NAME}')
+ payload = create_element(f"m:{self.SERVICE_NAME}")
payload.append(
- folder_ids_element(folders=[parent_folder], version=self.account.version, tag='m:ParentFolderId')
+ folder_ids_element(folders=[parent_folder], version=self.account.version, tag="m:ParentFolderId")
)
- payload.append(folder_ids_element(folders=folders, version=self.account.version, tag='m:Folders'))
+ payload.append(folder_ids_element(folders=folders, version=self.account.version, tag="m:Folders"))
return payload
@@ -874,34 +880,36 @@ Inherited members
MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/createitem-operation
"""
- SERVICE_NAME = 'CreateItem'
- element_container_name = f'{{{MNS}}}Items'
+ SERVICE_NAME = "CreateItem"
+ element_container_name = f"{{{MNS}}}Items"
def call(self, items, folder, message_disposition, send_meeting_invitations):
if message_disposition not in MESSAGE_DISPOSITION_CHOICES:
- raise InvalidEnumValue('message_disposition', message_disposition, MESSAGE_DISPOSITION_CHOICES)
+ raise InvalidEnumValue("message_disposition", message_disposition, MESSAGE_DISPOSITION_CHOICES)
if send_meeting_invitations not in SEND_MEETING_INVITATIONS_CHOICES:
raise InvalidEnumValue(
- 'send_meeting_invitations', send_meeting_invitations, SEND_MEETING_INVITATIONS_CHOICES
+ "send_meeting_invitations", send_meeting_invitations, SEND_MEETING_INVITATIONS_CHOICES
)
if folder is not None:
if not isinstance(folder, (BaseFolder, FolderId)):
- raise InvalidTypeError('folder', folder, (BaseFolder, FolderId))
+ raise InvalidTypeError("folder", folder, (BaseFolder, FolderId))
if folder.account != self.account:
- raise ValueError('Folder must belong to account')
+ raise ValueError("Folder must belong to account")
if message_disposition == SAVE_ONLY and folder is None:
raise AttributeError("Folder must be supplied when in save-only mode")
if message_disposition == SEND_AND_SAVE_COPY and folder is None:
folder = self.account.sent # 'Sent' is default EWS behaviour
if message_disposition == SEND_ONLY and folder is not None:
raise AttributeError("Folder must be None in send-ony mode")
- return self._elems_to_objs(self._chunked_get_elements(
- self.get_payload,
- items=items,
- folder=folder,
- message_disposition=message_disposition,
- send_meeting_invitations=send_meeting_invitations,
- ))
+ return self._elems_to_objs(
+ self._chunked_get_elements(
+ self.get_payload,
+ items=items,
+ folder=folder,
+ message_disposition=message_disposition,
+ send_meeting_invitations=send_meeting_invitations,
+ )
+ )
def _elem_to_obj(self, elem):
if isinstance(elem, bool):
@@ -933,14 +941,14 @@ Inherited members
:param send_meeting_invitations:
"""
payload = create_element(
- f'm:{self.SERVICE_NAME}',
- attrs=dict(MessageDisposition=message_disposition, SendMeetingInvitations=send_meeting_invitations)
+ f"m:{self.SERVICE_NAME}",
+ attrs=dict(MessageDisposition=message_disposition, SendMeetingInvitations=send_meeting_invitations),
)
if folder:
- payload.append(folder_ids_element(
- folders=[folder], version=self.account.version, tag='m:SavedItemFolderId'
- ))
- item_elems = create_element('m:Items')
+ payload.append(
+ folder_ids_element(folders=[folder], version=self.account.version, tag="m:SavedItemFolderId")
+ )
+ item_elems = create_element("m:Items")
for item in items:
if not item.account:
item.account = self.account
@@ -977,29 +985,31 @@ Methods
def call(self, items, folder, message_disposition, send_meeting_invitations):
if message_disposition not in MESSAGE_DISPOSITION_CHOICES:
- raise InvalidEnumValue('message_disposition', message_disposition, MESSAGE_DISPOSITION_CHOICES)
+ raise InvalidEnumValue("message_disposition", message_disposition, MESSAGE_DISPOSITION_CHOICES)
if send_meeting_invitations not in SEND_MEETING_INVITATIONS_CHOICES:
raise InvalidEnumValue(
- 'send_meeting_invitations', send_meeting_invitations, SEND_MEETING_INVITATIONS_CHOICES
+ "send_meeting_invitations", send_meeting_invitations, SEND_MEETING_INVITATIONS_CHOICES
)
if folder is not None:
if not isinstance(folder, (BaseFolder, FolderId)):
- raise InvalidTypeError('folder', folder, (BaseFolder, FolderId))
+ raise InvalidTypeError("folder", folder, (BaseFolder, FolderId))
if folder.account != self.account:
- raise ValueError('Folder must belong to account')
+ raise ValueError("Folder must belong to account")
if message_disposition == SAVE_ONLY and folder is None:
raise AttributeError("Folder must be supplied when in save-only mode")
if message_disposition == SEND_AND_SAVE_COPY and folder is None:
folder = self.account.sent # 'Sent' is default EWS behaviour
if message_disposition == SEND_ONLY and folder is not None:
raise AttributeError("Folder must be None in send-ony mode")
- return self._elems_to_objs(self._chunked_get_elements(
- self.get_payload,
- items=items,
- folder=folder,
- message_disposition=message_disposition,
- send_meeting_invitations=send_meeting_invitations,
- ))
+ return self._elems_to_objs(
+ self._chunked_get_elements(
+ self.get_payload,
+ items=items,
+ folder=folder,
+ message_disposition=message_disposition,
+ send_meeting_invitations=send_meeting_invitations,
+ )
+ )
@@ -1044,14 +1054,14 @@ Methods
:param send_meeting_invitations:
"""
payload = create_element(
- f'm:{self.SERVICE_NAME}',
- attrs=dict(MessageDisposition=message_disposition, SendMeetingInvitations=send_meeting_invitations)
+ f"m:{self.SERVICE_NAME}",
+ attrs=dict(MessageDisposition=message_disposition, SendMeetingInvitations=send_meeting_invitations),
)
if folder:
- payload.append(folder_ids_element(
- folders=[folder], version=self.account.version, tag='m:SavedItemFolderId'
- ))
- item_elems = create_element('m:Items')
+ payload.append(
+ folder_ids_element(folders=[folder], version=self.account.version, tag="m:SavedItemFolderId")
+ )
+ item_elems = create_element("m:Items")
for item in items:
if not item.account:
item.account = self.account
@@ -1089,7 +1099,7 @@ Inherited members
https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/createuserconfiguration-operation
"""
- SERVICE_NAME = 'CreateUserConfiguration'
+ SERVICE_NAME = "CreateUserConfiguration"
returns_elements = False
def call(self, user_configuration):
@@ -1097,7 +1107,7 @@ Inherited members
def get_payload(self, user_configuration):
return set_xml_value(
- create_element(f'm:{self.SERVICE_NAME}'), user_configuration, version=self.protocol.version
+ create_element(f"m:{self.SERVICE_NAME}"), user_configuration, version=self.protocol.version
)
def get_payload(self, user_configuration):
return set_xml_value(
- create_element(f'm:{self.SERVICE_NAME}'), user_configuration, version=self.protocol.version
+ create_element(f"m:{self.SERVICE_NAME}"), user_configuration, version=self.protocol.version
)
@@ -1175,7 +1185,7 @@ def get_payload(self, items):
return set_xml_value(
- create_element(f'm:{self.SERVICE_NAME}'),
+ create_element(f"m:{self.SERVICE_NAME}"),
attachment_ids_element(items=items, version=self.account.version),
- version=self.account.version
+ version=self.account.version,
)
@@ -1264,16 +1274,16 @@ class DeleteFolder(EWSAccountService):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/deletefolder-operation"""
- SERVICE_NAME = 'DeleteFolder'
+ SERVICE_NAME = "DeleteFolder"
returns_elements = False
def call(self, folders, delete_type):
if delete_type not in DELETE_TYPE_CHOICES:
- raise InvalidEnumValue('delete_type', delete_type, DELETE_TYPE_CHOICES)
+ raise InvalidEnumValue("delete_type", delete_type, DELETE_TYPE_CHOICES)
return self._chunked_get_elements(self.get_payload, items=folders, delete_type=delete_type)
def get_payload(self, folders, delete_type):
- payload = create_element(f'm:{self.SERVICE_NAME}', attrs=dict(DeleteType=delete_type))
+ payload = create_element(f"m:{self.SERVICE_NAME}", attrs=dict(DeleteType=delete_type))
payload.append(folder_ids_element(folders=folders, version=self.account.version))
return payload
@@ -1306,7 +1316,7 @@ def call(self, folders, delete_type):
if delete_type not in DELETE_TYPE_CHOICES:
- raise InvalidEnumValue('delete_type', delete_type, DELETE_TYPE_CHOICES)
+ raise InvalidEnumValue("delete_type", delete_type, DELETE_TYPE_CHOICES)
return self._chunked_get_elements(self.get_payload, items=folders, delete_type=delete_type)
@@ -1320,7 +1330,7 @@ def get_payload(self, folders, delete_type):
- payload = create_element(f'm:{self.SERVICE_NAME}', attrs=dict(DeleteType=delete_type))
+ payload = create_element(f"m:{self.SERVICE_NAME}", attrs=dict(DeleteType=delete_type))
payload.append(folder_ids_element(folders=folders, version=self.account.version))
return payload
@@ -1357,19 +1367,19 @@ def call(self, items, delete_type, send_meeting_cancellations, affected_task_occurrences, suppress_read_receipts):
if delete_type not in DELETE_TYPE_CHOICES:
- raise InvalidEnumValue('delete_type', delete_type, DELETE_TYPE_CHOICES)
+ raise InvalidEnumValue("delete_type", delete_type, DELETE_TYPE_CHOICES)
if send_meeting_cancellations not in SEND_MEETING_CANCELLATIONS_CHOICES:
raise InvalidEnumValue(
- 'send_meeting_cancellations', send_meeting_cancellations, SEND_MEETING_CANCELLATIONS_CHOICES
+ "send_meeting_cancellations", send_meeting_cancellations, SEND_MEETING_CANCELLATIONS_CHOICES
)
if affected_task_occurrences not in AFFECTED_TASK_OCCURRENCES_CHOICES:
raise InvalidEnumValue(
- 'affected_task_occurrences', affected_task_occurrences, AFFECTED_TASK_OCCURRENCES_CHOICES
+ "affected_task_occurrences", affected_task_occurrences, AFFECTED_TASK_OCCURRENCES_CHOICES
)
return self._chunked_get_elements(
self.get_payload,
@@ -1451,8 +1462,9 @@ Methods
Expand source code
-def get_payload(self, items, delete_type, send_meeting_cancellations, affected_task_occurrences,
- suppress_read_receipts):
+def get_payload(
+ self, items, delete_type, send_meeting_cancellations, affected_task_occurrences, suppress_read_receipts
+):
# Takes a list of (id, changekey) tuples or Item objects and returns the XML for a DeleteItem request.
attrs = dict(
DeleteType=delete_type,
@@ -1460,8 +1472,8 @@ Methods
AffectedTaskOccurrences=affected_task_occurrences,
)
if self.account.version.build >= EXCHANGE_2013_SP1:
- attrs['SuppressReadReceipts'] = suppress_read_receipts
- payload = create_element(f'm:{self.SERVICE_NAME}', attrs=attrs)
+ attrs["SuppressReadReceipts"] = suppress_read_receipts
+ payload = create_element(f"m:{self.SERVICE_NAME}", attrs=attrs)
payload.append(item_ids_element(items=items, version=self.account.version))
return payload
@@ -1495,7 +1507,7 @@ Inherited members
https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/deleteuserconfiguration-operation
"""
- SERVICE_NAME = 'DeleteUserConfiguration'
+ SERVICE_NAME = "DeleteUserConfiguration"
returns_elements = False
def call(self, user_configuration_name):
@@ -1503,7 +1515,7 @@ Inherited members
def get_payload(self, user_configuration_name):
return set_xml_value(
- create_element(f'm:{self.SERVICE_NAME}'), user_configuration_name, version=self.account.version
+ create_element(f"m:{self.SERVICE_NAME}"), user_configuration_name, version=self.account.version
)
Ancestors
@@ -1548,7 +1560,7 @@ Methods
def get_payload(self, user_configuration_name):
return set_xml_value(
- create_element(f'm:{self.SERVICE_NAME}'), user_configuration_name, version=self.account.version
+ create_element(f"m:{self.SERVICE_NAME}"), user_configuration_name, version=self.account.version
)
@@ -1578,20 +1590,19 @@ Inherited members
class EmptyFolder(EWSAccountService):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/emptyfolder-operation"""
- SERVICE_NAME = 'EmptyFolder'
+ SERVICE_NAME = "EmptyFolder"
returns_elements = False
def call(self, folders, delete_type, delete_sub_folders):
if delete_type not in DELETE_TYPE_CHOICES:
- raise InvalidEnumValue('delete_type', delete_type, DELETE_TYPE_CHOICES)
+ raise InvalidEnumValue("delete_type", delete_type, DELETE_TYPE_CHOICES)
return self._chunked_get_elements(
self.get_payload, items=folders, delete_type=delete_type, delete_sub_folders=delete_sub_folders
)
def get_payload(self, folders, delete_type, delete_sub_folders):
payload = create_element(
- f'm:{self.SERVICE_NAME}',
- attrs=dict(DeleteType=delete_type, DeleteSubFolders=delete_sub_folders)
+ f"m:{self.SERVICE_NAME}", attrs=dict(DeleteType=delete_type, DeleteSubFolders=delete_sub_folders)
)
payload.append(folder_ids_element(folders=folders, version=self.account.version))
return payload
@@ -1625,7 +1636,7 @@ Methods
def call(self, folders, delete_type, delete_sub_folders):
if delete_type not in DELETE_TYPE_CHOICES:
- raise InvalidEnumValue('delete_type', delete_type, DELETE_TYPE_CHOICES)
+ raise InvalidEnumValue("delete_type", delete_type, DELETE_TYPE_CHOICES)
return self._chunked_get_elements(
self.get_payload, items=folders, delete_type=delete_type, delete_sub_folders=delete_sub_folders
)
@@ -1642,8 +1653,7 @@ Methods
def get_payload(self, folders, delete_type, delete_sub_folders):
payload = create_element(
- f'm:{self.SERVICE_NAME}',
- attrs=dict(DeleteType=delete_type, DeleteSubFolders=delete_sub_folders)
+ f"m:{self.SERVICE_NAME}", attrs=dict(DeleteType=delete_type, DeleteSubFolders=delete_sub_folders)
)
payload.append(folder_ids_element(folders=folders, version=self.account.version))
return payload
@@ -1675,8 +1685,8 @@ Inherited members
class ExpandDL(EWSService):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/expanddl-operation"""
- SERVICE_NAME = 'ExpandDL'
- element_container_name = f'{{{MNS}}}DLExpansion'
+ SERVICE_NAME = "ExpandDL"
+ element_container_name = f"{{{MNS}}}DLExpansion"
WARNINGS_TO_IGNORE_IN_RESPONSE = ErrorNameResolutionMultipleResults
def call(self, distribution_list):
@@ -1686,7 +1696,7 @@ Inherited members
return Mailbox.from_xml(elem, account=None)
def get_payload(self, distribution_list):
- return set_xml_value(create_element(f'm:{self.SERVICE_NAME}'), distribution_list, version=self.protocol.version)
+ return set_xml_value(create_element(f"m:{self.SERVICE_NAME}"), distribution_list, version=self.protocol.version)
def get_payload(self, distribution_list):
- return set_xml_value(create_element(f'm:{self.SERVICE_NAME}'), distribution_list, version=self.protocol.version)
+ return set_xml_value(create_element(f"m:{self.SERVICE_NAME}"), distribution_list, version=self.protocol.version)
@@ -1762,8 +1772,8 @@ def get_payload(self, items):
- payload = create_element(f'm:{self.SERVICE_NAME}')
+ payload = create_element(f"m:{self.SERVICE_NAME}")
payload.append(item_ids_element(items=items, version=self.account.version))
return payload
@@ -1858,9 +1868,9 @@ class FindFolder(EWSPagingService):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/findfolder-operation"""
- SERVICE_NAME = 'FindFolder'
- element_container_name = f'{{{TNS}}}Folders'
- paging_container_name = f'{{{MNS}}}RootFolder'
+ SERVICE_NAME = "FindFolder"
+ element_container_name = f"{{{TNS}}}Folders"
+ paging_container_name = f"{{{MNS}}}RootFolder"
supports_paging = True
def __init__(self, *args, **kwargs):
@@ -1881,14 +1891,15 @@ Inherited members
:return: XML elements for the matching folders
"""
if shape not in SHAPE_CHOICES:
- raise InvalidEnumValue('shape', shape, SHAPE_CHOICES)
+ raise InvalidEnumValue("shape", shape, SHAPE_CHOICES)
if depth not in FOLDER_TRAVERSAL_CHOICES:
- raise InvalidEnumValue('depth', depth, FOLDER_TRAVERSAL_CHOICES)
+ raise InvalidEnumValue("depth", depth, FOLDER_TRAVERSAL_CHOICES)
roots = {f.root for f in folders}
if len(roots) != 1:
raise ValueError(f"All folders in 'roots' must have the same root hierarchy ({roots})")
self.root = roots.pop()
- return self._elems_to_objs(self._paged_call(
+ return self._elems_to_objs(
+ self._paged_call(
payload_func=self.get_payload,
max_items=max_items,
folders=folders,
@@ -1899,21 +1910,24 @@ Inherited members
depth=depth,
page_size=self.page_size,
offset=offset,
- )
- ))
+ ),
+ )
+ )
def _elem_to_obj(self, elem):
return Folder.from_xml_with_root(elem=elem, root=self.root)
def get_payload(self, folders, additional_fields, restriction, shape, depth, page_size, offset=0):
- payload = create_element(f'm:{self.SERVICE_NAME}', attrs=dict(Traversal=depth))
- payload.append(shape_element(
- tag='m:FolderShape', shape=shape, additional_fields=additional_fields, version=self.account.version
- ))
+ payload = create_element(f"m:{self.SERVICE_NAME}", attrs=dict(Traversal=depth))
+ payload.append(
+ shape_element(
+ tag="m:FolderShape", shape=shape, additional_fields=additional_fields, version=self.account.version
+ )
+ )
if self.account.version.build >= EXCHANGE_2010:
indexed_page_folder_view = create_element(
- 'm:IndexedPageFolderView',
- attrs=dict(MaxEntriesReturned=page_size, Offset=offset, BasePoint='Beginning')
+ "m:IndexedPageFolderView",
+ attrs=dict(MaxEntriesReturned=page_size, Offset=offset, BasePoint="Beginning"),
)
payload.append(indexed_page_folder_view)
else:
@@ -1921,7 +1935,7 @@ Inherited members
raise NotImplementedError("'offset' is only supported for Exchange 2010 servers and later")
if restriction:
payload.append(restriction.to_xml(version=self.account.version))
- payload.append(folder_ids_element(folders=folders, version=self.protocol.version, tag='m:ParentFolderIds'))
+ payload.append(folder_ids_element(folders=folders, version=self.protocol.version, tag="m:ParentFolderIds"))
return payload
@@ -2014,14 +2030,16 @@ Methods
Expand source code
def get_payload(self, folders, additional_fields, restriction, shape, depth, page_size, offset=0):
- payload = create_element(f'm:{self.SERVICE_NAME}', attrs=dict(Traversal=depth))
- payload.append(shape_element(
- tag='m:FolderShape', shape=shape, additional_fields=additional_fields, version=self.account.version
- ))
+ payload = create_element(f"m:{self.SERVICE_NAME}", attrs=dict(Traversal=depth))
+ payload.append(
+ shape_element(
+ tag="m:FolderShape", shape=shape, additional_fields=additional_fields, version=self.account.version
+ )
+ )
if self.account.version.build >= EXCHANGE_2010:
indexed_page_folder_view = create_element(
- 'm:IndexedPageFolderView',
- attrs=dict(MaxEntriesReturned=page_size, Offset=offset, BasePoint='Beginning')
+ "m:IndexedPageFolderView",
+ attrs=dict(MaxEntriesReturned=page_size, Offset=offset, BasePoint="Beginning"),
)
payload.append(indexed_page_folder_view)
else:
@@ -2029,7 +2047,7 @@ Methods
raise NotImplementedError("'offset' is only supported for Exchange 2010 servers and later")
if restriction:
payload.append(restriction.to_xml(version=self.account.version))
- payload.append(folder_ids_element(folders=folders, version=self.protocol.version, tag='m:ParentFolderIds'))
+ payload.append(folder_ids_element(folders=folders, version=self.protocol.version, tag="m:ParentFolderIds"))
return payload
@@ -2059,9 +2077,9 @@ Inherited members
class FindItem(EWSPagingService):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/finditem-operation"""
- SERVICE_NAME = 'FindItem'
- element_container_name = f'{{{TNS}}}Items'
- paging_container_name = f'{{{MNS}}}RootFolder'
+ SERVICE_NAME = "FindItem"
+ element_container_name = f"{{{TNS}}}Items"
+ paging_container_name = f"{{{MNS}}}RootFolder"
supports_paging = True
def __init__(self, *args, **kwargs):
@@ -2070,8 +2088,19 @@ Inherited members
self.additional_fields = None
self.shape = None
- def call(self, folders, additional_fields, restriction, order_fields, shape, query_string, depth, calendar_view,
- max_items, offset):
+ def call(
+ self,
+ folders,
+ additional_fields,
+ restriction,
+ order_fields,
+ shape,
+ query_string,
+ depth,
+ calendar_view,
+ max_items,
+ offset,
+ ):
"""Find items in an account.
:param folders: the folders to act on
@@ -2088,43 +2117,57 @@ Inherited members
:return: XML elements for the matching items
"""
if shape not in SHAPE_CHOICES:
- raise InvalidEnumValue('shape', shape, SHAPE_CHOICES)
+ raise InvalidEnumValue("shape", shape, SHAPE_CHOICES)
if depth not in ITEM_TRAVERSAL_CHOICES:
- raise InvalidEnumValue('depth', depth, ITEM_TRAVERSAL_CHOICES)
+ raise InvalidEnumValue("depth", depth, ITEM_TRAVERSAL_CHOICES)
self.additional_fields = additional_fields
self.shape = shape
- return self._elems_to_objs(self._paged_call(
- payload_func=self.get_payload,
- max_items=max_items,
- folders=folders,
- **dict(
- additional_fields=additional_fields,
- restriction=restriction,
- order_fields=order_fields,
- query_string=query_string,
- shape=shape,
- depth=depth,
- calendar_view=calendar_view,
- page_size=self.page_size,
- offset=offset,
+ return self._elems_to_objs(
+ self._paged_call(
+ payload_func=self.get_payload,
+ max_items=max_items,
+ folders=folders,
+ **dict(
+ additional_fields=additional_fields,
+ restriction=restriction,
+ order_fields=order_fields,
+ query_string=query_string,
+ shape=shape,
+ depth=depth,
+ calendar_view=calendar_view,
+ page_size=self.page_size,
+ offset=offset,
+ ),
)
- ))
+ )
def _elem_to_obj(self, elem):
if self.shape == ID_ONLY and self.additional_fields is None:
return Item.id_from_xml(elem)
return BaseFolder.item_model_from_tag(elem.tag).from_xml(elem=elem, account=self.account)
- def get_payload(self, folders, additional_fields, restriction, order_fields, query_string, shape, depth,
- calendar_view, page_size, offset=0):
- payload = create_element(f'm:{self.SERVICE_NAME}', attrs=dict(Traversal=depth))
- payload.append(shape_element(
- tag='m:ItemShape', shape=shape, additional_fields=additional_fields, version=self.account.version
- ))
+ def get_payload(
+ self,
+ folders,
+ additional_fields,
+ restriction,
+ order_fields,
+ query_string,
+ shape,
+ depth,
+ calendar_view,
+ page_size,
+ offset=0,
+ ):
+ payload = create_element(f"m:{self.SERVICE_NAME}", attrs=dict(Traversal=depth))
+ payload.append(
+ shape_element(
+ tag="m:ItemShape", shape=shape, additional_fields=additional_fields, version=self.account.version
+ )
+ )
if calendar_view is None:
view_type = create_element(
- 'm:IndexedPageItemView',
- attrs=dict(MaxEntriesReturned=page_size, Offset=offset, BasePoint='Beginning')
+ "m:IndexedPageItemView", attrs=dict(MaxEntriesReturned=page_size, Offset=offset, BasePoint="Beginning")
)
else:
view_type = calendar_view.to_xml(version=self.account.version)
@@ -2132,12 +2175,8 @@ Inherited members
if restriction:
payload.append(restriction.to_xml(version=self.account.version))
if order_fields:
- payload.append(set_xml_value(
- create_element('m:SortOrder'),
- order_fields,
- version=self.account.version
- ))
- payload.append(folder_ids_element(folders=folders, version=self.protocol.version, tag='m:ParentFolderIds'))
+ payload.append(set_xml_value(create_element("m:SortOrder"), order_fields, version=self.account.version))
+ payload.append(folder_ids_element(folders=folders, version=self.protocol.version, tag="m:ParentFolderIds"))
if query_string:
payload.append(query_string.to_xml(version=self.account.version))
return payload
@@ -2189,8 +2228,19 @@ Methods
Expand source code
-def call(self, folders, additional_fields, restriction, order_fields, shape, query_string, depth, calendar_view,
- max_items, offset):
+def call(
+ self,
+ folders,
+ additional_fields,
+ restriction,
+ order_fields,
+ shape,
+ query_string,
+ depth,
+ calendar_view,
+ max_items,
+ offset,
+):
"""Find items in an account.
:param folders: the folders to act on
@@ -2207,27 +2257,29 @@ Methods
:return: XML elements for the matching items
"""
if shape not in SHAPE_CHOICES:
- raise InvalidEnumValue('shape', shape, SHAPE_CHOICES)
+ raise InvalidEnumValue("shape", shape, SHAPE_CHOICES)
if depth not in ITEM_TRAVERSAL_CHOICES:
- raise InvalidEnumValue('depth', depth, ITEM_TRAVERSAL_CHOICES)
+ raise InvalidEnumValue("depth", depth, ITEM_TRAVERSAL_CHOICES)
self.additional_fields = additional_fields
self.shape = shape
- return self._elems_to_objs(self._paged_call(
- payload_func=self.get_payload,
- max_items=max_items,
- folders=folders,
- **dict(
- additional_fields=additional_fields,
- restriction=restriction,
- order_fields=order_fields,
- query_string=query_string,
- shape=shape,
- depth=depth,
- calendar_view=calendar_view,
- page_size=self.page_size,
- offset=offset,
+ return self._elems_to_objs(
+ self._paged_call(
+ payload_func=self.get_payload,
+ max_items=max_items,
+ folders=folders,
+ **dict(
+ additional_fields=additional_fields,
+ restriction=restriction,
+ order_fields=order_fields,
+ query_string=query_string,
+ shape=shape,
+ depth=depth,
+ calendar_view=calendar_view,
+ page_size=self.page_size,
+ offset=offset,
+ ),
)
- ))
+ )
@@ -2239,16 +2291,28 @@ Methods
Expand source code
-def get_payload(self, folders, additional_fields, restriction, order_fields, query_string, shape, depth,
- calendar_view, page_size, offset=0):
- payload = create_element(f'm:{self.SERVICE_NAME}', attrs=dict(Traversal=depth))
- payload.append(shape_element(
- tag='m:ItemShape', shape=shape, additional_fields=additional_fields, version=self.account.version
- ))
+def get_payload(
+ self,
+ folders,
+ additional_fields,
+ restriction,
+ order_fields,
+ query_string,
+ shape,
+ depth,
+ calendar_view,
+ page_size,
+ offset=0,
+):
+ payload = create_element(f"m:{self.SERVICE_NAME}", attrs=dict(Traversal=depth))
+ payload.append(
+ shape_element(
+ tag="m:ItemShape", shape=shape, additional_fields=additional_fields, version=self.account.version
+ )
+ )
if calendar_view is None:
view_type = create_element(
- 'm:IndexedPageItemView',
- attrs=dict(MaxEntriesReturned=page_size, Offset=offset, BasePoint='Beginning')
+ "m:IndexedPageItemView", attrs=dict(MaxEntriesReturned=page_size, Offset=offset, BasePoint="Beginning")
)
else:
view_type = calendar_view.to_xml(version=self.account.version)
@@ -2256,12 +2320,8 @@ Methods
if restriction:
payload.append(restriction.to_xml(version=self.account.version))
if order_fields:
- payload.append(set_xml_value(
- create_element('m:SortOrder'),
- order_fields,
- version=self.account.version
- ))
- payload.append(folder_ids_element(folders=folders, version=self.protocol.version, tag='m:ParentFolderIds'))
+ payload.append(set_xml_value(create_element("m:SortOrder"), order_fields, version=self.account.version))
+ payload.append(folder_ids_element(folders=folders, version=self.protocol.version, tag="m:ParentFolderIds"))
if query_string:
payload.append(query_string.to_xml(version=self.account.version))
return payload
@@ -2293,8 +2353,8 @@ Inherited members
class FindPeople(EWSPagingService):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/findpeople-operation"""
- SERVICE_NAME = 'FindPeople'
- element_container_name = f'{{{MNS}}}People'
+ SERVICE_NAME = "FindPeople"
+ element_container_name = f"{{{MNS}}}People"
supported_from = EXCHANGE_2013
supports_paging = True
@@ -2320,52 +2380,54 @@ Inherited members
:return: XML elements for the matching items
"""
if shape not in SHAPE_CHOICES:
- raise InvalidEnumValue('shape', shape, SHAPE_CHOICES)
+ raise InvalidEnumValue("shape", shape, SHAPE_CHOICES)
if depth not in ITEM_TRAVERSAL_CHOICES:
- raise InvalidEnumValue('depth', depth, ITEM_TRAVERSAL_CHOICES)
+ raise InvalidEnumValue("depth", depth, ITEM_TRAVERSAL_CHOICES)
self.additional_fields = additional_fields
self.shape = shape
- return self._elems_to_objs(self._paged_call(
- payload_func=self.get_payload,
- max_items=max_items,
- folders=[folder], # We just need the list to satisfy self._paged_call()
- **dict(
- additional_fields=additional_fields,
- restriction=restriction,
- order_fields=order_fields,
- query_string=query_string,
- shape=shape,
- depth=depth,
- page_size=self.page_size,
- offset=offset,
+ return self._elems_to_objs(
+ self._paged_call(
+ payload_func=self.get_payload,
+ max_items=max_items,
+ folders=[folder], # We just need the list to satisfy self._paged_call()
+ **dict(
+ additional_fields=additional_fields,
+ restriction=restriction,
+ order_fields=order_fields,
+ query_string=query_string,
+ shape=shape,
+ depth=depth,
+ page_size=self.page_size,
+ offset=offset,
+ ),
)
- ))
+ )
def _elem_to_obj(self, elem):
if self.shape == ID_ONLY and self.additional_fields is None:
return Persona.id_from_xml(elem)
return Persona.from_xml(elem, account=self.account)
- def get_payload(self, folders, additional_fields, restriction, order_fields, query_string, shape, depth, page_size,
- offset=0):
+ def get_payload(
+ self, folders, additional_fields, restriction, order_fields, query_string, shape, depth, page_size, offset=0
+ ):
# We actually only support a single folder, but self._paged_call() sends us a list
- payload = create_element(f'm:{self.SERVICE_NAME}', attrs=dict(Traversal=depth))
- payload.append(shape_element(
- tag='m:PersonaShape', shape=shape, additional_fields=additional_fields, version=self.account.version
- ))
- payload.append(create_element(
- 'm:IndexedPageItemView',
- attrs=dict(MaxEntriesReturned=page_size, Offset=offset, BasePoint='Beginning')
- ))
+ payload = create_element(f"m:{self.SERVICE_NAME}", attrs=dict(Traversal=depth))
+ payload.append(
+ shape_element(
+ tag="m:PersonaShape", shape=shape, additional_fields=additional_fields, version=self.account.version
+ )
+ )
+ payload.append(
+ create_element(
+ "m:IndexedPageItemView", attrs=dict(MaxEntriesReturned=page_size, Offset=offset, BasePoint="Beginning")
+ )
+ )
if restriction:
payload.append(restriction.to_xml(version=self.account.version))
if order_fields:
- payload.append(set_xml_value(
- create_element('m:SortOrder'),
- order_fields,
- version=self.account.version
- ))
- payload.append(folder_ids_element(folders=folders, version=self.account.version, tag='m:ParentFolderId'))
+ payload.append(set_xml_value(create_element("m:SortOrder"), order_fields, version=self.account.version))
+ payload.append(folder_ids_element(folders=folders, version=self.account.version, tag="m:ParentFolderId"))
if query_string:
payload.append(query_string.to_xml(version=self.account.version))
return payload
@@ -2373,11 +2435,15 @@ Inherited members
@staticmethod
def _get_paging_values(elem):
"""Find paging values. The paging element from FindPeople is different from other paging containers."""
- item_count = int(elem.find(f'{{{MNS}}}TotalNumberOfPeopleInView').text)
- first_matching = int(elem.find(f'{{{MNS}}}FirstMatchingRowIndex').text)
- first_loaded = int(elem.find(f'{{{MNS}}}FirstLoadedRowIndex').text)
- log.debug('Got page with total items %s, first matching %s, first loaded %s ', item_count, first_matching,
- first_loaded)
+ item_count = int(elem.find(f"{{{MNS}}}TotalNumberOfPeopleInView").text)
+ first_matching = int(elem.find(f"{{{MNS}}}FirstMatchingRowIndex").text)
+ first_loaded = int(elem.find(f"{{{MNS}}}FirstLoadedRowIndex").text)
+ log.debug(
+ "Got page with total items %s, first matching %s, first loaded %s ",
+ item_count,
+ first_matching,
+ first_loaded,
+ )
next_offset = None # GetPersona does not support fetching more pages
return item_count, next_offset
@@ -2443,26 +2509,28 @@ Methods
:return: XML elements for the matching items
"""
if shape not in SHAPE_CHOICES:
- raise InvalidEnumValue('shape', shape, SHAPE_CHOICES)
+ raise InvalidEnumValue("shape", shape, SHAPE_CHOICES)
if depth not in ITEM_TRAVERSAL_CHOICES:
- raise InvalidEnumValue('depth', depth, ITEM_TRAVERSAL_CHOICES)
+ raise InvalidEnumValue("depth", depth, ITEM_TRAVERSAL_CHOICES)
self.additional_fields = additional_fields
self.shape = shape
- return self._elems_to_objs(self._paged_call(
- payload_func=self.get_payload,
- max_items=max_items,
- folders=[folder], # We just need the list to satisfy self._paged_call()
- **dict(
- additional_fields=additional_fields,
- restriction=restriction,
- order_fields=order_fields,
- query_string=query_string,
- shape=shape,
- depth=depth,
- page_size=self.page_size,
- offset=offset,
+ return self._elems_to_objs(
+ self._paged_call(
+ payload_func=self.get_payload,
+ max_items=max_items,
+ folders=[folder], # We just need the list to satisfy self._paged_call()
+ **dict(
+ additional_fields=additional_fields,
+ restriction=restriction,
+ order_fields=order_fields,
+ query_string=query_string,
+ shape=shape,
+ depth=depth,
+ page_size=self.page_size,
+ offset=offset,
+ ),
)
- ))
+ )
@@ -2474,26 +2542,26 @@ Methods
Expand source code
-def get_payload(self, folders, additional_fields, restriction, order_fields, query_string, shape, depth, page_size,
- offset=0):
+def get_payload(
+ self, folders, additional_fields, restriction, order_fields, query_string, shape, depth, page_size, offset=0
+):
# We actually only support a single folder, but self._paged_call() sends us a list
- payload = create_element(f'm:{self.SERVICE_NAME}', attrs=dict(Traversal=depth))
- payload.append(shape_element(
- tag='m:PersonaShape', shape=shape, additional_fields=additional_fields, version=self.account.version
- ))
- payload.append(create_element(
- 'm:IndexedPageItemView',
- attrs=dict(MaxEntriesReturned=page_size, Offset=offset, BasePoint='Beginning')
- ))
+ payload = create_element(f"m:{self.SERVICE_NAME}", attrs=dict(Traversal=depth))
+ payload.append(
+ shape_element(
+ tag="m:PersonaShape", shape=shape, additional_fields=additional_fields, version=self.account.version
+ )
+ )
+ payload.append(
+ create_element(
+ "m:IndexedPageItemView", attrs=dict(MaxEntriesReturned=page_size, Offset=offset, BasePoint="Beginning")
+ )
+ )
if restriction:
payload.append(restriction.to_xml(version=self.account.version))
if order_fields:
- payload.append(set_xml_value(
- create_element('m:SortOrder'),
- order_fields,
- version=self.account.version
- ))
- payload.append(folder_ids_element(folders=folders, version=self.account.version, tag='m:ParentFolderId'))
+ payload.append(set_xml_value(create_element("m:SortOrder"), order_fields, version=self.account.version))
+ payload.append(folder_ids_element(folders=folders, version=self.account.version, tag="m:ParentFolderId"))
if query_string:
payload.append(query_string.to_xml(version=self.account.version))
return payload
@@ -2525,37 +2593,44 @@ Inherited members
class GetAttachment(EWSAccountService):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/getattachment-operation"""
- SERVICE_NAME = 'GetAttachment'
- element_container_name = f'{{{MNS}}}Attachments'
+ SERVICE_NAME = "GetAttachment"
+ element_container_name = f"{{{MNS}}}Attachments"
cls_map = {cls.response_tag(): cls for cls in (FileAttachment, ItemAttachment)}
def call(self, items, include_mime_content, body_type, filter_html_content, additional_fields):
if body_type and body_type not in BODY_TYPE_CHOICES:
- raise InvalidEnumValue('body_type', body_type, BODY_TYPE_CHOICES)
- return self._elems_to_objs(self._chunked_get_elements(
- self.get_payload, items=items, include_mime_content=include_mime_content,
- body_type=body_type, filter_html_content=filter_html_content, additional_fields=additional_fields,
- ))
+ raise InvalidEnumValue("body_type", body_type, BODY_TYPE_CHOICES)
+ return self._elems_to_objs(
+ self._chunked_get_elements(
+ self.get_payload,
+ items=items,
+ include_mime_content=include_mime_content,
+ body_type=body_type,
+ filter_html_content=filter_html_content,
+ additional_fields=additional_fields,
+ )
+ )
def _elem_to_obj(self, elem):
return self.cls_map[elem.tag].from_xml(elem=elem, account=self.account)
def get_payload(self, items, include_mime_content, body_type, filter_html_content, additional_fields):
- payload = create_element(f'm:{self.SERVICE_NAME}')
- shape_elem = create_element('m:AttachmentShape')
+ payload = create_element(f"m:{self.SERVICE_NAME}")
+ shape_elem = create_element("m:AttachmentShape")
if include_mime_content:
- add_xml_child(shape_elem, 't:IncludeMimeContent', 'true')
+ add_xml_child(shape_elem, "t:IncludeMimeContent", "true")
if body_type:
- add_xml_child(shape_elem, 't:BodyType', body_type)
+ add_xml_child(shape_elem, "t:BodyType", body_type)
if filter_html_content is not None:
- add_xml_child(shape_elem, 't:FilterHtmlContent', 'true' if filter_html_content else 'false')
+ add_xml_child(shape_elem, "t:FilterHtmlContent", "true" if filter_html_content else "false")
if additional_fields:
- additional_properties = create_element('t:AdditionalProperties')
+ additional_properties = create_element("t:AdditionalProperties")
expanded_fields = chain(*(f.expand(version=self.account.version) for f in additional_fields))
- set_xml_value(additional_properties, sorted(
- expanded_fields,
- key=lambda f: (getattr(f.field, 'field_uri', ''), f.path)
- ), version=self.account.version)
+ set_xml_value(
+ additional_properties,
+ sorted(expanded_fields, key=lambda f: (getattr(f.field, "field_uri", ""), f.path)),
+ version=self.account.version,
+ )
shape_elem.append(additional_properties)
if len(shape_elem):
payload.append(shape_elem)
@@ -2563,26 +2638,26 @@ Inherited members
return payload
def _update_api_version(self, api_version, header, **parse_opts):
- if not parse_opts.get('stream_file_content', False):
+ if not parse_opts.get("stream_file_content", False):
super()._update_api_version(api_version, header, **parse_opts)
# TODO: We're skipping this part in streaming mode because StreamingBase64Parser cannot parse the SOAP header
@classmethod
def _get_soap_parts(cls, response, **parse_opts):
- if not parse_opts.get('stream_file_content', False):
+ if not parse_opts.get("stream_file_content", False):
return super()._get_soap_parts(response, **parse_opts)
# Pass the response unaltered. We want to use our custom streaming parser
return None, response
def _get_soap_messages(self, body, **parse_opts):
- if not parse_opts.get('stream_file_content', False):
+ if not parse_opts.get("stream_file_content", False):
return super()._get_soap_messages(body, **parse_opts)
# 'body' is actually the raw response passed on by '_get_soap_parts'
r = body
parser = StreamingBase64Parser()
- field = FileAttachment.get_field_by_fieldname('_content')
+ field = FileAttachment.get_field_by_fieldname("_content")
handler = StreamingContentHandler(parser=parser, ns=field.namespace, element_name=field.field_uri)
parser.setContentHandler(handler)
return parser.parse(r)
@@ -2590,7 +2665,10 @@ Inherited members
def stream_file_content(self, attachment_id):
# The streaming XML parser can only stream content of one attachment
payload = self.get_payload(
- items=[attachment_id], include_mime_content=False, body_type=None, filter_html_content=None,
+ items=[attachment_id],
+ include_mime_content=False,
+ body_type=None,
+ filter_html_content=None,
additional_fields=None,
)
self.streaming = True
@@ -2645,11 +2723,17 @@ Methods
def call(self, items, include_mime_content, body_type, filter_html_content, additional_fields):
if body_type and body_type not in BODY_TYPE_CHOICES:
- raise InvalidEnumValue('body_type', body_type, BODY_TYPE_CHOICES)
- return self._elems_to_objs(self._chunked_get_elements(
- self.get_payload, items=items, include_mime_content=include_mime_content,
- body_type=body_type, filter_html_content=filter_html_content, additional_fields=additional_fields,
- ))
+ raise InvalidEnumValue("body_type", body_type, BODY_TYPE_CHOICES)
+ return self._elems_to_objs(
+ self._chunked_get_elements(
+ self.get_payload,
+ items=items,
+ include_mime_content=include_mime_content,
+ body_type=body_type,
+ filter_html_content=filter_html_content,
+ additional_fields=additional_fields,
+ )
+ )
@@ -2662,21 +2746,22 @@ Methods
Expand source code
def get_payload(self, items, include_mime_content, body_type, filter_html_content, additional_fields):
- payload = create_element(f'm:{self.SERVICE_NAME}')
- shape_elem = create_element('m:AttachmentShape')
+ payload = create_element(f"m:{self.SERVICE_NAME}")
+ shape_elem = create_element("m:AttachmentShape")
if include_mime_content:
- add_xml_child(shape_elem, 't:IncludeMimeContent', 'true')
+ add_xml_child(shape_elem, "t:IncludeMimeContent", "true")
if body_type:
- add_xml_child(shape_elem, 't:BodyType', body_type)
+ add_xml_child(shape_elem, "t:BodyType", body_type)
if filter_html_content is not None:
- add_xml_child(shape_elem, 't:FilterHtmlContent', 'true' if filter_html_content else 'false')
+ add_xml_child(shape_elem, "t:FilterHtmlContent", "true" if filter_html_content else "false")
if additional_fields:
- additional_properties = create_element('t:AdditionalProperties')
+ additional_properties = create_element("t:AdditionalProperties")
expanded_fields = chain(*(f.expand(version=self.account.version) for f in additional_fields))
- set_xml_value(additional_properties, sorted(
- expanded_fields,
- key=lambda f: (getattr(f.field, 'field_uri', ''), f.path)
- ), version=self.account.version)
+ set_xml_value(
+ additional_properties,
+ sorted(expanded_fields, key=lambda f: (getattr(f.field, "field_uri", ""), f.path)),
+ version=self.account.version,
+ )
shape_elem.append(additional_properties)
if len(shape_elem):
payload.append(shape_elem)
@@ -2696,7 +2781,10 @@ Methods
def stream_file_content(self, attachment_id):
# The streaming XML parser can only stream content of one attachment
payload = self.get_payload(
- items=[attachment_id], include_mime_content=False, body_type=None, filter_html_content=None,
+ items=[attachment_id],
+ include_mime_content=False,
+ body_type=None,
+ filter_html_content=None,
additional_fields=None,
)
self.streaming = True
@@ -2745,26 +2833,28 @@ Inherited members
class GetDelegate(EWSAccountService):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/getdelegate-operation"""
- SERVICE_NAME = 'GetDelegate'
+ SERVICE_NAME = "GetDelegate"
ERRORS_TO_CATCH_IN_RESPONSE = ()
supported_from = EXCHANGE_2007_SP1
def call(self, user_ids, include_permissions):
- return self._elems_to_objs(self._chunked_get_elements(
- self.get_payload,
- items=user_ids or [None],
- mailbox=DLMailbox(email_address=self.account.primary_smtp_address),
- include_permissions=include_permissions,
- ))
+ return self._elems_to_objs(
+ self._chunked_get_elements(
+ self.get_payload,
+ items=user_ids or [None],
+ mailbox=DLMailbox(email_address=self.account.primary_smtp_address),
+ include_permissions=include_permissions,
+ )
+ )
def _elem_to_obj(self, elem):
return DelegateUser.from_xml(elem=elem, account=self.account)
def get_payload(self, user_ids, mailbox, include_permissions):
- payload = create_element(f'm:{self.SERVICE_NAME}', attrs=dict(IncludePermissions=include_permissions))
+ payload = create_element(f"m:{self.SERVICE_NAME}", attrs=dict(IncludePermissions=include_permissions))
set_xml_value(payload, mailbox, version=self.protocol.version)
if user_ids != [None]:
- user_ids_elem = create_element('m:UserIds')
+ user_ids_elem = create_element("m:UserIds")
for user_id in user_ids:
if isinstance(user_id, str):
user_id = UserId(primary_smtp_address=user_id)
@@ -2778,7 +2868,7 @@ Inherited members
@classmethod
def _response_message_tag(cls):
- return f'{{{MNS}}}DelegateUserResponseMessageType'
+ return f"{{{MNS}}}DelegateUserResponseMessageType"
Ancestors
@@ -2812,12 +2902,14 @@ Methods
Expand source code
def call(self, user_ids, include_permissions):
- return self._elems_to_objs(self._chunked_get_elements(
- self.get_payload,
- items=user_ids or [None],
- mailbox=DLMailbox(email_address=self.account.primary_smtp_address),
- include_permissions=include_permissions,
- ))
+ return self._elems_to_objs(
+ self._chunked_get_elements(
+ self.get_payload,
+ items=user_ids or [None],
+ mailbox=DLMailbox(email_address=self.account.primary_smtp_address),
+ include_permissions=include_permissions,
+ )
+ )
@@ -2830,10 +2922,10 @@ Methods
Expand source code
def get_payload(self, user_ids, mailbox, include_permissions):
- payload = create_element(f'm:{self.SERVICE_NAME}', attrs=dict(IncludePermissions=include_permissions))
+ payload = create_element(f"m:{self.SERVICE_NAME}", attrs=dict(IncludePermissions=include_permissions))
set_xml_value(payload, mailbox, version=self.protocol.version)
if user_ids != [None]:
- user_ids_elem = create_element('m:UserIds')
+ user_ids_elem = create_element("m:UserIds")
for user_id in user_ids:
if isinstance(user_id, str):
user_id = UserId(primary_smtp_address=user_id)
@@ -2871,13 +2963,18 @@ Inherited members
https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/getevents-operation
"""
- SERVICE_NAME = 'GetEvents'
+ SERVICE_NAME = "GetEvents"
prefer_affinity = True
def call(self, subscription_id, watermark):
- return self._elems_to_objs(self._get_elements(payload=self.get_payload(
- subscription_id=subscription_id, watermark=watermark,
- )))
+ return self._elems_to_objs(
+ self._get_elements(
+ payload=self.get_payload(
+ subscription_id=subscription_id,
+ watermark=watermark,
+ )
+ )
+ )
def _elem_to_obj(self, elem):
return Notification.from_xml(elem=elem, account=None)
@@ -2887,9 +2984,9 @@ Inherited members
return container.findall(Notification.response_tag())
def get_payload(self, subscription_id, watermark):
- payload = create_element(f'm:{self.SERVICE_NAME}')
- add_xml_child(payload, 'm:SubscriptionId', subscription_id)
- add_xml_child(payload, 'm:Watermark', watermark)
+ payload = create_element(f"m:{self.SERVICE_NAME}")
+ add_xml_child(payload, "m:SubscriptionId", subscription_id)
+ add_xml_child(payload, "m:Watermark", watermark)
return payload
Ancestors
@@ -2920,9 +3017,14 @@ Methods
Expand source code
def call(self, subscription_id, watermark):
- return self._elems_to_objs(self._get_elements(payload=self.get_payload(
- subscription_id=subscription_id, watermark=watermark,
- )))
+ return self._elems_to_objs(
+ self._get_elements(
+ payload=self.get_payload(
+ subscription_id=subscription_id,
+ watermark=watermark,
+ )
+ )
+ )
@@ -2935,9 +3037,9 @@ Methods
Expand source code
def get_payload(self, subscription_id, watermark):
- payload = create_element(f'm:{self.SERVICE_NAME}')
- add_xml_child(payload, 'm:SubscriptionId', subscription_id)
- add_xml_child(payload, 'm:Watermark', watermark)
+ payload = create_element(f"m:{self.SERVICE_NAME}")
+ add_xml_child(payload, "m:SubscriptionId", subscription_id)
+ add_xml_child(payload, "m:Watermark", watermark)
return payload
@@ -2967,10 +3069,12 @@ Inherited members
class GetFolder(EWSAccountService):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/getfolder-operation"""
- SERVICE_NAME = 'GetFolder'
- element_container_name = f'{{{MNS}}}Folders'
+ SERVICE_NAME = "GetFolder"
+ element_container_name = f"{{{MNS}}}Folders"
ERRORS_TO_CATCH_IN_RESPONSE = EWSAccountService.ERRORS_TO_CATCH_IN_RESPONSE + (
- ErrorFolderNotFound, ErrorNoPublicFolderReplicaAvailable, ErrorInvalidOperation,
+ ErrorFolderNotFound,
+ ErrorNoPublicFolderReplicaAvailable,
+ ErrorInvalidOperation,
)
def __init__(self, *args, **kwargs):
@@ -2989,12 +3093,14 @@ Inherited members
# We can't easily find the correct folder class from the returned XML. Instead, return objects with the same
# class as the folder instance it was requested with.
self.folders = list(folders) # Convert to a list, in case 'folders' is a generator. We're iterating twice.
- return self._elems_to_objs(self._chunked_get_elements(
- self.get_payload,
- items=self.folders,
- additional_fields=additional_fields,
- shape=shape,
- ))
+ return self._elems_to_objs(
+ self._chunked_get_elements(
+ self.get_payload,
+ items=self.folders,
+ additional_fields=additional_fields,
+ shape=shape,
+ )
+ )
def _elems_to_objs(self, elems):
for folder, elem in zip(self.folders, elems):
@@ -3004,10 +3110,12 @@ Inherited members
yield parse_folder_elem(elem=elem, folder=folder, account=self.account)
def get_payload(self, folders, additional_fields, shape):
- payload = create_element(f'm:{self.SERVICE_NAME}')
- payload.append(shape_element(
- tag='m:FolderShape', shape=shape, additional_fields=additional_fields, version=self.account.version
- ))
+ payload = create_element(f"m:{self.SERVICE_NAME}")
+ payload.append(
+ shape_element(
+ tag="m:FolderShape", shape=shape, additional_fields=additional_fields, version=self.account.version
+ )
+ )
payload.append(folder_ids_element(folders=folders, version=self.account.version))
return payload
@@ -3058,12 +3166,14 @@ Methods
# We can't easily find the correct folder class from the returned XML. Instead, return objects with the same
# class as the folder instance it was requested with.
self.folders = list(folders) # Convert to a list, in case 'folders' is a generator. We're iterating twice.
- return self._elems_to_objs(self._chunked_get_elements(
- self.get_payload,
- items=self.folders,
- additional_fields=additional_fields,
- shape=shape,
- ))
+ return self._elems_to_objs(
+ self._chunked_get_elements(
+ self.get_payload,
+ items=self.folders,
+ additional_fields=additional_fields,
+ shape=shape,
+ )
+ )
@@ -3076,10 +3186,12 @@ Methods
Expand source code
def get_payload(self, folders, additional_fields, shape):
- payload = create_element(f'm:{self.SERVICE_NAME}')
- payload.append(shape_element(
- tag='m:FolderShape', shape=shape, additional_fields=additional_fields, version=self.account.version
- ))
+ payload = create_element(f"m:{self.SERVICE_NAME}")
+ payload.append(
+ shape_element(
+ tag="m:FolderShape", shape=shape, additional_fields=additional_fields, version=self.account.version
+ )
+ )
payload.append(folder_ids_element(folders=folders, version=self.account.version))
return payload
@@ -3110,8 +3222,8 @@ Inherited members
class GetItem(EWSAccountService):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/getitem-operation"""
- SERVICE_NAME = 'GetItem'
- element_container_name = f'{{{MNS}}}Items'
+ SERVICE_NAME = "GetItem"
+ element_container_name = f"{{{MNS}}}Items"
def call(self, items, additional_fields, shape):
"""Return all items in an account that correspond to a list of ID's, in stable order.
@@ -3122,18 +3234,25 @@ Inherited members
:return: XML elements for the items, in stable order
"""
- return self._elems_to_objs(self._chunked_get_elements(
- self.get_payload, items=items, additional_fields=additional_fields, shape=shape,
- ))
+ return self._elems_to_objs(
+ self._chunked_get_elements(
+ self.get_payload,
+ items=items,
+ additional_fields=additional_fields,
+ shape=shape,
+ )
+ )
def _elem_to_obj(self, elem):
return BaseFolder.item_model_from_tag(elem.tag).from_xml(elem=elem, account=self.account)
def get_payload(self, items, additional_fields, shape):
- payload = create_element(f'm:{self.SERVICE_NAME}')
- payload.append(shape_element(
- tag='m:ItemShape', shape=shape, additional_fields=additional_fields, version=self.account.version
- ))
+ payload = create_element(f"m:{self.SERVICE_NAME}")
+ payload.append(
+ shape_element(
+ tag="m:ItemShape", shape=shape, additional_fields=additional_fields, version=self.account.version
+ )
+ )
payload.append(item_ids_element(items=items, version=self.account.version))
return payload
@@ -3177,9 +3296,14 @@ Methods
:return: XML elements for the items, in stable order
"""
- return self._elems_to_objs(self._chunked_get_elements(
- self.get_payload, items=items, additional_fields=additional_fields, shape=shape,
- ))
+ return self._elems_to_objs(
+ self._chunked_get_elements(
+ self.get_payload,
+ items=items,
+ additional_fields=additional_fields,
+ shape=shape,
+ )
+ )
@@ -3192,10 +3316,12 @@ Methods
Expand source code
def get_payload(self, items, additional_fields, shape):
- payload = create_element(f'm:{self.SERVICE_NAME}')
- payload.append(shape_element(
- tag='m:ItemShape', shape=shape, additional_fields=additional_fields, version=self.account.version
- ))
+ payload = create_element(f"m:{self.SERVICE_NAME}")
+ payload.append(
+ shape_element(
+ tag="m:ItemShape", shape=shape, additional_fields=additional_fields, version=self.account.version
+ )
+ )
payload.append(item_ids_element(items=items, version=self.account.version))
return payload
@@ -3226,24 +3352,26 @@ Inherited members
class GetMailTips(EWSService):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/getmailtips-operation"""
- SERVICE_NAME = 'GetMailTips'
+ SERVICE_NAME = "GetMailTips"
def call(self, sending_as, recipients, mail_tips_requested):
- return self._elems_to_objs(self._chunked_get_elements(
- self.get_payload,
- items=recipients,
- sending_as=sending_as,
- mail_tips_requested=mail_tips_requested,
- ))
+ return self._elems_to_objs(
+ self._chunked_get_elements(
+ self.get_payload,
+ items=recipients,
+ sending_as=sending_as,
+ mail_tips_requested=mail_tips_requested,
+ )
+ )
def _elem_to_obj(self, elem):
return MailTips.from_xml(elem=elem, account=None)
- def get_payload(self, recipients, sending_as, mail_tips_requested):
- payload = create_element(f'm:{self.SERVICE_NAME}')
+ def get_payload(self, recipients, sending_as, mail_tips_requested):
+ payload = create_element(f"m:{self.SERVICE_NAME}")
set_xml_value(payload, sending_as, version=self.protocol.version)
- recipients_elem = create_element('m:Recipients')
+ recipients_elem = create_element("m:Recipients")
for recipient in recipients:
set_xml_value(recipients_elem, recipient, version=self.protocol.version)
payload.append(recipients_elem)
@@ -3258,7 +3386,7 @@ Inherited members
@classmethod
def _response_message_tag(cls):
- return f'{{{MNS}}}MailTipsResponseMessageType'
+ return f"{{{MNS}}}MailTipsResponseMessageType"
def call(self, sending_as, recipients, mail_tips_requested):
- return self._elems_to_objs(self._chunked_get_elements(
- self.get_payload,
- items=recipients,
- sending_as=sending_as,
- mail_tips_requested=mail_tips_requested,
- ))
+ return self._elems_to_objs(
+ self._chunked_get_elements(
+ self.get_payload,
+ items=recipients,
+ sending_as=sending_as,
+ mail_tips_requested=mail_tips_requested,
+ )
+ )
@@ -3300,11 +3430,11 @@ Methods
Expand source code
-def get_payload(self, recipients, sending_as, mail_tips_requested):
- payload = create_element(f'm:{self.SERVICE_NAME}')
+def get_payload(self, recipients, sending_as, mail_tips_requested):
+ payload = create_element(f"m:{self.SERVICE_NAME}")
set_xml_value(payload, sending_as, version=self.protocol.version)
- recipients_elem = create_element('m:Recipients')
+ recipients_elem = create_element("m:Recipients")
for recipient in recipients:
set_xml_value(recipients_elem, recipient, version=self.protocol.version)
payload.append(recipients_elem)
@@ -3340,7 +3470,7 @@ Inherited members
class GetPersona(EWSAccountService):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/getpersona-operation"""
- SERVICE_NAME = 'GetPersona'
+ SERVICE_NAME = "GetPersona"
def call(self, personas):
# GetPersona only accepts one persona ID per request. Crazy.
@@ -3352,18 +3482,16 @@ Inherited members
def get_payload(self, persona):
return set_xml_value(
- create_element(f'm:{self.SERVICE_NAME}'),
- to_item_id(persona, PersonaId),
- version=self.protocol.version
+ create_element(f"m:{self.SERVICE_NAME}"), to_item_id(persona, PersonaId), version=self.protocol.version
)
@classmethod
def _get_elements_in_container(cls, container):
- return container.findall(f'{{{MNS}}}{Persona.ELEMENT_NAME}')
+ return container.findall(f"{{{MNS}}}{Persona.ELEMENT_NAME}")
@classmethod
def _response_tag(cls):
- return f'{{{MNS}}}{cls.SERVICE_NAME}ResponseMessage'
+ return f"{{{MNS}}}{cls.SERVICE_NAME}ResponseMessage"
Ancestors
@@ -3405,9 +3533,7 @@ Methods
def get_payload(self, persona):
return set_xml_value(
- create_element(f'm:{self.SERVICE_NAME}'),
- to_item_id(persona, PersonaId),
- version=self.protocol.version
+ create_element(f"m:{self.SERVICE_NAME}"), to_item_id(persona, PersonaId), version=self.protocol.version
)
@@ -3437,8 +3563,8 @@ Inherited members
class GetRoomLists(EWSService):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/getroomlists-operation"""
- SERVICE_NAME = 'GetRoomLists'
- element_container_name = f'{{{MNS}}}RoomLists'
+ SERVICE_NAME = "GetRoomLists"
+ element_container_name = f"{{{MNS}}}RoomLists"
supported_from = EXCHANGE_2010
def call(self):
@@ -3448,7 +3574,7 @@ Inherited members
return RoomList.from_xml(elem=elem, account=None)
def get_payload(self):
- return create_element(f'm:{self.SERVICE_NAME}')
+ return create_element(f"m:{self.SERVICE_NAME}")
Ancestors
@@ -3494,7 +3620,7 @@ Methods
Expand source code
def get_payload(self):
- return create_element(f'm:{self.SERVICE_NAME}')
+ return create_element(f"m:{self.SERVICE_NAME}")
@@ -3523,8 +3649,8 @@ class GetRooms(EWSService):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/getrooms-operation"""
- SERVICE_NAME = 'GetRooms'
- element_container_name = f'{{{MNS}}}Rooms'
+ SERVICE_NAME = "GetRooms"
+ element_container_name = f"{{{MNS}}}Rooms"
supported_from = EXCHANGE_2010
def call(self, room_list):
@@ -3534,7 +3660,7 @@ Inherited members
return Room.from_xml(elem=elem, account=None)
def get_payload(self, room_list):
- return set_xml_value(create_element(f'm:{self.SERVICE_NAME}'), room_list, version=self.protocol.version)
+ return set_xml_value(create_element(f"m:{self.SERVICE_NAME}"), room_list, version=self.protocol.version)
def get_payload(self, room_list):
- return set_xml_value(create_element(f'm:{self.SERVICE_NAME}'), room_list, version=self.protocol.version)
+ return set_xml_value(create_element(f"m:{self.SERVICE_NAME}"), room_list, version=self.protocol.version)
@@ -3612,27 +3738,31 @@ def call(self, search_filter, expand_group_membership):
- return self._elems_to_objs(self._get_elements(payload=self.get_payload(
- search_filter=search_filter,
- expand_group_membership=expand_group_membership,
- )))
+ return self._elems_to_objs(
+ self._get_elements(
+ payload=self.get_payload(
+ search_filter=search_filter,
+ expand_group_membership=expand_group_membership,
+ )
+ )
+ )
@@ -3700,11 +3834,11 @@ Methods
Expand source code
def get_payload(self, search_filter, expand_group_membership):
- payload = create_element(f'm:{self.SERVICE_NAME}')
+ payload = create_element(f"m:{self.SERVICE_NAME}")
if search_filter:
- add_xml_child(payload, 'm:SearchFilter', search_filter)
+ add_xml_child(payload, "m:SearchFilter", search_filter)
if expand_group_membership is not None:
- add_xml_child(payload, 'm:ExpandGroupMembership', 'true' if expand_group_membership else 'false')
+ add_xml_child(payload, "m:ExpandGroupMembership", "true" if expand_group_membership else "false")
return payload
@@ -3737,27 +3871,28 @@ Inherited members
https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/getservertimezones-operation
"""
- SERVICE_NAME = 'GetServerTimeZones'
- element_container_name = f'{{{MNS}}}TimeZoneDefinitions'
+ SERVICE_NAME = "GetServerTimeZones"
+ element_container_name = f"{{{MNS}}}TimeZoneDefinitions"
supported_from = EXCHANGE_2010
def call(self, timezones=None, return_full_timezone_data=False):
- return self._elems_to_objs(self._get_elements(payload=self.get_payload(
- timezones=timezones,
- return_full_timezone_data=return_full_timezone_data
- )))
+ return self._elems_to_objs(
+ self._get_elements(
+ payload=self.get_payload(timezones=timezones, return_full_timezone_data=return_full_timezone_data)
+ )
+ )
def get_payload(self, timezones, return_full_timezone_data):
payload = create_element(
- f'm:{self.SERVICE_NAME}',
+ f"m:{self.SERVICE_NAME}",
attrs=dict(ReturnFullTimeZoneData=return_full_timezone_data),
)
if timezones is not None:
is_empty, timezones = peek(timezones)
if not is_empty:
- tz_ids = create_element('m:Ids')
+ tz_ids = create_element("m:Ids")
for timezone in timezones:
- tz_id = set_xml_value(create_element('t:Id'), timezone.ms_id)
+ tz_id = set_xml_value(create_element("t:Id"), timezone.ms_id)
tz_ids.append(tz_id)
payload.append(tz_ids)
return payload
@@ -3796,10 +3931,11 @@ Methods
Expand source code
def call(self, timezones=None, return_full_timezone_data=False):
- return self._elems_to_objs(self._get_elements(payload=self.get_payload(
- timezones=timezones,
- return_full_timezone_data=return_full_timezone_data
- )))
+ return self._elems_to_objs(
+ self._get_elements(
+ payload=self.get_payload(timezones=timezones, return_full_timezone_data=return_full_timezone_data)
+ )
+ )
@@ -3813,15 +3949,15 @@ Methods
def get_payload(self, timezones, return_full_timezone_data):
payload = create_element(
- f'm:{self.SERVICE_NAME}',
+ f"m:{self.SERVICE_NAME}",
attrs=dict(ReturnFullTimeZoneData=return_full_timezone_data),
)
if timezones is not None:
is_empty, timezones = peek(timezones)
if not is_empty:
- tz_ids = create_element('m:Ids')
+ tz_ids = create_element("m:Ids")
for timezone in timezones:
- tz_id = set_xml_value(create_element('t:Id'), timezone.ms_id)
+ tz_id = set_xml_value(create_element("t:Id"), timezone.ms_id)
tz_ids.append(tz_id)
payload.append(tz_ids)
return payload
@@ -3856,13 +3992,13 @@ Inherited members
https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/getstreamingevents-operation
"""
- SERVICE_NAME = 'GetStreamingEvents'
- element_container_name = f'{{{MNS}}}Notifications'
+ SERVICE_NAME = "GetStreamingEvents"
+ element_container_name = f"{{{MNS}}}Notifications"
prefer_affinity = True
# Connection status values
- OK = 'OK'
- CLOSED = 'Closed'
+ OK = "OK"
+ CLOSED = "Closed"
def __init__(self, *args, **kwargs):
# These values are set each time call() is consumed
@@ -3872,14 +4008,19 @@ Inherited members
def call(self, subscription_ids, connection_timeout):
if not isinstance(connection_timeout, int):
- raise InvalidTypeError('connection_timeout', connection_timeout, int)
+ raise InvalidTypeError("connection_timeout", connection_timeout, int)
if connection_timeout < 1:
raise ValueError(f"'connection_timeout' {connection_timeout} must be a positive integer")
# Add 60 seconds to the timeout, to allow us to always get the final message containing ConnectionStatus=Closed
self.timeout = connection_timeout * 60 + 60
- return self._elems_to_objs(self._get_elements(payload=self.get_payload(
- subscription_ids=subscription_ids, connection_timeout=connection_timeout,
- )))
+ return self._elems_to_objs(
+ self._get_elements(
+ payload=self.get_payload(
+ subscription_ids=subscription_ids,
+ connection_timeout=connection_timeout,
+ )
+ )
+ )
def _elem_to_obj(self, elem):
return Notification.from_xml(elem=elem, account=None)
@@ -3895,7 +4036,7 @@ Inherited members
# XML response.
r = body
for i, doc in enumerate(DocumentYielder(r.iter_content()), start=1):
- xml_log.debug('''Response XML (docs counter: %(i)s): %(xml_response)s''', dict(i=i, xml_response=doc))
+ xml_log.debug("Response XML (docs counter: %(i)s): %(xml_response)s", dict(i=i, xml_response=doc))
response = DummyResponse(content=doc)
try:
_, body = super()._get_soap_parts(response=response, **parse_opts)
@@ -3910,10 +4051,10 @@ Inherited members
break
def _get_element_container(self, message, name=None):
- error_ids_elem = message.find(f'{{{MNS}}}ErrorSubscriptionIds')
- error_ids = [] if error_ids_elem is None else get_xml_attrs(error_ids_elem, f'{{{MNS}}}SubscriptionId')
- self.connection_status = get_xml_attr(message, f'{{{MNS}}}ConnectionStatus') # Either 'OK' or 'Closed'
- log.debug('Connection status is: %s', self.connection_status)
+ error_ids_elem = message.find(f"{{{MNS}}}ErrorSubscriptionIds")
+ error_ids = [] if error_ids_elem is None else get_xml_attrs(error_ids_elem, f"{{{MNS}}}SubscriptionId")
+ self.connection_status = get_xml_attr(message, f"{{{MNS}}}ConnectionStatus") # Either 'OK' or 'Closed'
+ log.debug("Connection status is: %s", self.connection_status)
# Upstream normally expects to find a 'name' tag but our response does not always have it. We still want to
# call upstream, to have exceptions raised. Return an empty list if there is no 'name' tag and no errors.
if message.find(name) is None:
@@ -3925,20 +4066,20 @@ Inherited members
# subscriptions seem to never be returned even though the XML spec allows it. This means there's no point in
# trying to collect any notifications here and delivering a combination of errors and return values.
if error_ids:
- e.value += f' (subscription IDs: {error_ids})'
+ e.value += f" (subscription IDs: {error_ids})"
raise e
return [] if name is None else res
def get_payload(self, subscription_ids, connection_timeout):
- payload = create_element(f'm:{self.SERVICE_NAME}')
- subscriptions_elem = create_element('m:SubscriptionIds')
+ payload = create_element(f"m:{self.SERVICE_NAME}")
+ subscriptions_elem = create_element("m:SubscriptionIds")
for subscription_id in subscription_ids:
- add_xml_child(subscriptions_elem, 't:SubscriptionId', subscription_id)
+ add_xml_child(subscriptions_elem, "t:SubscriptionId", subscription_id)
if not len(subscriptions_elem):
raise ValueError("'subscription_ids' must not be empty")
payload.append(subscriptions_elem)
- add_xml_child(payload, 'm:ConnectionTimeout', connection_timeout)
+ add_xml_child(payload, "m:ConnectionTimeout", connection_timeout)
return payload
def call(self, subscription_ids, connection_timeout):
if not isinstance(connection_timeout, int):
- raise InvalidTypeError('connection_timeout', connection_timeout, int)
+ raise InvalidTypeError("connection_timeout", connection_timeout, int)
if connection_timeout < 1:
raise ValueError(f"'connection_timeout' {connection_timeout} must be a positive integer")
# Add 60 seconds to the timeout, to allow us to always get the final message containing ConnectionStatus=Closed
self.timeout = connection_timeout * 60 + 60
- return self._elems_to_objs(self._get_elements(payload=self.get_payload(
- subscription_ids=subscription_ids, connection_timeout=connection_timeout,
- )))
+ return self._elems_to_objs(
+ self._get_elements(
+ payload=self.get_payload(
+ subscription_ids=subscription_ids,
+ connection_timeout=connection_timeout,
+ )
+ )
+ )
@@ -4002,15 +4148,15 @@ Methods
Expand source code
def get_payload(self, subscription_ids, connection_timeout):
- payload = create_element(f'm:{self.SERVICE_NAME}')
- subscriptions_elem = create_element('m:SubscriptionIds')
+ payload = create_element(f"m:{self.SERVICE_NAME}")
+ subscriptions_elem = create_element("m:SubscriptionIds")
for subscription_id in subscription_ids:
- add_xml_child(subscriptions_elem, 't:SubscriptionId', subscription_id)
+ add_xml_child(subscriptions_elem, "t:SubscriptionId", subscription_id)
if not len(subscriptions_elem):
raise ValueError("'subscription_ids' must not be empty")
payload.append(subscriptions_elem)
- add_xml_child(payload, 'm:ConnectionTimeout', connection_timeout)
+ add_xml_child(payload, "m:ConnectionTimeout", connection_timeout)
return payload
@@ -4045,45 +4191,47 @@ Inherited members
https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/getuseravailability-operation
"""
- SERVICE_NAME = 'GetUserAvailability'
+ SERVICE_NAME = "GetUserAvailability"
def call(self, timezone, mailbox_data, free_busy_view_options):
# TODO: Also supports SuggestionsViewOptions, see
# https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/suggestionsviewoptions
- return self._elems_to_objs(self._get_elements(payload=self.get_payload(
- timezone=timezone,
- mailbox_data=mailbox_data,
- free_busy_view_options=free_busy_view_options
- )))
+ return self._elems_to_objs(
+ self._get_elements(
+ payload=self.get_payload(
+ timezone=timezone, mailbox_data=mailbox_data, free_busy_view_options=free_busy_view_options
+ )
+ )
+ )
def _elem_to_obj(self, elem):
return FreeBusyView.from_xml(elem=elem, account=None)
def get_payload(self, timezone, mailbox_data, free_busy_view_options):
- payload = create_element(f'm:{self.SERVICE_NAME}Request')
+ payload = create_element(f"m:{self.SERVICE_NAME}Request")
set_xml_value(payload, timezone, version=self.protocol.version)
- mailbox_data_array = create_element('m:MailboxDataArray')
+ mailbox_data_array = create_element("m:MailboxDataArray")
set_xml_value(mailbox_data_array, mailbox_data, version=self.protocol.version)
payload.append(mailbox_data_array)
return set_xml_value(payload, free_busy_view_options, version=self.protocol.version)
@staticmethod
def _response_messages_tag():
- return f'{{{MNS}}}FreeBusyResponseArray'
+ return f"{{{MNS}}}FreeBusyResponseArray"
@classmethod
def _response_message_tag(cls):
- return f'{{{MNS}}}FreeBusyResponse'
+ return f"{{{MNS}}}FreeBusyResponse"
def _get_elements_in_response(self, response):
for msg in response:
# Just check the response code and raise errors
- self._get_element_container(message=msg.find(f'{{{MNS}}}ResponseMessage'))
+ self._get_element_container(message=msg.find(f"{{{MNS}}}ResponseMessage"))
yield from self._get_elements_in_container(container=msg)
@classmethod
def _get_elements_in_container(cls, container):
- return [container.find(f'{{{MNS}}}FreeBusyView')]
+ return [container.find(f"{{{MNS}}}FreeBusyView")]
def call(self, timezone, mailbox_data, free_busy_view_options):
# TODO: Also supports SuggestionsViewOptions, see
# https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/suggestionsviewoptions
- return self._elems_to_objs(self._get_elements(payload=self.get_payload(
- timezone=timezone,
- mailbox_data=mailbox_data,
- free_busy_view_options=free_busy_view_options
- )))
+ return self._elems_to_objs(
+ self._get_elements(
+ payload=self.get_payload(
+ timezone=timezone, mailbox_data=mailbox_data, free_busy_view_options=free_busy_view_options
+ )
+ )
+ )
@@ -4127,9 +4277,9 @@ Methods
Expand source code
def get_payload(self, timezone, mailbox_data, free_busy_view_options):
- payload = create_element(f'm:{self.SERVICE_NAME}Request')
+ payload = create_element(f"m:{self.SERVICE_NAME}Request")
set_xml_value(payload, timezone, version=self.protocol.version)
- mailbox_data_array = create_element('m:MailboxDataArray')
+ mailbox_data_array = create_element("m:MailboxDataArray")
set_xml_value(mailbox_data_array, mailbox_data, version=self.protocol.version)
payload.append(mailbox_data_array)
return set_xml_value(payload, free_busy_view_options, version=self.protocol.version)
@@ -4164,14 +4314,16 @@ Inherited members
https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/getuserconfiguration-operation
"""
- SERVICE_NAME = 'GetUserConfiguration'
+ SERVICE_NAME = "GetUserConfiguration"
def call(self, user_configuration_name, properties):
if properties not in PROPERTIES_CHOICES:
- raise InvalidEnumValue('properties', properties, PROPERTIES_CHOICES)
- return self._elems_to_objs(self._get_elements(payload=self.get_payload(
- user_configuration_name=user_configuration_name, properties=properties
- )))
+ raise InvalidEnumValue("properties", properties, PROPERTIES_CHOICES)
+ return self._elems_to_objs(
+ self._get_elements(
+ payload=self.get_payload(user_configuration_name=user_configuration_name, properties=properties)
+ )
+ )
def _elem_to_obj(self, elem):
return UserConfiguration.from_xml(elem=elem, account=self.account)
@@ -4181,10 +4333,10 @@ Inherited members
return container.findall(UserConfiguration.response_tag())
def get_payload(self, user_configuration_name, properties):
- payload = create_element(f'm:{self.SERVICE_NAME}')
+ payload = create_element(f"m:{self.SERVICE_NAME}")
set_xml_value(payload, user_configuration_name, version=self.account.version)
payload.append(
- set_xml_value(create_element('m:UserConfigurationProperties'), properties, version=self.account.version)
+ set_xml_value(create_element("m:UserConfigurationProperties"), properties, version=self.account.version)
)
return payload
@@ -4213,10 +4365,12 @@ def call(self, user_configuration_name, properties):
if properties not in PROPERTIES_CHOICES:
- raise InvalidEnumValue('properties', properties, PROPERTIES_CHOICES)
- return self._elems_to_objs(self._get_elements(payload=self.get_payload(
- user_configuration_name=user_configuration_name, properties=properties
- )))
+ raise InvalidEnumValue("properties", properties, PROPERTIES_CHOICES)
+ return self._elems_to_objs(
+ self._get_elements(
+ payload=self.get_payload(user_configuration_name=user_configuration_name, properties=properties)
+ )
+ )
@@ -4229,10 +4383,10 @@ Methods
Expand source code
def get_payload(self, user_configuration_name, properties):
- payload = create_element(f'm:{self.SERVICE_NAME}')
+ payload = create_element(f"m:{self.SERVICE_NAME}")
set_xml_value(payload, user_configuration_name, version=self.account.version)
payload.append(
- set_xml_value(create_element('m:UserConfigurationProperties'), properties, version=self.account.version)
+ set_xml_value(create_element("m:UserConfigurationProperties"), properties, version=self.account.version)
)
return payload
@@ -4266,8 +4420,8 @@ Inherited members
MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/getuseroofsettings-operation
"""
- SERVICE_NAME = 'GetUserOofSettings'
- element_container_name = f'{{{TNS}}}OofSettings'
+ SERVICE_NAME = "GetUserOofSettings"
+ element_container_name = f"{{{TNS}}}OofSettings"
def call(self, mailbox):
return self._elems_to_objs(self._get_elements(payload=self.get_payload(mailbox=mailbox)))
@@ -4277,9 +4431,9 @@ Inherited members
def get_payload(self, mailbox):
return set_xml_value(
- create_element(f'm:{self.SERVICE_NAME}Request'),
+ create_element(f"m:{self.SERVICE_NAME}Request"),
AvailabilityMailbox.from_mailbox(mailbox),
- version=self.account.version
+ version=self.account.version,
)
@classmethod
@@ -4294,7 +4448,7 @@ Inherited members
@classmethod
def _response_message_tag(cls):
- return f'{{{MNS}}}ResponseMessage'
+ return f"{{{MNS}}}ResponseMessage"
def get_payload(self, mailbox):
return set_xml_value(
- create_element(f'm:{self.SERVICE_NAME}Request'),
+ create_element(f"m:{self.SERVICE_NAME}Request"),
AvailabilityMailbox.from_mailbox(mailbox),
- version=self.account.version
+ version=self.account.version,
)
@@ -4370,7 +4524,7 @@ class MarkAsJunk(EWSAccountService):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/markasjunk-operation"""
- SERVICE_NAME = 'MarkAsJunk'
+ SERVICE_NAME = "MarkAsJunk"
def call(self, items, is_junk, move_item):
return self._elems_to_objs(
@@ -4386,7 +4540,7 @@ Inherited members
def get_payload(self, items, is_junk, move_item):
# Takes a list of items and returns either success or raises an error message
- payload = create_element(f'm:{self.SERVICE_NAME}', attrs=dict(IsJunk=is_junk, MoveItem=move_item))
+ payload = create_element(f"m:{self.SERVICE_NAME}", attrs=dict(IsJunk=is_junk, MoveItem=move_item))
payload.append(item_ids_element(items=items, version=self.account.version))
return payload
@@ -4430,7 +4584,7 @@ def get_payload(self, items, is_junk, move_item):
# Takes a list of items and returns either success or raises an error message
- payload = create_element(f'm:{self.SERVICE_NAME}', attrs=dict(IsJunk=is_junk, MoveItem=move_item))
+ payload = create_element(f"m:{self.SERVICE_NAME}", attrs=dict(IsJunk=is_junk, MoveItem=move_item))
payload.append(item_ids_element(items=items, version=self.account.version))
return payload
@@ -4462,11 +4616,11 @@ def call(self, folders, to_folder):
if not isinstance(to_folder, (BaseFolder, FolderId)):
- raise InvalidTypeError('to_folder', to_folder, (BaseFolder, FolderId))
+ raise InvalidTypeError("to_folder", to_folder, (BaseFolder, FolderId))
return self._elems_to_objs(self._chunked_get_elements(self.get_payload, items=folders, to_folder=to_folder))
@@ -4523,8 +4677,8 @@ def get_payload(self, folders, to_folder):
# Takes a list of folders and returns their new folder IDs
- payload = create_element(f'm:{self.SERVICE_NAME}')
- payload.append(folder_ids_element(folders=[to_folder], version=self.account.version, tag='m:ToFolderId'))
+ payload = create_element(f"m:{self.SERVICE_NAME}")
+ payload.append(folder_ids_element(folders=[to_folder], version=self.account.version, tag="m:ToFolderId"))
payload.append(folder_ids_element(folders=folders, version=self.account.version))
return payload
@@ -4555,12 +4709,12 @@ class MoveItem(EWSAccountService):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/moveitem-operation"""
- SERVICE_NAME = 'MoveItem'
- element_container_name = f'{{{MNS}}}Items'
+ SERVICE_NAME = "MoveItem"
+ element_container_name = f"{{{MNS}}}Items"
def call(self, items, to_folder):
if not isinstance(to_folder, (BaseFolder, FolderId)):
- raise InvalidTypeError('to_folder', to_folder, (BaseFolder, FolderId))
+ raise InvalidTypeError("to_folder", to_folder, (BaseFolder, FolderId))
return self._elems_to_objs(self._chunked_get_elements(self.get_payload, items=items, to_folder=to_folder))
def _elem_to_obj(self, elem):
@@ -4568,8 +4722,8 @@ Inherited members
def get_payload(self, items, to_folder):
# Takes a list of items and returns their new item IDs
- payload = create_element(f'm:{self.SERVICE_NAME}')
- payload.append(folder_ids_element(folders=[to_folder], version=self.account.version, tag='m:ToFolderId'))
+ payload = create_element(f"m:{self.SERVICE_NAME}")
+ payload.append(folder_ids_element(folders=[to_folder], version=self.account.version, tag="m:ToFolderId"))
payload.append(item_ids_element(items=items, version=self.account.version))
return payload
@@ -4606,7 +4760,7 @@ def call(self, items, to_folder):
if not isinstance(to_folder, (BaseFolder, FolderId)):
- raise InvalidTypeError('to_folder', to_folder, (BaseFolder, FolderId))
+ raise InvalidTypeError("to_folder", to_folder, (BaseFolder, FolderId))
return self._elems_to_objs(self._chunked_get_elements(self.get_payload, items=items, to_folder=to_folder))
@@ -4621,8 +4775,8 @@ def get_payload(self, items, to_folder):
# Takes a list of items and returns their new item IDs
- payload = create_element(f'm:{self.SERVICE_NAME}')
- payload.append(folder_ids_element(folders=[to_folder], version=self.account.version, tag='m:ToFolderId'))
+ payload = create_element(f"m:{self.SERVICE_NAME}")
+ payload.append(folder_ids_element(folders=[to_folder], version=self.account.version, tag="m:ToFolderId"))
payload.append(item_ids_element(items=items, version=self.account.version))
return payload
@@ -4653,8 +4807,8 @@ class ResolveNames(EWSService):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/resolvenames-operation"""
- SERVICE_NAME = 'ResolveNames'
- element_container_name = f'{{{MNS}}}ResolutionSet'
+ SERVICE_NAME = "ResolveNames"
+ element_container_name = f"{{{MNS}}}ResolutionSet"
ERRORS_TO_CATCH_IN_RESPONSE = ErrorNameResolutionNoResults
WARNINGS_TO_IGNORE_IN_RESPONSE = ErrorNameResolutionMultipleResults
# Note: paging information is returned as attrs on the 'ResolutionSet' element, but this service does not
@@ -4666,26 +4820,34 @@ Inherited members
super().__init__(*args, **kwargs)
self.return_full_contact_data = False # A hack to communicate parsing args to _elems_to_objs()
- def call(self, unresolved_entries, parent_folders=None, return_full_contact_data=False, search_scope=None,
- contact_data_shape=None):
+ def call(
+ self,
+ unresolved_entries,
+ parent_folders=None,
+ return_full_contact_data=False,
+ search_scope=None,
+ contact_data_shape=None,
+ ):
if self.chunk_size > 100:
raise ValueError(
- f'Chunk size {self.chunk_size} is too high. {self.SERVICE_NAME} supports returning at most 100 '
- f'candidates for a lookup',
+ f"Chunk size {self.chunk_size} is too high. {self.SERVICE_NAME} supports returning at most 100 "
+ f"candidates for a lookup",
)
if search_scope and search_scope not in SEARCH_SCOPE_CHOICES:
- raise InvalidEnumValue('search_scope', search_scope, SEARCH_SCOPE_CHOICES)
+ raise InvalidEnumValue("search_scope", search_scope, SEARCH_SCOPE_CHOICES)
if contact_data_shape and contact_data_shape not in SHAPE_CHOICES:
- raise InvalidEnumValue('contact_data_shape', contact_data_shape, SHAPE_CHOICES)
+ raise InvalidEnumValue("contact_data_shape", contact_data_shape, SHAPE_CHOICES)
self.return_full_contact_data = return_full_contact_data
- return self._elems_to_objs(self._chunked_get_elements(
- self.get_payload,
- items=unresolved_entries,
- parent_folders=parent_folders,
- return_full_contact_data=return_full_contact_data,
- search_scope=search_scope,
- contact_data_shape=contact_data_shape,
- ))
+ return self._elems_to_objs(
+ self._chunked_get_elements(
+ self.get_payload,
+ items=unresolved_entries,
+ parent_folders=parent_folders,
+ return_full_contact_data=return_full_contact_data,
+ search_scope=search_scope,
+ contact_data_shape=contact_data_shape,
+ )
+ )
def _elem_to_obj(self, elem):
if self.return_full_contact_data:
@@ -4697,23 +4859,25 @@ Inherited members
)
return Mailbox.from_xml(elem=elem.find(Mailbox.response_tag()), account=None)
- def get_payload(self, unresolved_entries, parent_folders, return_full_contact_data, search_scope,
- contact_data_shape):
+ def get_payload(
+ self, unresolved_entries, parent_folders, return_full_contact_data, search_scope, contact_data_shape
+ ):
attrs = dict(ReturnFullContactData=return_full_contact_data)
if search_scope:
- attrs['SearchScope'] = search_scope
+ attrs["SearchScope"] = search_scope
if contact_data_shape:
if self.protocol.version.build < EXCHANGE_2010_SP2:
raise NotImplementedError(
- "'contact_data_shape' is only supported for Exchange 2010 SP2 servers and later")
- attrs['ContactDataShape'] = contact_data_shape
- payload = create_element(f'm:{self.SERVICE_NAME}', attrs=attrs)
+ "'contact_data_shape' is only supported for Exchange 2010 SP2 servers and later"
+ )
+ attrs["ContactDataShape"] = contact_data_shape
+ payload = create_element(f"m:{self.SERVICE_NAME}", attrs=attrs)
if parent_folders:
- payload.append(folder_ids_element(
- folders=parent_folders, version=self.protocol.version, tag='m:ParentFolderIds'
- ))
+ payload.append(
+ folder_ids_element(folders=parent_folders, version=self.protocol.version, tag="m:ParentFolderIds")
+ )
for entry in unresolved_entries:
- add_xml_child(payload, 'm:UnresolvedEntry', entry)
+ add_xml_child(payload, "m:UnresolvedEntry", entry)
return payload
def call(self, unresolved_entries, parent_folders=None, return_full_contact_data=False, search_scope=None,
- contact_data_shape=None):
+def call(
+ self,
+ unresolved_entries,
+ parent_folders=None,
+ return_full_contact_data=False,
+ search_scope=None,
+ contact_data_shape=None,
+):
if self.chunk_size > 100:
raise ValueError(
- f'Chunk size {self.chunk_size} is too high. {self.SERVICE_NAME} supports returning at most 100 '
- f'candidates for a lookup',
+ f"Chunk size {self.chunk_size} is too high. {self.SERVICE_NAME} supports returning at most 100 "
+ f"candidates for a lookup",
)
if search_scope and search_scope not in SEARCH_SCOPE_CHOICES:
- raise InvalidEnumValue('search_scope', search_scope, SEARCH_SCOPE_CHOICES)
+ raise InvalidEnumValue("search_scope", search_scope, SEARCH_SCOPE_CHOICES)
if contact_data_shape and contact_data_shape not in SHAPE_CHOICES:
- raise InvalidEnumValue('contact_data_shape', contact_data_shape, SHAPE_CHOICES)
+ raise InvalidEnumValue("contact_data_shape", contact_data_shape, SHAPE_CHOICES)
self.return_full_contact_data = return_full_contact_data
- return self._elems_to_objs(self._chunked_get_elements(
- self.get_payload,
- items=unresolved_entries,
- parent_folders=parent_folders,
- return_full_contact_data=return_full_contact_data,
- search_scope=search_scope,
- contact_data_shape=contact_data_shape,
- ))
+ return self._elems_to_objs(
+ self._chunked_get_elements(
+ self.get_payload,
+ items=unresolved_entries,
+ parent_folders=parent_folders,
+ return_full_contact_data=return_full_contact_data,
+ search_scope=search_scope,
+ contact_data_shape=contact_data_shape,
+ )
+ )
@@ -4785,23 +4957,25 @@ Methods
Expand source code
-def get_payload(self, unresolved_entries, parent_folders, return_full_contact_data, search_scope,
- contact_data_shape):
+def get_payload(
+ self, unresolved_entries, parent_folders, return_full_contact_data, search_scope, contact_data_shape
+):
attrs = dict(ReturnFullContactData=return_full_contact_data)
if search_scope:
- attrs['SearchScope'] = search_scope
+ attrs["SearchScope"] = search_scope
if contact_data_shape:
if self.protocol.version.build < EXCHANGE_2010_SP2:
raise NotImplementedError(
- "'contact_data_shape' is only supported for Exchange 2010 SP2 servers and later")
- attrs['ContactDataShape'] = contact_data_shape
- payload = create_element(f'm:{self.SERVICE_NAME}', attrs=attrs)
+ "'contact_data_shape' is only supported for Exchange 2010 SP2 servers and later"
+ )
+ attrs["ContactDataShape"] = contact_data_shape
+ payload = create_element(f"m:{self.SERVICE_NAME}", attrs=attrs)
if parent_folders:
- payload.append(folder_ids_element(
- folders=parent_folders, version=self.protocol.version, tag='m:ParentFolderIds'
- ))
+ payload.append(
+ folder_ids_element(folders=parent_folders, version=self.protocol.version, tag="m:ParentFolderIds")
+ )
for entry in unresolved_entries:
- add_xml_child(payload, 'm:UnresolvedEntry', entry)
+ add_xml_child(payload, "m:UnresolvedEntry", entry)
return payload
@@ -4831,21 +5005,21 @@ Inherited members
class SendItem(EWSAccountService):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/senditem-operation"""
- SERVICE_NAME = 'SendItem'
+ SERVICE_NAME = "SendItem"
returns_elements = False
def call(self, items, saved_item_folder):
if saved_item_folder and not isinstance(saved_item_folder, (BaseFolder, FolderId)):
- raise InvalidTypeError('saved_item_folder', saved_item_folder, (BaseFolder, FolderId))
+ raise InvalidTypeError("saved_item_folder", saved_item_folder, (BaseFolder, FolderId))
return self._chunked_get_elements(self.get_payload, items=items, saved_item_folder=saved_item_folder)
def get_payload(self, items, saved_item_folder):
- payload = create_element(f'm:{self.SERVICE_NAME}', attrs=dict(SaveItemToFolder=bool(saved_item_folder)))
+ payload = create_element(f"m:{self.SERVICE_NAME}", attrs=dict(SaveItemToFolder=bool(saved_item_folder)))
payload.append(item_ids_element(items=items, version=self.account.version))
if saved_item_folder:
- payload.append(folder_ids_element(
- folders=[saved_item_folder], version=self.account.version, tag='m:SavedItemFolderId'
- ))
+ payload.append(
+ folder_ids_element(folders=[saved_item_folder], version=self.account.version, tag="m:SavedItemFolderId")
+ )
return payload
Ancestors
@@ -4877,7 +5051,7 @@ Methods
def call(self, items, saved_item_folder):
if saved_item_folder and not isinstance(saved_item_folder, (BaseFolder, FolderId)):
- raise InvalidTypeError('saved_item_folder', saved_item_folder, (BaseFolder, FolderId))
+ raise InvalidTypeError("saved_item_folder", saved_item_folder, (BaseFolder, FolderId))
return self._chunked_get_elements(self.get_payload, items=items, saved_item_folder=saved_item_folder)
@@ -4891,12 +5065,12 @@ Methods
Expand source code
def get_payload(self, items, saved_item_folder):
- payload = create_element(f'm:{self.SERVICE_NAME}', attrs=dict(SaveItemToFolder=bool(saved_item_folder)))
+ payload = create_element(f"m:{self.SERVICE_NAME}", attrs=dict(SaveItemToFolder=bool(saved_item_folder)))
payload.append(item_ids_element(items=items, version=self.account.version))
if saved_item_folder:
- payload.append(folder_ids_element(
- folders=[saved_item_folder], version=self.account.version, tag='m:SavedItemFolderId'
- ))
+ payload.append(
+ folder_ids_element(folders=[saved_item_folder], version=self.account.version, tag="m:SavedItemFolderId")
+ )
return payload
@@ -4934,9 +5108,9 @@ Inherited members
push notifications.
"""
- SERVICE_NAME = 'SendNotification'
- OK = 'OK'
- UNSUBSCRIBE = 'Unsubscribe'
+ SERVICE_NAME = "SendNotification"
+ OK = "OK"
+ UNSUBSCRIBE = "Unsubscribe"
STATUS_CHOICES = (OK, UNSUBSCRIBE)
def ok_payload(self):
@@ -4951,7 +5125,7 @@ Inherited members
@classmethod
def _response_tag(cls):
"""Return the name of the element containing the service response."""
- return f'{{{MNS}}}{cls.SERVICE_NAME}'
+ return f"{{{MNS}}}{cls.SERVICE_NAME}"
@classmethod
def _get_elements_in_container(cls, container):
@@ -4959,9 +5133,9 @@ Inherited members
def get_payload(self, status):
if status not in self.STATUS_CHOICES:
- raise InvalidEnumValue('status', status, self.STATUS_CHOICES)
- payload = create_element(f'm:{self.SERVICE_NAME}Result')
- add_xml_child(payload, 'm:SubscriptionStatus', status)
+ raise InvalidEnumValue("status", status, self.STATUS_CHOICES)
+ payload = create_element(f"m:{self.SERVICE_NAME}Result")
+ add_xml_child(payload, "m:SubscriptionStatus", status)
return payload
Ancestors
@@ -5000,9 +5174,9 @@ Methods
def get_payload(self, status):
if status not in self.STATUS_CHOICES:
- raise InvalidEnumValue('status', status, self.STATUS_CHOICES)
- payload = create_element(f'm:{self.SERVICE_NAME}Result')
- add_xml_child(payload, 'm:SubscriptionStatus', status)
+ raise InvalidEnumValue("status", status, self.STATUS_CHOICES)
+ payload = create_element(f"m:{self.SERVICE_NAME}Result")
+ add_xml_child(payload, "m:SubscriptionStatus", status)
return payload
@@ -5061,18 +5235,18 @@ Inherited members
MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/setuseroofsettings-operation
"""
- SERVICE_NAME = 'SetUserOofSettings'
+ SERVICE_NAME = "SetUserOofSettings"
returns_elements = False
def call(self, oof_settings, mailbox):
if not isinstance(oof_settings, OofSettings):
- raise InvalidTypeError('oof_settings', oof_settings, OofSettings)
+ raise InvalidTypeError("oof_settings", oof_settings, OofSettings)
if not isinstance(mailbox, Mailbox):
- raise InvalidTypeError('mailbox', mailbox, Mailbox)
+ raise InvalidTypeError("mailbox", mailbox, Mailbox)
return self._get_elements(payload=self.get_payload(oof_settings=oof_settings, mailbox=mailbox))
def get_payload(self, oof_settings, mailbox):
- payload = create_element(f'm:{self.SERVICE_NAME}Request')
+ payload = create_element(f"m:{self.SERVICE_NAME}Request")
set_xml_value(payload, AvailabilityMailbox.from_mailbox(mailbox), version=self.account.version)
return set_xml_value(payload, oof_settings, version=self.account.version)
@@ -5082,7 +5256,7 @@ Inherited members
@classmethod
def _response_message_tag(cls):
- return f'{{{MNS}}}ResponseMessage'
+ return f"{{{MNS}}}ResponseMessage"
def call(self, oof_settings, mailbox):
if not isinstance(oof_settings, OofSettings):
- raise InvalidTypeError('oof_settings', oof_settings, OofSettings)
+ raise InvalidTypeError("oof_settings", oof_settings, OofSettings)
if not isinstance(mailbox, Mailbox):
- raise InvalidTypeError('mailbox', mailbox, Mailbox)
+ raise InvalidTypeError("mailbox", mailbox, Mailbox)
return self._get_elements(payload=self.get_payload(oof_settings=oof_settings, mailbox=mailbox))
@@ -5129,7 +5303,7 @@ def get_payload(self, oof_settings, mailbox):
- payload = create_element(f'm:{self.SERVICE_NAME}Request')
+ payload = create_element(f"m:{self.SERVICE_NAME}Request")
set_xml_value(payload, AvailabilityMailbox.from_mailbox(mailbox), version=self.account.version)
return set_xml_value(payload, oof_settings, version=self.account.version)
@@ -5158,21 +5332,24 @@ class SubscribeToPull(Subscribe):
- subscription_request_elem_tag = 'm:PullSubscriptionRequest'
+ subscription_request_elem_tag = "m:PullSubscriptionRequest"
prefer_affinity = True
def call(self, folders, event_types, watermark, timeout):
yield from self._partial_call(
- payload_func=self.get_payload, folders=folders, event_types=event_types, timeout=timeout,
+ payload_func=self.get_payload,
+ folders=folders,
+ event_types=event_types,
+ timeout=timeout,
watermark=watermark,
)
def get_payload(self, folders, event_types, watermark, timeout):
- payload = create_element(f'm:{self.SERVICE_NAME}')
+ payload = create_element(f"m:{self.SERVICE_NAME}")
request_elem = self._partial_payload(folders=folders, event_types=event_types)
if watermark:
- add_xml_child(request_elem, 'm:Watermark', watermark)
- add_xml_child(request_elem, 't:Timeout', timeout) # In minutes
+ add_xml_child(request_elem, "m:Watermark", watermark)
+ add_xml_child(request_elem, "t:Timeout", timeout) # In minutes
payload.append(request_elem)
return payload
@@ -5206,7 +5383,10 @@ def call(self, folders, event_types, watermark, timeout):
yield from self._partial_call(
- payload_func=self.get_payload, folders=folders, event_types=event_types, timeout=timeout,
+ payload_func=self.get_payload,
+ folders=folders,
+ event_types=event_types,
+ timeout=timeout,
watermark=watermark,
)
@@ -5221,11 +5401,11 @@ def get_payload(self, folders, event_types, watermark, timeout):
- payload = create_element(f'm:{self.SERVICE_NAME}')
+ payload = create_element(f"m:{self.SERVICE_NAME}")
request_elem = self._partial_payload(folders=folders, event_types=event_types)
if watermark:
- add_xml_child(request_elem, 'm:Watermark', watermark)
- add_xml_child(request_elem, 't:Timeout', timeout) # In minutes
+ add_xml_child(request_elem, "m:Watermark", watermark)
+ add_xml_child(request_elem, "t:Timeout", timeout) # In minutes
payload.append(request_elem)
return payload
@@ -5254,21 +5434,25 @@ class SubscribeToPush(Subscribe):
- subscription_request_elem_tag = 'm:PushSubscriptionRequest'
+ subscription_request_elem_tag = "m:PushSubscriptionRequest"
def call(self, folders, event_types, watermark, status_frequency, url):
yield from self._partial_call(
- payload_func=self.get_payload, folders=folders, event_types=event_types,
- status_frequency=status_frequency, url=url, watermark=watermark,
+ payload_func=self.get_payload,
+ folders=folders,
+ event_types=event_types,
+ status_frequency=status_frequency,
+ url=url,
+ watermark=watermark,
)
def get_payload(self, folders, event_types, watermark, status_frequency, url):
- payload = create_element(f'm:{self.SERVICE_NAME}')
+ payload = create_element(f"m:{self.SERVICE_NAME}")
request_elem = self._partial_payload(folders=folders, event_types=event_types)
if watermark:
- add_xml_child(request_elem, 'm:Watermark', watermark)
- add_xml_child(request_elem, 't:StatusFrequency', status_frequency) # In minutes
- add_xml_child(request_elem, 't:URL', url)
+ add_xml_child(request_elem, "m:Watermark", watermark)
+ add_xml_child(request_elem, "t:StatusFrequency", status_frequency) # In minutes
+ add_xml_child(request_elem, "t:URL", url)
payload.append(request_elem)
return payload
@@ -5298,8 +5482,12 @@ def call(self, folders, event_types, watermark, status_frequency, url):
yield from self._partial_call(
- payload_func=self.get_payload, folders=folders, event_types=event_types,
- status_frequency=status_frequency, url=url, watermark=watermark,
+ payload_func=self.get_payload,
+ folders=folders,
+ event_types=event_types,
+ status_frequency=status_frequency,
+ url=url,
+ watermark=watermark,
)
@@ -5313,12 +5501,12 @@ def get_payload(self, folders, event_types, watermark, status_frequency, url):
- payload = create_element(f'm:{self.SERVICE_NAME}')
+ payload = create_element(f"m:{self.SERVICE_NAME}")
request_elem = self._partial_payload(folders=folders, event_types=event_types)
if watermark:
- add_xml_child(request_elem, 'm:Watermark', watermark)
- add_xml_child(request_elem, 't:StatusFrequency', status_frequency) # In minutes
- add_xml_child(request_elem, 't:URL', url)
+ add_xml_child(request_elem, "m:Watermark", watermark)
+ add_xml_child(request_elem, "t:StatusFrequency", status_frequency) # In minutes
+ add_xml_child(request_elem, "t:URL", url)
payload.append(request_elem)
return payload
@@ -5347,7 +5535,7 @@ class SubscribeToStreaming(Subscribe):
- subscription_request_elem_tag = 'm:StreamingSubscriptionRequest'
+ subscription_request_elem_tag = "m:StreamingSubscriptionRequest"
prefer_affinity = True
def call(self, folders, event_types):
@@ -5358,10 +5546,10 @@ Inherited members
@classmethod
def _get_elements_in_container(cls, container):
- return [container.find(f'{{{MNS}}}SubscriptionId')]
+ return [container.find(f"{{{MNS}}}SubscriptionId")]
def get_payload(self, folders, event_types):
- payload = create_element(f'm:{self.SERVICE_NAME}')
+ payload = create_element(f"m:{self.SERVICE_NAME}")
payload.append(self._partial_payload(folders=folders, event_types=event_types))
return payload
@@ -5407,7 +5595,7 @@ def get_payload(self, folders, event_types):
- payload = create_element(f'm:{self.SERVICE_NAME}')
+ payload = create_element(f"m:{self.SERVICE_NAME}")
payload.append(self._partial_payload(folders=folders, event_types=event_types))
return payload
@@ -5441,9 +5629,9 @@ def call(self, folder, shape, additional_fields, sync_state):
self.sync_state = sync_state
self.folder = folder
- return self._elems_to_objs(self._get_elements(payload=self.get_payload(
- folder=folder,
- shape=shape,
- additional_fields=additional_fields,
- sync_state=sync_state,
- )))
+ return self._elems_to_objs(
+ self._get_elements(
+ payload=self.get_payload(
+ folder=folder,
+ shape=shape,
+ additional_fields=additional_fields,
+ sync_state=sync_state,
+ )
+ )
+ )
@@ -5563,45 +5759,49 @@ Inherited members
https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/syncfolderitems-operation
"""
- SERVICE_NAME = 'SyncFolderItems'
+ SERVICE_NAME = "SyncFolderItems"
SYNC_SCOPES = (
- 'NormalItems',
- 'NormalAndAssociatedItems',
+ "NormalItems",
+ "NormalAndAssociatedItems",
)
# Extra change type
- READ_FLAG_CHANGE = 'read_flag_change'
+ READ_FLAG_CHANGE = "read_flag_change"
CHANGE_TYPES = SyncFolder.CHANGE_TYPES + (READ_FLAG_CHANGE,)
- shape_tag = 'm:ItemShape'
- last_in_range_name = f'{{{MNS}}}IncludesLastItemInRange'
+ shape_tag = "m:ItemShape"
+ last_in_range_name = f"{{{MNS}}}IncludesLastItemInRange"
change_types_map = SyncFolder.change_types_map
- change_types_map[f'{{{TNS}}}ReadFlagChange'] = READ_FLAG_CHANGE
+ change_types_map[f"{{{TNS}}}ReadFlagChange"] = READ_FLAG_CHANGE
def call(self, folder, shape, additional_fields, sync_state, ignore, max_changes_returned, sync_scope):
self.sync_state = sync_state
if max_changes_returned is None:
max_changes_returned = self.page_size
if not isinstance(max_changes_returned, int):
- raise InvalidTypeError('max_changes_returned', max_changes_returned, int)
+ raise InvalidTypeError("max_changes_returned", max_changes_returned, int)
if max_changes_returned <= 0:
raise ValueError(f"'max_changes_returned' {max_changes_returned} must be a positive integer")
if sync_scope is not None and sync_scope not in self.SYNC_SCOPES:
- raise InvalidEnumValue('sync_scope', sync_scope, self.SYNC_SCOPES)
- return self._elems_to_objs(self._get_elements(payload=self.get_payload(
- folder=folder,
- shape=shape,
- additional_fields=additional_fields,
- sync_state=sync_state,
- ignore=ignore,
- max_changes_returned=max_changes_returned,
- sync_scope=sync_scope,
- )))
+ raise InvalidEnumValue("sync_scope", sync_scope, self.SYNC_SCOPES)
+ return self._elems_to_objs(
+ self._get_elements(
+ payload=self.get_payload(
+ folder=folder,
+ shape=shape,
+ additional_fields=additional_fields,
+ sync_state=sync_state,
+ ignore=ignore,
+ max_changes_returned=max_changes_returned,
+ sync_scope=sync_scope,
+ )
+ )
+ )
def _elem_to_obj(self, elem):
change_type = self.change_types_map[elem.tag]
if change_type == self.READ_FLAG_CHANGE:
item = (
ItemId.from_xml(elem=elem.find(ItemId.response_tag()), account=self.account),
- xml_text_to_value(elem.find(f'{{{TNS}}}IsRead').text, bool)
+ xml_text_to_value(elem.find(f"{{{TNS}}}IsRead").text, bool),
)
elif change_type == self.DELETE:
item = ItemId.from_xml(elem=elem.find(ItemId.response_tag()), account=self.account)
@@ -5618,10 +5818,10 @@ Inherited members
)
is_empty, ignore = (True, None) if ignore is None else peek(ignore)
if not is_empty:
- sync_folder_items.append(item_ids_element(items=ignore, version=self.account.version, tag='m:Ignore'))
- add_xml_child(sync_folder_items, 'm:MaxChangesReturned', max_changes_returned)
+ sync_folder_items.append(item_ids_element(items=ignore, version=self.account.version, tag="m:Ignore"))
+ add_xml_child(sync_folder_items, "m:MaxChangesReturned", max_changes_returned)
if sync_scope:
- add_xml_child(sync_folder_items, 'm:SyncScope', sync_scope)
+ add_xml_child(sync_folder_items, "m:SyncScope", sync_scope)
return sync_folder_items
@@ -5709,10 +5913,10 @@ Methods
)
is_empty, ignore = (True, None) if ignore is None else peek(ignore)
if not is_empty:
- sync_folder_items.append(item_ids_element(items=ignore, version=self.account.version, tag='m:Ignore'))
- add_xml_child(sync_folder_items, 'm:MaxChangesReturned', max_changes_returned)
+ sync_folder_items.append(item_ids_element(items=ignore, version=self.account.version, tag="m:Ignore"))
+ add_xml_child(sync_folder_items, "m:MaxChangesReturned", max_changes_returned)
if sync_scope:
- add_xml_child(sync_folder_items, 'm:SyncScope', sync_scope)
+ add_xml_child(sync_folder_items, "m:SyncScope", sync_scope)
return sync_folder_items
@@ -5746,7 +5950,7 @@ def get_payload(self, subscription_id):
- payload = create_element(f'm:{self.SERVICE_NAME}')
- add_xml_child(payload, 'm:SubscriptionId', subscription_id)
+ payload = create_element(f"m:{self.SERVICE_NAME}")
+ add_xml_child(payload, "m:SubscriptionId", subscription_id)
return payload
@@ -5834,12 +6038,12 @@ class UpdateFolder(BaseUpdateService):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/updatefolder-operation"""
- SERVICE_NAME = 'UpdateFolder'
- SET_FIELD_ELEMENT_NAME = 't:SetFolderField'
- DELETE_FIELD_ELEMENT_NAME = 't:DeleteFolderField'
- CHANGE_ELEMENT_NAME = 't:FolderChange'
- CHANGES_ELEMENT_NAME = 'm:FolderChanges'
- element_container_name = f'{{{MNS}}}Folders'
+ SERVICE_NAME = "UpdateFolder"
+ SET_FIELD_ELEMENT_NAME = "t:SetFolderField"
+ DELETE_FIELD_ELEMENT_NAME = "t:DeleteFolderField"
+ CHANGE_ELEMENT_NAME = "t:FolderChange"
+ CHANGES_ELEMENT_NAME = "m:FolderChanges"
+ element_container_name = f"{{{MNS}}}Folders"
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
@@ -5864,7 +6068,7 @@ Inherited members
def get_payload(self, folders):
# Takes a list of (Folder, fieldnames) tuples where 'Folder' is a instance of a subclass of Folder and
# 'fieldnames' are the attribute names that were updated.
- payload = create_element(f'm:{self.SERVICE_NAME}')
+ payload = create_element(f"m:{self.SERVICE_NAME}")
payload.append(self._changes_elem(target_changes=folders))
return payload
@@ -5931,7 +6135,7 @@ def get_payload(self, folders):
# Takes a list of (Folder, fieldnames) tuples where 'Folder' is a instance of a subclass of Folder and
# 'fieldnames' are the attribute names that were updated.
- payload = create_element(f'm:{self.SERVICE_NAME}')
+ payload = create_element(f"m:{self.SERVICE_NAME}")
payload.append(self._changes_elem(target_changes=folders))
return payload
@@ -5962,34 +6166,43 @@ class UpdateItem(BaseUpdateService):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/updateitem-operation"""
- SERVICE_NAME = 'UpdateItem'
- SET_FIELD_ELEMENT_NAME = 't:SetItemField'
- DELETE_FIELD_ELEMENT_NAME = 't:DeleteItemField'
- CHANGE_ELEMENT_NAME = 't:ItemChange'
- CHANGES_ELEMENT_NAME = 'm:ItemChanges'
- element_container_name = f'{{{MNS}}}Items'
-
- def call(self, items, conflict_resolution, message_disposition, send_meeting_invitations_or_cancellations,
- suppress_read_receipts):
+ SERVICE_NAME = "UpdateItem"
+ SET_FIELD_ELEMENT_NAME = "t:SetItemField"
+ DELETE_FIELD_ELEMENT_NAME = "t:DeleteItemField"
+ CHANGE_ELEMENT_NAME = "t:ItemChange"
+ CHANGES_ELEMENT_NAME = "m:ItemChanges"
+ element_container_name = f"{{{MNS}}}Items"
+
+ def call(
+ self,
+ items,
+ conflict_resolution,
+ message_disposition,
+ send_meeting_invitations_or_cancellations,
+ suppress_read_receipts,
+ ):
if conflict_resolution not in CONFLICT_RESOLUTION_CHOICES:
- raise InvalidEnumValue('conflict_resolution', conflict_resolution, CONFLICT_RESOLUTION_CHOICES)
+ raise InvalidEnumValue("conflict_resolution", conflict_resolution, CONFLICT_RESOLUTION_CHOICES)
if message_disposition not in MESSAGE_DISPOSITION_CHOICES:
- raise InvalidEnumValue('message_disposition', message_disposition, MESSAGE_DISPOSITION_CHOICES)
+ raise InvalidEnumValue("message_disposition", message_disposition, MESSAGE_DISPOSITION_CHOICES)
if send_meeting_invitations_or_cancellations not in SEND_MEETING_INVITATIONS_AND_CANCELLATIONS_CHOICES:
raise InvalidEnumValue(
- 'send_meeting_invitations_or_cancellations', send_meeting_invitations_or_cancellations,
- SEND_MEETING_INVITATIONS_AND_CANCELLATIONS_CHOICES
+ "send_meeting_invitations_or_cancellations",
+ send_meeting_invitations_or_cancellations,
+ SEND_MEETING_INVITATIONS_AND_CANCELLATIONS_CHOICES,
)
if message_disposition == SEND_ONLY:
- raise ValueError('Cannot send-only existing objects. Use SendItem service instead')
- return self._elems_to_objs(self._chunked_get_elements(
- self.get_payload,
- items=items,
- conflict_resolution=conflict_resolution,
- message_disposition=message_disposition,
- send_meeting_invitations_or_cancellations=send_meeting_invitations_or_cancellations,
- suppress_read_receipts=suppress_read_receipts,
- ))
+ raise ValueError("Cannot send-only existing objects. Use SendItem service instead")
+ return self._elems_to_objs(
+ self._chunked_get_elements(
+ self.get_payload,
+ items=items,
+ conflict_resolution=conflict_resolution,
+ message_disposition=message_disposition,
+ send_meeting_invitations_or_cancellations=send_meeting_invitations_or_cancellations,
+ suppress_read_receipts=suppress_read_receipts,
+ )
+ )
def _elem_to_obj(self, elem):
return Item.id_from_xml(elem)
@@ -6000,7 +6213,7 @@ Inherited members
if target.__class__ == CalendarItem:
# For CalendarItem items where we update 'start' or 'end', we want to update internal timezone fields
target.clean_timezone_fields(version=self.account.version) # Possibly also sets timezone values
- for field_name in ('start', 'end'):
+ for field_name in ("start", "end"):
if field_name in fieldnames_copy:
tz_field_name = target.tz_field_for_field_name(field_name).name
if tz_field_name not in fieldnames_copy:
@@ -6013,7 +6226,7 @@ Inherited members
if target.__class__ == CalendarItem:
# For CalendarItem items where we update 'start' or 'end', we want to send values in the local timezone
- if field.name in ('start', 'end'):
+ if field.name in ("start", "end"):
if type(value) is EWSDate:
# EWS always expects a datetime
return target.date_to_datetime(field_name=field.name)
@@ -6025,8 +6238,14 @@ Inherited members
def _target_elem(self, target):
return to_item_id(target, ItemId)
- def get_payload(self, items, conflict_resolution, message_disposition, send_meeting_invitations_or_cancellations,
- suppress_read_receipts):
+ def get_payload(
+ self,
+ items,
+ conflict_resolution,
+ message_disposition,
+ send_meeting_invitations_or_cancellations,
+ suppress_read_receipts,
+ ):
# Takes a list of (Item, fieldnames) tuples where 'Item' is a instance of a subclass of Item and 'fieldnames'
# are the attribute names that were updated.
attrs = dict(
@@ -6035,8 +6254,8 @@ Inherited members
SendMeetingInvitationsOrCancellations=send_meeting_invitations_or_cancellations,
)
if self.account.version.build >= EXCHANGE_2013_SP1:
- attrs['SuppressReadReceipts'] = suppress_read_receipts
- payload = create_element(f'm:{self.SERVICE_NAME}', attrs=attrs)
+ attrs["SuppressReadReceipts"] = suppress_read_receipts
+ payload = create_element(f"m:{self.SERVICE_NAME}", attrs=attrs)
payload.append(self._changes_elem(target_changes=items))
return payload
@@ -6084,27 +6303,36 @@ def call(self, items, conflict_resolution, message_disposition, send_meeting_invitations_or_cancellations,
- suppress_read_receipts):
+def call(
+ self,
+ items,
+ conflict_resolution,
+ message_disposition,
+ send_meeting_invitations_or_cancellations,
+ suppress_read_receipts,
+):
if conflict_resolution not in CONFLICT_RESOLUTION_CHOICES:
- raise InvalidEnumValue('conflict_resolution', conflict_resolution, CONFLICT_RESOLUTION_CHOICES)
+ raise InvalidEnumValue("conflict_resolution", conflict_resolution, CONFLICT_RESOLUTION_CHOICES)
if message_disposition not in MESSAGE_DISPOSITION_CHOICES:
- raise InvalidEnumValue('message_disposition', message_disposition, MESSAGE_DISPOSITION_CHOICES)
+ raise InvalidEnumValue("message_disposition", message_disposition, MESSAGE_DISPOSITION_CHOICES)
if send_meeting_invitations_or_cancellations not in SEND_MEETING_INVITATIONS_AND_CANCELLATIONS_CHOICES:
raise InvalidEnumValue(
- 'send_meeting_invitations_or_cancellations', send_meeting_invitations_or_cancellations,
- SEND_MEETING_INVITATIONS_AND_CANCELLATIONS_CHOICES
+ "send_meeting_invitations_or_cancellations",
+ send_meeting_invitations_or_cancellations,
+ SEND_MEETING_INVITATIONS_AND_CANCELLATIONS_CHOICES,
)
if message_disposition == SEND_ONLY:
- raise ValueError('Cannot send-only existing objects. Use SendItem service instead')
- return self._elems_to_objs(self._chunked_get_elements(
- self.get_payload,
- items=items,
- conflict_resolution=conflict_resolution,
- message_disposition=message_disposition,
- send_meeting_invitations_or_cancellations=send_meeting_invitations_or_cancellations,
- suppress_read_receipts=suppress_read_receipts,
- ))
+ raise ValueError("Cannot send-only existing objects. Use SendItem service instead")
+ return self._elems_to_objs(
+ self._chunked_get_elements(
+ self.get_payload,
+ items=items,
+ conflict_resolution=conflict_resolution,
+ message_disposition=message_disposition,
+ send_meeting_invitations_or_cancellations=send_meeting_invitations_or_cancellations,
+ suppress_read_receipts=suppress_read_receipts,
+ )
+ )
@@ -6116,8 +6344,14 @@ Methods
Expand source code
-def get_payload(self, items, conflict_resolution, message_disposition, send_meeting_invitations_or_cancellations,
- suppress_read_receipts):
+def get_payload(
+ self,
+ items,
+ conflict_resolution,
+ message_disposition,
+ send_meeting_invitations_or_cancellations,
+ suppress_read_receipts,
+):
# Takes a list of (Item, fieldnames) tuples where 'Item' is a instance of a subclass of Item and 'fieldnames'
# are the attribute names that were updated.
attrs = dict(
@@ -6126,8 +6360,8 @@ Methods
SendMeetingInvitationsOrCancellations=send_meeting_invitations_or_cancellations,
)
if self.account.version.build >= EXCHANGE_2013_SP1:
- attrs['SuppressReadReceipts'] = suppress_read_receipts
- payload = create_element(f'm:{self.SERVICE_NAME}', attrs=attrs)
+ attrs["SuppressReadReceipts"] = suppress_read_receipts
+ payload = create_element(f"m:{self.SERVICE_NAME}", attrs=attrs)
payload.append(self._changes_elem(target_changes=items))
return payload
@@ -6161,14 +6395,14 @@ Inherited members
https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/updateuserconfiguration-operation
"""
- SERVICE_NAME = 'UpdateUserConfiguration'
+ SERVICE_NAME = "UpdateUserConfiguration"
returns_elements = False
def call(self, user_configuration):
return self._get_elements(payload=self.get_payload(user_configuration=user_configuration))
def get_payload(self, user_configuration):
- return set_xml_value(create_element(f'm:{self.SERVICE_NAME}'), user_configuration, version=self.account.version)
+ return set_xml_value(create_element(f"m:{self.SERVICE_NAME}"), user_configuration, version=self.account.version)
def get_payload(self, user_configuration):
- return set_xml_value(create_element(f'm:{self.SERVICE_NAME}'), user_configuration, version=self.account.version)
+ return set_xml_value(create_element(f"m:{self.SERVICE_NAME}"), user_configuration, version=self.account.version)
@@ -6238,11 +6472,10 @@ class UploadItems(EWSAccountService):
- """MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/uploaditems-operation
- """
+ """MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/uploaditems-operation"""
- SERVICE_NAME = 'UploadItems'
- element_container_name = f'{{{MNS}}}ItemId'
+ SERVICE_NAME = "UploadItems"
+ element_container_name = f"{{{MNS}}}ItemId"
def call(self, items):
# _pool_requests expects 'items', not 'data'
@@ -6258,19 +6491,19 @@ Inherited members
:param items:
"""
- payload = create_element(f'm:{self.SERVICE_NAME}')
- items_elem = create_element('m:Items')
+ payload = create_element(f"m:{self.SERVICE_NAME}")
+ items_elem = create_element("m:Items")
payload.append(items_elem)
for parent_folder, (item_id, is_associated, data_str) in items:
# TODO: The full spec also allows the "UpdateOrCreate" create action.
- attrs = dict(CreateAction='Update' if item_id else 'CreateNew')
+ attrs = dict(CreateAction="Update" if item_id else "CreateNew")
if is_associated is not None:
- attrs['IsAssociated'] = is_associated
- item = create_element('t:Item', attrs=attrs)
+ attrs["IsAssociated"] = is_associated
+ item = create_element("t:Item", attrs=attrs)
set_xml_value(item, ParentFolderId(parent_folder.id, parent_folder.changekey), version=self.account.version)
if item_id:
set_xml_value(item, to_item_id(item_id, ItemId), version=self.account.version)
- add_xml_child(item, 't:Data', data_str)
+ add_xml_child(item, "t:Data", data_str)
items_elem.append(item)
return payload
@@ -6337,19 +6570,19 @@ Methods
:param items:
"""
- payload = create_element(f'm:{self.SERVICE_NAME}')
- items_elem = create_element('m:Items')
+ payload = create_element(f"m:{self.SERVICE_NAME}")
+ items_elem = create_element("m:Items")
payload.append(items_elem)
for parent_folder, (item_id, is_associated, data_str) in items:
# TODO: The full spec also allows the "UpdateOrCreate" create action.
- attrs = dict(CreateAction='Update' if item_id else 'CreateNew')
+ attrs = dict(CreateAction="Update" if item_id else "CreateNew")
if is_associated is not None:
- attrs['IsAssociated'] = is_associated
- item = create_element('t:Item', attrs=attrs)
+ attrs["IsAssociated"] = is_associated
+ item = create_element("t:Item", attrs=attrs)
set_xml_value(item, ParentFolderId(parent_folder.id, parent_folder.changekey), version=self.account.version)
if item_id:
set_xml_value(item, to_item_id(item_id, ItemId), version=self.account.version)
- add_xml_child(item, 't:Data', data_str)
+ add_xml_child(item, "t:Data", data_str)
items_elem.append(item)
return payload
diff --git a/docs/exchangelib/services/mark_as_junk.html b/docs/exchangelib/services/mark_as_junk.html
index 82afdea9..ce00d979 100644
--- a/docs/exchangelib/services/mark_as_junk.html
+++ b/docs/exchangelib/services/mark_as_junk.html
@@ -26,15 +26,15 @@ exchangelib.services.mark_as_junk
from .common import EWSAccountService, item_ids_element
-from ..properties import MovedItemId
+from ..properties import MovedItemId
from ..util import create_element
+from .common import EWSAccountService, item_ids_element
class MarkAsJunk(EWSAccountService):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/markasjunk-operation"""
- SERVICE_NAME = 'MarkAsJunk'
+ SERVICE_NAME = "MarkAsJunk"
def call(self, items, is_junk, move_item):
return self._elems_to_objs(
@@ -50,7 +50,7 @@ Module exchangelib.services.mark_as_junk
def get_payload(self, items, is_junk, move_item):
# Takes a list of items and returns either success or raises an error message
- payload = create_element(f'm:{self.SERVICE_NAME}', attrs=dict(IsJunk=is_junk, MoveItem=move_item))
+ payload = create_element(f"m:{self.SERVICE_NAME}", attrs=dict(IsJunk=is_junk, MoveItem=move_item))
payload.append(item_ids_element(items=items, version=self.account.version))
return payload
@@ -77,7 +77,7 @@ Classes
class MarkAsJunk(EWSAccountService):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/markasjunk-operation"""
- SERVICE_NAME = 'MarkAsJunk'
+ SERVICE_NAME = "MarkAsJunk"
def call(self, items, is_junk, move_item):
return self._elems_to_objs(
@@ -93,7 +93,7 @@ Classes
def get_payload(self, items, is_junk, move_item):
# Takes a list of items and returns either success or raises an error message
- payload = create_element(f'm:{self.SERVICE_NAME}', attrs=dict(IsJunk=is_junk, MoveItem=move_item))
+ payload = create_element(f"m:{self.SERVICE_NAME}", attrs=dict(IsJunk=is_junk, MoveItem=move_item))
payload.append(item_ids_element(items=items, version=self.account.version))
return payload
@@ -137,7 +137,7 @@ Methods
def get_payload(self, items, is_junk, move_item):
# Takes a list of items and returns either success or raises an error message
- payload = create_element(f'm:{self.SERVICE_NAME}', attrs=dict(IsJunk=is_junk, MoveItem=move_item))
+ payload = create_element(f"m:{self.SERVICE_NAME}", attrs=dict(IsJunk=is_junk, MoveItem=move_item))
payload.append(item_ids_element(items=items, version=self.account.version))
return payload
diff --git a/docs/exchangelib/services/move_folder.html b/docs/exchangelib/services/move_folder.html
index 1eb2fec8..eb45bd1e 100644
--- a/docs/exchangelib/services/move_folder.html
+++ b/docs/exchangelib/services/move_folder.html
@@ -26,22 +26,22 @@ Module exchangelib.services.move_folder
Expand source code
-from .common import EWSAccountService, folder_ids_element
-from ..errors import InvalidTypeError
+from ..errors import InvalidTypeError
from ..folders import BaseFolder
from ..properties import FolderId
-from ..util import create_element, MNS
+from ..util import MNS, create_element
+from .common import EWSAccountService, folder_ids_element
class MoveFolder(EWSAccountService):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/movefolder-operation"""
SERVICE_NAME = "MoveFolder"
- element_container_name = f'{{{MNS}}}Folders'
+ element_container_name = f"{{{MNS}}}Folders"
def call(self, folders, to_folder):
if not isinstance(to_folder, (BaseFolder, FolderId)):
- raise InvalidTypeError('to_folder', to_folder, (BaseFolder, FolderId))
+ raise InvalidTypeError("to_folder", to_folder, (BaseFolder, FolderId))
return self._elems_to_objs(self._chunked_get_elements(self.get_payload, items=folders, to_folder=to_folder))
def _elem_to_obj(self, elem):
@@ -49,8 +49,8 @@ Module exchangelib.services.move_folder
def get_payload(self, folders, to_folder):
# Takes a list of folders and returns their new folder IDs
- payload = create_element(f'm:{self.SERVICE_NAME}')
- payload.append(folder_ids_element(folders=[to_folder], version=self.account.version, tag='m:ToFolderId'))
+ payload = create_element(f"m:{self.SERVICE_NAME}")
+ payload.append(folder_ids_element(folders=[to_folder], version=self.account.version, tag="m:ToFolderId"))
payload.append(folder_ids_element(folders=folders, version=self.account.version))
return payload
@@ -78,11 +78,11 @@ Classes
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/movefolder-operation"""
SERVICE_NAME = "MoveFolder"
- element_container_name = f'{{{MNS}}}Folders'
+ element_container_name = f"{{{MNS}}}Folders"
def call(self, folders, to_folder):
if not isinstance(to_folder, (BaseFolder, FolderId)):
- raise InvalidTypeError('to_folder', to_folder, (BaseFolder, FolderId))
+ raise InvalidTypeError("to_folder", to_folder, (BaseFolder, FolderId))
return self._elems_to_objs(self._chunked_get_elements(self.get_payload, items=folders, to_folder=to_folder))
def _elem_to_obj(self, elem):
@@ -90,8 +90,8 @@ Classes
def get_payload(self, folders, to_folder):
# Takes a list of folders and returns their new folder IDs
- payload = create_element(f'm:{self.SERVICE_NAME}')
- payload.append(folder_ids_element(folders=[to_folder], version=self.account.version, tag='m:ToFolderId'))
+ payload = create_element(f"m:{self.SERVICE_NAME}")
+ payload.append(folder_ids_element(folders=[to_folder], version=self.account.version, tag="m:ToFolderId"))
payload.append(folder_ids_element(folders=folders, version=self.account.version))
return payload
@@ -124,7 +124,7 @@ Methods
def call(self, folders, to_folder):
if not isinstance(to_folder, (BaseFolder, FolderId)):
- raise InvalidTypeError('to_folder', to_folder, (BaseFolder, FolderId))
+ raise InvalidTypeError("to_folder", to_folder, (BaseFolder, FolderId))
return self._elems_to_objs(self._chunked_get_elements(self.get_payload, items=folders, to_folder=to_folder))
@@ -139,8 +139,8 @@ Methods
def get_payload(self, folders, to_folder):
# Takes a list of folders and returns their new folder IDs
- payload = create_element(f'm:{self.SERVICE_NAME}')
- payload.append(folder_ids_element(folders=[to_folder], version=self.account.version, tag='m:ToFolderId'))
+ payload = create_element(f"m:{self.SERVICE_NAME}")
+ payload.append(folder_ids_element(folders=[to_folder], version=self.account.version, tag="m:ToFolderId"))
payload.append(folder_ids_element(folders=folders, version=self.account.version))
return payload
diff --git a/docs/exchangelib/services/move_item.html b/docs/exchangelib/services/move_item.html
index 8fc63570..910da7ac 100644
--- a/docs/exchangelib/services/move_item.html
+++ b/docs/exchangelib/services/move_item.html
@@ -26,23 +26,23 @@ Module exchangelib.services.move_item
Expand source code
-from .common import EWSAccountService, item_ids_element, folder_ids_element
-from ..errors import InvalidTypeError
+from ..errors import InvalidTypeError
from ..folders import BaseFolder
from ..items import Item
from ..properties import FolderId
-from ..util import create_element, MNS
+from ..util import MNS, create_element
+from .common import EWSAccountService, folder_ids_element, item_ids_element
class MoveItem(EWSAccountService):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/moveitem-operation"""
- SERVICE_NAME = 'MoveItem'
- element_container_name = f'{{{MNS}}}Items'
+ SERVICE_NAME = "MoveItem"
+ element_container_name = f"{{{MNS}}}Items"
def call(self, items, to_folder):
if not isinstance(to_folder, (BaseFolder, FolderId)):
- raise InvalidTypeError('to_folder', to_folder, (BaseFolder, FolderId))
+ raise InvalidTypeError("to_folder", to_folder, (BaseFolder, FolderId))
return self._elems_to_objs(self._chunked_get_elements(self.get_payload, items=items, to_folder=to_folder))
def _elem_to_obj(self, elem):
@@ -50,8 +50,8 @@ Module exchangelib.services.move_item
def get_payload(self, items, to_folder):
# Takes a list of items and returns their new item IDs
- payload = create_element(f'm:{self.SERVICE_NAME}')
- payload.append(folder_ids_element(folders=[to_folder], version=self.account.version, tag='m:ToFolderId'))
+ payload = create_element(f"m:{self.SERVICE_NAME}")
+ payload.append(folder_ids_element(folders=[to_folder], version=self.account.version, tag="m:ToFolderId"))
payload.append(item_ids_element(items=items, version=self.account.version))
return payload
@@ -78,12 +78,12 @@ Classes
class MoveItem(EWSAccountService):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/moveitem-operation"""
- SERVICE_NAME = 'MoveItem'
- element_container_name = f'{{{MNS}}}Items'
+ SERVICE_NAME = "MoveItem"
+ element_container_name = f"{{{MNS}}}Items"
def call(self, items, to_folder):
if not isinstance(to_folder, (BaseFolder, FolderId)):
- raise InvalidTypeError('to_folder', to_folder, (BaseFolder, FolderId))
+ raise InvalidTypeError("to_folder", to_folder, (BaseFolder, FolderId))
return self._elems_to_objs(self._chunked_get_elements(self.get_payload, items=items, to_folder=to_folder))
def _elem_to_obj(self, elem):
@@ -91,8 +91,8 @@ Classes
def get_payload(self, items, to_folder):
# Takes a list of items and returns their new item IDs
- payload = create_element(f'm:{self.SERVICE_NAME}')
- payload.append(folder_ids_element(folders=[to_folder], version=self.account.version, tag='m:ToFolderId'))
+ payload = create_element(f"m:{self.SERVICE_NAME}")
+ payload.append(folder_ids_element(folders=[to_folder], version=self.account.version, tag="m:ToFolderId"))
payload.append(item_ids_element(items=items, version=self.account.version))
return payload
@@ -129,7 +129,7 @@ Methods
def call(self, items, to_folder):
if not isinstance(to_folder, (BaseFolder, FolderId)):
- raise InvalidTypeError('to_folder', to_folder, (BaseFolder, FolderId))
+ raise InvalidTypeError("to_folder", to_folder, (BaseFolder, FolderId))
return self._elems_to_objs(self._chunked_get_elements(self.get_payload, items=items, to_folder=to_folder))
@@ -144,8 +144,8 @@ Methods
def get_payload(self, items, to_folder):
# Takes a list of items and returns their new item IDs
- payload = create_element(f'm:{self.SERVICE_NAME}')
- payload.append(folder_ids_element(folders=[to_folder], version=self.account.version, tag='m:ToFolderId'))
+ payload = create_element(f"m:{self.SERVICE_NAME}")
+ payload.append(folder_ids_element(folders=[to_folder], version=self.account.version, tag="m:ToFolderId"))
payload.append(item_ids_element(items=items, version=self.account.version))
return payload
diff --git a/docs/exchangelib/services/resolve_names.html b/docs/exchangelib/services/resolve_names.html
index b3ebbfab..8a998907 100644
--- a/docs/exchangelib/services/resolve_names.html
+++ b/docs/exchangelib/services/resolve_names.html
@@ -28,12 +28,12 @@ Module exchangelib.services.resolve_names
import logging
-from .common import EWSService, folder_ids_element
-from ..errors import ErrorNameResolutionNoResults, ErrorNameResolutionMultipleResults, InvalidEnumValue
-from ..items import SHAPE_CHOICES, SEARCH_SCOPE_CHOICES, Contact
+from ..errors import ErrorNameResolutionMultipleResults, ErrorNameResolutionNoResults, InvalidEnumValue
+from ..items import SEARCH_SCOPE_CHOICES, SHAPE_CHOICES, Contact
from ..properties import Mailbox
-from ..util import create_element, add_xml_child, MNS
+from ..util import MNS, add_xml_child, create_element
from ..version import EXCHANGE_2010_SP2
+from .common import EWSService, folder_ids_element
log = logging.getLogger(__name__)
@@ -41,8 +41,8 @@ Module exchangelib.services.resolve_names
class ResolveNames(EWSService):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/resolvenames-operation"""
- SERVICE_NAME = 'ResolveNames'
- element_container_name = f'{{{MNS}}}ResolutionSet'
+ SERVICE_NAME = "ResolveNames"
+ element_container_name = f"{{{MNS}}}ResolutionSet"
ERRORS_TO_CATCH_IN_RESPONSE = ErrorNameResolutionNoResults
WARNINGS_TO_IGNORE_IN_RESPONSE = ErrorNameResolutionMultipleResults
# Note: paging information is returned as attrs on the 'ResolutionSet' element, but this service does not
@@ -54,26 +54,34 @@ Module exchangelib.services.resolve_names
super().__init__(*args, **kwargs)
self.return_full_contact_data = False # A hack to communicate parsing args to _elems_to_objs()
- def call(self, unresolved_entries, parent_folders=None, return_full_contact_data=False, search_scope=None,
- contact_data_shape=None):
+ def call(
+ self,
+ unresolved_entries,
+ parent_folders=None,
+ return_full_contact_data=False,
+ search_scope=None,
+ contact_data_shape=None,
+ ):
if self.chunk_size > 100:
raise ValueError(
- f'Chunk size {self.chunk_size} is too high. {self.SERVICE_NAME} supports returning at most 100 '
- f'candidates for a lookup',
+ f"Chunk size {self.chunk_size} is too high. {self.SERVICE_NAME} supports returning at most 100 "
+ f"candidates for a lookup",
)
if search_scope and search_scope not in SEARCH_SCOPE_CHOICES:
- raise InvalidEnumValue('search_scope', search_scope, SEARCH_SCOPE_CHOICES)
+ raise InvalidEnumValue("search_scope", search_scope, SEARCH_SCOPE_CHOICES)
if contact_data_shape and contact_data_shape not in SHAPE_CHOICES:
- raise InvalidEnumValue('contact_data_shape', contact_data_shape, SHAPE_CHOICES)
+ raise InvalidEnumValue("contact_data_shape", contact_data_shape, SHAPE_CHOICES)
self.return_full_contact_data = return_full_contact_data
- return self._elems_to_objs(self._chunked_get_elements(
- self.get_payload,
- items=unresolved_entries,
- parent_folders=parent_folders,
- return_full_contact_data=return_full_contact_data,
- search_scope=search_scope,
- contact_data_shape=contact_data_shape,
- ))
+ return self._elems_to_objs(
+ self._chunked_get_elements(
+ self.get_payload,
+ items=unresolved_entries,
+ parent_folders=parent_folders,
+ return_full_contact_data=return_full_contact_data,
+ search_scope=search_scope,
+ contact_data_shape=contact_data_shape,
+ )
+ )
def _elem_to_obj(self, elem):
if self.return_full_contact_data:
@@ -85,23 +93,25 @@ Module exchangelib.services.resolve_names
)
return Mailbox.from_xml(elem=elem.find(Mailbox.response_tag()), account=None)
- def get_payload(self, unresolved_entries, parent_folders, return_full_contact_data, search_scope,
- contact_data_shape):
+ def get_payload(
+ self, unresolved_entries, parent_folders, return_full_contact_data, search_scope, contact_data_shape
+ ):
attrs = dict(ReturnFullContactData=return_full_contact_data)
if search_scope:
- attrs['SearchScope'] = search_scope
+ attrs["SearchScope"] = search_scope
if contact_data_shape:
if self.protocol.version.build < EXCHANGE_2010_SP2:
raise NotImplementedError(
- "'contact_data_shape' is only supported for Exchange 2010 SP2 servers and later")
- attrs['ContactDataShape'] = contact_data_shape
- payload = create_element(f'm:{self.SERVICE_NAME}', attrs=attrs)
+ "'contact_data_shape' is only supported for Exchange 2010 SP2 servers and later"
+ )
+ attrs["ContactDataShape"] = contact_data_shape
+ payload = create_element(f"m:{self.SERVICE_NAME}", attrs=attrs)
if parent_folders:
- payload.append(folder_ids_element(
- folders=parent_folders, version=self.protocol.version, tag='m:ParentFolderIds'
- ))
+ payload.append(
+ folder_ids_element(folders=parent_folders, version=self.protocol.version, tag="m:ParentFolderIds")
+ )
for entry in unresolved_entries:
- add_xml_child(payload, 'm:UnresolvedEntry', entry)
+ add_xml_child(payload, "m:UnresolvedEntry", entry)
return payload
@@ -127,8 +137,8 @@ Classes
class ResolveNames(EWSService):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/resolvenames-operation"""
- SERVICE_NAME = 'ResolveNames'
- element_container_name = f'{{{MNS}}}ResolutionSet'
+ SERVICE_NAME = "ResolveNames"
+ element_container_name = f"{{{MNS}}}ResolutionSet"
ERRORS_TO_CATCH_IN_RESPONSE = ErrorNameResolutionNoResults
WARNINGS_TO_IGNORE_IN_RESPONSE = ErrorNameResolutionMultipleResults
# Note: paging information is returned as attrs on the 'ResolutionSet' element, but this service does not
@@ -140,26 +150,34 @@ Classes
super().__init__(*args, **kwargs)
self.return_full_contact_data = False # A hack to communicate parsing args to _elems_to_objs()
- def call(self, unresolved_entries, parent_folders=None, return_full_contact_data=False, search_scope=None,
- contact_data_shape=None):
+ def call(
+ self,
+ unresolved_entries,
+ parent_folders=None,
+ return_full_contact_data=False,
+ search_scope=None,
+ contact_data_shape=None,
+ ):
if self.chunk_size > 100:
raise ValueError(
- f'Chunk size {self.chunk_size} is too high. {self.SERVICE_NAME} supports returning at most 100 '
- f'candidates for a lookup',
+ f"Chunk size {self.chunk_size} is too high. {self.SERVICE_NAME} supports returning at most 100 "
+ f"candidates for a lookup",
)
if search_scope and search_scope not in SEARCH_SCOPE_CHOICES:
- raise InvalidEnumValue('search_scope', search_scope, SEARCH_SCOPE_CHOICES)
+ raise InvalidEnumValue("search_scope", search_scope, SEARCH_SCOPE_CHOICES)
if contact_data_shape and contact_data_shape not in SHAPE_CHOICES:
- raise InvalidEnumValue('contact_data_shape', contact_data_shape, SHAPE_CHOICES)
+ raise InvalidEnumValue("contact_data_shape", contact_data_shape, SHAPE_CHOICES)
self.return_full_contact_data = return_full_contact_data
- return self._elems_to_objs(self._chunked_get_elements(
- self.get_payload,
- items=unresolved_entries,
- parent_folders=parent_folders,
- return_full_contact_data=return_full_contact_data,
- search_scope=search_scope,
- contact_data_shape=contact_data_shape,
- ))
+ return self._elems_to_objs(
+ self._chunked_get_elements(
+ self.get_payload,
+ items=unresolved_entries,
+ parent_folders=parent_folders,
+ return_full_contact_data=return_full_contact_data,
+ search_scope=search_scope,
+ contact_data_shape=contact_data_shape,
+ )
+ )
def _elem_to_obj(self, elem):
if self.return_full_contact_data:
@@ -171,23 +189,25 @@ Classes
)
return Mailbox.from_xml(elem=elem.find(Mailbox.response_tag()), account=None)
- def get_payload(self, unresolved_entries, parent_folders, return_full_contact_data, search_scope,
- contact_data_shape):
+ def get_payload(
+ self, unresolved_entries, parent_folders, return_full_contact_data, search_scope, contact_data_shape
+ ):
attrs = dict(ReturnFullContactData=return_full_contact_data)
if search_scope:
- attrs['SearchScope'] = search_scope
+ attrs["SearchScope"] = search_scope
if contact_data_shape:
if self.protocol.version.build < EXCHANGE_2010_SP2:
raise NotImplementedError(
- "'contact_data_shape' is only supported for Exchange 2010 SP2 servers and later")
- attrs['ContactDataShape'] = contact_data_shape
- payload = create_element(f'm:{self.SERVICE_NAME}', attrs=attrs)
+ "'contact_data_shape' is only supported for Exchange 2010 SP2 servers and later"
+ )
+ attrs["ContactDataShape"] = contact_data_shape
+ payload = create_element(f"m:{self.SERVICE_NAME}", attrs=attrs)
if parent_folders:
- payload.append(folder_ids_element(
- folders=parent_folders, version=self.protocol.version, tag='m:ParentFolderIds'
- ))
+ payload.append(
+ folder_ids_element(folders=parent_folders, version=self.protocol.version, tag="m:ParentFolderIds")
+ )
for entry in unresolved_entries:
- add_xml_child(payload, 'm:UnresolvedEntry', entry)
+ add_xml_child(payload, "m:UnresolvedEntry", entry)
return payload
Ancestors
@@ -228,26 +248,34 @@ Methods
Expand source code
-def call(self, unresolved_entries, parent_folders=None, return_full_contact_data=False, search_scope=None,
- contact_data_shape=None):
+def call(
+ self,
+ unresolved_entries,
+ parent_folders=None,
+ return_full_contact_data=False,
+ search_scope=None,
+ contact_data_shape=None,
+):
if self.chunk_size > 100:
raise ValueError(
- f'Chunk size {self.chunk_size} is too high. {self.SERVICE_NAME} supports returning at most 100 '
- f'candidates for a lookup',
+ f"Chunk size {self.chunk_size} is too high. {self.SERVICE_NAME} supports returning at most 100 "
+ f"candidates for a lookup",
)
if search_scope and search_scope not in SEARCH_SCOPE_CHOICES:
- raise InvalidEnumValue('search_scope', search_scope, SEARCH_SCOPE_CHOICES)
+ raise InvalidEnumValue("search_scope", search_scope, SEARCH_SCOPE_CHOICES)
if contact_data_shape and contact_data_shape not in SHAPE_CHOICES:
- raise InvalidEnumValue('contact_data_shape', contact_data_shape, SHAPE_CHOICES)
+ raise InvalidEnumValue("contact_data_shape", contact_data_shape, SHAPE_CHOICES)
self.return_full_contact_data = return_full_contact_data
- return self._elems_to_objs(self._chunked_get_elements(
- self.get_payload,
- items=unresolved_entries,
- parent_folders=parent_folders,
- return_full_contact_data=return_full_contact_data,
- search_scope=search_scope,
- contact_data_shape=contact_data_shape,
- ))
+ return self._elems_to_objs(
+ self._chunked_get_elements(
+ self.get_payload,
+ items=unresolved_entries,
+ parent_folders=parent_folders,
+ return_full_contact_data=return_full_contact_data,
+ search_scope=search_scope,
+ contact_data_shape=contact_data_shape,
+ )
+ )
@@ -259,23 +287,25 @@ Methods
Expand source code
-def get_payload(self, unresolved_entries, parent_folders, return_full_contact_data, search_scope,
- contact_data_shape):
+def get_payload(
+ self, unresolved_entries, parent_folders, return_full_contact_data, search_scope, contact_data_shape
+):
attrs = dict(ReturnFullContactData=return_full_contact_data)
if search_scope:
- attrs['SearchScope'] = search_scope
+ attrs["SearchScope"] = search_scope
if contact_data_shape:
if self.protocol.version.build < EXCHANGE_2010_SP2:
raise NotImplementedError(
- "'contact_data_shape' is only supported for Exchange 2010 SP2 servers and later")
- attrs['ContactDataShape'] = contact_data_shape
- payload = create_element(f'm:{self.SERVICE_NAME}', attrs=attrs)
+ "'contact_data_shape' is only supported for Exchange 2010 SP2 servers and later"
+ )
+ attrs["ContactDataShape"] = contact_data_shape
+ payload = create_element(f"m:{self.SERVICE_NAME}", attrs=attrs)
if parent_folders:
- payload.append(folder_ids_element(
- folders=parent_folders, version=self.protocol.version, tag='m:ParentFolderIds'
- ))
+ payload.append(
+ folder_ids_element(folders=parent_folders, version=self.protocol.version, tag="m:ParentFolderIds")
+ )
for entry in unresolved_entries:
- add_xml_child(payload, 'm:UnresolvedEntry', entry)
+ add_xml_child(payload, "m:UnresolvedEntry", entry)
return payload
diff --git a/docs/exchangelib/services/send_item.html b/docs/exchangelib/services/send_item.html
index 590243e4..2d60609c 100644
--- a/docs/exchangelib/services/send_item.html
+++ b/docs/exchangelib/services/send_item.html
@@ -26,31 +26,31 @@ Module exchangelib.services.send_item
Expand source code
-from .common import EWSAccountService, item_ids_element, folder_ids_element
-from ..errors import InvalidTypeError
+from ..errors import InvalidTypeError
from ..folders import BaseFolder
from ..properties import FolderId
from ..util import create_element
+from .common import EWSAccountService, folder_ids_element, item_ids_element
class SendItem(EWSAccountService):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/senditem-operation"""
- SERVICE_NAME = 'SendItem'
+ SERVICE_NAME = "SendItem"
returns_elements = False
def call(self, items, saved_item_folder):
if saved_item_folder and not isinstance(saved_item_folder, (BaseFolder, FolderId)):
- raise InvalidTypeError('saved_item_folder', saved_item_folder, (BaseFolder, FolderId))
+ raise InvalidTypeError("saved_item_folder", saved_item_folder, (BaseFolder, FolderId))
return self._chunked_get_elements(self.get_payload, items=items, saved_item_folder=saved_item_folder)
def get_payload(self, items, saved_item_folder):
- payload = create_element(f'm:{self.SERVICE_NAME}', attrs=dict(SaveItemToFolder=bool(saved_item_folder)))
+ payload = create_element(f"m:{self.SERVICE_NAME}", attrs=dict(SaveItemToFolder=bool(saved_item_folder)))
payload.append(item_ids_element(items=items, version=self.account.version))
if saved_item_folder:
- payload.append(folder_ids_element(
- folders=[saved_item_folder], version=self.account.version, tag='m:SavedItemFolderId'
- ))
+ payload.append(
+ folder_ids_element(folders=[saved_item_folder], version=self.account.version, tag="m:SavedItemFolderId")
+ )
return payload
@@ -76,21 +76,21 @@ Classes
class SendItem(EWSAccountService):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/senditem-operation"""
- SERVICE_NAME = 'SendItem'
+ SERVICE_NAME = "SendItem"
returns_elements = False
def call(self, items, saved_item_folder):
if saved_item_folder and not isinstance(saved_item_folder, (BaseFolder, FolderId)):
- raise InvalidTypeError('saved_item_folder', saved_item_folder, (BaseFolder, FolderId))
+ raise InvalidTypeError("saved_item_folder", saved_item_folder, (BaseFolder, FolderId))
return self._chunked_get_elements(self.get_payload, items=items, saved_item_folder=saved_item_folder)
def get_payload(self, items, saved_item_folder):
- payload = create_element(f'm:{self.SERVICE_NAME}', attrs=dict(SaveItemToFolder=bool(saved_item_folder)))
+ payload = create_element(f"m:{self.SERVICE_NAME}", attrs=dict(SaveItemToFolder=bool(saved_item_folder)))
payload.append(item_ids_element(items=items, version=self.account.version))
if saved_item_folder:
- payload.append(folder_ids_element(
- folders=[saved_item_folder], version=self.account.version, tag='m:SavedItemFolderId'
- ))
+ payload.append(
+ folder_ids_element(folders=[saved_item_folder], version=self.account.version, tag="m:SavedItemFolderId")
+ )
return payload
Ancestors
@@ -122,7 +122,7 @@ Methods
def call(self, items, saved_item_folder):
if saved_item_folder and not isinstance(saved_item_folder, (BaseFolder, FolderId)):
- raise InvalidTypeError('saved_item_folder', saved_item_folder, (BaseFolder, FolderId))
+ raise InvalidTypeError("saved_item_folder", saved_item_folder, (BaseFolder, FolderId))
return self._chunked_get_elements(self.get_payload, items=items, saved_item_folder=saved_item_folder)
@@ -136,12 +136,12 @@ Methods
Expand source code
def get_payload(self, items, saved_item_folder):
- payload = create_element(f'm:{self.SERVICE_NAME}', attrs=dict(SaveItemToFolder=bool(saved_item_folder)))
+ payload = create_element(f"m:{self.SERVICE_NAME}", attrs=dict(SaveItemToFolder=bool(saved_item_folder)))
payload.append(item_ids_element(items=items, version=self.account.version))
if saved_item_folder:
- payload.append(folder_ids_element(
- folders=[saved_item_folder], version=self.account.version, tag='m:SavedItemFolderId'
- ))
+ payload.append(
+ folder_ids_element(folders=[saved_item_folder], version=self.account.version, tag="m:SavedItemFolderId")
+ )
return payload
diff --git a/docs/exchangelib/services/send_notification.html b/docs/exchangelib/services/send_notification.html
index 665754f1..fa0da538 100644
--- a/docs/exchangelib/services/send_notification.html
+++ b/docs/exchangelib/services/send_notification.html
@@ -26,11 +26,11 @@ Module exchangelib.services.send_notification
Expand source code
-from .common import EWSService, add_xml_child
-from ..errors import InvalidEnumValue
+from ..errors import InvalidEnumValue
from ..properties import Notification
from ..transport import wrap
-from ..util import create_element, MNS
+from ..util import MNS, create_element
+from .common import EWSService, add_xml_child
class SendNotification(EWSService):
@@ -41,9 +41,9 @@ Module exchangelib.services.send_notification
Module exchangelib.services.send_notification
Module exchangelib.services.send_notification
@@ -102,9 +102,9 @@ Classes
push notifications.
"""
- SERVICE_NAME = 'SendNotification'
- OK = 'OK'
- UNSUBSCRIBE = 'Unsubscribe'
+ SERVICE_NAME = "SendNotification"
+ OK = "OK"
+ UNSUBSCRIBE = "Unsubscribe"
STATUS_CHOICES = (OK, UNSUBSCRIBE)
def ok_payload(self):
@@ -119,7 +119,7 @@ Classes
@classmethod
def _response_tag(cls):
"""Return the name of the element containing the service response."""
- return f'{{{MNS}}}{cls.SERVICE_NAME}'
+ return f"{{{MNS}}}{cls.SERVICE_NAME}"
@classmethod
def _get_elements_in_container(cls, container):
@@ -127,9 +127,9 @@ Classes
def get_payload(self, status):
if status not in self.STATUS_CHOICES:
- raise InvalidEnumValue('status', status, self.STATUS_CHOICES)
- payload = create_element(f'm:{self.SERVICE_NAME}Result')
- add_xml_child(payload, 'm:SubscriptionStatus', status)
+ raise InvalidEnumValue("status", status, self.STATUS_CHOICES)
+ payload = create_element(f"m:{self.SERVICE_NAME}Result")
+ add_xml_child(payload, "m:SubscriptionStatus", status)
return payload
Ancestors
@@ -168,9 +168,9 @@ Methods
def get_payload(self, status):
if status not in self.STATUS_CHOICES:
- raise InvalidEnumValue('status', status, self.STATUS_CHOICES)
- payload = create_element(f'm:{self.SERVICE_NAME}Result')
- add_xml_child(payload, 'm:SubscriptionStatus', status)
+ raise InvalidEnumValue("status", status, self.STATUS_CHOICES)
+ payload = create_element(f"m:{self.SERVICE_NAME}Result")
+ add_xml_child(payload, "m:SubscriptionStatus", status)
return payload
diff --git a/docs/exchangelib/services/set_user_oof_settings.html b/docs/exchangelib/services/set_user_oof_settings.html
index 67d430b3..22a03525 100644
--- a/docs/exchangelib/services/set_user_oof_settings.html
+++ b/docs/exchangelib/services/set_user_oof_settings.html
@@ -26,11 +26,11 @@ Module exchangelib.services.set_user_oof_settings
Expand source code
-from .common import EWSAccountService
-from ..errors import InvalidTypeError
+from ..errors import InvalidTypeError
from ..properties import AvailabilityMailbox, Mailbox
from ..settings import OofSettings
-from ..util import create_element, set_xml_value, MNS
+from ..util import MNS, create_element, set_xml_value
+from .common import EWSAccountService
class SetUserOofSettings(EWSAccountService):
@@ -38,18 +38,18 @@ Module exchangelib.services.set_user_oof_settings
MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/setuseroofsettings-operation
"""
- SERVICE_NAME = 'SetUserOofSettings'
+ SERVICE_NAME = "SetUserOofSettings"
returns_elements = False
def call(self, oof_settings, mailbox):
if not isinstance(oof_settings, OofSettings):
- raise InvalidTypeError('oof_settings', oof_settings, OofSettings)
+ raise InvalidTypeError("oof_settings", oof_settings, OofSettings)
if not isinstance(mailbox, Mailbox):
- raise InvalidTypeError('mailbox', mailbox, Mailbox)
+ raise InvalidTypeError("mailbox", mailbox, Mailbox)
return self._get_elements(payload=self.get_payload(oof_settings=oof_settings, mailbox=mailbox))
def get_payload(self, oof_settings, mailbox):
- payload = create_element(f'm:{self.SERVICE_NAME}Request')
+ payload = create_element(f"m:{self.SERVICE_NAME}Request")
set_xml_value(payload, AvailabilityMailbox.from_mailbox(mailbox), version=self.account.version)
return set_xml_value(payload, oof_settings, version=self.account.version)
@@ -59,7 +59,7 @@ Module exchangelib.services.set_user_oof_settings
@classmethod
def _response_message_tag(cls):
- return f'{{{MNS}}}ResponseMessage'
+ return f"{{{MNS}}}ResponseMessage"
@@ -87,18 +87,18 @@ Classes
MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/setuseroofsettings-operation
"""
- SERVICE_NAME = 'SetUserOofSettings'
+ SERVICE_NAME = "SetUserOofSettings"
returns_elements = False
def call(self, oof_settings, mailbox):
if not isinstance(oof_settings, OofSettings):
- raise InvalidTypeError('oof_settings', oof_settings, OofSettings)
+ raise InvalidTypeError("oof_settings", oof_settings, OofSettings)
if not isinstance(mailbox, Mailbox):
- raise InvalidTypeError('mailbox', mailbox, Mailbox)
+ raise InvalidTypeError("mailbox", mailbox, Mailbox)
return self._get_elements(payload=self.get_payload(oof_settings=oof_settings, mailbox=mailbox))
def get_payload(self, oof_settings, mailbox):
- payload = create_element(f'm:{self.SERVICE_NAME}Request')
+ payload = create_element(f"m:{self.SERVICE_NAME}Request")
set_xml_value(payload, AvailabilityMailbox.from_mailbox(mailbox), version=self.account.version)
return set_xml_value(payload, oof_settings, version=self.account.version)
@@ -108,7 +108,7 @@ Classes
@classmethod
def _response_message_tag(cls):
- return f'{{{MNS}}}ResponseMessage'
+ return f"{{{MNS}}}ResponseMessage"
Ancestors
@@ -139,9 +139,9 @@ Methods
def call(self, oof_settings, mailbox):
if not isinstance(oof_settings, OofSettings):
- raise InvalidTypeError('oof_settings', oof_settings, OofSettings)
+ raise InvalidTypeError("oof_settings", oof_settings, OofSettings)
if not isinstance(mailbox, Mailbox):
- raise InvalidTypeError('mailbox', mailbox, Mailbox)
+ raise InvalidTypeError("mailbox", mailbox, Mailbox)
return self._get_elements(payload=self.get_payload(oof_settings=oof_settings, mailbox=mailbox))
@@ -155,7 +155,7 @@ Methods
Expand source code
def get_payload(self, oof_settings, mailbox):
- payload = create_element(f'm:{self.SERVICE_NAME}Request')
+ payload = create_element(f"m:{self.SERVICE_NAME}Request")
set_xml_value(payload, AvailabilityMailbox.from_mailbox(mailbox), version=self.account.version)
return set_xml_value(payload, oof_settings, version=self.account.version)
diff --git a/docs/exchangelib/services/subscribe.html b/docs/exchangelib/services/subscribe.html
index d896db2f..0a470bca 100644
--- a/docs/exchangelib/services/subscribe.html
+++ b/docs/exchangelib/services/subscribe.html
@@ -34,31 +34,31 @@ Module exchangelib.services.subscribe
"""
import abc
-from .common import EWSAccountService, folder_ids_element, add_xml_child
-from ..util import create_element, MNS
+from ..util import MNS, create_element
+from .common import EWSAccountService, add_xml_child, folder_ids_element
class Subscribe(EWSAccountService, metaclass=abc.ABCMeta):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/subscribe-operation"""
- SERVICE_NAME = 'Subscribe'
+ SERVICE_NAME = "Subscribe"
EVENT_TYPES = (
- 'CopiedEvent',
- 'CreatedEvent',
- 'DeletedEvent',
- 'ModifiedEvent',
- 'MovedEvent',
- 'NewMailEvent',
- 'FreeBusyChangedEvent',
+ "CopiedEvent",
+ "CreatedEvent",
+ "DeletedEvent",
+ "ModifiedEvent",
+ "MovedEvent",
+ "NewMailEvent",
+ "FreeBusyChangedEvent",
)
subscription_request_elem_tag = None
def _partial_call(self, payload_func, folders, event_types, **kwargs):
if set(event_types) - set(self.EVENT_TYPES):
raise ValueError(f"'event_types' values must consist of values in {self.EVENT_TYPES}")
- return self._elems_to_objs(self._get_elements(
- payload=payload_func(folders=folders, event_types=event_types, **kwargs)
- ))
+ return self._elems_to_objs(
+ self._get_elements(payload=payload_func(folders=folders, event_types=event_types, **kwargs))
+ )
def _elem_to_obj(self, elem):
subscription_elem, watermark_elem = elem
@@ -66,15 +66,15 @@ Module exchangelib.services.subscribe
@classmethod
def _get_elements_in_container(cls, container):
- return [(container.find(f'{{{MNS}}}SubscriptionId'), container.find(f'{{{MNS}}}Watermark'))]
+ return [(container.find(f"{{{MNS}}}SubscriptionId"), container.find(f"{{{MNS}}}Watermark"))]
def _partial_payload(self, folders, event_types):
request_elem = create_element(self.subscription_request_elem_tag)
- folder_ids = folder_ids_element(folders=folders, version=self.account.version, tag='t:FolderIds')
+ folder_ids = folder_ids_element(folders=folders, version=self.account.version, tag="t:FolderIds")
request_elem.append(folder_ids)
- event_types_elem = create_element('t:EventTypes')
+ event_types_elem = create_element("t:EventTypes")
for event_type in event_types:
- add_xml_child(event_types_elem, 't:EventType', event_type)
+ add_xml_child(event_types_elem, "t:EventType", event_type)
if not len(event_types_elem):
raise ValueError("'event_types' must not be empty")
request_elem.append(event_types_elem)
@@ -82,47 +82,54 @@ Module exchangelib.services.subscribe
class SubscribeToPull(Subscribe):
- subscription_request_elem_tag = 'm:PullSubscriptionRequest'
+ subscription_request_elem_tag = "m:PullSubscriptionRequest"
prefer_affinity = True
def call(self, folders, event_types, watermark, timeout):
yield from self._partial_call(
- payload_func=self.get_payload, folders=folders, event_types=event_types, timeout=timeout,
+ payload_func=self.get_payload,
+ folders=folders,
+ event_types=event_types,
+ timeout=timeout,
watermark=watermark,
)
def get_payload(self, folders, event_types, watermark, timeout):
- payload = create_element(f'm:{self.SERVICE_NAME}')
+ payload = create_element(f"m:{self.SERVICE_NAME}")
request_elem = self._partial_payload(folders=folders, event_types=event_types)
if watermark:
- add_xml_child(request_elem, 'm:Watermark', watermark)
- add_xml_child(request_elem, 't:Timeout', timeout) # In minutes
+ add_xml_child(request_elem, "m:Watermark", watermark)
+ add_xml_child(request_elem, "t:Timeout", timeout) # In minutes
payload.append(request_elem)
return payload
class SubscribeToPush(Subscribe):
- subscription_request_elem_tag = 'm:PushSubscriptionRequest'
+ subscription_request_elem_tag = "m:PushSubscriptionRequest"
def call(self, folders, event_types, watermark, status_frequency, url):
yield from self._partial_call(
- payload_func=self.get_payload, folders=folders, event_types=event_types,
- status_frequency=status_frequency, url=url, watermark=watermark,
+ payload_func=self.get_payload,
+ folders=folders,
+ event_types=event_types,
+ status_frequency=status_frequency,
+ url=url,
+ watermark=watermark,
)
def get_payload(self, folders, event_types, watermark, status_frequency, url):
- payload = create_element(f'm:{self.SERVICE_NAME}')
+ payload = create_element(f"m:{self.SERVICE_NAME}")
request_elem = self._partial_payload(folders=folders, event_types=event_types)
if watermark:
- add_xml_child(request_elem, 'm:Watermark', watermark)
- add_xml_child(request_elem, 't:StatusFrequency', status_frequency) # In minutes
- add_xml_child(request_elem, 't:URL', url)
+ add_xml_child(request_elem, "m:Watermark", watermark)
+ add_xml_child(request_elem, "t:StatusFrequency", status_frequency) # In minutes
+ add_xml_child(request_elem, "t:URL", url)
payload.append(request_elem)
return payload
class SubscribeToStreaming(Subscribe):
- subscription_request_elem_tag = 'm:StreamingSubscriptionRequest'
+ subscription_request_elem_tag = "m:StreamingSubscriptionRequest"
prefer_affinity = True
def call(self, folders, event_types):
@@ -133,10 +140,10 @@ Module exchangelib.services.subscribe
@classmethod
def _get_elements_in_container(cls, container):
- return [container.find(f'{{{MNS}}}SubscriptionId')]
+ return [container.find(f"{{{MNS}}}SubscriptionId")]
def get_payload(self, folders, event_types):
- payload = create_element(f'm:{self.SERVICE_NAME}')
+ payload = create_element(f"m:{self.SERVICE_NAME}")
payload.append(self._partial_payload(folders=folders, event_types=event_types))
return payload
@@ -163,24 +170,24 @@ Classes
class Subscribe(EWSAccountService, metaclass=abc.ABCMeta):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/subscribe-operation"""
- SERVICE_NAME = 'Subscribe'
+ SERVICE_NAME = "Subscribe"
EVENT_TYPES = (
- 'CopiedEvent',
- 'CreatedEvent',
- 'DeletedEvent',
- 'ModifiedEvent',
- 'MovedEvent',
- 'NewMailEvent',
- 'FreeBusyChangedEvent',
+ "CopiedEvent",
+ "CreatedEvent",
+ "DeletedEvent",
+ "ModifiedEvent",
+ "MovedEvent",
+ "NewMailEvent",
+ "FreeBusyChangedEvent",
)
subscription_request_elem_tag = None
def _partial_call(self, payload_func, folders, event_types, **kwargs):
if set(event_types) - set(self.EVENT_TYPES):
raise ValueError(f"'event_types' values must consist of values in {self.EVENT_TYPES}")
- return self._elems_to_objs(self._get_elements(
- payload=payload_func(folders=folders, event_types=event_types, **kwargs)
- ))
+ return self._elems_to_objs(
+ self._get_elements(payload=payload_func(folders=folders, event_types=event_types, **kwargs))
+ )
def _elem_to_obj(self, elem):
subscription_elem, watermark_elem = elem
@@ -188,15 +195,15 @@ Classes
@classmethod
def _get_elements_in_container(cls, container):
- return [(container.find(f'{{{MNS}}}SubscriptionId'), container.find(f'{{{MNS}}}Watermark'))]
+ return [(container.find(f"{{{MNS}}}SubscriptionId"), container.find(f"{{{MNS}}}Watermark"))]
def _partial_payload(self, folders, event_types):
request_elem = create_element(self.subscription_request_elem_tag)
- folder_ids = folder_ids_element(folders=folders, version=self.account.version, tag='t:FolderIds')
+ folder_ids = folder_ids_element(folders=folders, version=self.account.version, tag="t:FolderIds")
request_elem.append(folder_ids)
- event_types_elem = create_element('t:EventTypes')
+ event_types_elem = create_element("t:EventTypes")
for event_type in event_types:
- add_xml_child(event_types_elem, 't:EventType', event_type)
+ add_xml_child(event_types_elem, "t:EventType", event_type)
if not len(event_types_elem):
raise ValueError("'event_types' must not be empty")
request_elem.append(event_types_elem)
@@ -251,21 +258,24 @@ Inherited members
Expand source code
class SubscribeToPull(Subscribe):
- subscription_request_elem_tag = 'm:PullSubscriptionRequest'
+ subscription_request_elem_tag = "m:PullSubscriptionRequest"
prefer_affinity = True
def call(self, folders, event_types, watermark, timeout):
yield from self._partial_call(
- payload_func=self.get_payload, folders=folders, event_types=event_types, timeout=timeout,
+ payload_func=self.get_payload,
+ folders=folders,
+ event_types=event_types,
+ timeout=timeout,
watermark=watermark,
)
def get_payload(self, folders, event_types, watermark, timeout):
- payload = create_element(f'm:{self.SERVICE_NAME}')
+ payload = create_element(f"m:{self.SERVICE_NAME}")
request_elem = self._partial_payload(folders=folders, event_types=event_types)
if watermark:
- add_xml_child(request_elem, 'm:Watermark', watermark)
- add_xml_child(request_elem, 't:Timeout', timeout) # In minutes
+ add_xml_child(request_elem, "m:Watermark", watermark)
+ add_xml_child(request_elem, "t:Timeout", timeout) # In minutes
payload.append(request_elem)
return payload
@@ -299,7 +309,10 @@ Methods
def call(self, folders, event_types, watermark, timeout):
yield from self._partial_call(
- payload_func=self.get_payload, folders=folders, event_types=event_types, timeout=timeout,
+ payload_func=self.get_payload,
+ folders=folders,
+ event_types=event_types,
+ timeout=timeout,
watermark=watermark,
)
@@ -314,11 +327,11 @@ Methods
Expand source code
def get_payload(self, folders, event_types, watermark, timeout):
- payload = create_element(f'm:{self.SERVICE_NAME}')
+ payload = create_element(f"m:{self.SERVICE_NAME}")
request_elem = self._partial_payload(folders=folders, event_types=event_types)
if watermark:
- add_xml_child(request_elem, 'm:Watermark', watermark)
- add_xml_child(request_elem, 't:Timeout', timeout) # In minutes
+ add_xml_child(request_elem, "m:Watermark", watermark)
+ add_xml_child(request_elem, "t:Timeout", timeout) # In minutes
payload.append(request_elem)
return payload
@@ -347,21 +360,25 @@ Inherited members
Expand source code
class SubscribeToPush(Subscribe):
- subscription_request_elem_tag = 'm:PushSubscriptionRequest'
+ subscription_request_elem_tag = "m:PushSubscriptionRequest"
def call(self, folders, event_types, watermark, status_frequency, url):
yield from self._partial_call(
- payload_func=self.get_payload, folders=folders, event_types=event_types,
- status_frequency=status_frequency, url=url, watermark=watermark,
+ payload_func=self.get_payload,
+ folders=folders,
+ event_types=event_types,
+ status_frequency=status_frequency,
+ url=url,
+ watermark=watermark,
)
def get_payload(self, folders, event_types, watermark, status_frequency, url):
- payload = create_element(f'm:{self.SERVICE_NAME}')
+ payload = create_element(f"m:{self.SERVICE_NAME}")
request_elem = self._partial_payload(folders=folders, event_types=event_types)
if watermark:
- add_xml_child(request_elem, 'm:Watermark', watermark)
- add_xml_child(request_elem, 't:StatusFrequency', status_frequency) # In minutes
- add_xml_child(request_elem, 't:URL', url)
+ add_xml_child(request_elem, "m:Watermark", watermark)
+ add_xml_child(request_elem, "t:StatusFrequency", status_frequency) # In minutes
+ add_xml_child(request_elem, "t:URL", url)
payload.append(request_elem)
return payload
@@ -391,8 +408,12 @@ Methods
def call(self, folders, event_types, watermark, status_frequency, url):
yield from self._partial_call(
- payload_func=self.get_payload, folders=folders, event_types=event_types,
- status_frequency=status_frequency, url=url, watermark=watermark,
+ payload_func=self.get_payload,
+ folders=folders,
+ event_types=event_types,
+ status_frequency=status_frequency,
+ url=url,
+ watermark=watermark,
)
@@ -406,12 +427,12 @@ Methods
Expand source code
def get_payload(self, folders, event_types, watermark, status_frequency, url):
- payload = create_element(f'm:{self.SERVICE_NAME}')
+ payload = create_element(f"m:{self.SERVICE_NAME}")
request_elem = self._partial_payload(folders=folders, event_types=event_types)
if watermark:
- add_xml_child(request_elem, 'm:Watermark', watermark)
- add_xml_child(request_elem, 't:StatusFrequency', status_frequency) # In minutes
- add_xml_child(request_elem, 't:URL', url)
+ add_xml_child(request_elem, "m:Watermark", watermark)
+ add_xml_child(request_elem, "t:StatusFrequency", status_frequency) # In minutes
+ add_xml_child(request_elem, "t:URL", url)
payload.append(request_elem)
return payload
@@ -440,7 +461,7 @@ Inherited members
Expand source code
class SubscribeToStreaming(Subscribe):
- subscription_request_elem_tag = 'm:StreamingSubscriptionRequest'
+ subscription_request_elem_tag = "m:StreamingSubscriptionRequest"
prefer_affinity = True
def call(self, folders, event_types):
@@ -451,10 +472,10 @@ Inherited members
@classmethod
def _get_elements_in_container(cls, container):
- return [container.find(f'{{{MNS}}}SubscriptionId')]
+ return [container.find(f"{{{MNS}}}SubscriptionId")]
def get_payload(self, folders, event_types):
- payload = create_element(f'm:{self.SERVICE_NAME}')
+ payload = create_element(f"m:{self.SERVICE_NAME}")
payload.append(self._partial_payload(folders=folders, event_types=event_types))
return payload
@@ -500,7 +521,7 @@ Methods
Expand source code
def get_payload(self, folders, event_types):
- payload = create_element(f'm:{self.SERVICE_NAME}')
+ payload = create_element(f"m:{self.SERVICE_NAME}")
payload.append(self._partial_payload(folders=folders, event_types=event_types))
return payload
diff --git a/docs/exchangelib/services/sync_folder_hierarchy.html b/docs/exchangelib/services/sync_folder_hierarchy.html
index f1938238..0f3870ef 100644
--- a/docs/exchangelib/services/sync_folder_hierarchy.html
+++ b/docs/exchangelib/services/sync_folder_hierarchy.html
@@ -29,9 +29,9 @@ Module exchangelib.services.sync_folder_hierarchy
import abc
import logging
-from .common import EWSPagingService, add_xml_child, folder_ids_element, shape_element, parse_folder_elem
from ..properties import FolderId
-from ..util import create_element, xml_text_to_value, MNS, TNS
+from ..util import MNS, TNS, create_element, xml_text_to_value
+from .common import EWSPagingService, add_xml_child, folder_ids_element, parse_folder_elem, shape_element
log = logging.getLogger(__name__)
@@ -39,18 +39,18 @@ Module exchangelib.services.sync_folder_hierarchy
class SyncFolder(EWSPagingService, metaclass=abc.ABCMeta):
"""Base class for SyncFolderHierarchy and SyncFolderItems."""
- element_container_name = f'{{{MNS}}}Changes'
+ element_container_name = f"{{{MNS}}}Changes"
# Change types
- CREATE = 'create'
- UPDATE = 'update'
- DELETE = 'delete'
+ CREATE = "create"
+ UPDATE = "update"
+ DELETE = "delete"
CHANGE_TYPES = (CREATE, UPDATE, DELETE)
shape_tag = None
last_in_range_name = None
change_types_map = {
- f'{{{TNS}}}Create': CREATE,
- f'{{{TNS}}}Update': UPDATE,
- f'{{{TNS}}}Delete': DELETE,
+ f"{{{TNS}}}Create": CREATE,
+ f"{{{TNS}}}Update": UPDATE,
+ f"{{{TNS}}}Delete": DELETE,
}
def __init__(self, *args, **kwargs):
@@ -60,22 +60,22 @@ Module exchangelib.services.sync_folder_hierarchy
super().__init__(*args, **kwargs)
def _get_element_container(self, message, name=None):
- self.sync_state = message.find(f'{{{MNS}}}SyncState').text
- log.debug('Sync state is: %s', self.sync_state)
- self.includes_last_item_in_range = xml_text_to_value(
- message.find(self.last_in_range_name).text, bool
- )
- log.debug('Includes last item in range: %s', self.includes_last_item_in_range)
+ self.sync_state = message.find(f"{{{MNS}}}SyncState").text
+ log.debug("Sync state is: %s", self.sync_state)
+ self.includes_last_item_in_range = xml_text_to_value(message.find(self.last_in_range_name).text, bool)
+ log.debug("Includes last item in range: %s", self.includes_last_item_in_range)
return super()._get_element_container(message=message, name=name)
def _partial_get_payload(self, folder, shape, additional_fields, sync_state):
- payload = create_element(f'm:{self.SERVICE_NAME}')
- payload.append(shape_element(
- tag=self.shape_tag, shape=shape, additional_fields=additional_fields, version=self.account.version
- ))
- payload.append(folder_ids_element(folders=[folder], version=self.account.version, tag='m:SyncFolderId'))
+ payload = create_element(f"m:{self.SERVICE_NAME}")
+ payload.append(
+ shape_element(
+ tag=self.shape_tag, shape=shape, additional_fields=additional_fields, version=self.account.version
+ )
+ )
+ payload.append(folder_ids_element(folders=[folder], version=self.account.version, tag="m:SyncFolderId"))
if sync_state:
- add_xml_child(payload, 'm:SyncState', sync_state)
+ add_xml_child(payload, "m:SyncState", sync_state)
return payload
@@ -84,9 +84,9 @@ Module exchangelib.services.sync_folder_hierarchy
https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/syncfolderhierarchy-operation
"""
- SERVICE_NAME = 'SyncFolderHierarchy'
- shape_tag = 'm:FolderShape'
- last_in_range_name = f'{{{MNS}}}IncludesLastFolderInRange'
+ SERVICE_NAME = "SyncFolderHierarchy"
+ shape_tag = "m:FolderShape"
+ last_in_range_name = f"{{{MNS}}}IncludesLastFolderInRange"
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
@@ -95,12 +95,16 @@ Module exchangelib.services.sync_folder_hierarchy
def call(self, folder, shape, additional_fields, sync_state):
self.sync_state = sync_state
self.folder = folder
- return self._elems_to_objs(self._get_elements(payload=self.get_payload(
- folder=folder,
- shape=shape,
- additional_fields=additional_fields,
- sync_state=sync_state,
- )))
+ return self._elems_to_objs(
+ self._get_elements(
+ payload=self.get_payload(
+ folder=folder,
+ shape=shape,
+ additional_fields=additional_fields,
+ sync_state=sync_state,
+ )
+ )
+ )
def _elem_to_obj(self, elem):
change_type = self.change_types_map[elem.tag]
@@ -141,18 +145,18 @@ Classes
class SyncFolder(EWSPagingService, metaclass=abc.ABCMeta):
"""Base class for SyncFolderHierarchy and SyncFolderItems."""
- element_container_name = f'{{{MNS}}}Changes'
+ element_container_name = f"{{{MNS}}}Changes"
# Change types
- CREATE = 'create'
- UPDATE = 'update'
- DELETE = 'delete'
+ CREATE = "create"
+ UPDATE = "update"
+ DELETE = "delete"
CHANGE_TYPES = (CREATE, UPDATE, DELETE)
shape_tag = None
last_in_range_name = None
change_types_map = {
- f'{{{TNS}}}Create': CREATE,
- f'{{{TNS}}}Update': UPDATE,
- f'{{{TNS}}}Delete': DELETE,
+ f"{{{TNS}}}Create": CREATE,
+ f"{{{TNS}}}Update": UPDATE,
+ f"{{{TNS}}}Delete": DELETE,
}
def __init__(self, *args, **kwargs):
@@ -162,22 +166,22 @@ Classes
super().__init__(*args, **kwargs)
def _get_element_container(self, message, name=None):
- self.sync_state = message.find(f'{{{MNS}}}SyncState').text
- log.debug('Sync state is: %s', self.sync_state)
- self.includes_last_item_in_range = xml_text_to_value(
- message.find(self.last_in_range_name).text, bool
- )
- log.debug('Includes last item in range: %s', self.includes_last_item_in_range)
+ self.sync_state = message.find(f"{{{MNS}}}SyncState").text
+ log.debug("Sync state is: %s", self.sync_state)
+ self.includes_last_item_in_range = xml_text_to_value(message.find(self.last_in_range_name).text, bool)
+ log.debug("Includes last item in range: %s", self.includes_last_item_in_range)
return super()._get_element_container(message=message, name=name)
def _partial_get_payload(self, folder, shape, additional_fields, sync_state):
- payload = create_element(f'm:{self.SERVICE_NAME}')
- payload.append(shape_element(
- tag=self.shape_tag, shape=shape, additional_fields=additional_fields, version=self.account.version
- ))
- payload.append(folder_ids_element(folders=[folder], version=self.account.version, tag='m:SyncFolderId'))
+ payload = create_element(f"m:{self.SERVICE_NAME}")
+ payload.append(
+ shape_element(
+ tag=self.shape_tag, shape=shape, additional_fields=additional_fields, version=self.account.version
+ )
+ )
+ payload.append(folder_ids_element(folders=[folder], version=self.account.version, tag="m:SyncFolderId"))
if sync_state:
- add_xml_child(payload, 'm:SyncState', sync_state)
+ add_xml_child(payload, "m:SyncState", sync_state)
return payload
Ancestors
@@ -254,9 +258,9 @@ Inherited members
https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/syncfolderhierarchy-operation
"""
- SERVICE_NAME = 'SyncFolderHierarchy'
- shape_tag = 'm:FolderShape'
- last_in_range_name = f'{{{MNS}}}IncludesLastFolderInRange'
+ SERVICE_NAME = "SyncFolderHierarchy"
+ shape_tag = "m:FolderShape"
+ last_in_range_name = f"{{{MNS}}}IncludesLastFolderInRange"
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
@@ -265,12 +269,16 @@ Inherited members
def call(self, folder, shape, additional_fields, sync_state):
self.sync_state = sync_state
self.folder = folder
- return self._elems_to_objs(self._get_elements(payload=self.get_payload(
- folder=folder,
- shape=shape,
- additional_fields=additional_fields,
- sync_state=sync_state,
- )))
+ return self._elems_to_objs(
+ self._get_elements(
+ payload=self.get_payload(
+ folder=folder,
+ shape=shape,
+ additional_fields=additional_fields,
+ sync_state=sync_state,
+ )
+ )
+ )
def _elem_to_obj(self, elem):
change_type = self.change_types_map[elem.tag]
@@ -324,12 +332,16 @@ Methods
def call(self, folder, shape, additional_fields, sync_state):
self.sync_state = sync_state
self.folder = folder
- return self._elems_to_objs(self._get_elements(payload=self.get_payload(
- folder=folder,
- shape=shape,
- additional_fields=additional_fields,
- sync_state=sync_state,
- )))
+ return self._elems_to_objs(
+ self._get_elements(
+ payload=self.get_payload(
+ folder=folder,
+ shape=shape,
+ additional_fields=additional_fields,
+ sync_state=sync_state,
+ )
+ )
+ )
diff --git a/docs/exchangelib/services/sync_folder_items.html b/docs/exchangelib/services/sync_folder_items.html
index 8804be99..ba9c103a 100644
--- a/docs/exchangelib/services/sync_folder_items.html
+++ b/docs/exchangelib/services/sync_folder_items.html
@@ -26,12 +26,12 @@ Module exchangelib.services.sync_folder_items
Expand source code
-from .common import add_xml_child, item_ids_element
-from .sync_folder_hierarchy import SyncFolder
-from ..errors import InvalidEnumValue, InvalidTypeError
+from ..errors import InvalidEnumValue, InvalidTypeError
from ..folders import BaseFolder
from ..properties import ItemId
-from ..util import xml_text_to_value, peek, TNS, MNS
+from ..util import MNS, TNS, peek, xml_text_to_value
+from .common import add_xml_child, item_ids_element
+from .sync_folder_hierarchy import SyncFolder
class SyncFolderItems(SyncFolder):
@@ -39,45 +39,49 @@ Module exchangelib.services.sync_folder_items
Module exchangelib.services.sync_folder_items
@@ -126,45 +130,49 @@ Classes
https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/syncfolderitems-operation
"""
- SERVICE_NAME = 'SyncFolderItems'
+ SERVICE_NAME = "SyncFolderItems"
SYNC_SCOPES = (
- 'NormalItems',
- 'NormalAndAssociatedItems',
+ "NormalItems",
+ "NormalAndAssociatedItems",
)
# Extra change type
- READ_FLAG_CHANGE = 'read_flag_change'
+ READ_FLAG_CHANGE = "read_flag_change"
CHANGE_TYPES = SyncFolder.CHANGE_TYPES + (READ_FLAG_CHANGE,)
- shape_tag = 'm:ItemShape'
- last_in_range_name = f'{{{MNS}}}IncludesLastItemInRange'
+ shape_tag = "m:ItemShape"
+ last_in_range_name = f"{{{MNS}}}IncludesLastItemInRange"
change_types_map = SyncFolder.change_types_map
- change_types_map[f'{{{TNS}}}ReadFlagChange'] = READ_FLAG_CHANGE
+ change_types_map[f"{{{TNS}}}ReadFlagChange"] = READ_FLAG_CHANGE
def call(self, folder, shape, additional_fields, sync_state, ignore, max_changes_returned, sync_scope):
self.sync_state = sync_state
if max_changes_returned is None:
max_changes_returned = self.page_size
if not isinstance(max_changes_returned, int):
- raise InvalidTypeError('max_changes_returned', max_changes_returned, int)
+ raise InvalidTypeError("max_changes_returned", max_changes_returned, int)
if max_changes_returned <= 0:
raise ValueError(f"'max_changes_returned' {max_changes_returned} must be a positive integer")
if sync_scope is not None and sync_scope not in self.SYNC_SCOPES:
- raise InvalidEnumValue('sync_scope', sync_scope, self.SYNC_SCOPES)
- return self._elems_to_objs(self._get_elements(payload=self.get_payload(
- folder=folder,
- shape=shape,
- additional_fields=additional_fields,
- sync_state=sync_state,
- ignore=ignore,
- max_changes_returned=max_changes_returned,
- sync_scope=sync_scope,
- )))
+ raise InvalidEnumValue("sync_scope", sync_scope, self.SYNC_SCOPES)
+ return self._elems_to_objs(
+ self._get_elements(
+ payload=self.get_payload(
+ folder=folder,
+ shape=shape,
+ additional_fields=additional_fields,
+ sync_state=sync_state,
+ ignore=ignore,
+ max_changes_returned=max_changes_returned,
+ sync_scope=sync_scope,
+ )
+ )
+ )
def _elem_to_obj(self, elem):
change_type = self.change_types_map[elem.tag]
if change_type == self.READ_FLAG_CHANGE:
item = (
ItemId.from_xml(elem=elem.find(ItemId.response_tag()), account=self.account),
- xml_text_to_value(elem.find(f'{{{TNS}}}IsRead').text, bool)
+ xml_text_to_value(elem.find(f"{{{TNS}}}IsRead").text, bool),
)
elif change_type == self.DELETE:
item = ItemId.from_xml(elem=elem.find(ItemId.response_tag()), account=self.account)
@@ -181,10 +189,10 @@ Classes
)
is_empty, ignore = (True, None) if ignore is None else peek(ignore)
if not is_empty:
- sync_folder_items.append(item_ids_element(items=ignore, version=self.account.version, tag='m:Ignore'))
- add_xml_child(sync_folder_items, 'm:MaxChangesReturned', max_changes_returned)
+ sync_folder_items.append(item_ids_element(items=ignore, version=self.account.version, tag="m:Ignore"))
+ add_xml_child(sync_folder_items, "m:MaxChangesReturned", max_changes_returned)
if sync_scope:
- add_xml_child(sync_folder_items, 'm:SyncScope', sync_scope)
+ add_xml_child(sync_folder_items, "m:SyncScope", sync_scope)
return sync_folder_items
@@ -272,10 +284,10 @@ Methods
)
is_empty, ignore = (True, None) if ignore is None else peek(ignore)
if not is_empty:
- sync_folder_items.append(item_ids_element(items=ignore, version=self.account.version, tag='m:Ignore'))
- add_xml_child(sync_folder_items, 'm:MaxChangesReturned', max_changes_returned)
+ sync_folder_items.append(item_ids_element(items=ignore, version=self.account.version, tag="m:Ignore"))
+ add_xml_child(sync_folder_items, "m:MaxChangesReturned", max_changes_returned)
if sync_scope:
- add_xml_child(sync_folder_items, 'm:SyncScope', sync_scope)
+ add_xml_child(sync_folder_items, "m:SyncScope", sync_scope)
return sync_folder_items
diff --git a/docs/exchangelib/services/unsubscribe.html b/docs/exchangelib/services/unsubscribe.html
index 707171c5..aa7ebb88 100644
--- a/docs/exchangelib/services/unsubscribe.html
+++ b/docs/exchangelib/services/unsubscribe.html
@@ -26,8 +26,8 @@ exchangelib.services.unsubscribe
from .common import EWSAccountService, add_xml_child
-from ..util import create_element
+from ..util import create_element
+from .common import EWSAccountService, add_xml_child
class Unsubscribe(EWSAccountService):
@@ -36,7 +36,7 @@ Module exchangelib.services.unsubscribe
MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/unsubscribe-operation
"""
- SERVICE_NAME = 'Unsubscribe'
+ SERVICE_NAME = "Unsubscribe"
returns_elements = False
prefer_affinity = True
@@ -44,8 +44,8 @@ Module exchangelib.services.unsubscribe
return self._get_elements(payload=self.get_payload(subscription_id=subscription_id))
def get_payload(self, subscription_id):
- payload = create_element(f'm:{self.SERVICE_NAME}')
- add_xml_child(payload, 'm:SubscriptionId', subscription_id)
+ payload = create_element(f"m:{self.SERVICE_NAME}")
+ add_xml_child(payload, "m:SubscriptionId", subscription_id)
return payload
@@ -75,7 +75,7 @@ Classes
MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/unsubscribe-operation
"""
- SERVICE_NAME = 'Unsubscribe'
+ SERVICE_NAME = "Unsubscribe"
returns_elements = False
prefer_affinity = True
@@ -83,8 +83,8 @@ Classes
return self._get_elements(payload=self.get_payload(subscription_id=subscription_id))
def get_payload(self, subscription_id):
- payload = create_element(f'm:{self.SERVICE_NAME}')
- add_xml_child(payload, 'm:SubscriptionId', subscription_id)
+ payload = create_element(f"m:{self.SERVICE_NAME}")
+ add_xml_child(payload, "m:SubscriptionId", subscription_id)
return payload
def get_payload(self, subscription_id):
- payload = create_element(f'm:{self.SERVICE_NAME}')
- add_xml_child(payload, 'm:SubscriptionId', subscription_id)
+ payload = create_element(f"m:{self.SERVICE_NAME}")
+ add_xml_child(payload, "m:SubscriptionId", subscription_id)
return payload
diff --git a/docs/exchangelib/services/update_folder.html b/docs/exchangelib/services/update_folder.html
index 81183325..82b98424 100644
--- a/docs/exchangelib/services/update_folder.html
+++ b/docs/exchangelib/services/update_folder.html
@@ -28,14 +28,15 @@ exchangelib.services.update_folder
import abc
-from .common import EWSAccountService, parse_folder_elem, to_item_id
from ..fields import FieldPath, IndexedField
from ..properties import FolderId
-from ..util import create_element, set_xml_value, MNS
+from ..util import MNS, create_element, set_xml_value
+from .common import EWSAccountService, parse_folder_elem, to_item_id
class BaseUpdateService(EWSAccountService, metaclass=abc.ABCMeta):
"""Base class for UpdateFolder and UpdateItem"""
+
SET_FIELD_ELEMENT_NAME = None
DELETE_FIELD_ELEMENT_NAME = None
CHANGE_ELEMENT_NAME = None
@@ -60,8 +61,9 @@ Module exchangelib.services.update_folder
def _set_field_elems(self, target_model, field, value):
if isinstance(field, IndexedField):
# Generate either set or delete elements for all combinations of labels and subfields
- supported_labels = field.value_cls.get_field_by_fieldname('label')\
- .supported_choices(version=self.account.version)
+ supported_labels = field.value_cls.get_field_by_fieldname("label").supported_choices(
+ version=self.account.version
+ )
seen_labels = set()
subfields = field.value_cls.supported_fields(version=self.account.version)
for v in value:
@@ -77,7 +79,7 @@ Module exchangelib.services.update_folder
yield self._set_field_elem(
target_model=target_model,
field_path=field_path,
- value=field.value_cls(**{'label': v.label, subfield.name: subfield_value}),
+ value=field.value_cls(**{"label": v.label, subfield.name: subfield_value}),
)
# Generate delete elements for all subfields of all labels not mentioned in the list of values
for label in (label for label in supported_labels if label not in seen_labels):
@@ -108,13 +110,13 @@ Module exchangelib.services.update_folder
for field in self._sorted_fields(target_model=target_model, fieldnames=fieldnames):
if field.is_read_only:
- raise ValueError(f'{field.name!r} is a read-only field')
+ raise ValueError(f"{field.name!r} is a read-only field")
value = self._get_value(target, field)
if value is None or (field.is_list and not value):
# A value of None or [] means we want to remove this field from the item
if field.is_required or field.is_required_after_save:
- raise ValueError(f'{field.name!r} is a required field and may not be deleted')
+ raise ValueError(f"{field.name!r} is a required field and may not be deleted")
yield from self._delete_field_elems(field)
continue
@@ -125,7 +127,7 @@ Module exchangelib.services.update_folder
raise ValueError("'fieldnames' must not be empty")
change = create_element(self.CHANGE_ELEMENT_NAME)
set_xml_value(change, self._target_elem(target), version=self.account.version)
- updates = create_element('t:Updates')
+ updates = create_element("t:Updates")
for elem in self._update_elems(target=target, fieldnames=fieldnames):
updates.append(elem)
change.append(updates)
@@ -147,12 +149,12 @@ Module exchangelib.services.update_folder
class UpdateFolder(BaseUpdateService):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/updatefolder-operation"""
- SERVICE_NAME = 'UpdateFolder'
- SET_FIELD_ELEMENT_NAME = 't:SetFolderField'
- DELETE_FIELD_ELEMENT_NAME = 't:DeleteFolderField'
- CHANGE_ELEMENT_NAME = 't:FolderChange'
- CHANGES_ELEMENT_NAME = 'm:FolderChanges'
- element_container_name = f'{{{MNS}}}Folders'
+ SERVICE_NAME = "UpdateFolder"
+ SET_FIELD_ELEMENT_NAME = "t:SetFolderField"
+ DELETE_FIELD_ELEMENT_NAME = "t:DeleteFolderField"
+ CHANGE_ELEMENT_NAME = "t:FolderChange"
+ CHANGES_ELEMENT_NAME = "m:FolderChanges"
+ element_container_name = f"{{{MNS}}}Folders"
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
@@ -177,7 +179,7 @@ Module exchangelib.services.update_folder
def get_payload(self, folders):
# Takes a list of (Folder, fieldnames) tuples where 'Folder' is a instance of a subclass of Folder and
# 'fieldnames' are the attribute names that were updated.
- payload = create_element(f'm:{self.SERVICE_NAME}')
+ payload = create_element(f"m:{self.SERVICE_NAME}")
payload.append(self._changes_elem(target_changes=folders))
return payload
@@ -203,6 +205,7 @@ class BaseUpdateService(EWSAccountService, metaclass=abc.ABCMeta):
"""Base class for UpdateFolder and UpdateItem"""
+
SET_FIELD_ELEMENT_NAME = None
DELETE_FIELD_ELEMENT_NAME = None
CHANGE_ELEMENT_NAME = None
@@ -227,8 +230,9 @@ Classes
def _set_field_elems(self, target_model, field, value):
if isinstance(field, IndexedField):
# Generate either set or delete elements for all combinations of labels and subfields
- supported_labels = field.value_cls.get_field_by_fieldname('label')\
- .supported_choices(version=self.account.version)
+ supported_labels = field.value_cls.get_field_by_fieldname("label").supported_choices(
+ version=self.account.version
+ )
seen_labels = set()
subfields = field.value_cls.supported_fields(version=self.account.version)
for v in value:
@@ -244,7 +248,7 @@ Classes
yield self._set_field_elem(
target_model=target_model,
field_path=field_path,
- value=field.value_cls(**{'label': v.label, subfield.name: subfield_value}),
+ value=field.value_cls(**{"label": v.label, subfield.name: subfield_value}),
)
# Generate delete elements for all subfields of all labels not mentioned in the list of values
for label in (label for label in supported_labels if label not in seen_labels):
@@ -275,13 +279,13 @@ Classes
for field in self._sorted_fields(target_model=target_model, fieldnames=fieldnames):
if field.is_read_only:
- raise ValueError(f'{field.name!r} is a read-only field')
+ raise ValueError(f"{field.name!r} is a read-only field")
value = self._get_value(target, field)
if value is None or (field.is_list and not value):
# A value of None or [] means we want to remove this field from the item
if field.is_required or field.is_required_after_save:
- raise ValueError(f'{field.name!r} is a required field and may not be deleted')
+ raise ValueError(f"{field.name!r} is a required field and may not be deleted")
yield from self._delete_field_elems(field)
continue
@@ -292,7 +296,7 @@ Classes
raise ValueError("'fieldnames' must not be empty")
change = create_element(self.CHANGE_ELEMENT_NAME)
set_xml_value(change, self._target_elem(target), version=self.account.version)
- updates = create_element('t:Updates')
+ updates = create_element("t:Updates")
for elem in self._update_elems(target=target, fieldnames=fieldnames):
updates.append(elem)
change.append(updates)
@@ -364,12 +368,12 @@ Inherited members
class UpdateFolder(BaseUpdateService):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/updatefolder-operation"""
- SERVICE_NAME = 'UpdateFolder'
- SET_FIELD_ELEMENT_NAME = 't:SetFolderField'
- DELETE_FIELD_ELEMENT_NAME = 't:DeleteFolderField'
- CHANGE_ELEMENT_NAME = 't:FolderChange'
- CHANGES_ELEMENT_NAME = 'm:FolderChanges'
- element_container_name = f'{{{MNS}}}Folders'
+ SERVICE_NAME = "UpdateFolder"
+ SET_FIELD_ELEMENT_NAME = "t:SetFolderField"
+ DELETE_FIELD_ELEMENT_NAME = "t:DeleteFolderField"
+ CHANGE_ELEMENT_NAME = "t:FolderChange"
+ CHANGES_ELEMENT_NAME = "m:FolderChanges"
+ element_container_name = f"{{{MNS}}}Folders"
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
@@ -394,7 +398,7 @@ Inherited members
def get_payload(self, folders):
# Takes a list of (Folder, fieldnames) tuples where 'Folder' is a instance of a subclass of Folder and
# 'fieldnames' are the attribute names that were updated.
- payload = create_element(f'm:{self.SERVICE_NAME}')
+ payload = create_element(f"m:{self.SERVICE_NAME}")
payload.append(self._changes_elem(target_changes=folders))
return payload
@@ -461,7 +465,7 @@ Methods
def get_payload(self, folders):
# Takes a list of (Folder, fieldnames) tuples where 'Folder' is a instance of a subclass of Folder and
# 'fieldnames' are the attribute names that were updated.
- payload = create_element(f'm:{self.SERVICE_NAME}')
+ payload = create_element(f"m:{self.SERVICE_NAME}")
payload.append(self._changes_elem(target_changes=folders))
return payload
diff --git a/docs/exchangelib/services/update_item.html b/docs/exchangelib/services/update_item.html
index 7f22eb3f..53a75279 100644
--- a/docs/exchangelib/services/update_item.html
+++ b/docs/exchangelib/services/update_item.html
@@ -26,48 +26,63 @@ Module exchangelib.services.update_item
Expand source code
-from .common import to_item_id
-from ..errors import InvalidEnumValue
+from ..errors import InvalidEnumValue
from ..ewsdatetime import EWSDate
-from ..items import CONFLICT_RESOLUTION_CHOICES, MESSAGE_DISPOSITION_CHOICES, \
- SEND_MEETING_INVITATIONS_AND_CANCELLATIONS_CHOICES, SEND_ONLY, Item, CalendarItem
+from ..items import (
+ CONFLICT_RESOLUTION_CHOICES,
+ MESSAGE_DISPOSITION_CHOICES,
+ SEND_MEETING_INVITATIONS_AND_CANCELLATIONS_CHOICES,
+ SEND_ONLY,
+ CalendarItem,
+ Item,
+)
from ..properties import ItemId
-from ..util import create_element, MNS
+from ..util import MNS, create_element
from ..version import EXCHANGE_2013_SP1
+from .common import to_item_id
from .update_folder import BaseUpdateService
class UpdateItem(BaseUpdateService):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/updateitem-operation"""
- SERVICE_NAME = 'UpdateItem'
- SET_FIELD_ELEMENT_NAME = 't:SetItemField'
- DELETE_FIELD_ELEMENT_NAME = 't:DeleteItemField'
- CHANGE_ELEMENT_NAME = 't:ItemChange'
- CHANGES_ELEMENT_NAME = 'm:ItemChanges'
- element_container_name = f'{{{MNS}}}Items'
+ SERVICE_NAME = "UpdateItem"
+ SET_FIELD_ELEMENT_NAME = "t:SetItemField"
+ DELETE_FIELD_ELEMENT_NAME = "t:DeleteItemField"
+ CHANGE_ELEMENT_NAME = "t:ItemChange"
+ CHANGES_ELEMENT_NAME = "m:ItemChanges"
+ element_container_name = f"{{{MNS}}}Items"
- def call(self, items, conflict_resolution, message_disposition, send_meeting_invitations_or_cancellations,
- suppress_read_receipts):
+ def call(
+ self,
+ items,
+ conflict_resolution,
+ message_disposition,
+ send_meeting_invitations_or_cancellations,
+ suppress_read_receipts,
+ ):
if conflict_resolution not in CONFLICT_RESOLUTION_CHOICES:
- raise InvalidEnumValue('conflict_resolution', conflict_resolution, CONFLICT_RESOLUTION_CHOICES)
+ raise InvalidEnumValue("conflict_resolution", conflict_resolution, CONFLICT_RESOLUTION_CHOICES)
if message_disposition not in MESSAGE_DISPOSITION_CHOICES:
- raise InvalidEnumValue('message_disposition', message_disposition, MESSAGE_DISPOSITION_CHOICES)
+ raise InvalidEnumValue("message_disposition", message_disposition, MESSAGE_DISPOSITION_CHOICES)
if send_meeting_invitations_or_cancellations not in SEND_MEETING_INVITATIONS_AND_CANCELLATIONS_CHOICES:
raise InvalidEnumValue(
- 'send_meeting_invitations_or_cancellations', send_meeting_invitations_or_cancellations,
- SEND_MEETING_INVITATIONS_AND_CANCELLATIONS_CHOICES
+ "send_meeting_invitations_or_cancellations",
+ send_meeting_invitations_or_cancellations,
+ SEND_MEETING_INVITATIONS_AND_CANCELLATIONS_CHOICES,
)
if message_disposition == SEND_ONLY:
- raise ValueError('Cannot send-only existing objects. Use SendItem service instead')
- return self._elems_to_objs(self._chunked_get_elements(
- self.get_payload,
- items=items,
- conflict_resolution=conflict_resolution,
- message_disposition=message_disposition,
- send_meeting_invitations_or_cancellations=send_meeting_invitations_or_cancellations,
- suppress_read_receipts=suppress_read_receipts,
- ))
+ raise ValueError("Cannot send-only existing objects. Use SendItem service instead")
+ return self._elems_to_objs(
+ self._chunked_get_elements(
+ self.get_payload,
+ items=items,
+ conflict_resolution=conflict_resolution,
+ message_disposition=message_disposition,
+ send_meeting_invitations_or_cancellations=send_meeting_invitations_or_cancellations,
+ suppress_read_receipts=suppress_read_receipts,
+ )
+ )
def _elem_to_obj(self, elem):
return Item.id_from_xml(elem)
@@ -78,7 +93,7 @@ Module exchangelib.services.update_item
if target.__class__ == CalendarItem:
# For CalendarItem items where we update 'start' or 'end', we want to update internal timezone fields
target.clean_timezone_fields(version=self.account.version) # Possibly also sets timezone values
- for field_name in ('start', 'end'):
+ for field_name in ("start", "end"):
if field_name in fieldnames_copy:
tz_field_name = target.tz_field_for_field_name(field_name).name
if tz_field_name not in fieldnames_copy:
@@ -91,7 +106,7 @@ Module exchangelib.services.update_item
if target.__class__ == CalendarItem:
# For CalendarItem items where we update 'start' or 'end', we want to send values in the local timezone
- if field.name in ('start', 'end'):
+ if field.name in ("start", "end"):
if type(value) is EWSDate:
# EWS always expects a datetime
return target.date_to_datetime(field_name=field.name)
@@ -103,8 +118,14 @@ Module exchangelib.services.update_item
def _target_elem(self, target):
return to_item_id(target, ItemId)
- def get_payload(self, items, conflict_resolution, message_disposition, send_meeting_invitations_or_cancellations,
- suppress_read_receipts):
+ def get_payload(
+ self,
+ items,
+ conflict_resolution,
+ message_disposition,
+ send_meeting_invitations_or_cancellations,
+ suppress_read_receipts,
+ ):
# Takes a list of (Item, fieldnames) tuples where 'Item' is a instance of a subclass of Item and 'fieldnames'
# are the attribute names that were updated.
attrs = dict(
@@ -113,8 +134,8 @@ Module exchangelib.services.update_item
SendMeetingInvitationsOrCancellations=send_meeting_invitations_or_cancellations,
)
if self.account.version.build >= EXCHANGE_2013_SP1:
- attrs['SuppressReadReceipts'] = suppress_read_receipts
- payload = create_element(f'm:{self.SERVICE_NAME}', attrs=attrs)
+ attrs["SuppressReadReceipts"] = suppress_read_receipts
+ payload = create_element(f"m:{self.SERVICE_NAME}", attrs=attrs)
payload.append(self._changes_elem(target_changes=items))
return payload
@@ -141,34 +162,43 @@ Classes
class UpdateItem(BaseUpdateService):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/updateitem-operation"""
- SERVICE_NAME = 'UpdateItem'
- SET_FIELD_ELEMENT_NAME = 't:SetItemField'
- DELETE_FIELD_ELEMENT_NAME = 't:DeleteItemField'
- CHANGE_ELEMENT_NAME = 't:ItemChange'
- CHANGES_ELEMENT_NAME = 'm:ItemChanges'
- element_container_name = f'{{{MNS}}}Items'
+ SERVICE_NAME = "UpdateItem"
+ SET_FIELD_ELEMENT_NAME = "t:SetItemField"
+ DELETE_FIELD_ELEMENT_NAME = "t:DeleteItemField"
+ CHANGE_ELEMENT_NAME = "t:ItemChange"
+ CHANGES_ELEMENT_NAME = "m:ItemChanges"
+ element_container_name = f"{{{MNS}}}Items"
- def call(self, items, conflict_resolution, message_disposition, send_meeting_invitations_or_cancellations,
- suppress_read_receipts):
+ def call(
+ self,
+ items,
+ conflict_resolution,
+ message_disposition,
+ send_meeting_invitations_or_cancellations,
+ suppress_read_receipts,
+ ):
if conflict_resolution not in CONFLICT_RESOLUTION_CHOICES:
- raise InvalidEnumValue('conflict_resolution', conflict_resolution, CONFLICT_RESOLUTION_CHOICES)
+ raise InvalidEnumValue("conflict_resolution", conflict_resolution, CONFLICT_RESOLUTION_CHOICES)
if message_disposition not in MESSAGE_DISPOSITION_CHOICES:
- raise InvalidEnumValue('message_disposition', message_disposition, MESSAGE_DISPOSITION_CHOICES)
+ raise InvalidEnumValue("message_disposition", message_disposition, MESSAGE_DISPOSITION_CHOICES)
if send_meeting_invitations_or_cancellations not in SEND_MEETING_INVITATIONS_AND_CANCELLATIONS_CHOICES:
raise InvalidEnumValue(
- 'send_meeting_invitations_or_cancellations', send_meeting_invitations_or_cancellations,
- SEND_MEETING_INVITATIONS_AND_CANCELLATIONS_CHOICES
+ "send_meeting_invitations_or_cancellations",
+ send_meeting_invitations_or_cancellations,
+ SEND_MEETING_INVITATIONS_AND_CANCELLATIONS_CHOICES,
)
if message_disposition == SEND_ONLY:
- raise ValueError('Cannot send-only existing objects. Use SendItem service instead')
- return self._elems_to_objs(self._chunked_get_elements(
- self.get_payload,
- items=items,
- conflict_resolution=conflict_resolution,
- message_disposition=message_disposition,
- send_meeting_invitations_or_cancellations=send_meeting_invitations_or_cancellations,
- suppress_read_receipts=suppress_read_receipts,
- ))
+ raise ValueError("Cannot send-only existing objects. Use SendItem service instead")
+ return self._elems_to_objs(
+ self._chunked_get_elements(
+ self.get_payload,
+ items=items,
+ conflict_resolution=conflict_resolution,
+ message_disposition=message_disposition,
+ send_meeting_invitations_or_cancellations=send_meeting_invitations_or_cancellations,
+ suppress_read_receipts=suppress_read_receipts,
+ )
+ )
def _elem_to_obj(self, elem):
return Item.id_from_xml(elem)
@@ -179,7 +209,7 @@ Classes
if target.__class__ == CalendarItem:
# For CalendarItem items where we update 'start' or 'end', we want to update internal timezone fields
target.clean_timezone_fields(version=self.account.version) # Possibly also sets timezone values
- for field_name in ('start', 'end'):
+ for field_name in ("start", "end"):
if field_name in fieldnames_copy:
tz_field_name = target.tz_field_for_field_name(field_name).name
if tz_field_name not in fieldnames_copy:
@@ -192,7 +222,7 @@ Classes
if target.__class__ == CalendarItem:
# For CalendarItem items where we update 'start' or 'end', we want to send values in the local timezone
- if field.name in ('start', 'end'):
+ if field.name in ("start", "end"):
if type(value) is EWSDate:
# EWS always expects a datetime
return target.date_to_datetime(field_name=field.name)
@@ -204,8 +234,14 @@ Classes
def _target_elem(self, target):
return to_item_id(target, ItemId)
- def get_payload(self, items, conflict_resolution, message_disposition, send_meeting_invitations_or_cancellations,
- suppress_read_receipts):
+ def get_payload(
+ self,
+ items,
+ conflict_resolution,
+ message_disposition,
+ send_meeting_invitations_or_cancellations,
+ suppress_read_receipts,
+ ):
# Takes a list of (Item, fieldnames) tuples where 'Item' is a instance of a subclass of Item and 'fieldnames'
# are the attribute names that were updated.
attrs = dict(
@@ -214,8 +250,8 @@ Classes
SendMeetingInvitationsOrCancellations=send_meeting_invitations_or_cancellations,
)
if self.account.version.build >= EXCHANGE_2013_SP1:
- attrs['SuppressReadReceipts'] = suppress_read_receipts
- payload = create_element(f'm:{self.SERVICE_NAME}', attrs=attrs)
+ attrs["SuppressReadReceipts"] = suppress_read_receipts
+ payload = create_element(f"m:{self.SERVICE_NAME}", attrs=attrs)
payload.append(self._changes_elem(target_changes=items))
return payload
@@ -263,27 +299,36 @@ Methods
Expand source code
-def call(self, items, conflict_resolution, message_disposition, send_meeting_invitations_or_cancellations,
- suppress_read_receipts):
+def call(
+ self,
+ items,
+ conflict_resolution,
+ message_disposition,
+ send_meeting_invitations_or_cancellations,
+ suppress_read_receipts,
+):
if conflict_resolution not in CONFLICT_RESOLUTION_CHOICES:
- raise InvalidEnumValue('conflict_resolution', conflict_resolution, CONFLICT_RESOLUTION_CHOICES)
+ raise InvalidEnumValue("conflict_resolution", conflict_resolution, CONFLICT_RESOLUTION_CHOICES)
if message_disposition not in MESSAGE_DISPOSITION_CHOICES:
- raise InvalidEnumValue('message_disposition', message_disposition, MESSAGE_DISPOSITION_CHOICES)
+ raise InvalidEnumValue("message_disposition", message_disposition, MESSAGE_DISPOSITION_CHOICES)
if send_meeting_invitations_or_cancellations not in SEND_MEETING_INVITATIONS_AND_CANCELLATIONS_CHOICES:
raise InvalidEnumValue(
- 'send_meeting_invitations_or_cancellations', send_meeting_invitations_or_cancellations,
- SEND_MEETING_INVITATIONS_AND_CANCELLATIONS_CHOICES
+ "send_meeting_invitations_or_cancellations",
+ send_meeting_invitations_or_cancellations,
+ SEND_MEETING_INVITATIONS_AND_CANCELLATIONS_CHOICES,
)
if message_disposition == SEND_ONLY:
- raise ValueError('Cannot send-only existing objects. Use SendItem service instead')
- return self._elems_to_objs(self._chunked_get_elements(
- self.get_payload,
- items=items,
- conflict_resolution=conflict_resolution,
- message_disposition=message_disposition,
- send_meeting_invitations_or_cancellations=send_meeting_invitations_or_cancellations,
- suppress_read_receipts=suppress_read_receipts,
- ))
+ raise ValueError("Cannot send-only existing objects. Use SendItem service instead")
+ return self._elems_to_objs(
+ self._chunked_get_elements(
+ self.get_payload,
+ items=items,
+ conflict_resolution=conflict_resolution,
+ message_disposition=message_disposition,
+ send_meeting_invitations_or_cancellations=send_meeting_invitations_or_cancellations,
+ suppress_read_receipts=suppress_read_receipts,
+ )
+ )
@@ -295,8 +340,14 @@ Methods
Expand source code
-def get_payload(self, items, conflict_resolution, message_disposition, send_meeting_invitations_or_cancellations,
- suppress_read_receipts):
+def get_payload(
+ self,
+ items,
+ conflict_resolution,
+ message_disposition,
+ send_meeting_invitations_or_cancellations,
+ suppress_read_receipts,
+):
# Takes a list of (Item, fieldnames) tuples where 'Item' is a instance of a subclass of Item and 'fieldnames'
# are the attribute names that were updated.
attrs = dict(
@@ -305,8 +356,8 @@ Methods
SendMeetingInvitationsOrCancellations=send_meeting_invitations_or_cancellations,
)
if self.account.version.build >= EXCHANGE_2013_SP1:
- attrs['SuppressReadReceipts'] = suppress_read_receipts
- payload = create_element(f'm:{self.SERVICE_NAME}', attrs=attrs)
+ attrs["SuppressReadReceipts"] = suppress_read_receipts
+ payload = create_element(f"m:{self.SERVICE_NAME}", attrs=attrs)
payload.append(self._changes_elem(target_changes=items))
return payload
diff --git a/docs/exchangelib/services/update_user_configuration.html b/docs/exchangelib/services/update_user_configuration.html
index c7bbfb11..2e2747df 100644
--- a/docs/exchangelib/services/update_user_configuration.html
+++ b/docs/exchangelib/services/update_user_configuration.html
@@ -26,8 +26,8 @@ Module exchangelib.services.update_user_configuration
Expand source code
-from .common import EWSAccountService
-from ..util import create_element, set_xml_value
+from ..util import create_element, set_xml_value
+from .common import EWSAccountService
class UpdateUserConfiguration(EWSAccountService):
@@ -35,14 +35,14 @@ Module exchangelib.services.update_user_configuration
+ return set_xml_value(create_element(f"m:{self.SERVICE_NAME}"), user_configuration, version=self.account.version)
@@ -70,14 +70,14 @@ Classes
https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/updateuserconfiguration-operation
"""
- SERVICE_NAME = 'UpdateUserConfiguration'
+ SERVICE_NAME = "UpdateUserConfiguration"
returns_elements = False
def call(self, user_configuration):
return self._get_elements(payload=self.get_payload(user_configuration=user_configuration))
def get_payload(self, user_configuration):
- return set_xml_value(create_element(f'm:{self.SERVICE_NAME}'), user_configuration, version=self.account.version)
+ return set_xml_value(create_element(f"m:{self.SERVICE_NAME}"), user_configuration, version=self.account.version)
Ancestors
@@ -120,7 +120,7 @@ Methods
Expand source code
def get_payload(self, user_configuration):
- return set_xml_value(create_element(f'm:{self.SERVICE_NAME}'), user_configuration, version=self.account.version)
+ return set_xml_value(create_element(f"m:{self.SERVICE_NAME}"), user_configuration, version=self.account.version)
diff --git a/docs/exchangelib/services/upload_items.html b/docs/exchangelib/services/upload_items.html
index 8a527c4d..8a53732e 100644
--- a/docs/exchangelib/services/upload_items.html
+++ b/docs/exchangelib/services/upload_items.html
@@ -26,17 +26,16 @@ exchangelib.services.upload_items
from .common import EWSAccountService, to_item_id
-from ..properties import ItemId, ParentFolderId
-from ..util import create_element, set_xml_value, add_xml_child, MNS
+from ..properties import ItemId, ParentFolderId
+from ..util import MNS, add_xml_child, create_element, set_xml_value
+from .common import EWSAccountService, to_item_id
class UploadItems(EWSAccountService):
- """MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/uploaditems-operation
- """
+ """MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/uploaditems-operation"""
- SERVICE_NAME = 'UploadItems'
- element_container_name = f'{{{MNS}}}ItemId'
+ SERVICE_NAME = "UploadItems"
+ element_container_name = f"{{{MNS}}}ItemId"
def call(self, items):
# _pool_requests expects 'items', not 'data'
@@ -52,19 +51,19 @@ Module exchangelib.services.upload_items
:param items:
"""
- payload = create_element(f'm:{self.SERVICE_NAME}')
- items_elem = create_element('m:Items')
+ payload = create_element(f"m:{self.SERVICE_NAME}")
+ items_elem = create_element("m:Items")
payload.append(items_elem)
for parent_folder, (item_id, is_associated, data_str) in items:
# TODO: The full spec also allows the "UpdateOrCreate" create action.
- attrs = dict(CreateAction='Update' if item_id else 'CreateNew')
+ attrs = dict(CreateAction="Update" if item_id else "CreateNew")
if is_associated is not None:
- attrs['IsAssociated'] = is_associated
- item = create_element('t:Item', attrs=attrs)
+ attrs["IsAssociated"] = is_associated
+ item = create_element("t:Item", attrs=attrs)
set_xml_value(item, ParentFolderId(parent_folder.id, parent_folder.changekey), version=self.account.version)
if item_id:
set_xml_value(item, to_item_id(item_id, ItemId), version=self.account.version)
- add_xml_child(item, 't:Data', data_str)
+ add_xml_child(item, "t:Data", data_str)
items_elem.append(item)
return payload
@@ -96,11 +95,10 @@ Classes
Expand source code
class UploadItems(EWSAccountService):
- """MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/uploaditems-operation
- """
+ """MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/uploaditems-operation"""
- SERVICE_NAME = 'UploadItems'
- element_container_name = f'{{{MNS}}}ItemId'
+ SERVICE_NAME = "UploadItems"
+ element_container_name = f"{{{MNS}}}ItemId"
def call(self, items):
# _pool_requests expects 'items', not 'data'
@@ -116,19 +114,19 @@ Classes
:param items:
"""
- payload = create_element(f'm:{self.SERVICE_NAME}')
- items_elem = create_element('m:Items')
+ payload = create_element(f"m:{self.SERVICE_NAME}")
+ items_elem = create_element("m:Items")
payload.append(items_elem)
for parent_folder, (item_id, is_associated, data_str) in items:
# TODO: The full spec also allows the "UpdateOrCreate" create action.
- attrs = dict(CreateAction='Update' if item_id else 'CreateNew')
+ attrs = dict(CreateAction="Update" if item_id else "CreateNew")
if is_associated is not None:
- attrs['IsAssociated'] = is_associated
- item = create_element('t:Item', attrs=attrs)
+ attrs["IsAssociated"] = is_associated
+ item = create_element("t:Item", attrs=attrs)
set_xml_value(item, ParentFolderId(parent_folder.id, parent_folder.changekey), version=self.account.version)
if item_id:
set_xml_value(item, to_item_id(item_id, ItemId), version=self.account.version)
- add_xml_child(item, 't:Data', data_str)
+ add_xml_child(item, "t:Data", data_str)
items_elem.append(item)
return payload
@@ -195,19 +193,19 @@ Methods
:param items:
"""
- payload = create_element(f'm:{self.SERVICE_NAME}')
- items_elem = create_element('m:Items')
+ payload = create_element(f"m:{self.SERVICE_NAME}")
+ items_elem = create_element("m:Items")
payload.append(items_elem)
for parent_folder, (item_id, is_associated, data_str) in items:
# TODO: The full spec also allows the "UpdateOrCreate" create action.
- attrs = dict(CreateAction='Update' if item_id else 'CreateNew')
+ attrs = dict(CreateAction="Update" if item_id else "CreateNew")
if is_associated is not None:
- attrs['IsAssociated'] = is_associated
- item = create_element('t:Item', attrs=attrs)
+ attrs["IsAssociated"] = is_associated
+ item = create_element("t:Item", attrs=attrs)
set_xml_value(item, ParentFolderId(parent_folder.id, parent_folder.changekey), version=self.account.version)
if item_id:
set_xml_value(item, to_item_id(item_id, ItemId), version=self.account.version)
- add_xml_child(item, 't:Data', data_str)
+ add_xml_child(item, "t:Data", data_str)
items_elem.append(item)
return payload
diff --git a/docs/exchangelib/settings.html b/docs/exchangelib/settings.html
index 66bce215..d4bf01e8 100644
--- a/docs/exchangelib/settings.html
+++ b/docs/exchangelib/settings.html
@@ -29,7 +29,7 @@ Module exchangelib.settings
import datetime
from .ewsdatetime import UTC
-from .fields import DateTimeField, MessageField, ChoiceField, Choice
+from .fields import Choice, ChoiceField, DateTimeField, MessageField
from .properties import EWSElement, OutOfOffice
from .util import create_element, set_xml_value
@@ -37,21 +37,22 @@ Module exchangelib.settings
class OofSettings(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/oofsettings"""
- ELEMENT_NAME = 'OofSettings'
- REQUEST_ELEMENT_NAME = 'UserOofSettings'
+ ELEMENT_NAME = "OofSettings"
+ REQUEST_ELEMENT_NAME = "UserOofSettings"
- ENABLED = 'Enabled'
- SCHEDULED = 'Scheduled'
- DISABLED = 'Disabled'
+ ENABLED = "Enabled"
+ SCHEDULED = "Scheduled"
+ DISABLED = "Disabled"
STATE_CHOICES = (ENABLED, SCHEDULED, DISABLED)
- state = ChoiceField(field_uri='OofState', is_required=True, choices={Choice(c) for c in STATE_CHOICES})
- external_audience = ChoiceField(field_uri='ExternalAudience',
- choices={Choice('None'), Choice('Known'), Choice('All')}, default='All')
- start = DateTimeField(field_uri='StartTime')
- end = DateTimeField(field_uri='EndTime')
- internal_reply = MessageField(field_uri='InternalReply')
- external_reply = MessageField(field_uri='ExternalReply')
+ state = ChoiceField(field_uri="OofState", is_required=True, choices={Choice(c) for c in STATE_CHOICES})
+ external_audience = ChoiceField(
+ field_uri="ExternalAudience", choices={Choice("None"), Choice("Known"), Choice("All")}, default="All"
+ )
+ start = DateTimeField(field_uri="StartTime")
+ end = DateTimeField(field_uri="EndTime")
+ internal_reply = MessageField(field_uri="InternalReply")
+ external_reply = MessageField(field_uri="ExternalReply")
def clean(self, version=None):
super().clean(version=version)
@@ -68,7 +69,7 @@ Module exchangelib.settings
@classmethod
def from_xml(cls, elem, account):
kwargs = {}
- for attr in ('state', 'external_audience', 'internal_reply', 'external_reply'):
+ for attr in ("state", "external_audience", "internal_reply", "external_reply"):
f = cls.get_field_by_fieldname(attr)
kwargs[attr] = f.from_xml(elem=elem, account=account)
kwargs.update(OutOfOffice.duration_to_start_end(elem=elem, account=account))
@@ -77,24 +78,24 @@ Module exchangelib.settings
def to_xml(self, version):
self.clean(version=version)
- elem = create_element(f't:{self.REQUEST_ELEMENT_NAME}')
- for attr in ('state', 'external_audience'):
+ elem = create_element(f"t:{self.REQUEST_ELEMENT_NAME}")
+ for attr in ("state", "external_audience"):
value = getattr(self, attr)
f = self.get_field_by_fieldname(attr)
set_xml_value(elem, f.to_xml(value, version=version))
if self.start or self.end:
- duration = create_element('t:Duration')
+ duration = create_element("t:Duration")
if self.start:
- f = self.get_field_by_fieldname('start')
+ f = self.get_field_by_fieldname("start")
set_xml_value(duration, f.to_xml(self.start, version=version))
if self.end:
- f = self.get_field_by_fieldname('end')
+ f = self.get_field_by_fieldname("end")
set_xml_value(duration, f.to_xml(self.end, version=version))
elem.append(duration)
- for attr in ('internal_reply', 'external_reply'):
+ for attr in ("internal_reply", "external_reply"):
value = getattr(self, attr)
if value is None:
- value = '' # The value can be empty, but the XML element must always be present
+ value = "" # The value can be empty, but the XML element must always be present
f = self.get_field_by_fieldname(attr)
set_xml_value(elem, f.to_xml(value, version=version))
return elem
@@ -103,10 +104,10 @@ Module exchangelib.settings
# Customize comparison
if self.state == self.DISABLED:
# All values except state are ignored by the server
- relevant_attrs = ('state',)
+ relevant_attrs = ("state",)
elif self.state != self.SCHEDULED:
# 'start' and 'end' values are ignored by the server, and the server always returns today's date
- relevant_attrs = tuple(f.name for f in self.FIELDS if f.name not in ('start', 'end'))
+ relevant_attrs = tuple(f.name for f in self.FIELDS if f.name not in ("start", "end"))
else:
relevant_attrs = tuple(f.name for f in self.FIELDS)
return hash(tuple(getattr(self, attr) for attr in relevant_attrs))
@@ -134,21 +135,22 @@ Classes
class OofSettings(EWSElement):
"""MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/oofsettings"""
- ELEMENT_NAME = 'OofSettings'
- REQUEST_ELEMENT_NAME = 'UserOofSettings'
+ ELEMENT_NAME = "OofSettings"
+ REQUEST_ELEMENT_NAME = "UserOofSettings"
- ENABLED = 'Enabled'
- SCHEDULED = 'Scheduled'
- DISABLED = 'Disabled'
+ ENABLED = "Enabled"
+ SCHEDULED = "Scheduled"
+ DISABLED = "Disabled"
STATE_CHOICES = (ENABLED, SCHEDULED, DISABLED)
- state = ChoiceField(field_uri='OofState', is_required=True, choices={Choice(c) for c in STATE_CHOICES})
- external_audience = ChoiceField(field_uri='ExternalAudience',
- choices={Choice('None'), Choice('Known'), Choice('All')}, default='All')
- start = DateTimeField(field_uri='StartTime')
- end = DateTimeField(field_uri='EndTime')
- internal_reply = MessageField(field_uri='InternalReply')
- external_reply = MessageField(field_uri='ExternalReply')
+ state = ChoiceField(field_uri="OofState", is_required=True, choices={Choice(c) for c in STATE_CHOICES})
+ external_audience = ChoiceField(
+ field_uri="ExternalAudience", choices={Choice("None"), Choice("Known"), Choice("All")}, default="All"
+ )
+ start = DateTimeField(field_uri="StartTime")
+ end = DateTimeField(field_uri="EndTime")
+ internal_reply = MessageField(field_uri="InternalReply")
+ external_reply = MessageField(field_uri="ExternalReply")
def clean(self, version=None):
super().clean(version=version)
@@ -165,7 +167,7 @@ Classes
@classmethod
def from_xml(cls, elem, account):
kwargs = {}
- for attr in ('state', 'external_audience', 'internal_reply', 'external_reply'):
+ for attr in ("state", "external_audience", "internal_reply", "external_reply"):
f = cls.get_field_by_fieldname(attr)
kwargs[attr] = f.from_xml(elem=elem, account=account)
kwargs.update(OutOfOffice.duration_to_start_end(elem=elem, account=account))
@@ -174,24 +176,24 @@ Classes
def to_xml(self, version):
self.clean(version=version)
- elem = create_element(f't:{self.REQUEST_ELEMENT_NAME}')
- for attr in ('state', 'external_audience'):
+ elem = create_element(f"t:{self.REQUEST_ELEMENT_NAME}")
+ for attr in ("state", "external_audience"):
value = getattr(self, attr)
f = self.get_field_by_fieldname(attr)
set_xml_value(elem, f.to_xml(value, version=version))
if self.start or self.end:
- duration = create_element('t:Duration')
+ duration = create_element("t:Duration")
if self.start:
- f = self.get_field_by_fieldname('start')
+ f = self.get_field_by_fieldname("start")
set_xml_value(duration, f.to_xml(self.start, version=version))
if self.end:
- f = self.get_field_by_fieldname('end')
+ f = self.get_field_by_fieldname("end")
set_xml_value(duration, f.to_xml(self.end, version=version))
elem.append(duration)
- for attr in ('internal_reply', 'external_reply'):
+ for attr in ("internal_reply", "external_reply"):
value = getattr(self, attr)
if value is None:
- value = '' # The value can be empty, but the XML element must always be present
+ value = "" # The value can be empty, but the XML element must always be present
f = self.get_field_by_fieldname(attr)
set_xml_value(elem, f.to_xml(value, version=version))
return elem
@@ -200,10 +202,10 @@ Classes
# Customize comparison
if self.state == self.DISABLED:
# All values except state are ignored by the server
- relevant_attrs = ('state',)
+ relevant_attrs = ("state",)
elif self.state != self.SCHEDULED:
# 'start' and 'end' values are ignored by the server, and the server always returns today's date
- relevant_attrs = tuple(f.name for f in self.FIELDS if f.name not in ('start', 'end'))
+ relevant_attrs = tuple(f.name for f in self.FIELDS if f.name not in ("start", "end"))
else:
relevant_attrs = tuple(f.name for f in self.FIELDS)
return hash(tuple(getattr(self, attr) for attr in relevant_attrs))
@@ -257,7 +259,7 @@ Static methods
@classmethod
def from_xml(cls, elem, account):
kwargs = {}
- for attr in ('state', 'external_audience', 'internal_reply', 'external_reply'):
+ for attr in ("state", "external_audience", "internal_reply", "external_reply"):
f = cls.get_field_by_fieldname(attr)
kwargs[attr] = f.from_xml(elem=elem, account=account)
kwargs.update(OutOfOffice.duration_to_start_end(elem=elem, account=account))
@@ -328,24 +330,24 @@ Methods
def to_xml(self, version):
self.clean(version=version)
- elem = create_element(f't:{self.REQUEST_ELEMENT_NAME}')
- for attr in ('state', 'external_audience'):
+ elem = create_element(f"t:{self.REQUEST_ELEMENT_NAME}")
+ for attr in ("state", "external_audience"):
value = getattr(self, attr)
f = self.get_field_by_fieldname(attr)
set_xml_value(elem, f.to_xml(value, version=version))
if self.start or self.end:
- duration = create_element('t:Duration')
+ duration = create_element("t:Duration")
if self.start:
- f = self.get_field_by_fieldname('start')
+ f = self.get_field_by_fieldname("start")
set_xml_value(duration, f.to_xml(self.start, version=version))
if self.end:
- f = self.get_field_by_fieldname('end')
+ f = self.get_field_by_fieldname("end")
set_xml_value(duration, f.to_xml(self.end, version=version))
elem.append(duration)
- for attr in ('internal_reply', 'external_reply'):
+ for attr in ("internal_reply", "external_reply"):
value = getattr(self, attr)
if value is None:
- value = '' # The value can be empty, but the XML element must always be present
+ value = "" # The value can be empty, but the XML element must always be present
f = self.get_field_by_fieldname(attr)
set_xml_value(elem, f.to_xml(value, version=version))
return elem
diff --git a/docs/exchangelib/transport.html b/docs/exchangelib/transport.html
index a289c55e..15f3c988 100644
--- a/docs/exchangelib/transport.html
+++ b/docs/exchangelib/transport.html
@@ -33,21 +33,30 @@ Module exchangelib.transport
import requests_ntlm
import requests_oauthlib
-from .errors import UnauthorizedError, TransportError
-from .util import create_element, add_xml_child, xml_to_str, ns_translation, _back_off_if_needed, \
- _retry_after, DummyResponse, CONNECTION_ERRORS, RETRY_WAIT
+from .errors import TransportError, UnauthorizedError
+from .util import (
+ CONNECTION_ERRORS,
+ RETRY_WAIT,
+ DummyResponse,
+ _back_off_if_needed,
+ _retry_after,
+ add_xml_child,
+ create_element,
+ ns_translation,
+ xml_to_str,
+)
log = logging.getLogger(__name__)
# Authentication method enums
-NOAUTH = 'no authentication'
-NTLM = 'NTLM'
-BASIC = 'basic'
-DIGEST = 'digest'
-GSSAPI = 'gssapi'
-SSPI = 'sspi'
-OAUTH2 = 'OAuth 2.0'
-CBA = 'CBA' # Certificate Based Authentication
+NOAUTH = "no authentication"
+NTLM = "NTLM"
+BASIC = "basic"
+DIGEST = "digest"
+GSSAPI = "gssapi"
+SSPI = "sspi"
+OAUTH2 = "OAuth 2.0"
+CBA = "CBA" # Certificate Based Authentication
# The auth types that must be accompanied by a credentials object
CREDENTIALS_REQUIRED = (NTLM, BASIC, DIGEST, OAUTH2)
@@ -62,19 +71,21 @@ Module exchangelib.transport
}
try:
import requests_gssapi
+
AUTH_TYPE_MAP[GSSAPI] = requests_gssapi.HTTPSPNEGOAuth
except ImportError:
# Kerberos auth is optional
pass
try:
import requests_negotiate_sspi
+
AUTH_TYPE_MAP[SSPI] = requests_negotiate_sspi.HttpNegotiateAuth
except ImportError:
# SSPI auth is optional
pass
-DEFAULT_ENCODING = 'utf-8'
-DEFAULT_HEADERS = {'Content-Type': f'text/xml; charset={DEFAULT_ENCODING}', 'Accept-Encoding': 'gzip, deflate'}
+DEFAULT_ENCODING = "utf-8"
+DEFAULT_HEADERS = {"Content-Type": f"text/xml; charset={DEFAULT_ENCODING}", "Accept-Encoding": "gzip, deflate"}
def wrap(content, api_version=None, account_to_impersonate=None, timezone=None):
@@ -95,36 +106,36 @@ Module exchangelib.transport
:param account_to_impersonate: (Default value = None)
:param timezone: (Default value = None)
"""
- envelope = create_element('s:Envelope', nsmap=ns_translation)
- header = create_element('s:Header')
+ envelope = create_element("s:Envelope", nsmap=ns_translation)
+ header = create_element("s:Header")
if api_version:
- request_server_version = create_element('t:RequestServerVersion', attrs=dict(Version=api_version))
+ request_server_version = create_element("t:RequestServerVersion", attrs=dict(Version=api_version))
header.append(request_server_version)
if account_to_impersonate:
- exchange_impersonation = create_element('t:ExchangeImpersonation')
- connecting_sid = create_element('t:ConnectingSID')
+ exchange_impersonation = create_element("t:ExchangeImpersonation")
+ connecting_sid = create_element("t:ConnectingSID")
# We have multiple options for uniquely identifying the user. Here's a prioritized list in accordance with
# https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/connectingsid
for attr, tag in (
- ('sid', 'SID'),
- ('upn', 'PrincipalName'),
- ('smtp_address', 'SmtpAddress'),
- ('primary_smtp_address', 'PrimarySmtpAddress'),
+ ("sid", "SID"),
+ ("upn", "PrincipalName"),
+ ("smtp_address", "SmtpAddress"),
+ ("primary_smtp_address", "PrimarySmtpAddress"),
):
val = getattr(account_to_impersonate, attr)
if val:
- add_xml_child(connecting_sid, f't:{tag}', val)
+ add_xml_child(connecting_sid, f"t:{tag}", val)
break
exchange_impersonation.append(connecting_sid)
header.append(exchange_impersonation)
if timezone:
- timezone_context = create_element('t:TimeZoneContext')
- timezone_definition = create_element('t:TimeZoneDefinition', attrs=dict(Id=timezone.ms_id))
+ timezone_context = create_element("t:TimeZoneContext")
+ timezone_definition = create_element("t:TimeZoneDefinition", attrs=dict(Id=timezone.ms_id))
timezone_context.append(timezone_definition)
header.append(timezone_context)
if len(header):
envelope.append(header)
- body = create_element('s:Body')
+ body = create_element("s:Body")
body.append(content)
envelope.append(body)
return xml_to_str(envelope, encoding=DEFAULT_ENCODING, xml_declaration=True)
@@ -155,19 +166,25 @@ Module exchangelib.transport
# We don't know the API version yet, but we need it to create a valid request because some Exchange servers only
# respond when given a valid request. Try all known versions. Gross.
from .protocol import BaseProtocol
+
retry = 0
t_start = time.monotonic()
headers = DEFAULT_HEADERS.copy()
for api_version in api_versions:
data = dummy_xml(api_version=api_version, name=name)
- log.debug('Requesting %s from %s', data, service_endpoint)
+ log.debug("Requesting %s from %s", data, service_endpoint)
while True:
_back_off_if_needed(retry_policy.back_off_until)
- log.debug('Trying to get service auth type for %s', service_endpoint)
+ log.debug("Trying to get service auth type for %s", service_endpoint)
with BaseProtocol.raw_session(service_endpoint) as s:
try:
- r = s.post(url=service_endpoint, headers=headers, data=data, allow_redirects=False,
- timeout=BaseProtocol.TIMEOUT)
+ r = s.post(
+ url=service_endpoint,
+ headers=headers,
+ data=data,
+ allow_redirects=False,
+ timeout=BaseProtocol.TIMEOUT,
+ )
r.close() # Release memory
break
except CONNECTION_ERRORS as e:
@@ -176,66 +193,71 @@ Module exchangelib.transport
r = DummyResponse(url=service_endpoint, request_headers=headers)
if retry_policy.may_retry_on_error(response=r, wait=total_wait):
wait = _retry_after(r, RETRY_WAIT)
- log.info("Connection error on URL %s (retry %s, error: %s). Cool down %s secs",
- service_endpoint, retry, e, wait)
+ log.info(
+ "Connection error on URL %s (retry %s, error: %s). Cool down %s secs",
+ service_endpoint,
+ retry,
+ e,
+ wait,
+ )
retry_policy.back_off(wait)
retry += 1
continue
raise TransportError(str(e)) from e
if r.status_code not in (200, 401):
- log.debug('Unexpected response: %s %s', r.status_code, r.reason)
+ log.debug("Unexpected response: %s %s", r.status_code, r.reason)
continue
try:
auth_type = get_auth_method_from_response(response=r)
- log.debug('Auth type is %s', auth_type)
+ log.debug("Auth type is %s", auth_type)
return auth_type, api_version
except UnauthorizedError:
continue
- raise TransportError('Failed to get auth type from service')
+ raise TransportError("Failed to get auth type from service")
def get_auth_method_from_response(response):
# First, get the auth method from headers. Then, test credentials. Don't handle redirects - burden is on caller.
- log.debug('Request headers: %s', response.request.headers)
- log.debug('Response headers: %s', response.headers)
+ log.debug("Request headers: %s", response.request.headers)
+ log.debug("Response headers: %s", response.headers)
if response.status_code == 200:
return NOAUTH
# Get auth type from headers
for key, val in response.headers.items():
- if key.lower() == 'www-authenticate':
+ if key.lower() == "www-authenticate":
# Requests will combine multiple HTTP headers into one in 'request.headers'
vals = _tokenize(val.lower())
for v in vals:
- if v.startswith('realm'):
- realm = v.split('=')[1].strip('"')
- log.debug('realm: %s', realm)
+ if v.startswith("realm"):
+ realm = v.split("=")[1].strip('"')
+ log.debug("realm: %s", realm)
# Prefer most secure auth method if more than one is offered. See discussion at
# http://docs.oracle.com/javase/7/docs/technotes/guides/net/http-auth.html
- if 'digest' in vals:
+ if "digest" in vals:
return DIGEST
- if 'ntlm' in vals:
+ if "ntlm" in vals:
return NTLM
- if 'basic' in vals:
+ if "basic" in vals:
return BASIC
- raise UnauthorizedError('No compatible auth type was reported by server')
+ raise UnauthorizedError("No compatible auth type was reported by server")
def _tokenize(val):
# Splits cookie auth values
auth_methods = []
- auth_method = ''
+ auth_method = ""
quote = False
for c in val:
- if c in (' ', ',') and not quote:
- if auth_method not in ('', ','):
+ if c in (" ", ",") and not quote:
+ if auth_method not in ("", ","):
auth_methods.append(auth_method)
- auth_method = ''
+ auth_method = ""
continue
if c == '"':
auth_method += c
if quote:
auth_methods.append(auth_method)
- auth_method = ''
+ auth_method = ""
quote = not quote
continue
auth_method += c
@@ -247,13 +269,17 @@ Module exchangelib.transport
def dummy_xml(api_version, name):
# Generate a minimal, valid EWS request
from .services import ResolveNames # Avoid circular import
- return wrap(content=ResolveNames(protocol=None).get_payload(
- unresolved_entries=[name],
- parent_folders=None,
- return_full_contact_data=False,
- search_scope=None,
- contact_data_shape=None,
- ), api_version=api_version)
+
+ return wrap(
+ content=ResolveNames(protocol=None).get_payload(
+ unresolved_entries=[name],
+ parent_folders=None,
+ return_full_contact_data=False,
+ search_scope=None,
+ contact_data_shape=None,
+ ),
+ api_version=api_version,
+ )
@@ -275,13 +301,17 @@ Functions
def dummy_xml(api_version, name):
# Generate a minimal, valid EWS request
from .services import ResolveNames # Avoid circular import
- return wrap(content=ResolveNames(protocol=None).get_payload(
- unresolved_entries=[name],
- parent_folders=None,
- return_full_contact_data=False,
- search_scope=None,
- contact_data_shape=None,
- ), api_version=api_version)
+
+ return wrap(
+ content=ResolveNames(protocol=None).get_payload(
+ unresolved_entries=[name],
+ parent_folders=None,
+ return_full_contact_data=False,
+ search_scope=None,
+ contact_data_shape=None,
+ ),
+ api_version=api_version,
+ )
@@ -324,28 +354,28 @@ Functions
def get_auth_method_from_response(response):
# First, get the auth method from headers. Then, test credentials. Don't handle redirects - burden is on caller.
- log.debug('Request headers: %s', response.request.headers)
- log.debug('Response headers: %s', response.headers)
+ log.debug("Request headers: %s", response.request.headers)
+ log.debug("Response headers: %s", response.headers)
if response.status_code == 200:
return NOAUTH
# Get auth type from headers
for key, val in response.headers.items():
- if key.lower() == 'www-authenticate':
+ if key.lower() == "www-authenticate":
# Requests will combine multiple HTTP headers into one in 'request.headers'
vals = _tokenize(val.lower())
for v in vals:
- if v.startswith('realm'):
- realm = v.split('=')[1].strip('"')
- log.debug('realm: %s', realm)
+ if v.startswith("realm"):
+ realm = v.split("=")[1].strip('"')
+ log.debug("realm: %s", realm)
# Prefer most secure auth method if more than one is offered. See discussion at
# http://docs.oracle.com/javase/7/docs/technotes/guides/net/http-auth.html
- if 'digest' in vals:
+ if "digest" in vals:
return DIGEST
- if 'ntlm' in vals:
+ if "ntlm" in vals:
return NTLM
- if 'basic' in vals:
+ if "basic" in vals:
return BASIC
- raise UnauthorizedError('No compatible auth type was reported by server')
+ raise UnauthorizedError("No compatible auth type was reported by server")
@@ -364,19 +394,25 @@ Functions
# We don't know the API version yet, but we need it to create a valid request because some Exchange servers only
# respond when given a valid request. Try all known versions. Gross.
from .protocol import BaseProtocol
+
retry = 0
t_start = time.monotonic()
headers = DEFAULT_HEADERS.copy()
for api_version in api_versions:
data = dummy_xml(api_version=api_version, name=name)
- log.debug('Requesting %s from %s', data, service_endpoint)
+ log.debug("Requesting %s from %s", data, service_endpoint)
while True:
_back_off_if_needed(retry_policy.back_off_until)
- log.debug('Trying to get service auth type for %s', service_endpoint)
+ log.debug("Trying to get service auth type for %s", service_endpoint)
with BaseProtocol.raw_session(service_endpoint) as s:
try:
- r = s.post(url=service_endpoint, headers=headers, data=data, allow_redirects=False,
- timeout=BaseProtocol.TIMEOUT)
+ r = s.post(
+ url=service_endpoint,
+ headers=headers,
+ data=data,
+ allow_redirects=False,
+ timeout=BaseProtocol.TIMEOUT,
+ )
r.close() # Release memory
break
except CONNECTION_ERRORS as e:
@@ -385,22 +421,27 @@ Functions
r = DummyResponse(url=service_endpoint, request_headers=headers)
if retry_policy.may_retry_on_error(response=r, wait=total_wait):
wait = _retry_after(r, RETRY_WAIT)
- log.info("Connection error on URL %s (retry %s, error: %s). Cool down %s secs",
- service_endpoint, retry, e, wait)
+ log.info(
+ "Connection error on URL %s (retry %s, error: %s). Cool down %s secs",
+ service_endpoint,
+ retry,
+ e,
+ wait,
+ )
retry_policy.back_off(wait)
retry += 1
continue
raise TransportError(str(e)) from e
if r.status_code not in (200, 401):
- log.debug('Unexpected response: %s %s', r.status_code, r.reason)
+ log.debug("Unexpected response: %s %s", r.status_code, r.reason)
continue
try:
auth_type = get_auth_method_from_response(response=r)
- log.debug('Auth type is %s', auth_type)
+ log.debug("Auth type is %s", auth_type)
return auth_type, api_version
except UnauthorizedError:
continue
- raise TransportError('Failed to get auth type from service')
+ raise TransportError("Failed to get auth type from service")
@@ -443,36 +484,36 @@ Functions
:param account_to_impersonate: (Default value = None)
:param timezone: (Default value = None)
"""
- envelope = create_element('s:Envelope', nsmap=ns_translation)
- header = create_element('s:Header')
+ envelope = create_element("s:Envelope", nsmap=ns_translation)
+ header = create_element("s:Header")
if api_version:
- request_server_version = create_element('t:RequestServerVersion', attrs=dict(Version=api_version))
+ request_server_version = create_element("t:RequestServerVersion", attrs=dict(Version=api_version))
header.append(request_server_version)
if account_to_impersonate:
- exchange_impersonation = create_element('t:ExchangeImpersonation')
- connecting_sid = create_element('t:ConnectingSID')
+ exchange_impersonation = create_element("t:ExchangeImpersonation")
+ connecting_sid = create_element("t:ConnectingSID")
# We have multiple options for uniquely identifying the user. Here's a prioritized list in accordance with
# https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/connectingsid
for attr, tag in (
- ('sid', 'SID'),
- ('upn', 'PrincipalName'),
- ('smtp_address', 'SmtpAddress'),
- ('primary_smtp_address', 'PrimarySmtpAddress'),
+ ("sid", "SID"),
+ ("upn", "PrincipalName"),
+ ("smtp_address", "SmtpAddress"),
+ ("primary_smtp_address", "PrimarySmtpAddress"),
):
val = getattr(account_to_impersonate, attr)
if val:
- add_xml_child(connecting_sid, f't:{tag}', val)
+ add_xml_child(connecting_sid, f"t:{tag}", val)
break
exchange_impersonation.append(connecting_sid)
header.append(exchange_impersonation)
if timezone:
- timezone_context = create_element('t:TimeZoneContext')
- timezone_definition = create_element('t:TimeZoneDefinition', attrs=dict(Id=timezone.ms_id))
+ timezone_context = create_element("t:TimeZoneContext")
+ timezone_definition = create_element("t:TimeZoneDefinition", attrs=dict(Id=timezone.ms_id))
timezone_context.append(timezone_definition)
header.append(timezone_context)
if len(header):
envelope.append(header)
- body = create_element('s:Body')
+ body = create_element("s:Body")
body.append(content)
envelope.append(body)
return xml_to_str(envelope, encoding=DEFAULT_ENCODING, xml_declaration=True)
diff --git a/docs/exchangelib/util.html b/docs/exchangelib/util.html
index 53292197..9e0959bc 100644
--- a/docs/exchangelib/util.html
+++ b/docs/exchangelib/util.html
@@ -51,19 +51,26 @@ exchangelib.util
exchangelib.util
exchangelib.util
exchangelib.util
exchangelib.util
exchangelib.util
exchangelib.util
exchangelib.util
exchangelib.util
exchangelib.util
exchangelib.util
exchangelib.util
exchangelib.util
exchangelib.util
exchangelib.util
exchangelib.util
exchangelib.util
exchangelib.util
exchangelib.util
exchangelib.util
exchangelib.util
exchangelib.util
exchangelib.util
exchangelib.util
exchangelib.util
exchangelib.util
exchangelib.util
exchangelib.util
exchangelib.util
exchangelib.util
exchangelib.util
exchangelib.util
exchangelib.util
exchangelib.util
exchangelib.util
exchangelib.util
exchangelib.util
exchangelib.util
exchangelib.util
def create_element(name, attrs=None, nsmap=None):
- if ':' in name:
- ns, name = name.split(':')
- name = f'{{{ns_translation[ns]}}}{name}'
+ if ":" in name:
+ ns, name = name.split(":")
+ name = f"{{{ns_translation[ns]}}}{name}"
elem = _forgiving_parser.makeelement(name, nsmap=nsmap)
if attrs:
# Try hard to keep attribute order, to ensure deterministic output. This simplifies testing.
# Dicts in Python 3.6+ have stable ordering.
for k, v in attrs.items():
if isinstance(v, bool):
- v = 'true' if v else 'false'
+ v = "true" if v else "false"
elif isinstance(v, int):
v = str(v)
elem.set(k, v)
@@ -1059,7 +1090,7 @@ Functions
def get_domain(email):
try:
- return email.split('@')[1].lower()
+ return email.split("@")[1].lower()
except (IndexError, AttributeError):
raise ValueError(f"{email!r} is not a valid email")
@@ -1076,9 +1107,9 @@ Functions
def get_redirect_url(response, allow_relative=True, require_relative=False):
# allow_relative=False throws RelativeRedirect error if scheme and hostname are equal to the request
# require_relative=True throws RelativeRedirect error if scheme and hostname are not equal to the request
- redirect_url = response.headers.get('location')
+ redirect_url = response.headers.get("location")
if not redirect_url:
- raise TransportError('HTTP redirect but no location header')
+ raise TransportError("HTTP redirect but no location header")
# At least some servers are kind enough to supply a new location. It may be relative
redirect_has_ssl, redirect_server, redirect_path = split_url(redirect_url)
# The response may have been redirected already. Get the original URL
@@ -1090,13 +1121,13 @@ Functions
# Redirect URL is relative. Inherit server and scheme from response URL
redirect_server = response_server
redirect_has_ssl = response_has_ssl
- if not redirect_path.startswith('/'):
+ if not redirect_path.startswith("/"):
# The path is not top-level. Add response path
- redirect_path = (response_path or '/') + redirect_path
+ redirect_path = (response_path or "/") + redirect_path
redirect_url = f"{'https' if redirect_has_ssl else 'http'}://{redirect_server}{redirect_path}"
if redirect_url == request_url:
# And some are mean enough to redirect to the same location
- raise TransportError(f'Redirect to same location: {redirect_url}')
+ raise TransportError(f"Redirect to same location: {redirect_url}")
if not allow_relative and (request_has_ssl == response_has_ssl and request_server == redirect_server):
raise RelativeRedirect(redirect_url)
if require_relative and (request_has_ssl != response_has_ssl or request_server != redirect_server):
@@ -1158,7 +1189,7 @@ Functions
:return: True or False
"""
if generators_allowed:
- if not isinstance(value, (bytes, str)) and hasattr(value, '__iter__'):
+ if not isinstance(value, (bytes, str)) and hasattr(value, "__iter__"):
return True
else:
if isinstance(value, (tuple, list, set)):
@@ -1178,7 +1209,7 @@ Functions
Expand source code
-def is_xml(text, expected_prefix=b'<?xml'):
+def is_xml(text, expected_prefix=b"<?xml"):
"""Lightweight test if response is an XML doc. It's better to be fast than correct here.
:param text: The string to check
@@ -1189,7 +1220,7 @@ Functions
bom_len = len(BOM_UTF8)
prefix_len = len(expected_prefix)
if text[:bom_len] == BOM_UTF8:
- prefix = text[bom_len:bom_len + prefix_len]
+ prefix = text[bom_len : bom_len + prefix_len]
else:
prefix = text[:prefix_len]
return prefix == expected_prefix
@@ -1212,7 +1243,7 @@ Functions
:param iterable:
:return:
"""
- if hasattr(iterable, '__len__'):
+ if hasattr(iterable, "__len__"):
# tuple, list, set
return not iterable, iterable
# generator
@@ -1303,7 +1334,7 @@ Functions
wait = RETRY_WAIT # Initial retry wait. We double the value on each retry
retry = 0
redirects = 0
- log_msg = '''\
+ log_msg = """\
Retry: %(retry)s
Waited: %(wait)s
Timeout: %(timeout)s
@@ -1317,10 +1348,10 @@ Functions
Response time: %(response_time)s
Status code: %(status_code)s
Request headers: %(request_headers)s
-Response headers: %(response_headers)s'''
- xml_log_msg = '''\
+Response headers: %(response_headers)s"""
+ xml_log_msg = """\
Request XML: %(xml_request)s
-Response XML: %(xml_response)s'''
+Response XML: %(xml_response)s"""
log_vals = dict(
retry=retry,
wait=wait,
@@ -1348,28 +1379,36 @@ Functions
if backed_off:
# We may have slept for a long time. Renew the session.
session = protocol.renew_session(session)
- log.debug('Session %s thread %s: retry %s timeout %s POST\'ing to %s after %ss wait', session.session_id,
- thread_id, retry, timeout, url, wait)
+ log.debug(
+ "Session %s thread %s: retry %s timeout %s POST'ing to %s after %ss wait",
+ session.session_id,
+ thread_id,
+ retry,
+ timeout,
+ url,
+ wait,
+ )
d_start = time.monotonic()
# Always create a dummy response for logging purposes, in case we fail in the following
r = DummyResponse(url=url, request_headers=headers)
try:
- r = session.post(url=url, headers=headers, data=data, allow_redirects=False, timeout=timeout,
- stream=stream)
+ r = session.post(
+ url=url, headers=headers, data=data, allow_redirects=False, timeout=timeout, stream=stream
+ )
except TLS_ERRORS as e:
# Don't retry on TLS errors. They will most likely be persistent.
raise TransportError(str(e))
except CONNECTION_ERRORS as e:
- log.debug('Session %s thread %s: connection error POST\'ing to %s', session.session_id, thread_id, url)
- r = DummyResponse(url=url, headers={'TimeoutException': e}, request_headers=headers)
+ log.debug("Session %s thread %s: connection error POST'ing to %s", session.session_id, thread_id, url)
+ r = DummyResponse(url=url, headers={"TimeoutException": e}, request_headers=headers)
except TokenExpiredError as e:
- log.debug('Session %s thread %s: OAuth token expired; refreshing', session.session_id, thread_id)
- r = DummyResponse(url=url, headers={'TokenExpiredError': e}, request_headers=headers, status_code=401)
+ log.debug("Session %s thread %s: OAuth token expired; refreshing", session.session_id, thread_id)
+ r = DummyResponse(url=url, headers={"TokenExpiredError": e}, request_headers=headers, status_code=401)
except KeyError as e:
- if e.args[0] != 'www-authenticate':
+ if e.args[0] != "www-authenticate":
raise
- log.debug('Session %s thread %s: auth headers missing from %s', session.session_id, thread_id, url)
- r = DummyResponse(url=url, headers={'KeyError': e}, request_headers=headers)
+ log.debug("Session %s thread %s: auth headers missing from %s", session.session_id, thread_id, url)
+ r = DummyResponse(url=url, headers={"KeyError": e}, request_headers=headers)
finally:
log_vals.update(
retry=retry,
@@ -1383,7 +1422,7 @@ Functions
)
xml_log_vals.update(
xml_request=data,
- xml_response='[STREAMING]' if stream else r.content,
+ xml_response="[STREAMING]" if stream else r.content,
)
log.debug(log_msg, log_vals)
xml_log.debug(xml_log_msg, xml_log_vals)
@@ -1394,8 +1433,14 @@ Functions
total_wait = time.monotonic() - t_start
if protocol.retry_policy.may_retry_on_error(response=r, wait=total_wait):
r.close() # Release memory
- log.info("Session %s thread %s: Connection error on URL %s (code %s). Cool down %s secs",
- session.session_id, thread_id, r.url, r.status_code, wait)
+ log.info(
+ "Session %s thread %s: Connection error on URL %s (code %s). Cool down %s secs",
+ session.session_id,
+ thread_id,
+ r.url,
+ r.status_code,
+ wait,
+ )
wait = _retry_after(r, wait)
protocol.retry_policy.back_off(wait)
retry += 1
@@ -1412,22 +1457,20 @@ Functions
raise
except Exception as e:
# Let higher layers handle this. Add full context for better debugging.
- log.error('%s: %s\n%s\n%s', e.__class__.__name__, str(e), log_msg % log_vals, xml_log_msg % xml_log_vals)
+ log.error("%s: %s\n%s\n%s", e.__class__.__name__, str(e), log_msg % log_vals, xml_log_msg % xml_log_vals)
protocol.retire_session(session)
raise
if r.status_code == 500 and r.content and is_xml(r.content):
# Some genius at Microsoft thinks it's OK to send a valid SOAP response as an HTTP 500
- log.debug('Got status code %s but trying to parse content anyway', r.status_code)
+ log.debug("Got status code %s but trying to parse content anyway", r.status_code)
elif r.status_code != 200:
protocol.retire_session(session)
try:
protocol.retry_policy.raise_response_errors(r) # Always raises an exception
except MalformedResponseError as e:
- log.error('%s: %s\n%s\n%s', e.__class__.__name__, str(e), log_msg % log_vals, xml_log_msg % xml_log_vals)
- raise
- except Exception:
+ log.error("%s: %s\n%s\n%s", e.__class__.__name__, str(e), log_msg % log_vals, xml_log_msg % xml_log_vals)
raise
- log.debug('Session %s thread %s: Useful response from %s', session.session_id, thread_id, url)
+ log.debug("Session %s thread %s: Useful response from %s", session.session_id, thread_id, url)
return r, session
@@ -1461,8 +1504,9 @@ Functions
@wraps(f)
def wrapper(self, *args, **kwargs):
if not self.account:
- raise ValueError(f'{self.__class__.__name__} must have an account')
+ raise ValueError(f"{self.__class__.__name__} must have an account")
return f(self, *args, **kwargs)
+
return wrapper
@@ -1479,10 +1523,11 @@ Functions
@wraps(f)
def wrapper(self, *args, **kwargs):
if not self.account:
- raise ValueError(f'{self.__class__.__name__} must have an account')
+ raise ValueError(f"{self.__class__.__name__} must have an account")
if not self.id:
- raise ValueError(f'{self.__class__.__name__} must have an ID')
+ raise ValueError(f"{self.__class__.__name__} must have an ID")
return f(self, *args, **kwargs)
+
return wrapper
@@ -1501,9 +1546,9 @@ def safe_xml_value(value, replacement='?'):
+def safe_xml_value(value, replacement="?"):
return _ILLEGAL_XML_CHARS_RE.sub(replacement, value)
@@ -1531,10 +1576,11 @@ Functions
Expand source code
def set_xml_value(elem, value, version=None):
- from .ewsdatetime import EWSDateTime, EWSDate
- from .fields import FieldPath, FieldOrder
+ from .ewsdatetime import EWSDate, EWSDateTime
+ from .fields import FieldOrder, FieldPath
from .properties import EWSElement
from .version import Version
+
if isinstance(value, (str, bool, bytes, int, Decimal, datetime.time, EWSDate, EWSDateTime)):
elem.text = value_to_xml_text(value)
elif isinstance(value, _element_class):
@@ -1543,13 +1589,13 @@ Functions
elem.append(value.to_xml())
elif isinstance(value, EWSElement):
if not isinstance(version, Version):
- raise InvalidTypeError('version', version, Version)
+ raise InvalidTypeError("version", version, Version)
elem.append(value.to_xml(version=version))
elif is_iterable(value, generators_allowed=True):
for v in value:
set_xml_value(elem, v, version=version)
else:
- raise ValueError(f'Unsupported type {type(value)} for value {value} on elem {elem}')
+ raise ValueError(f"Unsupported type {type(value)} for value {value} on elem {elem}")
return elem
@@ -1565,7 +1611,7 @@ Functions
def split_url(url):
parsed_url = urlparse(url)
# Use netloc instead of hostname since hostname is None if URL is relative
- return parsed_url.scheme == 'https', parsed_url.netloc.lower(), parsed_url.path
+ return parsed_url.scheme == "https", parsed_url.netloc.lower(), parsed_url.path
@@ -1587,35 +1633,35 @@ Functions
try:
res = lxml.etree.parse(stream, parser=_forgiving_parser) # nosec
except AssertionError as e:
- raise ParseError(e.args[0], '<not from file>', -1, 0)
+ raise ParseError(e.args[0], "<not from file>", -1, 0)
except lxml.etree.ParseError as e:
- if hasattr(e, 'position'):
+ if hasattr(e, "position"):
e.lineno, e.offset = e.position
if not e.lineno:
- raise ParseError(str(e), '<not from file>', e.lineno, e.offset)
+ raise ParseError(str(e), "<not from file>", e.lineno, e.offset)
try:
stream.seek(0)
offending_line = stream.read().splitlines()[e.lineno - 1]
except (IndexError, io.UnsupportedOperation):
- raise ParseError(str(e), '<not from file>', e.lineno, e.offset)
+ raise ParseError(str(e), "<not from file>", e.lineno, e.offset)
else:
- offending_excerpt = offending_line[max(0, e.offset - 20):e.offset + 20]
+ offending_excerpt = offending_line[max(0, e.offset - 20) : e.offset + 20]
msg = f'{e}\nOffending text: [...]{offending_excerpt.decode("utf-8", errors="ignore")}[...]'
- raise ParseError(msg, '<not from file>', e.lineno, e.offset)
+ raise ParseError(msg, "<not from file>", e.lineno, e.offset)
except TypeError:
try:
stream.seek(0)
except (IndexError, io.UnsupportedOperation):
pass
- raise ParseError(f'This is not XML: {stream.read()!r}', '<not from file>', -1, 0)
+ raise ParseError(f"This is not XML: {stream.read()!r}", "<not from file>", -1, 0)
if res.getroot() is None:
try:
stream.seek(0)
- msg = f'No root element found: {stream.read()!r}'
+ msg = f"No root element found: {stream.read()!r}"
except (IndexError, io.UnsupportedOperation):
- msg = 'No root element found'
- raise ParseError(msg, '<not from file>', -1, 0)
+ msg = "No root element found"
+ raise ParseError(msg, "<not from file>", -1, 0)
return res
@@ -1629,16 +1675,17 @@ def value_to_xml_text(value):
- from .ewsdatetime import EWSTimeZone, EWSDateTime, EWSDate
- from .indexed_properties import PhoneNumber, EmailAddress
- from .properties import Mailbox, AssociatedCalendarItemId, Attendee, ConversationId
+ from .ewsdatetime import EWSDate, EWSDateTime, EWSTimeZone
+ from .indexed_properties import EmailAddress, PhoneNumber
+ from .properties import AssociatedCalendarItemId, Attendee, ConversationId, Mailbox
+
# We can't just create a map and look up with type(value) because we want to support subtypes
if isinstance(value, str):
return safe_xml_value(value)
if isinstance(value, bool):
- return '1' if value else '0'
+ return "1" if value else "0"
if isinstance(value, bytes):
- return b64encode(value).decode('ascii')
+ return b64encode(value).decode("ascii")
if isinstance(value, (int, Decimal)):
return str(value)
if isinstance(value, datetime.time):
@@ -1661,7 +1708,7 @@ Functions
return value.id
if isinstance(value, AssociatedCalendarItemId):
return value.id
- raise TypeError(f'Unsupported type: {type(value)} ({value})')
+ raise TypeError(f"Unsupported type: {type(value)} ({value})")
@@ -1675,15 +1722,16 @@ Functions
def xml_text_to_value(value, value_type):
from .ewsdatetime import EWSDate, EWSDateTime
+
if value_type == str:
return value
if value_type == bool:
try:
return {
- 'true': True,
- 'on': True,
- 'false': False,
- 'off': False,
+ "true": True,
+ "on": True,
+ "false": False,
+ "off": False,
}[value.lower()]
except KeyError:
return None
@@ -1746,7 +1794,8 @@ Classes
class AnonymizingXmlHandler(PrettyXmlHandler):
"""A steaming log handler that prettifies and anonymizes log statements containing XML when output is a terminal."""
- PRIVATE_TAGS = {'RootItemId', 'ItemId', 'Id', 'RootItemChangeKey', 'ChangeKey'}
+
+ PRIVATE_TAGS = {"RootItemId", "ItemId", "Id", "RootItemChangeKey", "ChangeKey"}
def __init__(self, forbidden_strings, *args, **kwargs):
self.forbidden_strings = forbidden_strings
@@ -1757,11 +1806,11 @@ Classes
for elem in root.iter():
# Anonymize element attribute values known to contain private data
for attr in set(elem.keys()) & self.PRIVATE_TAGS:
- elem.set(attr, 'DEADBEEF=')
+ elem.set(attr, "DEADBEEF=")
# Anonymize anything requested by the caller
for s in self.forbidden_strings:
if elem.text is not None:
- elem.text = elem.text.replace(s, '[REMOVED]')
+ elem.text = elem.text.replace(s, "[REMOVED]")
return root
Ancestors
@@ -1794,11 +1843,11 @@ Methods
for elem in root.iter():
# Anonymize element attribute values known to contain private data
for attr in set(elem.keys()) & self.PRIVATE_TAGS:
- elem.set(attr, 'DEADBEEF=')
+ elem.set(attr, "DEADBEEF=")
# Anonymize anything requested by the caller
for s in self.forbidden_strings:
if elem.text is not None:
- elem.text = elem.text.replace(s, '[REMOVED]')
+ elem.text = elem.text.replace(s, "[REMOVED]")
return root
@@ -1851,7 +1900,7 @@ Inherited members
if self.closed:
raise ValueError("read from a closed file")
if self._next is None:
- return b''
+ return b""
if size is None:
size = -1
@@ -1915,7 +1964,7 @@ Methods
if self.closed:
raise ValueError("read from a closed file")
if self._next is None:
- return b''
+ return b""
if size is None:
size = -1
@@ -1977,7 +2026,7 @@ Methods
class DocumentYielder:
"""Look for XML documents in a streaming HTTP response and yield them as they become available from the stream."""
- def __init__(self, content_iterator, document_tag='Envelope'):
+ def __init__(self, content_iterator, document_tag="Envelope"):
self._iterator = content_iterator
self._document_tag = document_tag.encode()
@@ -1985,16 +2034,16 @@ Methods
"""Iterate over the bytes until we have a full tag in the buffer. If there's a '>' in an attr value, then we'll
exit on that, but it's OK becaus wejust need the plain tag name later.
"""
- tag_buffer = [b'<']
+ tag_buffer = [b"<"]
while True:
try:
c = next(self._iterator)
except StopIteration:
break
tag_buffer.append(c)
- if c == b'>':
+ if c == b">":
break
- return b''.join(tag_buffer)
+ return b"".join(tag_buffer)
@staticmethod
def _normalize_tag(tag):
@@ -2004,7 +2053,7 @@ Methods
* <ns:tag foo='bar'>
* </ns:tag foo='bar'>
"""
- return tag.strip(b'<>/').split(b' ')[0].split(b':')[-1]
+ return tag.strip(b"<>/").split(b" ")[0].split(b":")[-1]
def __iter__(self):
"""Consumes the content iterator, looking for start and end tags. Returns each document when we have fully
@@ -2015,18 +2064,18 @@ Methods
try:
while True:
c = next(self._iterator)
- if not doc_started and c == b'<':
+ if not doc_started and c == b"<":
tag = self._get_tag()
if self._normalize_tag(tag) == self._document_tag:
# Start of document. Collect bytes from this point
buffer.append(tag)
doc_started = True
- elif doc_started and c == b'<':
+ elif doc_started and c == b"<":
tag = self._get_tag()
buffer.append(tag)
if self._normalize_tag(tag) == self._document_tag:
# End of document. Yield a valid document and reset the buffer
- yield b"<?xml version='1.0' encoding='utf-8'?>\n" + b''.join(buffer)
+ yield b"<?xml version='1.0' encoding='utf-8'?>\n" + b"".join(buffer)
doc_started = False
buffer = []
elif doc_started:
@@ -2065,15 +2114,16 @@ Methods
class DummyResponse:
"""A class to fake a requests Response object for functions that expect this."""
- def __init__(self, url=None, headers=None, request_headers=None, content=b'', status_code=503, streaming=False,
- history=None):
+ def __init__(
+ self, url=None, headers=None, request_headers=None, content=b"", status_code=503, streaming=False, history=None
+ ):
self.status_code = status_code
self.url = url
self.headers = headers or {}
self.content = iter((bytes([b]) for b in content)) if streaming else content
- self.text = content.decode('utf-8', errors='ignore')
+ self.text = content.decode("utf-8", errors="ignore")
self.request = DummyRequest(headers=request_headers)
- self.reason = ''
+ self.reason = ""
self.history = history
def iter_content(self):
@@ -2181,12 +2231,11 @@ Ancestors
@classmethod
def prettify_xml(cls, xml_bytes):
"""Re-format an XML document to a consistent style."""
- return lxml.etree.tostring(
- cls.parse_bytes(xml_bytes),
- xml_declaration=True,
- encoding='utf-8',
- pretty_print=True
- ).replace(b'\t', b' ').replace(b' xmlns:', b'\n xmlns:')
+ return (
+ lxml.etree.tostring(cls.parse_bytes(xml_bytes), xml_declaration=True, encoding="utf-8", pretty_print=True)
+ .replace(b"\t", b" ")
+ .replace(b" xmlns:", b"\n xmlns:")
+ )
@staticmethod
def highlight_xml(xml_str):
@@ -2203,7 +2252,7 @@ Ancestors
"""
if record.levelno == logging.DEBUG and self.is_tty() and isinstance(record.args, dict):
for key, value in record.args.items():
- if not key.startswith('xml_'):
+ if not key.startswith("xml_"):
continue
if not isinstance(value, bytes):
continue
@@ -2213,7 +2262,7 @@ Ancestors
record.args[key] = self.highlight_xml(self.prettify_xml(value))
except Exception as e:
# Something bad happened, but we don't want to crash the program just because logging failed
- print(f'XML highlighting failed: {e}')
+ print(f"XML highlighting failed: {e}")
return super().emit(record)
def is_tty(self):
@@ -2276,12 +2325,11 @@ Static methods
@classmethod
def prettify_xml(cls, xml_bytes):
"""Re-format an XML document to a consistent style."""
- return lxml.etree.tostring(
- cls.parse_bytes(xml_bytes),
- xml_declaration=True,
- encoding='utf-8',
- pretty_print=True
- ).replace(b'\t', b' ').replace(b' xmlns:', b'\n xmlns:')
+ return (
+ lxml.etree.tostring(cls.parse_bytes(xml_bytes), xml_declaration=True, encoding="utf-8", pretty_print=True)
+ .replace(b"\t", b" ")
+ .replace(b" xmlns:", b"\n xmlns:")
+ )
@@ -2310,7 +2358,7 @@ Methods
"""
if record.levelno == logging.DEBUG and self.is_tty() and isinstance(record.args, dict):
for key, value in record.args.items():
- if not key.startswith('xml_'):
+ if not key.startswith("xml_"):
continue
if not isinstance(value, bytes):
continue
@@ -2320,7 +2368,7 @@ Methods
record.args[key] = self.highlight_xml(self.prettify_xml(value))
except Exception as e:
# Something bad happened, but we don't want to crash the program just because logging failed
- print(f'XML highlighting failed: {e}')
+ print(f"XML highlighting failed: {e}")
return super().emit(record)
@@ -2382,7 +2430,7 @@ Methods
self.close()
if not self.element_found:
data = bytes(collected_data)
- raise ElementNotFound('The element to be streamed from was not found', data=bytes(data))
+ raise ElementNotFound("The element to be streamed from was not found", data=bytes(data))
def feed(self, data, isFinal=0):
"""Yield the current content of the character buffer."""
@@ -2390,13 +2438,13 @@ Methods
return self._decode_buffer()
def _decode_buffer(self):
- remainder = ''
+ remainder = ""
for data in self.buffer:
available = len(remainder) + len(data)
overflow = available % 4 # Make sure we always decode a multiple of 4
if remainder:
- data = (remainder + data)
- remainder = ''
+ data = remainder + data
+ remainder = ""
if overflow:
remainder, data = data[-overflow:], data[:-overflow]
if data:
@@ -2457,7 +2505,7 @@ Methods
self.close()
if not self.element_found:
data = bytes(collected_data)
- raise ElementNotFound('The element to be streamed from was not found', data=bytes(data))
+ raise ElementNotFound("The element to be streamed from was not found", data=bytes(data))
diff --git a/docs/exchangelib/version.html b/docs/exchangelib/version.html
index 1bdae272..f9e15872 100644
--- a/docs/exchangelib/version.html
+++ b/docs/exchangelib/version.html
@@ -29,8 +29,8 @@ exchangelib.version
import logging
import re
-from .errors import TransportError, ResponseMessageError, InvalidTypeError
-from .util import xml_to_str, TNS
+from .errors import InvalidTypeError, ResponseMessageError, TransportError
+from .util import TNS, xml_to_str
log = logging.getLogger(__name__)
@@ -44,20 +44,20 @@ Module exchangelib.version
# https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/requestserverversion
VERSIONS = {
- 'Exchange2007': ('Exchange2007', 'Microsoft Exchange Server 2007'),
- 'Exchange2007_SP1': ('Exchange2007_SP1', 'Microsoft Exchange Server 2007 SP1'),
- 'Exchange2007_SP2': ('Exchange2007_SP1', 'Microsoft Exchange Server 2007 SP2'),
- 'Exchange2007_SP3': ('Exchange2007_SP1', 'Microsoft Exchange Server 2007 SP3'),
- 'Exchange2010': ('Exchange2010', 'Microsoft Exchange Server 2010'),
- 'Exchange2010_SP1': ('Exchange2010_SP1', 'Microsoft Exchange Server 2010 SP1'),
- 'Exchange2010_SP2': ('Exchange2010_SP2', 'Microsoft Exchange Server 2010 SP2'),
- 'Exchange2010_SP3': ('Exchange2010_SP2', 'Microsoft Exchange Server 2010 SP3'),
- 'Exchange2013': ('Exchange2013', 'Microsoft Exchange Server 2013'),
- 'Exchange2013_SP1': ('Exchange2013_SP1', 'Microsoft Exchange Server 2013 SP1'),
- 'Exchange2015': ('Exchange2015', 'Microsoft Exchange Server 2015'),
- 'Exchange2015_SP1': ('Exchange2015_SP1', 'Microsoft Exchange Server 2015 SP1'),
- 'Exchange2016': ('Exchange2016', 'Microsoft Exchange Server 2016'),
- 'Exchange2019': ('Exchange2019', 'Microsoft Exchange Server 2019'),
+ "Exchange2007": ("Exchange2007", "Microsoft Exchange Server 2007"),
+ "Exchange2007_SP1": ("Exchange2007_SP1", "Microsoft Exchange Server 2007 SP1"),
+ "Exchange2007_SP2": ("Exchange2007_SP1", "Microsoft Exchange Server 2007 SP2"),
+ "Exchange2007_SP3": ("Exchange2007_SP1", "Microsoft Exchange Server 2007 SP3"),
+ "Exchange2010": ("Exchange2010", "Microsoft Exchange Server 2010"),
+ "Exchange2010_SP1": ("Exchange2010_SP1", "Microsoft Exchange Server 2010 SP1"),
+ "Exchange2010_SP2": ("Exchange2010_SP2", "Microsoft Exchange Server 2010 SP2"),
+ "Exchange2010_SP3": ("Exchange2010_SP2", "Microsoft Exchange Server 2010 SP3"),
+ "Exchange2013": ("Exchange2013", "Microsoft Exchange Server 2013"),
+ "Exchange2013_SP1": ("Exchange2013_SP1", "Microsoft Exchange Server 2013 SP1"),
+ "Exchange2015": ("Exchange2015", "Microsoft Exchange Server 2015"),
+ "Exchange2015_SP1": ("Exchange2015_SP1", "Microsoft Exchange Server 2015 SP1"),
+ "Exchange2016": ("Exchange2016", "Microsoft Exchange Server 2016"),
+ "Exchange2019": ("Exchange2019", "Microsoft Exchange Server 2019"),
}
# Build a list of unique API versions, used when guessing API version supported by the server. Use reverse order so we
@@ -71,36 +71,36 @@ Module exchangelib.version
# List of build numbers here: https://docs.microsoft.com/en-us/exchange/new-features/build-numbers-and-release-dates
API_VERSION_MAP = {
8: {
- 0: 'Exchange2007',
- 1: 'Exchange2007_SP1',
- 2: 'Exchange2007_SP1',
- 3: 'Exchange2007_SP1',
+ 0: "Exchange2007",
+ 1: "Exchange2007_SP1",
+ 2: "Exchange2007_SP1",
+ 3: "Exchange2007_SP1",
},
14: {
- 0: 'Exchange2010',
- 1: 'Exchange2010_SP1',
- 2: 'Exchange2010_SP2',
- 3: 'Exchange2010_SP2',
+ 0: "Exchange2010",
+ 1: "Exchange2010_SP1",
+ 2: "Exchange2010_SP2",
+ 3: "Exchange2010_SP2",
},
15: {
- 0: 'Exchange2013', # Minor builds starting from 847 are Exchange2013_SP1, see api_version()
- 1: 'Exchange2016',
- 2: 'Exchange2019',
- 20: 'Exchange2016', # This is Office365. See issue #221
+ 0: "Exchange2013", # Minor builds starting from 847 are Exchange2013_SP1, see api_version()
+ 1: "Exchange2016",
+ 2: "Exchange2019",
+ 20: "Exchange2016", # This is Office365. See issue #221
},
}
- __slots__ = 'major_version', 'minor_version', 'major_build', 'minor_build'
+ __slots__ = "major_version", "minor_version", "major_build", "minor_build"
def __init__(self, major_version, minor_version, major_build=0, minor_build=0):
if not isinstance(major_version, int):
- raise InvalidTypeError('major_version', major_version, int)
+ raise InvalidTypeError("major_version", major_version, int)
if not isinstance(minor_version, int):
- raise InvalidTypeError('minor_version', minor_version, int)
+ raise InvalidTypeError("minor_version", minor_version, int)
if not isinstance(major_build, int):
- raise InvalidTypeError('major_build', major_build, int)
+ raise InvalidTypeError("major_build", major_build, int)
if not isinstance(minor_build, int):
- raise InvalidTypeError('minor_build', minor_build, int)
+ raise InvalidTypeError("minor_build", minor_build, int)
self.major_version = major_version
self.minor_version = minor_version
self.major_build = major_build
@@ -111,10 +111,10 @@ Module exchangelib.version
@classmethod
def from_xml(cls, elem):
xml_elems_map = {
- 'major_version': 'MajorVersion',
- 'minor_version': 'MinorVersion',
- 'major_build': 'MajorBuildNumber',
- 'minor_build': 'MinorBuildNumber',
+ "major_version": "MajorVersion",
+ "minor_version": "MinorVersion",
+ "major_build": "MajorBuildNumber",
+ "minor_build": "MinorBuildNumber",
}
kwargs = {}
for k, xml_elem in xml_elems_map.items():
@@ -138,7 +138,7 @@ Module exchangelib.version
:param s:
"""
- bin_s = f'{int(s, 16):032b}' # Convert string to 32-bit binary string
+ bin_s = f"{int(s, 16):032b}" # Convert string to 32-bit binary string
major_version = int(bin_s[4:10], 2)
minor_version = int(bin_s[10:16], 2)
build_number = int(bin_s[17:32], 2)
@@ -146,11 +146,11 @@ Module exchangelib.version
def api_version(self):
if EXCHANGE_2013_SP1 <= self < EXCHANGE_2016:
- return 'Exchange2013_SP1'
+ return "Exchange2013_SP1"
try:
return self.API_VERSION_MAP[self.major_version][self.minor_version]
except KeyError:
- raise ValueError(f'API version for build {self} is unknown')
+ raise ValueError(f"API version for build {self} is unknown")
def fullname(self):
return VERSIONS[self.api_version()][1]
@@ -190,11 +190,12 @@ Module exchangelib.version
return self.__cmp__(other) >= 0
def __str__(self):
- return f'{self.major_version}.{self.minor_version}.{self.major_build}.{self.minor_build}'
+ return f"{self.major_version}.{self.minor_version}.{self.major_build}.{self.minor_build}"
def __repr__(self):
- return self.__class__.__name__ \
- + repr((self.major_version, self.minor_version, self.major_build, self.minor_build))
+ return self.__class__.__name__ + repr(
+ (self.major_version, self.minor_version, self.major_build, self.minor_build)
+ )
# Helpers for comparison operations elsewhere in this package
@@ -213,18 +214,18 @@ Module exchangelib.version
class Version:
"""Holds information about the server version."""
- __slots__ = 'build', 'api_version'
+ __slots__ = "build", "api_version"
def __init__(self, build, api_version=None):
if api_version is None:
if not isinstance(build, Build):
- raise InvalidTypeError('build', build, Build)
+ raise InvalidTypeError("build", build, Build)
self.api_version = build.api_version()
else:
if not isinstance(build, (Build, type(None))):
- raise InvalidTypeError('build', build, Build)
+ raise InvalidTypeError("build", build, Build)
if not isinstance(api_version, str):
- raise InvalidTypeError('api_version', api_version, str)
+ raise InvalidTypeError("api_version", api_version, str)
self.api_version = api_version
self.build = build
@@ -245,53 +246,62 @@ Module exchangelib.version
:param api_version_hint: (Default value = None)
"""
from .services import ResolveNames
+
# The protocol doesn't have a version yet, so default to latest supported version if we don't have a hint.
api_version = api_version_hint or API_VERSIONS[0]
- log.debug('Asking server for version info using API version %s', api_version)
+ log.debug("Asking server for version info using API version %s", api_version)
# We don't know the build version yet. Hopefully, the server will report it in the SOAP header. Lots of
# places expect a version to have a build, so this is a bit dangerous, but passing a fake build around is also
# dangerous. Make sure the call to ResolveNames does not require a version build.
protocol.config.version = Version(build=None, api_version=api_version)
# Use ResolveNames as a minimal request to the server to test if the version is correct. If not, ResolveNames
# will try to guess the version automatically.
- name = str(protocol.credentials) if protocol.credentials and str(protocol.credentials) else 'DUMMY'
+ name = str(protocol.credentials) if protocol.credentials and str(protocol.credentials) else "DUMMY"
try:
list(ResolveNames(protocol=protocol).call(unresolved_entries=[name]))
except ResponseMessageError as e:
# We may have survived long enough to get a new version
if not protocol.config.version.build:
- raise TransportError(f'No valid version headers found in response ({e!r})')
+ raise TransportError(f"No valid version headers found in response ({e!r})")
if not protocol.config.version.build:
- raise TransportError('No valid version headers found in response')
+ raise TransportError("No valid version headers found in response")
return protocol.config.version
@staticmethod
def _is_invalid_version_string(version):
# Check if a version string is bogus, e.g. V2_, V2015_ or V2018_
- return re.match(r'V[0-9]{1,4}_.*', version)
+ return re.match(r"V[0-9]{1,4}_.*", version)
@classmethod
def from_soap_header(cls, requested_api_version, header):
- info = header.find(f'{{{TNS}}}ServerVersionInfo')
+ info = header.find(f"{{{TNS}}}ServerVersionInfo")
if info is None:
- raise TransportError(f'No ServerVersionInfo in header: {xml_to_str(header)!r}')
+ raise TransportError(f"No ServerVersionInfo in header: {xml_to_str(header)!r}")
try:
build = Build.from_xml(elem=info)
except ValueError:
- raise TransportError(f'Bad ServerVersionInfo in response: {xml_to_str(header)!r}')
+ raise TransportError(f"Bad ServerVersionInfo in response: {xml_to_str(header)!r}")
# Not all Exchange servers send the Version element
- api_version_from_server = info.get('Version') or build.api_version()
+ api_version_from_server = info.get("Version") or build.api_version()
if api_version_from_server != requested_api_version:
if cls._is_invalid_version_string(api_version_from_server):
# For unknown reasons, Office 365 may respond with an API version strings that is invalid in a request.
# Detect these so we can fallback to a valid version string.
- log.debug('API version "%s" worked but server reports version "%s". Using "%s"', requested_api_version,
- api_version_from_server, requested_api_version)
+ log.debug(
+ 'API version "%s" worked but server reports version "%s". Using "%s"',
+ requested_api_version,
+ api_version_from_server,
+ requested_api_version,
+ )
api_version_from_server = requested_api_version
else:
# Trust API version from server response
- log.debug('API version "%s" worked but server reports version "%s". Using "%s"', requested_api_version,
- api_version_from_server, api_version_from_server)
+ log.debug(
+ 'API version "%s" worked but server reports version "%s". Using "%s"',
+ requested_api_version,
+ api_version_from_server,
+ api_version_from_server,
+ )
return cls(build=build, api_version=api_version_from_server)
def copy(self):
@@ -310,7 +320,7 @@ Module exchangelib.version
return self.__class__.__name__ + repr((self.build, self.api_version))
def __str__(self):
- return f'Build={self.build}, API={self.api_version}, Fullname={self.fullname}'
+ return f"Build={self.build}, API={self.api_version}, Fullname={self.fullname}"
@classmethod
def from_xml(cls, elem):
xml_elems_map = {
- 'major_version': 'MajorVersion',
- 'minor_version': 'MinorVersion',
- 'major_build': 'MajorBuildNumber',
- 'minor_build': 'MinorBuildNumber',
+ "major_version": "MajorVersion",
+ "minor_version": "MinorVersion",
+ "major_build": "MajorBuildNumber",
+ "minor_build": "MinorBuildNumber",
}
kwargs = {}
for k, xml_elem in xml_elems_map.items():
@@ -569,11 +580,11 @@ Methods
def api_version(self):
if EXCHANGE_2013_SP1 <= self < EXCHANGE_2016:
- return 'Exchange2013_SP1'
+ return "Exchange2013_SP1"
try:
return self.API_VERSION_MAP[self.major_version][self.minor_version]
except KeyError:
- raise ValueError(f'API version for build {self} is unknown')
+ raise ValueError(f"API version for build {self} is unknown")
@@ -604,18 +615,18 @@ Methods
class Version:
"""Holds information about the server version."""
- __slots__ = 'build', 'api_version'
+ __slots__ = "build", "api_version"
def __init__(self, build, api_version=None):
if api_version is None:
if not isinstance(build, Build):
- raise InvalidTypeError('build', build, Build)
+ raise InvalidTypeError("build", build, Build)
self.api_version = build.api_version()
else:
if not isinstance(build, (Build, type(None))):
- raise InvalidTypeError('build', build, Build)
+ raise InvalidTypeError("build", build, Build)
if not isinstance(api_version, str):
- raise InvalidTypeError('api_version', api_version, str)
+ raise InvalidTypeError("api_version", api_version, str)
self.api_version = api_version
self.build = build
@@ -636,53 +647,62 @@ Methods
:param api_version_hint: (Default value = None)
"""
from .services import ResolveNames
+
# The protocol doesn't have a version yet, so default to latest supported version if we don't have a hint.
api_version = api_version_hint or API_VERSIONS[0]
- log.debug('Asking server for version info using API version %s', api_version)
+ log.debug("Asking server for version info using API version %s", api_version)
# We don't know the build version yet. Hopefully, the server will report it in the SOAP header. Lots of
# places expect a version to have a build, so this is a bit dangerous, but passing a fake build around is also
# dangerous. Make sure the call to ResolveNames does not require a version build.
protocol.config.version = Version(build=None, api_version=api_version)
# Use ResolveNames as a minimal request to the server to test if the version is correct. If not, ResolveNames
# will try to guess the version automatically.
- name = str(protocol.credentials) if protocol.credentials and str(protocol.credentials) else 'DUMMY'
+ name = str(protocol.credentials) if protocol.credentials and str(protocol.credentials) else "DUMMY"
try:
list(ResolveNames(protocol=protocol).call(unresolved_entries=[name]))
except ResponseMessageError as e:
# We may have survived long enough to get a new version
if not protocol.config.version.build:
- raise TransportError(f'No valid version headers found in response ({e!r})')
+ raise TransportError(f"No valid version headers found in response ({e!r})")
if not protocol.config.version.build:
- raise TransportError('No valid version headers found in response')
+ raise TransportError("No valid version headers found in response")
return protocol.config.version
@staticmethod
def _is_invalid_version_string(version):
# Check if a version string is bogus, e.g. V2_, V2015_ or V2018_
- return re.match(r'V[0-9]{1,4}_.*', version)
+ return re.match(r"V[0-9]{1,4}_.*", version)
@classmethod
def from_soap_header(cls, requested_api_version, header):
- info = header.find(f'{{{TNS}}}ServerVersionInfo')
+ info = header.find(f"{{{TNS}}}ServerVersionInfo")
if info is None:
- raise TransportError(f'No ServerVersionInfo in header: {xml_to_str(header)!r}')
+ raise TransportError(f"No ServerVersionInfo in header: {xml_to_str(header)!r}")
try:
build = Build.from_xml(elem=info)
except ValueError:
- raise TransportError(f'Bad ServerVersionInfo in response: {xml_to_str(header)!r}')
+ raise TransportError(f"Bad ServerVersionInfo in response: {xml_to_str(header)!r}")
# Not all Exchange servers send the Version element
- api_version_from_server = info.get('Version') or build.api_version()
+ api_version_from_server = info.get("Version") or build.api_version()
if api_version_from_server != requested_api_version:
if cls._is_invalid_version_string(api_version_from_server):
# For unknown reasons, Office 365 may respond with an API version strings that is invalid in a request.
# Detect these so we can fallback to a valid version string.
- log.debug('API version "%s" worked but server reports version "%s". Using "%s"', requested_api_version,
- api_version_from_server, requested_api_version)
+ log.debug(
+ 'API version "%s" worked but server reports version "%s". Using "%s"',
+ requested_api_version,
+ api_version_from_server,
+ requested_api_version,
+ )
api_version_from_server = requested_api_version
else:
# Trust API version from server response
- log.debug('API version "%s" worked but server reports version "%s". Using "%s"', requested_api_version,
- api_version_from_server, api_version_from_server)
+ log.debug(
+ 'API version "%s" worked but server reports version "%s". Using "%s"',
+ requested_api_version,
+ api_version_from_server,
+ api_version_from_server,
+ )
return cls(build=build, api_version=api_version_from_server)
def copy(self):
@@ -701,7 +721,7 @@ Methods
return self.__class__.__name__ + repr((self.build, self.api_version))
def __str__(self):
- return f'Build={self.build}, API={self.api_version}, Fullname={self.fullname}'
+ return f"Build={self.build}, API={self.api_version}, Fullname={self.fullname}"
@classmethod
def from_soap_header(cls, requested_api_version, header):
- info = header.find(f'{{{TNS}}}ServerVersionInfo')
+ info = header.find(f"{{{TNS}}}ServerVersionInfo")
if info is None:
- raise TransportError(f'No ServerVersionInfo in header: {xml_to_str(header)!r}')
+ raise TransportError(f"No ServerVersionInfo in header: {xml_to_str(header)!r}")
try:
build = Build.from_xml(elem=info)
except ValueError:
- raise TransportError(f'Bad ServerVersionInfo in response: {xml_to_str(header)!r}')
+ raise TransportError(f"Bad ServerVersionInfo in response: {xml_to_str(header)!r}")
# Not all Exchange servers send the Version element
- api_version_from_server = info.get('Version') or build.api_version()
+ api_version_from_server = info.get("Version") or build.api_version()
if api_version_from_server != requested_api_version:
if cls._is_invalid_version_string(api_version_from_server):
# For unknown reasons, Office 365 may respond with an API version strings that is invalid in a request.
# Detect these so we can fallback to a valid version string.
- log.debug('API version "%s" worked but server reports version "%s". Using "%s"', requested_api_version,
- api_version_from_server, requested_api_version)
+ log.debug(
+ 'API version "%s" worked but server reports version "%s". Using "%s"',
+ requested_api_version,
+ api_version_from_server,
+ requested_api_version,
+ )
api_version_from_server = requested_api_version
else:
# Trust API version from server response
- log.debug('API version "%s" worked but server reports version "%s". Using "%s"', requested_api_version,
- api_version_from_server, api_version_from_server)
+ log.debug(
+ 'API version "%s" worked but server reports version "%s". Using "%s"',
+ requested_api_version,
+ api_version_from_server,
+ api_version_from_server,
+ )
return cls(build=build, api_version=api_version_from_server)
@@ -768,24 +796,25 @@ exchangelib.winzone
exchangelib.winzone
exchangelib.winzone
exchangelib.winzone
exchangelib.winzone