diff --git a/docs/exchangelib/fields.html b/docs/exchangelib/fields.html index 252253d4..0ef39cd5 100644 --- a/docs/exchangelib/fields.html +++ b/docs/exchangelib/fields.html @@ -1358,6 +1358,9 @@

Module exchangelib.fields

class IndexedField(EWSElementField, metaclass=abc.ABCMeta): """A base class for all indexed fields.""" + is_list = True + is_complex = True + PARENT_ELEMENT_NAME = None def __init__(self, *args, **kwargs): @@ -1378,16 +1381,15 @@

Module exchangelib.fields

return hash(self.field_uri) -class EmailAddressesField(IndexedField): - is_list = True - is_complex = True - - PARENT_ELEMENT_NAME = "EmailAddresses" +class SingleFieldIndexedField(IndexedField): + """A base class for all single-field indexed fields.""" def __init__(self, *args, **kwargs): - from .indexed_properties import EmailAddress + from .indexed_properties import SingleFieldIndexedElement - kwargs["value_cls"] = EmailAddress + value_cls = kwargs["value_cls"] + if not issubclass(value_cls, SingleFieldIndexedElement): + raise TypeError(f"'value_cls' {value_cls!r} must be a subclass of type {SingleFieldIndexedElement}") super().__init__(*args, **kwargs) def clean(self, value, version=None): @@ -1396,19 +1398,37 @@

Module exchangelib.fields

if len(value) > len(default_labels): raise ValueError(f"This field can handle at most {len(default_labels)} values (value: {value})") tmp = [] + value_field_name = self.value_cls.value_field(version=version).name for s, default_label in zip(value, default_labels): if not isinstance(s, str): tmp.append(s) continue - tmp.append(self.value_cls(email=s, label=default_label)) + tmp.append(self.value_cls(**{"label": default_label, value_field_name: s})) value = tmp return super().clean(value, version=version) -class PhoneNumberField(IndexedField): - is_list = True - is_complex = True +class EmailAddressesField(SingleFieldIndexedField): + PARENT_ELEMENT_NAME = "EmailAddresses" + def __init__(self, *args, **kwargs): + from .indexed_properties import EmailAddress + + kwargs["value_cls"] = EmailAddress + super().__init__(*args, **kwargs) + + +class ImAddressField(SingleFieldIndexedField): + PARENT_ELEMENT_NAME = "ImAddresses" + + def __init__(self, *args, **kwargs): + from .indexed_properties import ImAddress + + kwargs["value_cls"] = ImAddress + super().__init__(*args, **kwargs) + + +class PhoneNumberField(SingleFieldIndexedField): PARENT_ELEMENT_NAME = "PhoneNumbers" def __init__(self, *args, **kwargs): @@ -3599,39 +3619,23 @@

Inherited members

(*args, **kwargs)
-

A base class for all indexed fields.

+

A base class for all single-field indexed fields.

Expand source code -
class EmailAddressesField(IndexedField):
-    is_list = True
-    is_complex = True
-
+
class EmailAddressesField(SingleFieldIndexedField):
     PARENT_ELEMENT_NAME = "EmailAddresses"
 
     def __init__(self, *args, **kwargs):
         from .indexed_properties import EmailAddress
 
         kwargs["value_cls"] = EmailAddress
-        super().__init__(*args, **kwargs)
-
-    def clean(self, value, version=None):
-        if value is not None:
-            default_labels = self.value_cls.LABEL_CHOICES
-            if len(value) > len(default_labels):
-                raise ValueError(f"This field can handle at most {len(default_labels)} values (value: {value})")
-            tmp = []
-            for s, default_label in zip(value, default_labels):
-                if not isinstance(s, str):
-                    tmp.append(s)
-                    continue
-                tmp.append(self.value_cls(email=s, label=default_label))
-            value = tmp
-        return super().clean(value, version=version)
+ super().__init__(*args, **kwargs)

Ancestors

+
+class ImAddressField +(*args, **kwargs) +
+
+

A base class for all single-field indexed fields.

+
+ +Expand source code + +
class ImAddressField(SingleFieldIndexedField):
+    PARENT_ELEMENT_NAME = "ImAddresses"
+
+    def __init__(self, *args, **kwargs):
+        from .indexed_properties import ImAddress
+
+        kwargs["value_cls"] = ImAddress
+        super().__init__(*args, **kwargs)
+
+

Ancestors

+ +

Class variables

+
+
var PARENT_ELEMENT_NAME
+
+
+
+
+

Inherited members

+ +
class ImportanceField (*args, **kwargs) @@ -5155,6 +5169,9 @@

Inherited members

class IndexedField(EWSElementField, metaclass=abc.ABCMeta):
     """A base class for all indexed fields."""
 
+    is_list = True
+    is_complex = True
+
     PARENT_ELEMENT_NAME = None
 
     def __init__(self, *args, **kwargs):
@@ -5183,9 +5200,8 @@ 

Ancestors

Subclasses

Class variables

@@ -5193,6 +5209,14 @@

Class variables

+
var is_complex
+
+
+
+
var is_list
+
+
+

Methods

@@ -6083,15 +6107,12 @@

Inherited members

