diff --git a/docs/exchangelib/autodiscover/cache.html b/docs/exchangelib/autodiscover/cache.html index 907e0b57..bce9493c 100644 --- a/docs/exchangelib/autodiscover/cache.html +++ b/docs/exchangelib/autodiscover/cache.html @@ -144,9 +144,8 @@
exchangelib.autodiscover.cache
def get_user_settings(self, user, settings=None):
- if not settings:
- settings = [
- "user_dn",
- "mailbox_dn",
- "user_display_name",
- "auto_discover_smtp_address",
- "external_ews_url",
- "ews_supported_schemas",
- ]
+ if settings is None:
+ settings = sorted(UserResponse.SETTINGS_MAP.keys())
for setting in settings:
if setting not in UserResponse.SETTINGS_MAP:
raise ValueError(
diff --git a/docs/exchangelib/autodiscover/protocol.html b/docs/exchangelib/autodiscover/protocol.html
index 99875ef1..93dfd587 100644
--- a/docs/exchangelib/autodiscover/protocol.html
+++ b/docs/exchangelib/autodiscover/protocol.html
@@ -65,15 +65,8 @@ Module exchangelib.autodiscover.protocol
return get_autodiscover_authtype(protocol=self)
def get_user_settings(self, user, settings=None):
- if not settings:
- settings = [
- "user_dn",
- "mailbox_dn",
- "user_display_name",
- "auto_discover_smtp_address",
- "external_ews_url",
- "ews_supported_schemas",
- ]
+ if settings is None:
+ settings = sorted(UserResponse.SETTINGS_MAP.keys())
for setting in settings:
if setting not in UserResponse.SETTINGS_MAP:
raise ValueError(
@@ -144,15 +137,8 @@ Classes
return get_autodiscover_authtype(protocol=self)
def get_user_settings(self, user, settings=None):
- if not settings:
- settings = [
- "user_dn",
- "mailbox_dn",
- "user_display_name",
- "auto_discover_smtp_address",
- "external_ews_url",
- "ews_supported_schemas",
- ]
+ if settings is None:
+ settings = sorted(UserResponse.SETTINGS_MAP.keys())
for setting in settings:
if setting not in UserResponse.SETTINGS_MAP:
raise ValueError(
@@ -245,15 +231,8 @@ Methods
Expand source code
def get_user_settings(self, user, settings=None):
- if not settings:
- settings = [
- "user_dn",
- "mailbox_dn",
- "user_display_name",
- "auto_discover_smtp_address",
- "external_ews_url",
- "ews_supported_schemas",
- ]
+ if settings is None:
+ settings = sorted(UserResponse.SETTINGS_MAP.keys())
for setting in settings:
if setting not in UserResponse.SETTINGS_MAP:
raise ValueError(
diff --git a/docs/exchangelib/credentials.html b/docs/exchangelib/credentials.html
index a6df53cb..ed5d708b 100644
--- a/docs/exchangelib/credentials.html
+++ b/docs/exchangelib/credentials.html
@@ -199,7 +199,8 @@ Module exchangelib.credentials
)
return res
- def token_params(self):
+ @staticmethod
+ def token_params():
"""Extra parameters when requesting the token"""
return {"include_client_id": True}
@@ -506,7 +507,8 @@ Subclasses
)
return res
- def token_params(self):
+ @staticmethod
+ def token_params():
"""Extra parameters when requesting the token"""
return {"include_client_id": True}
@@ -549,6 +551,24 @@ Subclasses
OAuth2AuthorizationCodeCredentials
OAuth2Credentials
+Static methods
+
+
+def token_params()
+
+-
+
Extra parameters when requesting the token
+
+
+Expand source code
+
+@staticmethod
+def token_params():
+ """Extra parameters when requesting the token"""
+ return {"include_client_id": True}
+
+
+
Instance variables
var access_token
@@ -733,20 +753,6 @@ Methods
return hash(tuple(res))
-
-def token_params(self)
-
-
-Extra parameters when requesting the token
-
-
-Expand source code
-
-def token_params(self):
- """Extra parameters when requesting the token"""
- return {"include_client_id": True}
-
-
diff --git a/docs/exchangelib/fields.html b/docs/exchangelib/fields.html
index 0ef39cd5..ac6784f7 100644
--- a/docs/exchangelib/fields.html
+++ b/docs/exchangelib/fields.html
@@ -321,7 +321,6 @@ Module exchangelib.fields
is_searchable=True,
is_attribute=False,
default=None,
- *args,
**kwargs,
):
self.name = name # Usually set by the EWSMeta metaclass
@@ -338,7 +337,7 @@ Module exchangelib.fields
self.is_searchable = is_searchable
# When true, this field is treated as an XML attribute instead of an element
self.is_attribute = is_attribute
- super().__init__(*args, **kwargs)
+ super().__init__(**kwargs)
def clean(self, value, version=None):
if version and not self.supports_version(version):
@@ -3696,7 +3695,7 @@ Inherited members
class EmailSubField
-(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, *args, **kwargs)
+(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, **kwargs)
A field to hold the value on an SingleFieldIndexedElement.
@@ -4126,7 +4125,7 @@ Inherited members
class Field
-(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, *args, **kwargs)
+(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, **kwargs)
Holds information related to an item field.
@@ -4157,7 +4156,6 @@ Inherited members
is_searchable=True,
is_attribute=False,
default=None,
- *args,
**kwargs,
):
self.name = name # Usually set by the EWSMeta metaclass
@@ -4174,7 +4172,7 @@ Inherited members
self.is_searchable = is_searchable
# When true, this field is treated as an XML attribute instead of an element
self.is_attribute = is_attribute
- super().__init__(*args, **kwargs)
+ super().__init__(**kwargs)
def clean(self, value, version=None):
if version and not self.supports_version(version):
@@ -6562,7 +6560,7 @@ Inherited members
class SubField
-(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, *args, **kwargs)
+(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, **kwargs)
A field to hold the value on an IndexedElement.
diff --git a/docs/exchangelib/folders/base.html b/docs/exchangelib/folders/base.html
index 32a5ba63..6b8dc2b3 100644
--- a/docs/exchangelib/folders/base.html
+++ b/docs/exchangelib/folders/base.html
@@ -275,7 +275,7 @@ Module exchangelib.folders.base
from .known_folders import (
ApplicationData,
Calendar,
- Companies,
+ CompanyContacts,
Contacts,
ConversationSettings,
CrawlerData,
@@ -298,7 +298,7 @@ Module exchangelib.folders.base
for folder_cls in (
ApplicationData,
Calendar,
- Companies,
+ CompanyContacts,
Contacts,
ConversationSettings,
CrawlerData,
@@ -1190,7 +1190,7 @@ Classes
from .known_folders import (
ApplicationData,
Calendar,
- Companies,
+ CompanyContacts,
Contacts,
ConversationSettings,
CrawlerData,
@@ -1213,7 +1213,7 @@ Classes
for folder_cls in (
ApplicationData,
Calendar,
- Companies,
+ CompanyContacts,
Contacts,
ConversationSettings,
CrawlerData,
@@ -1872,7 +1872,7 @@ Static methods
from .known_folders import (
ApplicationData,
Calendar,
- Companies,
+ CompanyContacts,
Contacts,
ConversationSettings,
CrawlerData,
@@ -1895,7 +1895,7 @@ Static methods
for folder_cls in (
ApplicationData,
Calendar,
- Companies,
+ CompanyContacts,
Contacts,
ConversationSettings,
CrawlerData,
diff --git a/docs/exchangelib/folders/collections.html b/docs/exchangelib/folders/collections.html
index f6b93b79..f1c1b9bd 100644
--- a/docs/exchangelib/folders/collections.html
+++ b/docs/exchangelib/folders/collections.html
@@ -119,7 +119,7 @@ Module exchangelib.folders.collections
def people(self):
return QuerySet(self).people()
- def view(self, start, end, max_items=None, *args, **kwargs):
+ def view(self, start, end, max_items=None):
"""Implement the CalendarView option to FindItem. The difference between 'filter' and 'view' is that 'filter'
only returns the master CalendarItem for recurring items, while 'view' unfolds recurring items and returns all
CalendarItem occurrences as one would normally expect when presenting a calendar.
@@ -137,7 +137,7 @@ Module exchangelib.folders.collections
:param max_items: (Default value = None)
:return:
"""
- qs = QuerySet(self).filter(*args, **kwargs)
+ qs = QuerySet(self)
qs.calendar_view = CalendarView(start=start, end=end, max_items=max_items)
return qs
@@ -726,7 +726,7 @@ Subclasses
def people(self):
return QuerySet(self).people()
- def view(self, start, end, max_items=None, *args, **kwargs):
+ def view(self, start, end, max_items=None):
"""Implement the CalendarView option to FindItem. The difference between 'filter' and 'view' is that 'filter'
only returns the master CalendarItem for recurring items, while 'view' unfolds recurring items and returns all
CalendarItem occurrences as one would normally expect when presenting a calendar.
@@ -744,7 +744,7 @@ Subclasses
:param max_items: (Default value = None)
:return:
"""
- qs = QuerySet(self).filter(*args, **kwargs)
+ qs = QuerySet(self)
qs.calendar_view = CalendarView(start=start, end=end, max_items=max_items)
return qs
@@ -1831,7 +1831,7 @@ Examples
-def view(self, start, end, max_items=None, *args, **kwargs)
+def view(self, start, end, max_items=None)
Implement the CalendarView option to FindItem. The difference between 'filter' and 'view' is that 'filter'
@@ -1851,7 +1851,7 @@
Examples
Expand source code
-def view(self, start, end, max_items=None, *args, **kwargs):
+def view(self, start, end, max_items=None):
"""Implement the CalendarView option to FindItem. The difference between 'filter' and 'view' is that 'filter'
only returns the master CalendarItem for recurring items, while 'view' unfolds recurring items and returns all
CalendarItem occurrences as one would normally expect when presenting a calendar.
@@ -1869,7 +1869,7 @@ Examples
:param max_items: (Default value = None)
:return:
"""
- qs = QuerySet(self).filter(*args, **kwargs)
+ qs = QuerySet(self)
qs.calendar_view = CalendarView(start=start, end=end, max_items=max_items)
return qs
diff --git a/docs/exchangelib/folders/index.html b/docs/exchangelib/folders/index.html
index 982b1759..df85f225 100644
--- a/docs/exchangelib/folders/index.html
+++ b/docs/exchangelib/folders/index.html
@@ -51,7 +51,7 @@ Module exchangelib.folders
CalendarLogging,
CalendarSearchCache,
CommonViews,
- Companies,
+ CompanyContacts,
Conflicts,
Contacts,
ConversationHistory,
@@ -119,6 +119,7 @@ Module exchangelib.folders
SearchFolders,
SentItems,
ServerFailures,
+ ShadowItems,
SharePointNotifications,
Sharing,
Shortcuts,
@@ -166,7 +167,7 @@ Module exchangelib.folders
"CalendarLogging",
"CalendarSearchCache",
"CommonViews",
- "Companies",
+ "CompanyContacts",
"Conflicts",
"Contacts",
"ConversationHistory",
@@ -247,6 +248,7 @@ Module exchangelib.folders
"SearchFolders",
"SentItems",
"ServerFailures",
+ "ShadowItems",
"SharePointNotifications",
"Sharing",
"ShortNotes",
@@ -473,7 +475,8 @@ Inherited members
class AllContacts(WellknownFolder):
DISTINGUISHED_FOLDER_ID = "allcontacts"
- CONTAINER_CLASS = "IPF.Note"
+ CONTAINER_CLASS = "IPF.Note"
+ supported_from = EXCHANGE_O365
Ancestors
@@ -496,6 +499,10 @@ Class variables
-
+var supported_from
+-
+
+
Inherited members
@@ -547,7 +554,8 @@ Inherited members
class AllItems(WellknownFolder):
DISTINGUISHED_FOLDER_ID = "allitems"
- CONTAINER_CLASS = "IPF"
+ CONTAINER_CLASS = "IPF"
+ supported_from = EXCHANGE_O365
Ancestors
@@ -570,6 +578,10 @@ Class variables
-
+var supported_from
+-
+
+
Inherited members
@@ -621,7 +633,8 @@ Inherited members
class AllPersonMetadata(WellknownFolder):
DISTINGUISHED_FOLDER_ID = "allpersonmetadata"
- CONTAINER_CLASS = "IPF.Note"
+ CONTAINER_CLASS = "IPF.Note"
+ supported_from = EXCHANGE_O365
Ancestors
@@ -644,6 +657,10 @@ Class variables
-
+var supported_from
+-
+
+
Inherited members
@@ -1695,7 +1712,7 @@ Inherited members
from .known_folders import (
ApplicationData,
Calendar,
- Companies,
+ CompanyContacts,
Contacts,
ConversationSettings,
CrawlerData,
@@ -1718,7 +1735,7 @@ Inherited members
for folder_cls in (
ApplicationData,
Calendar,
- Companies,
+ CompanyContacts,
Contacts,
ConversationSettings,
CrawlerData,
@@ -2377,7 +2394,7 @@ Static methods
from .known_folders import (
ApplicationData,
Calendar,
- Companies,
+ CompanyContacts,
Contacts,
ConversationSettings,
CrawlerData,
@@ -2400,7 +2417,7 @@ Static methods
for folder_cls in (
ApplicationData,
Calendar,
- Companies,
+ CompanyContacts,
Contacts,
ConversationSettings,
CrawlerData,
@@ -3883,8 +3900,8 @@ Inherited members
-
-class Companies
+
+class CompanyContacts
(**kwargs)
-
@@ -3893,9 +3910,10 @@
Inherited members
Expand source code
-class Companies(WellknownFolder):
+class CompanyContacts(WellknownFolder):
DISTINGUISHED_FOLDER_ID = "companycontacts"
CONTAINER_CLASS = "IPF.Contact.Company"
+ supported_from = EXCHANGE_O365
supported_item_models = CONTACT_ITEM_CLASSES
LOCALIZED_NAMES = {
"da_DK": ("Firmaer",),
@@ -3914,19 +3932,23 @@ Ancestors
Class variables
-var CONTAINER_CLASS
+var CONTAINER_CLASS
+-
+
+
+var DISTINGUISHED_FOLDER_ID
-
-var DISTINGUISHED_FOLDER_ID
+var LOCALIZED_NAMES
-
-var LOCALIZED_NAMES
+var supported_from
-
-var supported_item_models
+var supported_item_models
-
@@ -5711,7 +5733,7 @@ Inherited members
def people(self):
return QuerySet(self).people()
- def view(self, start, end, max_items=None, *args, **kwargs):
+ def view(self, start, end, max_items=None):
"""Implement the CalendarView option to FindItem. The difference between 'filter' and 'view' is that 'filter'
only returns the master CalendarItem for recurring items, while 'view' unfolds recurring items and returns all
CalendarItem occurrences as one would normally expect when presenting a calendar.
@@ -5729,7 +5751,7 @@ Inherited members
:param max_items: (Default value = None)
:return:
"""
- qs = QuerySet(self).filter(*args, **kwargs)
+ qs = QuerySet(self)
qs.calendar_view = CalendarView(start=start, end=end, max_items=max_items)
return qs
@@ -6816,7 +6838,7 @@ Examples
-def view(self, start, end, max_items=None, *args, **kwargs)
+def view(self, start, end, max_items=None)
-
Implement the CalendarView option to FindItem. The difference between 'filter' and 'view' is that 'filter'
@@ -6836,7 +6858,7 @@
Examples
Expand source code
-def view(self, start, end, max_items=None, *args, **kwargs):
+def view(self, start, end, max_items=None):
"""Implement the CalendarView option to FindItem. The difference between 'filter' and 'view' is that 'filter'
only returns the master CalendarItem for recurring items, while 'view' unfolds recurring items and returns all
CalendarItem occurrences as one would normally expect when presenting a calendar.
@@ -6854,7 +6876,7 @@ Examples
:param max_items: (Default value = None)
:return:
"""
- qs = QuerySet(self).filter(*args, **kwargs)
+ qs = QuerySet(self)
qs.calendar_view = CalendarView(start=start, end=end, max_items=max_items)
return qs
@@ -7523,6 +7545,7 @@ Inherited members
class FromFavoriteSenders(WellknownFolder):
DISTINGUISHED_FOLDER_ID = "fromfavoritesenders"
CONTAINER_CLASS = "IPF.Note"
+ supported_from = EXCHANGE_O365
LOCALIZED_NAMES = {
"da_DK": ("Personer jeg kender",),
}
@@ -7552,6 +7575,10 @@ Class variables
-
+var supported_from
+-
+
+
Inherited members
@@ -7925,7 +7952,8 @@ Inherited members
Expand source code
class Inference(WellknownFolder):
- DISTINGUISHED_FOLDER_ID = "inference"
+ DISTINGUISHED_FOLDER_ID = "inference"
+ supported_from = EXCHANGE_O365
Ancestors
@@ -7944,6 +7972,10 @@ Class variables
-
+var supported_from
+-
+
+
Inherited members
class PeopleCentricConversationBuddies(WellknownFolder):
DISTINGUISHED_FOLDER_ID = "peoplecentricconversationbuddies"
CONTAINER_CLASS = "IPF.Contact.PeopleCentricConversationBuddies"
+ supported_from = EXCHANGE_O365
LOCALIZED_NAMES = {
None: ("PeopleCentricConversation Buddies",),
}
@@ -9357,6 +9391,10 @@ Class variables
-
+var supported_from
+-
+
+
Inherited members
@@ -9561,6 +9599,19 @@ Inherited members
if self._distinguished_id:
self._distinguished_id.mailbox = None # See DistinguishedFolderId.clean()
+ @property
+ def _folders_map(self):
+ # Top-level public folders may point to the root folder of the owning account and not the public folders root
+ # of this account. This breaks the assumption of get_children(). Fix it by overwriting the parent folder.
+ fix_parents = self._subfolders is None
+ res = super()._folders_map
+ if fix_parents:
+ with self._subfolders_lock:
+ for f in res.values():
+ if f.id != self.id:
+ f.parent = self
+ return res
+
def get_children(self, folder):
# EWS does not allow deep traversal of public folders, so self._folders_map will only populate the top-level
# subfolders. To traverse public folders at arbitrary depth, we need to get child folders on demand.
@@ -10846,7 +10897,8 @@ Inherited members
class RelevantContacts(WellknownFolder):
DISTINGUISHED_FOLDER_ID = "relevantcontacts"
- CONTAINER_CLASS = "IPF.Note"
+ CONTAINER_CLASS = "IPF.Note"
+ supported_from = EXCHANGE_O365
Ancestors
@@ -10869,6 +10921,10 @@ Class variables
-
+var supported_from
+-
+
+
Inherited members
@@ -11966,6 +12022,75 @@ Inherited members
+
+class ShadowItems
+(**kwargs)
+
+-
+
A mixin for non-wellknown folders than that are not deletable.
+
+
+Expand source code
+
+class ShadowItems(NonDeletableFolder):
+ CONTAINER_CLASS = "IPF.StoreItem.ShadowItems"
+
+Ancestors
+
+- NonDeletableFolder
+- Folder
+- BaseFolder
+- RegisterMixIn
+- IdChangeKeyMixIn
+- EWSElement
+- SearchableMixIn
+- SupportedVersionClassMixIn
+
+Class variables
+
+var CONTAINER_CLASS
+-
+
+
+
+Inherited members
+
+NonDeletableFolder
:
+
+ID_ELEMENT_CLS
+account
+add_field
+all
+deregister
+exclude
+filter
+folder_cls_from_container_class
+folder_sync_state
+get
+get_distinguished
+get_events
+get_streaming_events
+item_sync_state
+none
+parent
+people
+register
+remove_field
+root
+subscribe_to_pull
+subscribe_to_push
+subscribe_to_streaming
+supported_fields
+sync_hierarchy
+sync_items
+test_access
+tree
+unsubscribe
+validate_field
+
+
+
+
-
@@ -13787,12 +13925,13 @@
Companies
+CompanyContacts
-
@@ -14004,6 +14143,7 @@
CONTAINER_CLASS
DISTINGUISHED_FOLDER_ID
LOCALIZED_NAMES
+supported_from
-
@@ -14041,6 +14181,7 @@
Inference
-
@@ -14162,6 +14303,7 @@
CONTAINER_CLASS
DISTINGUISHED_FOLDER_ID
LOCALIZED_NAMES
+supported_from
-
@@ -14298,6 +14440,7 @@
CONTAINER_CLASS
DISTINGUISHED_FOLDER_ID
+supported_from
-
@@ -14357,9 +14500,16 @@
ShadowItems
+
+
+-
SharePointNotifications
-
@@ -14448,6 +14598,7 @@
TemporarySaves
-
diff --git a/docs/exchangelib/folders/known_folders.html b/docs/exchangelib/folders/known_folders.html
index bc3ec32a..a597eb83 100644
--- a/docs/exchangelib/folders/known_folders.html
+++ b/docs/exchangelib/folders/known_folders.html
@@ -95,16 +95,19 @@
Module exchangelib.folders.known_folders
class AllContacts(WellknownFolder):
DISTINGUISHED_FOLDER_ID = "allcontacts"
CONTAINER_CLASS = "IPF.Note"
+ supported_from = EXCHANGE_O365
class AllItems(WellknownFolder):
DISTINGUISHED_FOLDER_ID = "allitems"
CONTAINER_CLASS = "IPF"
+ supported_from = EXCHANGE_O365
class AllPersonMetadata(WellknownFolder):
DISTINGUISHED_FOLDER_ID = "allpersonmetadata"
CONTAINER_CLASS = "IPF.Note"
+ supported_from = EXCHANGE_O365
class ArchiveDeletedItems(WellknownFolder):
@@ -164,9 +167,10 @@ Module exchangelib.folders.known_folders
return FolderCollection(account=self.account, folders=[self]).view(*args, **kwargs)
-class Companies(WellknownFolder):
+class CompanyContacts(WellknownFolder):
DISTINGUISHED_FOLDER_ID = "companycontacts"
CONTAINER_CLASS = "IPF.Contact.Company"
+ supported_from = EXCHANGE_O365
supported_item_models = CONTACT_ITEM_CLASSES
LOCALIZED_NAMES = {
"da_DK": ("Firmaer",),
@@ -261,6 +265,7 @@ Module exchangelib.folders.known_folders
class FromFavoriteSenders(WellknownFolder):
DISTINGUISHED_FOLDER_ID = "fromfavoritesenders"
CONTAINER_CLASS = "IPF.Note"
+ supported_from = EXCHANGE_O365
LOCALIZED_NAMES = {
"da_DK": ("Personer jeg kender",),
}
@@ -291,6 +296,7 @@ Module exchangelib.folders.known_folders
class Inference(WellknownFolder):
DISTINGUISHED_FOLDER_ID = "inference"
+ supported_from = EXCHANGE_O365
class Journal(WellknownFolder):
@@ -373,6 +379,7 @@ Module exchangelib.folders.known_folders
class PeopleCentricConversationBuddies(WellknownFolder):
DISTINGUISHED_FOLDER_ID = "peoplecentricconversationbuddies"
CONTAINER_CLASS = "IPF.Contact.PeopleCentricConversationBuddies"
+ supported_from = EXCHANGE_O365
LOCALIZED_NAMES = {
None: ("PeopleCentricConversation Buddies",),
}
@@ -428,6 +435,7 @@ Module exchangelib.folders.known_folders
class RelevantContacts(WellknownFolder):
DISTINGUISHED_FOLDER_ID = "relevantcontacts"
CONTAINER_CLASS = "IPF.Note"
+ supported_from = EXCHANGE_O365
class RecoverableItemsDeletions(WellknownFolder):
@@ -484,6 +492,7 @@ Module exchangelib.folders.known_folders
class SharePointNotifications(WellknownFolder):
DISTINGUISHED_FOLDER_ID = "sharepointnotifications"
+ supported_from = EXCHANGE_O365
class ShortNotes(WellknownFolder):
@@ -516,6 +525,7 @@ Module exchangelib.folders.known_folders
class TemporarySaves(WellknownFolder):
DISTINGUISHED_FOLDER_ID = "temporarysaves"
+ supported_from = EXCHANGE_O365
class ToDoSearch(WellknownFolder):
@@ -696,6 +706,10 @@ Module exchangelib.folders.known_folders
pass
+class ShadowItems(NonDeletableFolder):
+ CONTAINER_CLASS = "IPF.StoreItem.ShadowItems"
+
+
class Sharing(NonDeletableFolder):
CONTAINER_CLASS = "IPF.Note"
@@ -766,6 +780,7 @@ Module exchangelib.folders.known_folders
RSSFeeds,
Reminders,
Schedule,
+ ShadowItems,
Sharing,
Shortcuts,
Signal,
@@ -785,7 +800,7 @@ Module exchangelib.folders.known_folders
AllItems,
AllPersonMetadata,
Calendar,
- Companies,
+ CompanyContacts,
Conflicts,
Contacts,
ConversationHistory,
@@ -1038,7 +1053,8 @@ Inherited members
class AllContacts(WellknownFolder):
DISTINGUISHED_FOLDER_ID = "allcontacts"
- CONTAINER_CLASS = "IPF.Note"
+ CONTAINER_CLASS = "IPF.Note"
+ supported_from = EXCHANGE_O365
Ancestors
@@ -1061,6 +1077,10 @@ Class variables
-
+var supported_from
+-
+
+
Inherited members
@@ -1112,7 +1132,8 @@ Inherited members
class AllItems(WellknownFolder):
DISTINGUISHED_FOLDER_ID = "allitems"
- CONTAINER_CLASS = "IPF"
+ CONTAINER_CLASS = "IPF"
+ supported_from = EXCHANGE_O365
Ancestors
@@ -1135,6 +1156,10 @@ Class variables
-
+var supported_from
+-
+
+
Inherited members
@@ -1186,7 +1211,8 @@ Inherited members
class AllPersonMetadata(WellknownFolder):
DISTINGUISHED_FOLDER_ID = "allpersonmetadata"
- CONTAINER_CLASS = "IPF.Note"
+ CONTAINER_CLASS = "IPF.Note"
+ supported_from = EXCHANGE_O365
Ancestors
@@ -1209,6 +1235,10 @@ Class variables
-
+var supported_from
+-
+
+
Inherited members
@@ -2384,8 +2414,8 @@ Inherited members
-
-class Companies
+
+class CompanyContacts
(**kwargs)
-
@@ -2394,9 +2424,10 @@
Inherited members
Expand source code
-class Companies(WellknownFolder):
+class CompanyContacts(WellknownFolder):
DISTINGUISHED_FOLDER_ID = "companycontacts"
CONTAINER_CLASS = "IPF.Contact.Company"
+ supported_from = EXCHANGE_O365
supported_item_models = CONTACT_ITEM_CLASSES
LOCALIZED_NAMES = {
"da_DK": ("Firmaer",),
@@ -2415,19 +2446,23 @@ Ancestors
Class variables
-var CONTAINER_CLASS
+var CONTAINER_CLASS
+-
+
+
+var DISTINGUISHED_FOLDER_ID
-
-var DISTINGUISHED_FOLDER_ID
+var LOCALIZED_NAMES
-
-var LOCALIZED_NAMES
+var supported_from
-
-var supported_item_models
+var supported_item_models
-
@@ -4004,6 +4039,7 @@ Inherited members
class FromFavoriteSenders(WellknownFolder):
DISTINGUISHED_FOLDER_ID = "fromfavoritesenders"
CONTAINER_CLASS = "IPF.Note"
+ supported_from = EXCHANGE_O365
LOCALIZED_NAMES = {
"da_DK": ("Personer jeg kender",),
}
@@ -4033,6 +4069,10 @@ Class variables
-
+var supported_from
+-
+
+
Inherited members
@@ -4406,7 +4446,8 @@ Inherited members
Expand source code
class Inference(WellknownFolder):
- DISTINGUISHED_FOLDER_ID = "inference"
+ DISTINGUISHED_FOLDER_ID = "inference"
+ supported_from = EXCHANGE_O365
Ancestors
@@ -4425,6 +4466,10 @@ Class variables
-
+var supported_from
+-
+
+
Inherited members
class PeopleCentricConversationBuddies(WellknownFolder):
DISTINGUISHED_FOLDER_ID = "peoplecentricconversationbuddies"
CONTAINER_CLASS = "IPF.Contact.PeopleCentricConversationBuddies"
+ supported_from = EXCHANGE_O365
LOCALIZED_NAMES = {
None: ("PeopleCentricConversation Buddies",),
}
@@ -5838,6 +5885,10 @@ Class variables
-
+var supported_from
+-
+
+
Inherited members
@@ -7155,7 +7206,8 @@ Inherited members
class RelevantContacts(WellknownFolder):
DISTINGUISHED_FOLDER_ID = "relevantcontacts"
- CONTAINER_CLASS = "IPF.Note"
+ CONTAINER_CLASS = "IPF.Note"
+ supported_from = EXCHANGE_O365
Ancestors
@@ -7178,6 +7230,10 @@ Class variables
-
+var supported_from
+-
+
+
Inherited members
@@ -7583,6 +7639,75 @@ Inherited members
+
+class ShadowItems
+(**kwargs)
+
+-
+
A mixin for non-wellknown folders than that are not deletable.
+
+
+Expand source code
+
+class ShadowItems(NonDeletableFolder):
+ CONTAINER_CLASS = "IPF.StoreItem.ShadowItems"
+
+Ancestors
+
+- NonDeletableFolder
+- Folder
+- BaseFolder
+- RegisterMixIn
+- IdChangeKeyMixIn
+- EWSElement
+- SearchableMixIn
+- SupportedVersionClassMixIn
+
+Class variables
+
+var CONTAINER_CLASS
+-
+
+
+
+Inherited members
+
+NonDeletableFolder
:
+
+ID_ELEMENT_CLS
+account
+add_field
+all
+deregister
+exclude
+filter
+folder_cls_from_container_class
+folder_sync_state
+get
+get_distinguished
+get_events
+get_streaming_events
+item_sync_state
+none
+parent
+people
+register
+remove_field
+root
+subscribe_to_pull
+subscribe_to_push
+subscribe_to_streaming
+supported_fields
+sync_hierarchy
+sync_items
+test_access
+tree
+unsubscribe
+validate_field
+
+
+
+
Ancestors
@@ -8550,6 +8681,10 @@ Class variables
-
+var supported_from
+-
+
+
Inherited members
@@ -8937,7 +9072,7 @@ Subclasses
- ArchiveRecoverableItemsRoot
- ArchiveRecoverableItemsVersions
- Calendar
-- Companies
+- CompanyContacts
- Conflicts
- Contacts
- ConversationHistory
@@ -9138,6 +9273,7 @@
CONTAINER_CLASS
DISTINGUISHED_FOLDER_ID
+supported_from
-
@@ -9145,6 +9281,7 @@
CONTAINER_CLASS
DISTINGUISHED_FOLDER_ID
+supported_from
-
@@ -9152,6 +9289,7 @@
CONTAINER_CLASS
DISTINGUISHED_FOLDER_ID
+supported_from
-
@@ -9259,12 +9397,13 @@
Companies
+CompanyContacts
-
@@ -9412,6 +9551,7 @@
CONTAINER_CLASS
DISTINGUISHED_FOLDER_ID
LOCALIZED_NAMES
+supported_from
-
@@ -9449,6 +9589,7 @@
Inference
-
@@ -9570,6 +9711,7 @@
CONTAINER_CLASS
DISTINGUISHED_FOLDER_ID
LOCALIZED_NAMES
+supported_from
-
@@ -9697,6 +9839,7 @@
CONTAINER_CLASS
DISTINGUISHED_FOLDER_ID
+supported_from
-
@@ -9730,9 +9873,16 @@
ShadowItems
+
+
+-
SharePointNotifications
-
@@ -9815,6 +9965,7 @@
TemporarySaves
-
diff --git a/docs/exchangelib/folders/roots.html b/docs/exchangelib/folders/roots.html
index 089b61cd..269eca9c 100644
--- a/docs/exchangelib/folders/roots.html
+++ b/docs/exchangelib/folders/roots.html
@@ -360,6 +360,19 @@
Module exchangelib.folders.roots
if self._distinguished_id:
self._distinguished_id.mailbox = None # See DistinguishedFolderId.clean()
+ @property
+ def _folders_map(self):
+ # Top-level public folders may point to the root folder of the owning account and not the public folders root
+ # of this account. This breaks the assumption of get_children(). Fix it by overwriting the parent folder.
+ fix_parents = self._subfolders is None
+ res = super()._folders_map
+ if fix_parents:
+ with self._subfolders_lock:
+ for f in res.values():
+ if f.id != self.id:
+ f.parent = self
+ return res
+
def get_children(self, folder):
# EWS does not allow deep traversal of public folders, so self._folders_map will only populate the top-level
# subfolders. To traverse public folders at arbitrary depth, we need to get child folders on demand.
@@ -518,6 +531,19 @@ Inherited members
if self._distinguished_id:
self._distinguished_id.mailbox = None # See DistinguishedFolderId.clean()
+ @property
+ def _folders_map(self):
+ # Top-level public folders may point to the root folder of the owning account and not the public folders root
+ # of this account. This breaks the assumption of get_children(). Fix it by overwriting the parent folder.
+ fix_parents = self._subfolders is None
+ res = super()._folders_map
+ if fix_parents:
+ with self._subfolders_lock:
+ for f in res.values():
+ if f.id != self.id:
+ f.parent = self
+ return res
+
def get_children(self, folder):
# EWS does not allow deep traversal of public folders, so self._folders_map will only populate the top-level
# subfolders. To traverse public folders at arbitrary depth, we need to get child folders on demand.
diff --git a/docs/exchangelib/index.html b/docs/exchangelib/index.html
index d819c223..ce03f73f 100644
--- a/docs/exchangelib/index.html
+++ b/docs/exchangelib/index.html
@@ -64,7 +64,7 @@ Package exchangelib
from .transport import BASIC, CBA, DIGEST, GSSAPI, NTLM, OAUTH2, SSPI
from .version import Build, Version
-__version__ = "5.4.0"
+__version__ = "5.4.1"
__all__ = [
"AcceptItem",
@@ -7677,7 +7677,7 @@ Inherited members
def people(self):
return QuerySet(self).people()
- def view(self, start, end, max_items=None, *args, **kwargs):
+ def view(self, start, end, max_items=None):
"""Implement the CalendarView option to FindItem. The difference between 'filter' and 'view' is that 'filter'
only returns the master CalendarItem for recurring items, while 'view' unfolds recurring items and returns all
CalendarItem occurrences as one would normally expect when presenting a calendar.
@@ -7695,7 +7695,7 @@ Inherited members
:param max_items: (Default value = None)
:return:
"""
- qs = QuerySet(self).filter(*args, **kwargs)
+ qs = QuerySet(self)
qs.calendar_view = CalendarView(start=start, end=end, max_items=max_items)
return qs
@@ -8782,7 +8782,7 @@ Examples
-def view(self, start, end, max_items=None, *args, **kwargs)
+def view(self, start, end, max_items=None)
-
Implement the CalendarView option to FindItem. The difference between 'filter' and 'view' is that 'filter'
@@ -8802,7 +8802,7 @@
Examples
Expand source code
-def view(self, start, end, max_items=None, *args, **kwargs):
+def view(self, start, end, max_items=None):
"""Implement the CalendarView option to FindItem. The difference between 'filter' and 'view' is that 'filter'
only returns the master CalendarItem for recurring items, while 'view' unfolds recurring items and returns all
CalendarItem occurrences as one would normally expect when presenting a calendar.
@@ -8820,7 +8820,7 @@ Examples
:param max_items: (Default value = None)
:return:
"""
- qs = QuerySet(self).filter(*args, **kwargs)
+ qs = QuerySet(self)
qs.calendar_view = CalendarView(start=start, end=end, max_items=max_items)
return qs
diff --git a/docs/exchangelib/properties.html b/docs/exchangelib/properties.html
index 7bab2a1f..f8178df5 100644
--- a/docs/exchangelib/properties.html
+++ b/docs/exchangelib/properties.html
@@ -2046,7 +2046,7 @@ Module exchangelib.properties
"external_mailbox_server": "ExternalMailboxServer",
"external_mailbox_server_requires_ssl": "ExternalMailboxServerRequiresSSL",
"external_mailbox_server_authentication_methods": "ExternalMailboxServerAuthenticationMethods",
- "ecp_voicemail_url_fragment,": "EcpVoicemailUrlFragment,",
+ "ecp_voicemail_url_fragment,": "EcpVoicemailUrlFragment",
"ecp_email_subscriptions_url_fragment": "EcpEmailSubscriptionsUrlFragment",
"ecp_text_messaging_url_fragment": "EcpTextMessagingUrlFragment",
"ecp_delivery_report_url_fragment": "EcpDeliveryReportUrlFragment",
@@ -2119,15 +2119,21 @@ Module exchangelib.properties
if self.error_code == "InvalidUser":
raise ErrorNonExistentMailbox(self.error_message)
if self.error_code in (
+ "InvalidDomain",
"InvalidRequest",
"InvalidSetting",
- "SettingIsNotAvailable",
- "InvalidDomain",
"NotFederated",
+ "SettingIsNotAvailable",
):
raise AutoDiscoverFailed(f"{self.error_code}: {self.error_message}")
- if self.user_settings_errors:
- raise AutoDiscoverFailed(f"User settings errors: {self.user_settings_errors}")
+ errors_to_report = {}
+ for field_name, (error, message) in (self.user_settings_errors or {}).items():
+ if error in ("InvalidSetting", "SettingIsNotAvailable") and field_name in self.SETTINGS_MAP:
+ # Setting is not available for this user or is unknown to this server. Harmless.
+ continue
+ errors_to_report[field_name] = (error, message)
+ if errors_to_report:
+ raise AutoDiscoverFailed(f"User settings errors: {errors_to_report}")
@classmethod
def parse_elem(cls, elem):
@@ -11627,7 +11633,7 @@ Inherited members
"external_mailbox_server": "ExternalMailboxServer",
"external_mailbox_server_requires_ssl": "ExternalMailboxServerRequiresSSL",
"external_mailbox_server_authentication_methods": "ExternalMailboxServerAuthenticationMethods",
- "ecp_voicemail_url_fragment,": "EcpVoicemailUrlFragment,",
+ "ecp_voicemail_url_fragment,": "EcpVoicemailUrlFragment",
"ecp_email_subscriptions_url_fragment": "EcpEmailSubscriptionsUrlFragment",
"ecp_text_messaging_url_fragment": "EcpTextMessagingUrlFragment",
"ecp_delivery_report_url_fragment": "EcpDeliveryReportUrlFragment",
@@ -11700,15 +11706,21 @@ Inherited members
if self.error_code == "InvalidUser":
raise ErrorNonExistentMailbox(self.error_message)
if self.error_code in (
+ "InvalidDomain",
"InvalidRequest",
"InvalidSetting",
- "SettingIsNotAvailable",
- "InvalidDomain",
"NotFederated",
+ "SettingIsNotAvailable",
):
raise AutoDiscoverFailed(f"{self.error_code}: {self.error_message}")
- if self.user_settings_errors:
- raise AutoDiscoverFailed(f"User settings errors: {self.user_settings_errors}")
+ errors_to_report = {}
+ for field_name, (error, message) in (self.user_settings_errors or {}).items():
+ if error in ("InvalidSetting", "SettingIsNotAvailable") and field_name in self.SETTINGS_MAP:
+ # Setting is not available for this user or is unknown to this server. Harmless.
+ continue
+ errors_to_report[field_name] = (error, message)
+ if errors_to_report:
+ raise AutoDiscoverFailed(f"User settings errors: {errors_to_report}")
@classmethod
def parse_elem(cls, elem):
@@ -11936,15 +11948,21 @@ Methods
if self.error_code == "InvalidUser":
raise ErrorNonExistentMailbox(self.error_message)
if self.error_code in (
+ "InvalidDomain",
"InvalidRequest",
"InvalidSetting",
- "SettingIsNotAvailable",
- "InvalidDomain",
"NotFederated",
+ "SettingIsNotAvailable",
):
raise AutoDiscoverFailed(f"{self.error_code}: {self.error_message}")
- if self.user_settings_errors:
- raise AutoDiscoverFailed(f"User settings errors: {self.user_settings_errors}")
+ errors_to_report = {}
+ for field_name, (error, message) in (self.user_settings_errors or {}).items():
+ if error in ("InvalidSetting", "SettingIsNotAvailable") and field_name in self.SETTINGS_MAP:
+ # Setting is not available for this user or is unknown to this server. Harmless.
+ continue
+ errors_to_report[field_name] = (error, message)
+ if errors_to_report:
+ raise AutoDiscoverFailed(f"User settings errors: {errors_to_report}")
diff --git a/docs/exchangelib/services/common.html b/docs/exchangelib/services/common.html
index b9ed6056..a4b6ee0c 100644
--- a/docs/exchangelib/services/common.html
+++ b/docs/exchangelib/services/common.html
@@ -249,6 +249,7 @@ Module exchangelib.services.common
yield self._elem_to_obj(elem)
def _elem_to_obj(self, elem):
+ """Convert a single XML element to a single Python object"""
if not self.returns_elements:
raise RuntimeError("Incorrect call to method when 'returns_elements' is False")
raise NotImplementedError()
@@ -363,7 +364,7 @@ Module exchangelib.services.common
self.stop_streaming()
def _handle_response_cookies(self, session):
- pass
+ """Code to react on response cookies"""
def _get_response(self, payload, api_version):
"""Send the actual HTTP request and get the response."""
@@ -403,13 +404,13 @@ Module exchangelib.services.common
v for v in self.supported_api_versions() if v != self._version_hint.api_version
)
- def _get_response_xml(self, payload, **parse_opts):
+ def _get_response_xml(self, payload):
"""Send the payload to the server and return relevant elements from the result. Several things happen here:
- * The payload is wrapped in SOAP headers and sent to the server
- * The Exchange API version is negotiated and stored in the protocol object
- * Connection errors are handled and possibly reraised as ErrorServerBusy
- * SOAP errors are raised
- * EWS errors are raised, or passed on to the caller
+ * Wraps the payload is wrapped in SOAP headers and sends to the server
+ * Negotiates the Exchange API version and stores it in the protocol object
+ * Handles connection errors and possibly re-raises them as ErrorServerBusy
+ * Raises SOAP errors
+ * Raises EWS errors or passes them on to the caller
:param payload: The request payload, as an XML object
:return: A generator of XML objects or None if the service does not return a result
@@ -425,15 +426,15 @@ Module exchangelib.services.common
# Let 'requests' decode raw data automatically
r.raw.decode_content = True
try:
- header, body = self._get_soap_parts(response=r, **parse_opts)
+ header, body = self._get_soap_parts(response=r)
except Exception:
r.close() # Release memory
raise
# The body may contain error messages from Exchange, but we still want to collect version info
if header is not None:
- self._update_api_version(api_version=api_version, header=header, **parse_opts)
+ self._update_api_version(api_version=api_version, header=header)
try:
- return self._get_soap_messages(body=body, **parse_opts)
+ return self._get_soap_messages(body=body)
except (
ErrorInvalidServerVersion,
ErrorIncorrectSchemaVersion,
@@ -466,7 +467,7 @@ Module exchangelib.services.common
self.protocol.retry_policy.back_off(e.back_off)
# We'll warn about this later if we actually need to sleep
- def _update_api_version(self, api_version, header, **parse_opts):
+ def _update_api_version(self, api_version, header):
"""Parse the server version contained in SOAP headers and update the version hint stored by the caller, if
necessary.
"""
@@ -499,7 +500,7 @@ Module exchangelib.services.common
return f"{{{MNS}}}{cls.SERVICE_NAME}ResponseMessage"
@classmethod
- def _get_soap_parts(cls, response, **parse_opts):
+ def _get_soap_parts(cls, response):
"""Split the SOAP response into its headers and body elements."""
try:
root = to_xml(response.iter_content())
@@ -514,7 +515,7 @@ Module exchangelib.services.common
raise MalformedResponseError("No Body element in SOAP response")
return header, body
- def _get_soap_messages(self, body, **parse_opts):
+ def _get_soap_messages(self, body):
"""Return the elements in the response containing the response messages. Raises any SOAP exceptions."""
response = body.find(self._response_tag())
if response is None:
@@ -1630,6 +1631,7 @@ Inherited members
yield self._elem_to_obj(elem)
def _elem_to_obj(self, elem):
+ """Convert a single XML element to a single Python object"""
if not self.returns_elements:
raise RuntimeError("Incorrect call to method when 'returns_elements' is False")
raise NotImplementedError()
@@ -1744,7 +1746,7 @@ Inherited members
self.stop_streaming()
def _handle_response_cookies(self, session):
- pass
+ """Code to react on response cookies"""
def _get_response(self, payload, api_version):
"""Send the actual HTTP request and get the response."""
@@ -1784,13 +1786,13 @@ Inherited members
v for v in self.supported_api_versions() if v != self._version_hint.api_version
)
- def _get_response_xml(self, payload, **parse_opts):
+ def _get_response_xml(self, payload):
"""Send the payload to the server and return relevant elements from the result. Several things happen here:
- * The payload is wrapped in SOAP headers and sent to the server
- * The Exchange API version is negotiated and stored in the protocol object
- * Connection errors are handled and possibly reraised as ErrorServerBusy
- * SOAP errors are raised
- * EWS errors are raised, or passed on to the caller
+ * Wraps the payload is wrapped in SOAP headers and sends to the server
+ * Negotiates the Exchange API version and stores it in the protocol object
+ * Handles connection errors and possibly re-raises them as ErrorServerBusy
+ * Raises SOAP errors
+ * Raises EWS errors or passes them on to the caller
:param payload: The request payload, as an XML object
:return: A generator of XML objects or None if the service does not return a result
@@ -1806,15 +1808,15 @@ Inherited members
# Let 'requests' decode raw data automatically
r.raw.decode_content = True
try:
- header, body = self._get_soap_parts(response=r, **parse_opts)
+ header, body = self._get_soap_parts(response=r)
except Exception:
r.close() # Release memory
raise
# The body may contain error messages from Exchange, but we still want to collect version info
if header is not None:
- self._update_api_version(api_version=api_version, header=header, **parse_opts)
+ self._update_api_version(api_version=api_version, header=header)
try:
- return self._get_soap_messages(body=body, **parse_opts)
+ return self._get_soap_messages(body=body)
except (
ErrorInvalidServerVersion,
ErrorIncorrectSchemaVersion,
@@ -1847,7 +1849,7 @@ Inherited members
self.protocol.retry_policy.back_off(e.back_off)
# We'll warn about this later if we actually need to sleep
- def _update_api_version(self, api_version, header, **parse_opts):
+ def _update_api_version(self, api_version, header):
"""Parse the server version contained in SOAP headers and update the version hint stored by the caller, if
necessary.
"""
@@ -1880,7 +1882,7 @@ Inherited members
return f"{{{MNS}}}{cls.SERVICE_NAME}ResponseMessage"
@classmethod
- def _get_soap_parts(cls, response, **parse_opts):
+ def _get_soap_parts(cls, response):
"""Split the SOAP response into its headers and body elements."""
try:
root = to_xml(response.iter_content())
@@ -1895,7 +1897,7 @@ Inherited members
raise MalformedResponseError("No Body element in SOAP response")
return header, body
- def _get_soap_messages(self, body, **parse_opts):
+ def _get_soap_messages(self, body):
"""Return the elements in the response containing the response messages. Raises any SOAP exceptions."""
response = body.find(self._response_tag())
if response is None:
diff --git a/docs/exchangelib/services/get_attachment.html b/docs/exchangelib/services/get_attachment.html
index 5f7c379c..a9cb27b6 100644
--- a/docs/exchangelib/services/get_attachment.html
+++ b/docs/exchangelib/services/get_attachment.html
@@ -93,23 +93,20 @@ Module exchangelib.services.get_attachment
payload.append(attachment_ids_element(items=items, version=self.account.version))
return payload
- def _update_api_version(self, api_version, header, **parse_opts):
- if not parse_opts.get("stream_file_content", False):
- super()._update_api_version(api_version, header, **parse_opts)
+ def _update_api_version(self, api_version, header):
+ if not self.streaming:
+ super()._update_api_version(api_version, header)
# 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):
- return super()._get_soap_parts(response, **parse_opts)
-
+ def _get_soap_parts(self, response):
+ if not self.streaming:
+ return super()._get_soap_parts(response)
# 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):
- return super()._get_soap_messages(body, **parse_opts)
-
+ def _get_soap_messages(self, body):
+ if not self.streaming:
+ return super()._get_soap_messages(body)
# 'body' is actually the raw response passed on by '_get_soap_parts'
r = body
parser = StreamingBase64Parser()
@@ -129,13 +126,14 @@ Module exchangelib.services.get_attachment
)
self.streaming = True
try:
- yield from self._get_response_xml(payload=payload, stream_file_content=True)
+ yield from self._get_response_xml(payload=payload)
except ElementNotFound as enf:
# When the returned XML does not contain a Content element, ElementNotFound is thrown by parser.parse().
# Let the non-streaming SOAP parser parse the response and hook into the normal exception handling.
# Wrap in DummyResponse because _get_soap_parts() expects an iter_content() method.
response = DummyResponse(content=enf.data)
_, body = super()._get_soap_parts(response=response)
+ # TODO: We're skipping ._update_api_version() here because we don't have access to the 'api_version' used.
res = super()._get_soap_messages(body=body)
for e in self._get_elements_in_response(response=res):
if isinstance(e, Exception):
@@ -213,23 +211,20 @@ Classes
payload.append(attachment_ids_element(items=items, version=self.account.version))
return payload
- def _update_api_version(self, api_version, header, **parse_opts):
- if not parse_opts.get("stream_file_content", False):
- super()._update_api_version(api_version, header, **parse_opts)
+ def _update_api_version(self, api_version, header):
+ if not self.streaming:
+ super()._update_api_version(api_version, header)
# 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):
- return super()._get_soap_parts(response, **parse_opts)
-
+ def _get_soap_parts(self, response):
+ if not self.streaming:
+ return super()._get_soap_parts(response)
# 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):
- return super()._get_soap_messages(body, **parse_opts)
-
+ def _get_soap_messages(self, body):
+ if not self.streaming:
+ return super()._get_soap_messages(body)
# 'body' is actually the raw response passed on by '_get_soap_parts'
r = body
parser = StreamingBase64Parser()
@@ -249,13 +244,14 @@ Classes
)
self.streaming = True
try:
- yield from self._get_response_xml(payload=payload, stream_file_content=True)
+ yield from self._get_response_xml(payload=payload)
except ElementNotFound as enf:
# When the returned XML does not contain a Content element, ElementNotFound is thrown by parser.parse().
# Let the non-streaming SOAP parser parse the response and hook into the normal exception handling.
# Wrap in DummyResponse because _get_soap_parts() expects an iter_content() method.
response = DummyResponse(content=enf.data)
_, body = super()._get_soap_parts(response=response)
+ # TODO: We're skipping ._update_api_version() here because we don't have access to the 'api_version' used.
res = super()._get_soap_messages(body=body)
for e in self._get_elements_in_response(response=res):
if isinstance(e, Exception):
@@ -366,13 +362,14 @@ Methods
)
self.streaming = True
try:
- yield from self._get_response_xml(payload=payload, stream_file_content=True)
+ yield from self._get_response_xml(payload=payload)
except ElementNotFound as enf:
# When the returned XML does not contain a Content element, ElementNotFound is thrown by parser.parse().
# Let the non-streaming SOAP parser parse the response and hook into the normal exception handling.
# Wrap in DummyResponse because _get_soap_parts() expects an iter_content() method.
response = DummyResponse(content=enf.data)
_, body = super()._get_soap_parts(response=response)
+ # TODO: We're skipping ._update_api_version() here because we don't have access to the 'api_version' used.
res = super()._get_soap_messages(body=body)
for e in self._get_elements_in_response(response=res):
if isinstance(e, Exception):
diff --git a/docs/exchangelib/services/get_streaming_events.html b/docs/exchangelib/services/get_streaming_events.html
index e5cda087..f422c883 100644
--- a/docs/exchangelib/services/get_streaming_events.html
+++ b/docs/exchangelib/services/get_streaming_events.html
@@ -76,11 +76,11 @@ Module exchangelib.services.get_streaming_events
<
return Notification.from_xml(elem=elem, account=None)
@classmethod
- def _get_soap_parts(cls, response, **parse_opts):
+ def _get_soap_parts(cls, response):
# Pass the response unaltered. We want to use our custom document yielder
return None, response
- def _get_soap_messages(self, body, **parse_opts):
+ def _get_soap_messages(self, body):
# 'body' is actually the raw response passed on by '_get_soap_parts'. We want to continuously read the content,
# looking for complete XML documents. When we have a full document, we want to parse it as if it was a normal
# XML response.
@@ -89,13 +89,13 @@ Module exchangelib.services.get_streaming_events
<
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)
+ _, body = super()._get_soap_parts(response=response)
except Exception:
r.close() # Release memory
raise
# TODO: We're skipping ._update_api_version() here because we don't have access to the 'api_version' used.
# TODO: We should be doing a lot of error handling for ._get_soap_messages().
- yield from super()._get_soap_messages(body=body, **parse_opts)
+ yield from super()._get_soap_messages(body=body)
if self.connection_status == self.CLOSED:
# Don't wait for the TCP connection to timeout
break
@@ -125,9 +125,6 @@ Module exchangelib.services.get_streaming_events
<
subscriptions_elem = create_element("m:SubscriptionIds")
for subscription_id in subscription_ids:
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)
return payload
@@ -192,11 +189,11 @@ Classes
return Notification.from_xml(elem=elem, account=None)
@classmethod
- def _get_soap_parts(cls, response, **parse_opts):
+ def _get_soap_parts(cls, response):
# Pass the response unaltered. We want to use our custom document yielder
return None, response
- def _get_soap_messages(self, body, **parse_opts):
+ def _get_soap_messages(self, body):
# 'body' is actually the raw response passed on by '_get_soap_parts'. We want to continuously read the content,
# looking for complete XML documents. When we have a full document, we want to parse it as if it was a normal
# XML response.
@@ -205,13 +202,13 @@ Classes
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)
+ _, body = super()._get_soap_parts(response=response)
except Exception:
r.close() # Release memory
raise
# TODO: We're skipping ._update_api_version() here because we don't have access to the 'api_version' used.
# TODO: We should be doing a lot of error handling for ._get_soap_messages().
- yield from super()._get_soap_messages(body=body, **parse_opts)
+ yield from super()._get_soap_messages(body=body)
if self.connection_status == self.CLOSED:
# Don't wait for the TCP connection to timeout
break
@@ -241,9 +238,6 @@ Classes
subscriptions_elem = create_element("m:SubscriptionIds")
for subscription_id in subscription_ids:
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)
return payload
@@ -319,9 +313,6 @@ Methods
subscriptions_elem = create_element("m:SubscriptionIds")
for subscription_id in subscription_ids:
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)
return payload
diff --git a/docs/exchangelib/services/get_user_settings.html b/docs/exchangelib/services/get_user_settings.html
index 83745e5d..795fe28a 100644
--- a/docs/exchangelib/services/get_user_settings.html
+++ b/docs/exchangelib/services/get_user_settings.html
@@ -81,14 +81,10 @@ Module exchangelib.services.get_user_settings
Classes
mailbox = create_element("a:Mailbox")
set_xml_value(mailbox, user)
add_xml_child(users_elem, "a:User", mailbox)
- if not len(users_elem):
- raise ValueError("'users' must not be empty")
request.append(users_elem)
requested_settings = create_element("a:RequestedSettings")
for setting in settings:
add_xml_child(requested_settings, "a:Setting", UserResponse.SETTINGS_MAP[setting])
- if not len(requested_settings):
- raise ValueError("'requested_settings' must not be empty")
request.append(requested_settings)
payload.append(request)
return payload
@@ -276,14 +268,10 @@ Methods
mailbox = create_element("a:Mailbox")
set_xml_value(mailbox, user)
add_xml_child(users_elem, "a:User", mailbox)
- if not len(users_elem):
- raise ValueError("'users' must not be empty")
request.append(users_elem)
requested_settings = create_element("a:RequestedSettings")
for setting in settings:
add_xml_child(requested_settings, "a:Setting", UserResponse.SETTINGS_MAP[setting])
- if not len(requested_settings):
- raise ValueError("'requested_settings' must not be empty")
request.append(requested_settings)
payload.append(request)
return payload
diff --git a/docs/exchangelib/services/index.html b/docs/exchangelib/services/index.html
index b2779535..bddc49e5 100644
--- a/docs/exchangelib/services/index.html
+++ b/docs/exchangelib/services/index.html
@@ -1874,6 +1874,7 @@ Inherited members
yield self._elem_to_obj(elem)
def _elem_to_obj(self, elem):
+ """Convert a single XML element to a single Python object"""
if not self.returns_elements:
raise RuntimeError("Incorrect call to method when 'returns_elements' is False")
raise NotImplementedError()
@@ -1988,7 +1989,7 @@ Inherited members
self.stop_streaming()
def _handle_response_cookies(self, session):
- pass
+ """Code to react on response cookies"""
def _get_response(self, payload, api_version):
"""Send the actual HTTP request and get the response."""
@@ -2028,13 +2029,13 @@ Inherited members
v for v in self.supported_api_versions() if v != self._version_hint.api_version
)
- def _get_response_xml(self, payload, **parse_opts):
+ def _get_response_xml(self, payload):
"""Send the payload to the server and return relevant elements from the result. Several things happen here:
- * The payload is wrapped in SOAP headers and sent to the server
- * The Exchange API version is negotiated and stored in the protocol object
- * Connection errors are handled and possibly reraised as ErrorServerBusy
- * SOAP errors are raised
- * EWS errors are raised, or passed on to the caller
+ * Wraps the payload is wrapped in SOAP headers and sends to the server
+ * Negotiates the Exchange API version and stores it in the protocol object
+ * Handles connection errors and possibly re-raises them as ErrorServerBusy
+ * Raises SOAP errors
+ * Raises EWS errors or passes them on to the caller
:param payload: The request payload, as an XML object
:return: A generator of XML objects or None if the service does not return a result
@@ -2050,15 +2051,15 @@ Inherited members
# Let 'requests' decode raw data automatically
r.raw.decode_content = True
try:
- header, body = self._get_soap_parts(response=r, **parse_opts)
+ header, body = self._get_soap_parts(response=r)
except Exception:
r.close() # Release memory
raise
# The body may contain error messages from Exchange, but we still want to collect version info
if header is not None:
- self._update_api_version(api_version=api_version, header=header, **parse_opts)
+ self._update_api_version(api_version=api_version, header=header)
try:
- return self._get_soap_messages(body=body, **parse_opts)
+ return self._get_soap_messages(body=body)
except (
ErrorInvalidServerVersion,
ErrorIncorrectSchemaVersion,
@@ -2091,7 +2092,7 @@ Inherited members
self.protocol.retry_policy.back_off(e.back_off)
# We'll warn about this later if we actually need to sleep
- def _update_api_version(self, api_version, header, **parse_opts):
+ def _update_api_version(self, api_version, header):
"""Parse the server version contained in SOAP headers and update the version hint stored by the caller, if
necessary.
"""
@@ -2124,7 +2125,7 @@ Inherited members
return f"{{{MNS}}}{cls.SERVICE_NAME}ResponseMessage"
@classmethod
- def _get_soap_parts(cls, response, **parse_opts):
+ def _get_soap_parts(cls, response):
"""Split the SOAP response into its headers and body elements."""
try:
root = to_xml(response.iter_content())
@@ -2139,7 +2140,7 @@ Inherited members
raise MalformedResponseError("No Body element in SOAP response")
return header, body
- def _get_soap_messages(self, body, **parse_opts):
+ def _get_soap_messages(self, body):
"""Return the elements in the response containing the response messages. Raises any SOAP exceptions."""
response = body.find(self._response_tag())
if response is None:
@@ -3630,23 +3631,20 @@ Inherited members
payload.append(attachment_ids_element(items=items, version=self.account.version))
return payload
- def _update_api_version(self, api_version, header, **parse_opts):
- if not parse_opts.get("stream_file_content", False):
- super()._update_api_version(api_version, header, **parse_opts)
+ def _update_api_version(self, api_version, header):
+ if not self.streaming:
+ super()._update_api_version(api_version, header)
# 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):
- return super()._get_soap_parts(response, **parse_opts)
-
+ def _get_soap_parts(self, response):
+ if not self.streaming:
+ return super()._get_soap_parts(response)
# 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):
- return super()._get_soap_messages(body, **parse_opts)
-
+ def _get_soap_messages(self, body):
+ if not self.streaming:
+ return super()._get_soap_messages(body)
# 'body' is actually the raw response passed on by '_get_soap_parts'
r = body
parser = StreamingBase64Parser()
@@ -3666,13 +3664,14 @@ Inherited members
)
self.streaming = True
try:
- yield from self._get_response_xml(payload=payload, stream_file_content=True)
+ yield from self._get_response_xml(payload=payload)
except ElementNotFound as enf:
# When the returned XML does not contain a Content element, ElementNotFound is thrown by parser.parse().
# Let the non-streaming SOAP parser parse the response and hook into the normal exception handling.
# Wrap in DummyResponse because _get_soap_parts() expects an iter_content() method.
response = DummyResponse(content=enf.data)
_, body = super()._get_soap_parts(response=response)
+ # TODO: We're skipping ._update_api_version() here because we don't have access to the 'api_version' used.
res = super()._get_soap_messages(body=body)
for e in self._get_elements_in_response(response=res):
if isinstance(e, Exception):
@@ -3783,13 +3782,14 @@ Methods
)
self.streaming = True
try:
- yield from self._get_response_xml(payload=payload, stream_file_content=True)
+ yield from self._get_response_xml(payload=payload)
except ElementNotFound as enf:
# When the returned XML does not contain a Content element, ElementNotFound is thrown by parser.parse().
# Let the non-streaming SOAP parser parse the response and hook into the normal exception handling.
# Wrap in DummyResponse because _get_soap_parts() expects an iter_content() method.
response = DummyResponse(content=enf.data)
_, body = super()._get_soap_parts(response=response)
+ # TODO: We're skipping ._update_api_version() here because we don't have access to the 'api_version' used.
res = super()._get_soap_messages(body=body)
for e in self._get_elements_in_response(response=res):
if isinstance(e, Exception):
@@ -5169,11 +5169,11 @@ Inherited members
return Notification.from_xml(elem=elem, account=None)
@classmethod
- def _get_soap_parts(cls, response, **parse_opts):
+ def _get_soap_parts(cls, response):
# Pass the response unaltered. We want to use our custom document yielder
return None, response
- def _get_soap_messages(self, body, **parse_opts):
+ def _get_soap_messages(self, body):
# 'body' is actually the raw response passed on by '_get_soap_parts'. We want to continuously read the content,
# looking for complete XML documents. When we have a full document, we want to parse it as if it was a normal
# XML response.
@@ -5182,13 +5182,13 @@ Inherited members
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)
+ _, body = super()._get_soap_parts(response=response)
except Exception:
r.close() # Release memory
raise
# TODO: We're skipping ._update_api_version() here because we don't have access to the 'api_version' used.
# TODO: We should be doing a lot of error handling for ._get_soap_messages().
- yield from super()._get_soap_messages(body=body, **parse_opts)
+ yield from super()._get_soap_messages(body=body)
if self.connection_status == self.CLOSED:
# Don't wait for the TCP connection to timeout
break
@@ -5218,9 +5218,6 @@ Inherited members
subscriptions_elem = create_element("m:SubscriptionIds")
for subscription_id in subscription_ids:
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)
return payload
@@ -5296,9 +5293,6 @@ Methods
subscriptions_elem = create_element("m:SubscriptionIds")
for subscription_id in subscription_ids:
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)
return payload
@@ -5725,14 +5719,10 @@ Inherited members
mailbox = create_element("a:Mailbox")
set_xml_value(mailbox, user)
add_xml_child(users_elem, "a:User", mailbox)
- if not len(users_elem):
- raise ValueError("'users' must not be empty")
request.append(users_elem)
requested_settings = create_element("a:RequestedSettings")
for setting in settings:
add_xml_child(requested_settings, "a:Setting", UserResponse.SETTINGS_MAP[setting])
- if not len(requested_settings):
- raise ValueError("'requested_settings' must not be empty")
request.append(requested_settings)
payload.append(request)
return payload
@@ -5818,14 +5808,10 @@ Methods
mailbox = create_element("a:Mailbox")
set_xml_value(mailbox, user)
add_xml_child(users_elem, "a:User", mailbox)
- if not len(users_elem):
- raise ValueError("'users' must not be empty")
request.append(users_elem)
requested_settings = create_element("a:RequestedSettings")
for setting in settings:
add_xml_child(requested_settings, "a:Setting", UserResponse.SETTINGS_MAP[setting])
- if not len(requested_settings):
- raise ValueError("'requested_settings' must not be empty")
request.append(requested_settings)
payload.append(request)
return payload
diff --git a/docs/exchangelib/services/subscribe.html b/docs/exchangelib/services/subscribe.html
index 1b9ae971..484bdf34 100644
--- a/docs/exchangelib/services/subscribe.html
+++ b/docs/exchangelib/services/subscribe.html
@@ -82,8 +82,6 @@ Module exchangelib.services.subscribe
event_types_elem = create_element("t:EventTypes")
for event_type in event_types:
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)
return request_elem
@@ -221,8 +219,6 @@ Classes
event_types_elem = create_element("t:EventTypes")
for event_type in event_types:
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)
return request_elem
diff --git a/docs/exchangelib/util.html b/docs/exchangelib/util.html
index 666efd08..e3a75255 100644
--- a/docs/exchangelib/util.html
+++ b/docs/exchangelib/util.html
@@ -450,10 +450,8 @@ Module exchangelib.util
return self._tell
def read(self, size=-1):
- # requests `iter_content()` auto-adjusts the number of bytes based on bandwidth
- # can't assume how many bytes next returns so stash any extra in `self._next`
- if self.closed:
- raise ValueError("read from a closed file")
+ # requests `iter_content()` auto-adjusts the number of bytes based on bandwidth.
+ # We can't assume how many bytes next returns so stash any extra in `self._next`.
if self._next is None:
return b""
if size is None:
@@ -562,10 +560,9 @@ Module exchangelib.util
offending_line = stream.read().splitlines()[e.lineno - 1]
except (IndexError, io.UnsupportedOperation):
raise ParseError(str(e), "<not from file>", e.lineno, e.offset)
- else:
- 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)
+ 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)
except TypeError:
with suppress(IndexError, io.UnsupportedOperation):
stream.seek(0)
@@ -604,7 +601,8 @@ Module exchangelib.util
class PrettyXmlHandler(logging.StreamHandler):
"""A steaming log handler that prettifies log statements containing XML when output is a terminal."""
- def parse_bytes(self, xml_bytes):
+ @staticmethod
+ def parse_bytes(xml_bytes):
return to_xml(xml_bytes)
def prettify_xml(self, xml_bytes):
@@ -699,7 +697,7 @@ Module exchangelib.util
return self.content
def close(self):
- pass
+ """We don't have an actual socket to close"""
def get_domain(email):
@@ -1544,10 +1542,9 @@ Functions
offending_line = stream.read().splitlines()[e.lineno - 1]
except (IndexError, io.UnsupportedOperation):
raise ParseError(str(e), "<not from file>", e.lineno, e.offset)
- else:
- 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)
+ 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)
except TypeError:
with suppress(IndexError, io.UnsupportedOperation):
stream.seek(0)
@@ -1787,10 +1784,8 @@ Inherited members
return self._tell
def read(self, size=-1):
- # requests `iter_content()` auto-adjusts the number of bytes based on bandwidth
- # can't assume how many bytes next returns so stash any extra in `self._next`
- if self.closed:
- raise ValueError("read from a closed file")
+ # requests `iter_content()` auto-adjusts the number of bytes based on bandwidth.
+ # We can't assume how many bytes next returns so stash any extra in `self._next`.
if self._next is None:
return b""
if size is None:
@@ -1851,10 +1846,8 @@ Methods
Expand source code
def read(self, size=-1):
- # requests `iter_content()` auto-adjusts the number of bytes based on bandwidth
- # can't assume how many bytes next returns so stash any extra in `self._next`
- if self.closed:
- raise ValueError("read from a closed file")
+ # requests `iter_content()` auto-adjusts the number of bytes based on bandwidth.
+ # We can't assume how many bytes next returns so stash any extra in `self._next`.
if self._next is None:
return b""
if size is None:
@@ -2022,7 +2015,7 @@ Methods
return self.content
def close(self):
- pass
+ """We don't have an actual socket to close"""
Methods
@@ -2030,13 +2023,13 @@ Methods
def close(self)
-
-
+
We don't have an actual socket to close
Expand source code
def close(self):
- pass
+ """We don't have an actual socket to close"""
@@ -2116,7 +2109,8 @@ Ancestors
class PrettyXmlHandler(logging.StreamHandler):
"""A steaming log handler that prettifies log statements containing XML when output is a terminal."""
- def parse_bytes(self, xml_bytes):
+ @staticmethod
+ def parse_bytes(xml_bytes):
return to_xml(xml_bytes)
def prettify_xml(self, xml_bytes):
@@ -2189,6 +2183,20 @@ Static methods
return highlight(xml_str, XmlLexer(), TerminalFormatter()).rstrip()
+
+def parse_bytes(xml_bytes)
+
+-
+
+
+
+Expand source code
+
+@staticmethod
+def parse_bytes(xml_bytes):
+ return to_xml(xml_bytes)
+
+
Methods
@@ -2246,19 +2254,6 @@ Methods
return False
-
-def parse_bytes(self, xml_bytes)
-
--
-
-
-
-Expand source code
-
-def parse_bytes(self, xml_bytes):
- return to_xml(xml_bytes)
-
-
def prettify_xml(self, xml_bytes)
diff --git a/docs/exchangelib/winzone.html b/docs/exchangelib/winzone.html
index 013ebaaf..715564e4 100644
--- a/docs/exchangelib/winzone.html
+++ b/docs/exchangelib/winzone.html
@@ -668,13 +668,11 @@ Module exchangelib.winzone
)
# Reverse map from Microsoft timezone ID to IANA timezone name. Non-IANA timezone ID's can be added here.
-MS_TIMEZONE_TO_IANA_MAP = dict(
+MS_TIMEZONE_TO_IANA_MAP = {
# Use the CLDR map because the IANA map contains deprecated aliases that not all systems support
- {v[0]: k for k, v in CLDR_TO_MS_TIMEZONE_MAP.items() if v[1] == DEFAULT_TERRITORY},
- **{
- "tzone://Microsoft/Utc": "UTC",
- },
-)
+ **{v[0]: k for k, v in CLDR_TO_MS_TIMEZONE_MAP.items() if v[1] == DEFAULT_TERRITORY},
+ "tzone://Microsoft/Utc": "UTC",
+}