(*args, **kwargs)
-

A base class for all indexed fields.

+

A base class for all single-field indexed fields.

Expand source code -
class PhoneNumberField(IndexedField):
-    is_list = True
-    is_complex = True
-
+
class PhoneNumberField(SingleFieldIndexedField):
     PARENT_ELEMENT_NAME = "PhoneNumbers"
 
     def __init__(self, *args, **kwargs):
@@ -6102,6 +6123,7 @@ 

Inherited members

Ancestors

+
+class SingleFieldIndexedField +(*args, **kwargs) +
+
+

A base class for all single-field indexed fields.

+
+ +Expand source code + +
class SingleFieldIndexedField(IndexedField):
+    """A base class for all single-field indexed fields."""
+
+    def __init__(self, *args, **kwargs):
+        from .indexed_properties import SingleFieldIndexedElement
+
+        value_cls = kwargs["value_cls"]
+        if not issubclass(value_cls, SingleFieldIndexedElement):
+            raise TypeError(f"'value_cls' {value_cls!r} must be a subclass of type {SingleFieldIndexedElement}")
+        super().__init__(*args, **kwargs)
+
+    def clean(self, value, version=None):
+        if value is not None:
+            default_labels = self.value_cls.LABEL_CHOICES
+            if len(value) > len(default_labels):
+                raise ValueError(f"This field can handle at most {len(default_labels)} values (value: {value})")
+            tmp = []
+            value_field_name = self.value_cls.value_field(version=version).name
+            for s, default_label in zip(value, default_labels):
+                if not isinstance(s, str):
+                    tmp.append(s)
+                    continue
+                tmp.append(self.value_cls(**{"label": default_label, value_field_name: s}))
+            value = tmp
+        return super().clean(value, version=version)
+
+

Ancestors

+ +

Subclasses

+ +

Methods

+
+
+def clean(self, value, version=None) +
+
+
+
+ +Expand source code + +
def clean(self, value, version=None):
+    if value is not None:
+        default_labels = self.value_cls.LABEL_CHOICES
+        if len(value) > len(default_labels):
+            raise ValueError(f"This field can handle at most {len(default_labels)} values (value: {value})")
+        tmp = []
+        value_field_name = self.value_cls.value_field(version=version).name
+        for s, default_label in zip(value, default_labels):
+            if not isinstance(s, str):
+                tmp.append(s)
+                continue
+            tmp.append(self.value_cls(**{"label": default_label, value_field_name: s}))
+        value = tmp
+    return super().clean(value, version=version)
+
+
+
+

Inherited members

+ +
class StringAttributedValueField (*args, **kwargs) @@ -7528,9 +7630,6 @@

EmailAddressesField

  • @@ -7631,12 +7730,20 @@

    IdField

  • +

    ImAddressField

    + +
  • +
  • ImportanceField

  • IndexedField

  • @@ -7731,8 +7838,6 @@

    PhoneNumberField

  • @@ -7768,6 +7873,12 @@

    SensitivityField

  • +

    SingleFieldIndexedField

    + +
  • +
  • StringAttributedValueField

  • diff --git a/docs/exchangelib/folders/base.html b/docs/exchangelib/folders/base.html index 9ba89d1b..8c39d417 100644 --- a/docs/exchangelib/folders/base.html +++ b/docs/exchangelib/folders/base.html @@ -122,6 +122,8 @@

    Module exchangelib.folders.base

    self.item_sync_state = kwargs.pop("item_sync_state", None) self.folder_sync_state = kwargs.pop("folder_sync_state", None) super().__init__(**kwargs) + if self._distinguished_id and self.account: + self._distinguished_id.mailbox = Mailbox(email_address=self.account.primary_smtp_address) @property @abc.abstractmethod @@ -241,6 +243,15 @@

    Module exchangelib.folders.base

    tree += f" {node}\n" return tree.strip() + @classmethod + def _get_distinguished(cls, folder): + if not cls.DISTINGUISHED_FOLDER_ID: + raise ValueError(f"Class {cls} must have a DISTINGUISHED_FOLDER_ID value") + try: + return cls.resolve(account=folder.account, folder=folder) + except MISSING_FOLDER_ERRORS as e: + raise ErrorFolderNotFound(f"Could not find distinguished folder {cls.DISTINGUISHED_FOLDER_ID!r} ({e})") + @property def has_distinguished_name(self): return self.name and self.DISTINGUISHED_FOLDER_ID and self.name.lower() == self.DISTINGUISHED_FOLDER_ID.lower() @@ -852,7 +863,7 @@

    Module exchangelib.folders.base

    if parent.root != self.root: raise ValueError("'parent.root' must match 'root'") else: - self.root = parent.root + self._root = parent.root 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) @@ -868,10 +879,6 @@

    Module exchangelib.folders.base

    def root(self): return self._root - @root.setter - def root(self, value): - self._root = value - @classmethod def register(cls, *args, **kwargs): if cls is not Folder: @@ -884,24 +891,6 @@

    Module exchangelib.folders.base

    raise TypeError("For folders, custom fields must be registered on the Folder class") return super().deregister(*args, **kwargs) - @classmethod - def get_distinguished(cls, account): - """Get the distinguished folder for this folder class. - - :param account: - :return: - """ - try: - return cls.resolve( - account=account, - folder=DistinguishedFolderId( - id=cls.DISTINGUISHED_FOLDER_ID, - mailbox=Mailbox(email_address=account.primary_smtp_address), - ), - ) - except MISSING_FOLDER_ERRORS: - raise ErrorFolderNotFound(f"Could not find distinguished folder {cls.DISTINGUISHED_FOLDER_ID!r}") - @property def parent(self): if not self.parent_folder_id: @@ -918,7 +907,7 @@

    Module exchangelib.folders.base

    else: if not isinstance(value, BaseFolder): raise InvalidTypeError("value", value, BaseFolder) - self.root = value.root + self._root = value.root self.parent_folder_id = ParentFolderId(id=value.id, changekey=value.changekey) def clean(self, version=None): @@ -928,6 +917,23 @@

    Module exchangelib.folders.base

    if self.root and not isinstance(self.root, RootOfHierarchy): raise InvalidTypeError("root", self.root, RootOfHierarchy) + @classmethod + def get_distinguished(cls, root): + """Get the distinguished folder for this folder class. + + :param root: + :return: + """ + return cls._get_distinguished( + folder=cls( + _distinguished_id=DistinguishedFolderId( + id=cls.DISTINGUISHED_FOLDER_ID, + mailbox=Mailbox(email_address=root.account.primary_smtp_address), + ), + root=root, + ) + ) + @classmethod def from_xml_with_root(cls, elem, root): folder = cls.from_xml(elem=elem, account=root.account) @@ -1025,6 +1031,8 @@

    Classes

    self.item_sync_state = kwargs.pop("item_sync_state", None) self.folder_sync_state = kwargs.pop("folder_sync_state", None) super().__init__(**kwargs) + if self._distinguished_id and self.account: + self._distinguished_id.mailbox = Mailbox(email_address=self.account.primary_smtp_address) @property @abc.abstractmethod @@ -1144,6 +1152,15 @@

    Classes

    tree += f" {node}\n" return tree.strip() + @classmethod + def _get_distinguished(cls, folder): + if not cls.DISTINGUISHED_FOLDER_ID: + raise ValueError(f"Class {cls} must have a DISTINGUISHED_FOLDER_ID value") + try: + return cls.resolve(account=folder.account, folder=folder) + except MISSING_FOLDER_ERRORS as e: + raise ErrorFolderNotFound(f"Could not find distinguished folder {cls.DISTINGUISHED_FOLDER_ID!r} ({e})") + @property def has_distinguished_name(self): return self.name and self.DISTINGUISHED_FOLDER_ID and self.name.lower() == self.DISTINGUISHED_FOLDER_ID.lower() @@ -2975,7 +2992,7 @@

    Inherited members

    if parent.root != self.root: raise ValueError("'parent.root' must match 'root'") else: - self.root = parent.root + self._root = parent.root 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) @@ -2991,10 +3008,6 @@

    Inherited members

    def root(self): return self._root - @root.setter - def root(self, value): - self._root = value - @classmethod def register(cls, *args, **kwargs): if cls is not Folder: @@ -3007,24 +3020,6 @@

    Inherited members

    raise TypeError("For folders, custom fields must be registered on the Folder class") return super().deregister(*args, **kwargs) - @classmethod - def get_distinguished(cls, account): - """Get the distinguished folder for this folder class. - - :param account: - :return: - """ - try: - return cls.resolve( - account=account, - folder=DistinguishedFolderId( - id=cls.DISTINGUISHED_FOLDER_ID, - mailbox=Mailbox(email_address=account.primary_smtp_address), - ), - ) - except MISSING_FOLDER_ERRORS: - raise ErrorFolderNotFound(f"Could not find distinguished folder {cls.DISTINGUISHED_FOLDER_ID!r}") - @property def parent(self): if not self.parent_folder_id: @@ -3041,7 +3036,7 @@

    Inherited members

    else: if not isinstance(value, BaseFolder): raise InvalidTypeError("value", value, BaseFolder) - self.root = value.root + self._root = value.root self.parent_folder_id = ParentFolderId(id=value.id, changekey=value.changekey) def clean(self, version=None): @@ -3051,6 +3046,23 @@

    Inherited members

    if self.root and not isinstance(self.root, RootOfHierarchy): raise InvalidTypeError("root", self.root, RootOfHierarchy) + @classmethod + def get_distinguished(cls, root): + """Get the distinguished folder for this folder class. + + :param root: + :return: + """ + return cls._get_distinguished( + folder=cls( + _distinguished_id=DistinguishedFolderId( + id=cls.DISTINGUISHED_FOLDER_ID, + mailbox=Mailbox(email_address=root.account.primary_smtp_address), + ), + root=root, + ) + ) + @classmethod def from_xml_with_root(cls, elem, root): folder = cls.from_xml(elem=elem, account=root.account) @@ -3173,33 +3185,32 @@

    Static methods

    -def get_distinguished(account) +def get_distinguished(root)

    Get the distinguished folder for this folder class.

    -

    :param account: +

    :param root: :return:

    Expand source code
    @classmethod
    -def get_distinguished(cls, account):
    +def get_distinguished(cls, root):
         """Get the distinguished folder for this folder class.
     
    -    :param account:
    +    :param root:
         :return:
         """
    -    try:
    -        return cls.resolve(
    -            account=account,
    -            folder=DistinguishedFolderId(
    +    return cls._get_distinguished(
    +        folder=cls(
    +            _distinguished_id=DistinguishedFolderId(
                     id=cls.DISTINGUISHED_FOLDER_ID,
    -                mailbox=Mailbox(email_address=account.primary_smtp_address),
    +                mailbox=Mailbox(email_address=root.account.primary_smtp_address),
                 ),
    +            root=root,
             )
    -    except MISSING_FOLDER_ERRORS:
    -        raise ErrorFolderNotFound(f"Could not find distinguished folder {cls.DISTINGUISHED_FOLDER_ID!r}")
    + )
    diff --git a/docs/exchangelib/folders/index.html b/docs/exchangelib/folders/index.html index 44e7b377..556e1f7c 100644 --- a/docs/exchangelib/folders/index.html +++ b/docs/exchangelib/folders/index.html @@ -1545,6 +1545,8 @@

    Inherited members

    self.item_sync_state = kwargs.pop("item_sync_state", None) self.folder_sync_state = kwargs.pop("folder_sync_state", None) super().__init__(**kwargs) + if self._distinguished_id and self.account: + self._distinguished_id.mailbox = Mailbox(email_address=self.account.primary_smtp_address) @property @abc.abstractmethod @@ -1664,6 +1666,15 @@

    Inherited members

    tree += f" {node}\n" return tree.strip() + @classmethod + def _get_distinguished(cls, folder): + if not cls.DISTINGUISHED_FOLDER_ID: + raise ValueError(f"Class {cls} must have a DISTINGUISHED_FOLDER_ID value") + try: + return cls.resolve(account=folder.account, folder=folder) + except MISSING_FOLDER_ERRORS as e: + raise ErrorFolderNotFound(f"Could not find distinguished folder {cls.DISTINGUISHED_FOLDER_ID!r} ({e})") + @property def has_distinguished_name(self): return self.name and self.DISTINGUISHED_FOLDER_ID and self.name.lower() == self.DISTINGUISHED_FOLDER_ID.lower() @@ -4611,7 +4622,9 @@

    Inherited members

    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 - self.mailbox = None
    + self.mailbox = None + elif not self.mailbox: + raise ValueError(f"DistinguishedFolderId {self.id} must have a mailbox")

    Ancestors

  • Get the distinguished folder for this folder class.

    -

    :param account:

    +

    :param account: +:return:

    Expand source code @@ -11253,19 +11293,17 @@

    Static methods

    """Get the distinguished folder for this folder class. :param account: + :return: """ - if not cls.DISTINGUISHED_FOLDER_ID: - raise ValueError(f"Class {cls} must have a DISTINGUISHED_FOLDER_ID value") - try: - return cls.resolve( - account=account, - folder=DistinguishedFolderId( + return cls._get_distinguished( + folder=cls( + _distinguished_id=DistinguishedFolderId( id=cls.DISTINGUISHED_FOLDER_ID, mailbox=Mailbox(email_address=account.primary_smtp_address), ), + account=account, ) - except MISSING_FOLDER_ERRORS: - raise ErrorFolderNotFound(f"Could not find distinguished folder {cls.DISTINGUISHED_FOLDER_ID}") + )
    @@ -11350,16 +11388,16 @@

    Methods

    return f try: log.debug("Requesting distinguished %s folder explicitly", folder_cls) - return folder_cls.get_distinguished(account=self.account) + return folder_cls.get_distinguished(root=self) except ErrorAccessDenied: # Maybe we just don't have GetFolder access? Try FindItem instead log.debug("Testing default %s folder with FindItem", folder_cls) fld = folder_cls( - root=self, _distinguished_id=DistinguishedFolderId( id=folder_cls.DISTINGUISHED_FOLDER_ID, mailbox=Mailbox(email_address=self.account.primary_smtp_address), ), + root=self, ) fld.test_access() return self._folders_map.get(fld.id, fld) # Use cached instance if available diff --git a/docs/exchangelib/folders/queryset.html b/docs/exchangelib/folders/queryset.html index 4098679d..17aa4796 100644 --- a/docs/exchangelib/folders/queryset.html +++ b/docs/exchangelib/folders/queryset.html @@ -102,11 +102,23 @@

    Module exchangelib.folders.queryset

    """Return the query result as exactly one item. Raises DoesNotExist if there are no results, and MultipleObjectsReturned if there are multiple results. """ + from .base import Folder from .collections import FolderCollection if not args and set(kwargs) in ({"id"}, {"id", "changekey"}): + roots = {f.root for f in self.folder_collection.folders} + if len(roots) != 1: + raise ValueError(f"All folders must have the same root hierarchy ({roots})") folders = list( - FolderCollection(account=self.folder_collection.account, folders=[FolderId(**kwargs)]).resolve() + FolderCollection( + account=self.folder_collection.account, + folders=[ + Folder( + _id=FolderId(**kwargs), + root=roots.pop(), + ) + ], + ).resolve() ) elif args or kwargs: folders = list(self.filter(*args, **kwargs)) @@ -278,11 +290,23 @@

    Classes

    """Return the query result as exactly one item. Raises DoesNotExist if there are no results, and MultipleObjectsReturned if there are multiple results. """ + from .base import Folder from .collections import FolderCollection if not args and set(kwargs) in ({"id"}, {"id", "changekey"}): + roots = {f.root for f in self.folder_collection.folders} + if len(roots) != 1: + raise ValueError(f"All folders must have the same root hierarchy ({roots})") folders = list( - FolderCollection(account=self.folder_collection.account, folders=[FolderId(**kwargs)]).resolve() + FolderCollection( + account=self.folder_collection.account, + folders=[ + Folder( + _id=FolderId(**kwargs), + root=roots.pop(), + ) + ], + ).resolve() ) elif args or kwargs: folders = list(self.filter(*args, **kwargs)) @@ -434,11 +458,23 @@

    Methods

    """Return the query result as exactly one item. Raises DoesNotExist if there are no results, and MultipleObjectsReturned if there are multiple results. """ + from .base import Folder from .collections import FolderCollection if not args and set(kwargs) in ({"id"}, {"id", "changekey"}): + roots = {f.root for f in self.folder_collection.folders} + if len(roots) != 1: + raise ValueError(f"All folders must have the same root hierarchy ({roots})") folders = list( - FolderCollection(account=self.folder_collection.account, folders=[FolderId(**kwargs)]).resolve() + FolderCollection( + account=self.folder_collection.account, + folders=[ + Folder( + _id=FolderId(**kwargs), + root=roots.pop(), + ) + ], + ).resolve() ) elif args or kwargs: folders = list(self.filter(*args, **kwargs)) diff --git a/docs/exchangelib/folders/roots.html b/docs/exchangelib/folders/roots.html index e4e8957a..089b61cd 100644 --- a/docs/exchangelib/folders/roots.html +++ b/docs/exchangelib/folders/roots.html @@ -129,25 +129,6 @@

    Module exchangelib.folders.roots

    if f.parent.id == folder.id: yield f - @classmethod - def get_distinguished(cls, account): - """Get the distinguished folder for this folder class. - - :param account: - """ - if not cls.DISTINGUISHED_FOLDER_ID: - raise ValueError(f"Class {cls} must have a DISTINGUISHED_FOLDER_ID value") - try: - return cls.resolve( - account=account, - folder=DistinguishedFolderId( - id=cls.DISTINGUISHED_FOLDER_ID, - mailbox=Mailbox(email_address=account.primary_smtp_address), - ), - ) - except MISSING_FOLDER_ERRORS: - 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 folder was found, try as best we can to return the default folder of type 'folder_cls' @@ -164,16 +145,16 @@

    Module exchangelib.folders.roots

    return f try: log.debug("Requesting distinguished %s folder explicitly", folder_cls) - return folder_cls.get_distinguished(account=self.account) + return folder_cls.get_distinguished(root=self) except ErrorAccessDenied: # Maybe we just don't have GetFolder access? Try FindItem instead log.debug("Testing default %s folder with FindItem", folder_cls) fld = folder_cls( - root=self, _distinguished_id=DistinguishedFolderId( id=folder_cls.DISTINGUISHED_FOLDER_ID, mailbox=Mailbox(email_address=self.account.primary_smtp_address), ), + root=self, ) fld.test_access() return self._folders_map.get(fld.id, fld) # Use cached instance if available @@ -182,6 +163,23 @@

    Module exchangelib.folders.roots

    pass raise ErrorFolderNotFound(f"No usable default {folder_cls} folders") + @classmethod + def get_distinguished(cls, account): + """Get the distinguished folder for this folder class. + + :param account: + :return: + """ + return cls._get_distinguished( + folder=cls( + _distinguished_id=DistinguishedFolderId( + id=cls.DISTINGUISHED_FOLDER_ID, + mailbox=Mailbox(email_address=account.primary_smtp_address), + ), + account=account, + ) + ) + @property def _folders_map(self): if self._subfolders is not None: @@ -192,9 +190,12 @@

    Module exchangelib.folders.roots

    # so we are sure to apply the correct Folder class, then fetch all sub-folders of this root. folders_map = {self.id: self} distinguished_folders = [ - DistinguishedFolderId( - id=cls.DISTINGUISHED_FOLDER_ID, - mailbox=Mailbox(email_address=self.account.primary_smtp_address), + cls( + _distinguished_id=DistinguishedFolderId( + id=cls.DISTINGUISHED_FOLDER_ID, + mailbox=Mailbox(email_address=self.account.primary_smtp_address), + ), + root=self, ) for cls in self.WELLKNOWN_FOLDERS if cls.get_folder_allowed and cls.supports_version(self.account.version) @@ -354,6 +355,11 @@

    Module exchangelib.folders.roots

    DEFAULT_FOLDER_TRAVERSAL_DEPTH = SHALLOW supported_from = EXCHANGE_2007_SP1 + def __init__(self, **kwargs): + super().__init__(**kwargs) + if self._distinguished_id: + self._distinguished_id.mailbox = None # See DistinguishedFolderId.clean() + 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. @@ -507,6 +513,11 @@

    Inherited members

    DEFAULT_FOLDER_TRAVERSAL_DEPTH = SHALLOW supported_from = EXCHANGE_2007_SP1 + def __init__(self, **kwargs): + super().__init__(**kwargs) + if self._distinguished_id: + self._distinguished_id.mailbox = None # See DistinguishedFolderId.clean() + 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. @@ -894,25 +905,6 @@

    Inherited members

    if f.parent.id == folder.id: yield f - @classmethod - def get_distinguished(cls, account): - """Get the distinguished folder for this folder class. - - :param account: - """ - if not cls.DISTINGUISHED_FOLDER_ID: - raise ValueError(f"Class {cls} must have a DISTINGUISHED_FOLDER_ID value") - try: - return cls.resolve( - account=account, - folder=DistinguishedFolderId( - id=cls.DISTINGUISHED_FOLDER_ID, - mailbox=Mailbox(email_address=account.primary_smtp_address), - ), - ) - except MISSING_FOLDER_ERRORS: - 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 folder was found, try as best we can to return the default folder of type 'folder_cls' @@ -929,16 +921,16 @@

    Inherited members

    return f try: log.debug("Requesting distinguished %s folder explicitly", folder_cls) - return folder_cls.get_distinguished(account=self.account) + return folder_cls.get_distinguished(root=self) except ErrorAccessDenied: # Maybe we just don't have GetFolder access? Try FindItem instead log.debug("Testing default %s folder with FindItem", folder_cls) fld = folder_cls( - root=self, _distinguished_id=DistinguishedFolderId( id=folder_cls.DISTINGUISHED_FOLDER_ID, mailbox=Mailbox(email_address=self.account.primary_smtp_address), ), + root=self, ) fld.test_access() return self._folders_map.get(fld.id, fld) # Use cached instance if available @@ -947,6 +939,23 @@

    Inherited members

    pass raise ErrorFolderNotFound(f"No usable default {folder_cls} folders") + @classmethod + def get_distinguished(cls, account): + """Get the distinguished folder for this folder class. + + :param account: + :return: + """ + return cls._get_distinguished( + folder=cls( + _distinguished_id=DistinguishedFolderId( + id=cls.DISTINGUISHED_FOLDER_ID, + mailbox=Mailbox(email_address=account.primary_smtp_address), + ), + account=account, + ) + ) + @property def _folders_map(self): if self._subfolders is not None: @@ -957,9 +966,12 @@

    Inherited members

    # so we are sure to apply the correct Folder class, then fetch all sub-folders of this root. folders_map = {self.id: self} distinguished_folders = [ - DistinguishedFolderId( - id=cls.DISTINGUISHED_FOLDER_ID, - mailbox=Mailbox(email_address=self.account.primary_smtp_address), + cls( + _distinguished_id=DistinguishedFolderId( + id=cls.DISTINGUISHED_FOLDER_ID, + mailbox=Mailbox(email_address=self.account.primary_smtp_address), + ), + root=self, ) for cls in self.WELLKNOWN_FOLDERS if cls.get_folder_allowed and cls.supports_version(self.account.version) @@ -1139,7 +1151,8 @@

    Static methods

    Get the distinguished folder for this folder class.

    -

    :param account:

    +

    :param account: +:return:

    Expand source code @@ -1149,19 +1162,17 @@

    Static methods

    """Get the distinguished folder for this folder class. :param account: + :return: """ - if not cls.DISTINGUISHED_FOLDER_ID: - raise ValueError(f"Class {cls} must have a DISTINGUISHED_FOLDER_ID value") - try: - return cls.resolve( - account=account, - folder=DistinguishedFolderId( + return cls._get_distinguished( + folder=cls( + _distinguished_id=DistinguishedFolderId( id=cls.DISTINGUISHED_FOLDER_ID, mailbox=Mailbox(email_address=account.primary_smtp_address), ), + account=account, ) - except MISSING_FOLDER_ERRORS: - raise ErrorFolderNotFound(f"Could not find distinguished folder {cls.DISTINGUISHED_FOLDER_ID}") + )
    @@ -1246,16 +1257,16 @@

    Methods

    return f try: log.debug("Requesting distinguished %s folder explicitly", folder_cls) - return folder_cls.get_distinguished(account=self.account) + return folder_cls.get_distinguished(root=self) except ErrorAccessDenied: # Maybe we just don't have GetFolder access? Try FindItem instead log.debug("Testing default %s folder with FindItem", folder_cls) fld = folder_cls( - root=self, _distinguished_id=DistinguishedFolderId( id=folder_cls.DISTINGUISHED_FOLDER_ID, mailbox=Mailbox(email_address=self.account.primary_smtp_address), ), + root=self, ) fld.test_access() return self._folders_map.get(fld.id, fld) # Use cached instance if available diff --git a/docs/exchangelib/index.html b/docs/exchangelib/index.html index 6d8252d1..f1539a2f 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.2.1" +__version__ = "5.3.0" __all__ = [ "__version__", @@ -5018,7 +5018,7 @@

    Instance variables

    ) department = TextField(field_uri="contacts:Department") generation = TextField(field_uri="contacts:Generation") - im_addresses = CharField(field_uri="contacts:ImAddresses", is_read_only=True) + im_addresses = ImAddressField(field_uri="contacts:ImAddress") job_title = TextField(field_uri="contacts:JobTitle") manager = TextField(field_uri="contacts:Manager") mileage = TextField(field_uri="contacts:Mileage") @@ -7292,7 +7292,7 @@

    Inherited members

    if parent.root != self.root: raise ValueError("'parent.root' must match 'root'") else: - self.root = parent.root + self._root = parent.root 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) @@ -7308,10 +7308,6 @@

    Inherited members

    def root(self): return self._root - @root.setter - def root(self, value): - self._root = value - @classmethod def register(cls, *args, **kwargs): if cls is not Folder: @@ -7324,24 +7320,6 @@

    Inherited members

    raise TypeError("For folders, custom fields must be registered on the Folder class") return super().deregister(*args, **kwargs) - @classmethod - def get_distinguished(cls, account): - """Get the distinguished folder for this folder class. - - :param account: - :return: - """ - try: - return cls.resolve( - account=account, - folder=DistinguishedFolderId( - id=cls.DISTINGUISHED_FOLDER_ID, - mailbox=Mailbox(email_address=account.primary_smtp_address), - ), - ) - except MISSING_FOLDER_ERRORS: - raise ErrorFolderNotFound(f"Could not find distinguished folder {cls.DISTINGUISHED_FOLDER_ID!r}") - @property def parent(self): if not self.parent_folder_id: @@ -7358,7 +7336,7 @@

    Inherited members

    else: if not isinstance(value, BaseFolder): raise InvalidTypeError("value", value, BaseFolder) - self.root = value.root + self._root = value.root self.parent_folder_id = ParentFolderId(id=value.id, changekey=value.changekey) def clean(self, version=None): @@ -7368,6 +7346,23 @@

    Inherited members

    if self.root and not isinstance(self.root, RootOfHierarchy): raise InvalidTypeError("root", self.root, RootOfHierarchy) + @classmethod + def get_distinguished(cls, root): + """Get the distinguished folder for this folder class. + + :param root: + :return: + """ + return cls._get_distinguished( + folder=cls( + _distinguished_id=DistinguishedFolderId( + id=cls.DISTINGUISHED_FOLDER_ID, + mailbox=Mailbox(email_address=root.account.primary_smtp_address), + ), + root=root, + ) + ) + @classmethod def from_xml_with_root(cls, elem, root): folder = cls.from_xml(elem=elem, account=root.account) @@ -7490,33 +7485,32 @@

    Static methods

    -def get_distinguished(account) +def get_distinguished(root)

    Get the distinguished folder for this folder class.

    -

    :param account: +

    :param root: :return:

    Expand source code
    @classmethod
    -def get_distinguished(cls, account):
    +def get_distinguished(cls, root):
         """Get the distinguished folder for this folder class.
     
    -    :param account:
    +    :param root:
         :return:
         """
    -    try:
    -        return cls.resolve(
    -            account=account,
    -            folder=DistinguishedFolderId(
    +    return cls._get_distinguished(
    +        folder=cls(
    +            _distinguished_id=DistinguishedFolderId(
                     id=cls.DISTINGUISHED_FOLDER_ID,
    -                mailbox=Mailbox(email_address=account.primary_smtp_address),
    +                mailbox=Mailbox(email_address=root.account.primary_smtp_address),
                 ),
    +            root=root,
             )
    -    except MISSING_FOLDER_ERRORS:
    -        raise ErrorFolderNotFound(f"Could not find distinguished folder {cls.DISTINGUISHED_FOLDER_ID!r}")
    + )
    @@ -11865,25 +11859,6 @@

    Inherited members

    if f.parent.id == folder.id: yield f - @classmethod - def get_distinguished(cls, account): - """Get the distinguished folder for this folder class. - - :param account: - """ - if not cls.DISTINGUISHED_FOLDER_ID: - raise ValueError(f"Class {cls} must have a DISTINGUISHED_FOLDER_ID value") - try: - return cls.resolve( - account=account, - folder=DistinguishedFolderId( - id=cls.DISTINGUISHED_FOLDER_ID, - mailbox=Mailbox(email_address=account.primary_smtp_address), - ), - ) - except MISSING_FOLDER_ERRORS: - 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 folder was found, try as best we can to return the default folder of type 'folder_cls' @@ -11900,16 +11875,16 @@

    Inherited members

    return f try: log.debug("Requesting distinguished %s folder explicitly", folder_cls) - return folder_cls.get_distinguished(account=self.account) + return folder_cls.get_distinguished(root=self) except ErrorAccessDenied: # Maybe we just don't have GetFolder access? Try FindItem instead log.debug("Testing default %s folder with FindItem", folder_cls) fld = folder_cls( - root=self, _distinguished_id=DistinguishedFolderId( id=folder_cls.DISTINGUISHED_FOLDER_ID, mailbox=Mailbox(email_address=self.account.primary_smtp_address), ), + root=self, ) fld.test_access() return self._folders_map.get(fld.id, fld) # Use cached instance if available @@ -11918,6 +11893,23 @@

    Inherited members

    pass raise ErrorFolderNotFound(f"No usable default {folder_cls} folders") + @classmethod + def get_distinguished(cls, account): + """Get the distinguished folder for this folder class. + + :param account: + :return: + """ + return cls._get_distinguished( + folder=cls( + _distinguished_id=DistinguishedFolderId( + id=cls.DISTINGUISHED_FOLDER_ID, + mailbox=Mailbox(email_address=account.primary_smtp_address), + ), + account=account, + ) + ) + @property def _folders_map(self): if self._subfolders is not None: @@ -11928,9 +11920,12 @@

    Inherited members

    # so we are sure to apply the correct Folder class, then fetch all sub-folders of this root. folders_map = {self.id: self} distinguished_folders = [ - DistinguishedFolderId( - id=cls.DISTINGUISHED_FOLDER_ID, - mailbox=Mailbox(email_address=self.account.primary_smtp_address), + cls( + _distinguished_id=DistinguishedFolderId( + id=cls.DISTINGUISHED_FOLDER_ID, + mailbox=Mailbox(email_address=self.account.primary_smtp_address), + ), + root=self, ) for cls in self.WELLKNOWN_FOLDERS if cls.get_folder_allowed and cls.supports_version(self.account.version) @@ -12110,7 +12105,8 @@

    Static methods

    Get the distinguished folder for this folder class.

    -

    :param account:

    +

    :param account: +:return:

    Expand source code @@ -12120,19 +12116,17 @@

    Static methods

    """Get the distinguished folder for this folder class. :param account: + :return: """ - if not cls.DISTINGUISHED_FOLDER_ID: - raise ValueError(f"Class {cls} must have a DISTINGUISHED_FOLDER_ID value") - try: - return cls.resolve( - account=account, - folder=DistinguishedFolderId( + return cls._get_distinguished( + folder=cls( + _distinguished_id=DistinguishedFolderId( id=cls.DISTINGUISHED_FOLDER_ID, mailbox=Mailbox(email_address=account.primary_smtp_address), ), + account=account, ) - except MISSING_FOLDER_ERRORS: - raise ErrorFolderNotFound(f"Could not find distinguished folder {cls.DISTINGUISHED_FOLDER_ID}") + )
    @@ -12217,16 +12211,16 @@

    Methods

    return f try: log.debug("Requesting distinguished %s folder explicitly", folder_cls) - return folder_cls.get_distinguished(account=self.account) + return folder_cls.get_distinguished(root=self) except ErrorAccessDenied: # Maybe we just don't have GetFolder access? Try FindItem instead log.debug("Testing default %s folder with FindItem", folder_cls) fld = folder_cls( - root=self, _distinguished_id=DistinguishedFolderId( id=folder_cls.DISTINGUISHED_FOLDER_ID, mailbox=Mailbox(email_address=self.account.primary_smtp_address), ), + root=self, ) fld.test_access() return self._folders_map.get(fld.id, fld) # Use cached instance if available diff --git a/docs/exchangelib/indexed_properties.html b/docs/exchangelib/indexed_properties.html index 797430b5..201fef0a 100644 --- a/docs/exchangelib/indexed_properties.html +++ b/docs/exchangelib/indexed_properties.html @@ -61,6 +61,16 @@

    Module exchangelib.indexed_properties

    email = EmailSubField(is_required=True) +class ImAddress(SingleFieldIndexedElement): + """MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/entry-imaddress""" + + ELEMENT_NAME = "Entry" + LABEL_CHOICES = ("ImAddress1", "ImAddress2", "ImAddress3") + + label = LabelField(field_uri="Key", choices={Choice(c) for c in LABEL_CHOICES}, default=LABEL_CHOICES[0]) + im_address = SubField(is_required=True) + + class PhoneNumber(SingleFieldIndexedElement): """MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/entry-phonenumber""" @@ -186,6 +196,69 @@

    Inherited members

    +
    +class ImAddress +(**kwargs) +
    +
    +

    MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/entry-imaddress

    +
    + +Expand source code + +
    class ImAddress(SingleFieldIndexedElement):
    +    """MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/entry-imaddress"""
    +
    +    ELEMENT_NAME = "Entry"
    +    LABEL_CHOICES = ("ImAddress1", "ImAddress2", "ImAddress3")
    +
    +    label = LabelField(field_uri="Key", choices={Choice(c) for c in LABEL_CHOICES}, default=LABEL_CHOICES[0])
    +    im_address = SubField(is_required=True)
    +
    +

    Ancestors

    + +

    Class variables

    +
    +
    var ELEMENT_NAME
    +
    +
    +
    +
    var FIELDS
    +
    +
    +
    +
    var LABEL_CHOICES
    +
    +
    +
    +
    +

    Instance variables

    +
    +
    var im_address
    +
    +
    +
    +
    var label
    +
    +
    +
    +
    +

    Inherited members

    + +
    class IndexedElement (**kwargs) @@ -480,6 +553,7 @@

    Ancestors

    Subclasses

    Static methods

    @@ -541,6 +615,16 @@

    ImAddress

    + + +
  • IndexedElement