exchangelib.items.task API documentation

# Module `exchangelib.items.task`

Expand source code

    import datetime
    import logging
    from decimal import Decimal

    from ..ewsdatetime import UTC, EWSDateTime
    from ..fields import (
        BooleanField,
        CharField,
        Choice,
        ChoiceField,
        DateTimeBackedDateField,
        DateTimeField,
        DecimalField,
        IntegerField,
        TaskRecurrenceField,
        TextField,
        TextListField,
    )
    from .item import Item

    log = logging.getLogger(__name__)

    class Task(Item):
        """MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/task"""

        ELEMENT_NAME = "Task"
        NOT_STARTED = "NotStarted"
        COMPLETED = "Completed"

        actual_work = IntegerField(field_uri="task:ActualWork", min=0)
        assigned_time = DateTimeField(field_uri="task:AssignedTime", is_read_only=True)
        billing_information = TextField(field_uri="task:BillingInformation")
        change_count = IntegerField(field_uri="task:ChangeCount", is_read_only=True, min=0)
        companies = TextListField(field_uri="task:Companies")
        # 'complete_date' can be set, but is ignored by the server, which sets it to now()
        complete_date = DateTimeField(field_uri="task:CompleteDate", is_read_only=True)
        contacts = TextListField(field_uri="task:Contacts")
        delegation_state = ChoiceField(
            field_uri="task:DelegationState",
            choices={
                Choice("NoMatch"),
                Choice("OwnNew"),
                Choice("Owned"),
                Choice("Accepted"),
                Choice("Declined"),
                Choice("Max"),
            },
            is_read_only=True,
        )
        delegator = CharField(field_uri="task:Delegator", is_read_only=True)
        due_date = DateTimeBackedDateField(field_uri="task:DueDate")
        is_editable = BooleanField(field_uri="task:IsAssignmentEditable", is_read_only=True)
        is_complete = BooleanField(field_uri="task:IsComplete", is_read_only=True)
        is_recurring = BooleanField(field_uri="task:IsRecurring", is_read_only=True)
        is_team_task = BooleanField(field_uri="task:IsTeamTask", is_read_only=True)
        mileage = TextField(field_uri="task:Mileage")
        owner = CharField(field_uri="task:Owner", is_read_only=True)
        percent_complete = DecimalField(
            field_uri="task:PercentComplete",
            is_required=True,
            default=Decimal(0.0),
            min=Decimal(0),
            max=Decimal(100),
            is_searchable=False,
        )
        recurrence = TaskRecurrenceField(field_uri="task:Recurrence", is_searchable=False)
        start_date = DateTimeBackedDateField(field_uri="task:StartDate")
        status = ChoiceField(
            field_uri="task:Status",
            choices={
                Choice(NOT_STARTED),
                Choice("InProgress"),
                Choice(COMPLETED),
                Choice("WaitingOnOthers"),
                Choice("Deferred"),
            },
            is_required=True,
            is_searchable=False,
            default=NOT_STARTED,
        )
        status_description = CharField(field_uri="task:StatusDescription", is_read_only=True)
        total_work = IntegerField(field_uri="task:TotalWork", min=0)

        # O365 throws ErrorInternalServerError "[0x004f0102] MapiReplyToBlob" if UniqueBody is requested
        unique_body_idx = Item.FIELDS.index_by_name("unique_body")
        FIELDS = Item.FIELDS[:unique_body_idx] + Item.FIELDS[unique_body_idx + 1 :]

        def clean(self, version=None):
            super().clean(version=version)
            if self.due_date and self.start_date and self.due_date < self.start_date:
                log.warning(
                    "'due_date' must be greater than 'start_date' (%s vs %s). Resetting 'due_date'",
                    self.due_date,
                    self.start_date,
                )
                self.due_date = self.start_date
            if self.complete_date:
                if self.status != self.COMPLETED:
                    log.warning(
                        "'status' must be '%s' when 'complete_date' is set (%s). Resetting", self.COMPLETED, self.status
                    )
                    self.status = self.COMPLETED
                now = datetime.datetime.now(tz=UTC)
                if (self.complete_date - now).total_seconds() > 120:
                    # Reset complete_date values that are in the future
                    # 'complete_date' can be set automatically by the server. Allow some grace between local and server time
                    log.warning("'complete_date' must be in the past (%s vs %s). Resetting", self.complete_date, now)
                    self.complete_date = now
                if self.start_date and self.complete_date.date() < self.start_date:
                    log.warning(
                        "'complete_date' must be greater than 'start_date' (%s vs %s). Resetting",
                        self.complete_date,
                        self.start_date,
                    )
                    self.complete_date = EWSDateTime.combine(self.start_date, datetime.time(0, 0)).replace(tzinfo=UTC)
            if self.percent_complete is not None:
                if self.status == self.COMPLETED and self.percent_complete != Decimal(100):
                    # percent_complete must be 100% if task is complete
                    log.warning(
                        "'percent_complete' must be 100 when 'status' is '%s' (%s). Resetting",
                        self.COMPLETED,
                        self.percent_complete,
                    )
                    self.percent_complete = Decimal(100)
                elif self.status == self.NOT_STARTED and self.percent_complete != Decimal(0):
                    # percent_complete must be 0% if task is not started
                    log.warning(
                        "'percent_complete' must be 0 when 'status' is '%s' (%s). Resetting",
                        self.NOT_STARTED,
                        self.percent_complete,
                    )
                    self.percent_complete = Decimal(0)

        def complete(self):
            # A helper method to mark a task as complete on the server
            self.status = Task.COMPLETED
            self.percent_complete = Decimal(100)
            self.save()

## Classes

`class Task (**kwargs)`

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

  Pick out optional 'account' and 'folder' kwargs, and pass the rest to the parent class.

  :param kwargs: 'account' is optional but allows calling 'send()' and 'delete()' 'folder' is optional but allows calling 'save()'. If 'folder' has an account, and 'account' is not set, we use folder.account.

  Expand source code

      class Task(Item):
          """MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/task"""

          ELEMENT_NAME = "Task"
          NOT_STARTED = "NotStarted"
          COMPLETED = "Completed"

          actual_work = IntegerField(field_uri="task:ActualWork", min=0)
          assigned_time = DateTimeField(field_uri="task:AssignedTime", is_read_only=True)
          billing_information = TextField(field_uri="task:BillingInformation")
          change_count = IntegerField(field_uri="task:ChangeCount", is_read_only=True, min=0)
          companies = TextListField(field_uri="task:Companies")
          # 'complete_date' can be set, but is ignored by the server, which sets it to now()
          complete_date = DateTimeField(field_uri="task:CompleteDate", is_read_only=True)
          contacts = TextListField(field_uri="task:Contacts")
          delegation_state = ChoiceField(
              field_uri="task:DelegationState",
              choices={
                  Choice("NoMatch"),
                  Choice("OwnNew"),
                  Choice("Owned"),
                  Choice("Accepted"),
                  Choice("Declined"),
                  Choice("Max"),
              },
              is_read_only=True,
          )
          delegator = CharField(field_uri="task:Delegator", is_read_only=True)
          due_date = DateTimeBackedDateField(field_uri="task:DueDate")
          is_editable = BooleanField(field_uri="task:IsAssignmentEditable", is_read_only=True)
          is_complete = BooleanField(field_uri="task:IsComplete", is_read_only=True)
          is_recurring = BooleanField(field_uri="task:IsRecurring", is_read_only=True)
          is_team_task = BooleanField(field_uri="task:IsTeamTask", is_read_only=True)
          mileage = TextField(field_uri="task:Mileage")
          owner = CharField(field_uri="task:Owner", is_read_only=True)
          percent_complete = DecimalField(
              field_uri="task:PercentComplete",
              is_required=True,
              default=Decimal(0.0),
              min=Decimal(0),
              max=Decimal(100),
              is_searchable=False,
          )
          recurrence = TaskRecurrenceField(field_uri="task:Recurrence", is_searchable=False)
          start_date = DateTimeBackedDateField(field_uri="task:StartDate")
          status = ChoiceField(
              field_uri="task:Status",
              choices={
                  Choice(NOT_STARTED),
                  Choice("InProgress"),
                  Choice(COMPLETED),
                  Choice("WaitingOnOthers"),
                  Choice("Deferred"),
              },
              is_required=True,
              is_searchable=False,
              default=NOT_STARTED,
          )
          status_description = CharField(field_uri="task:StatusDescription", is_read_only=True)
          total_work = IntegerField(field_uri="task:TotalWork", min=0)

          # O365 throws ErrorInternalServerError "[0x004f0102] MapiReplyToBlob" if UniqueBody is requested
          unique_body_idx = Item.FIELDS.index_by_name("unique_body")
          FIELDS = Item.FIELDS[:unique_body_idx] + Item.FIELDS[unique_body_idx + 1 :]

          def clean(self, version=None):
              super().clean(version=version)
              if self.due_date and self.start_date and self.due_date < self.start_date:
                  log.warning(
                      "'due_date' must be greater than 'start_date' (%s vs %s). Resetting 'due_date'",
                      self.due_date,
                      self.start_date,
                  )
                  self.due_date = self.start_date
              if self.complete_date:
                  if self.status != self.COMPLETED:
                      log.warning(
                          "'status' must be '%s' when 'complete_date' is set (%s). Resetting", self.COMPLETED, self.status
                      )
                      self.status = self.COMPLETED
                  now = datetime.datetime.now(tz=UTC)
                  if (self.complete_date - now).total_seconds() > 120:
                      # Reset complete_date values that are in the future
                      # 'complete_date' can be set automatically by the server. Allow some grace between local and server time
                      log.warning("'complete_date' must be in the past (%s vs %s). Resetting", self.complete_date, now)
                      self.complete_date = now
                  if self.start_date and self.complete_date.date() < self.start_date:
                      log.warning(
                          "'complete_date' must be greater than 'start_date' (%s vs %s). Resetting",
                          self.complete_date,
                          self.start_date,
                      )
                      self.complete_date = EWSDateTime.combine(self.start_date, datetime.time(0, 0)).replace(tzinfo=UTC)
              if self.percent_complete is not None:
                  if self.status == self.COMPLETED and self.percent_complete != Decimal(100):
                      # percent_complete must be 100% if task is complete
                      log.warning(
                          "'percent_complete' must be 100 when 'status' is '%s' (%s). Resetting",
                          self.COMPLETED,
                          self.percent_complete,
                      )
                      self.percent_complete = Decimal(100)
                  elif self.status == self.NOT_STARTED and self.percent_complete != Decimal(0):
                      # percent_complete must be 0% if task is not started
                      log.warning(
                          "'percent_complete' must be 0 when 'status' is '%s' (%s). Resetting",
                          self.NOT_STARTED,
                          self.percent_complete,
                      )
                      self.percent_complete = Decimal(0)

          def complete(self):
              # A helper method to mark a task as complete on the server
              self.status = Task.COMPLETED
              self.percent_complete = Decimal(100)
              self.save()

  ### Ancestors

  - Item
  - BaseItem
  - RegisterMixIn
  - IdChangeKeyMixIn
  - EWSElement

  ### Class variables

  `var COMPLETED`
  `var ELEMENT_NAME`
  `var FIELDS`
  `var NOT_STARTED`
  `var unique_body_idx`

  ### Instance variables

  `var actual_work`
  `var assigned_time`
  `var billing_information`
  `var change_count`
  `var companies`
  `var complete_date`
  `var contacts`
  `var delegation_state`
  `var delegator`
  `var due_date`
  `var is_complete`
  `var is_editable`
  `var is_recurring`
  `var is_team_task`
  `var mileage`
  `var owner`
  `var percent_complete`
  `var recurrence`
  `var start_date`
  `var status`
  `var status_description`
  `var total_work`

  ### Methods

  `def clean(self, version=None)`
    Expand source code

        def clean(self, version=None):
            super().clean(version=version)
            if self.due_date and self.start_date and self.due_date < self.start_date:
                log.warning(
                    "'due_date' must be greater than 'start_date' (%s vs %s). Resetting 'due_date'",
                    self.due_date,
                    self.start_date,
                )
                self.due_date = self.start_date
            if self.complete_date:
                if self.status != self.COMPLETED:
                    log.warning(
                        "'status' must be '%s' when 'complete_date' is set (%s). Resetting", self.COMPLETED, self.status
                    )
                    self.status = self.COMPLETED
                now = datetime.datetime.now(tz=UTC)
                if (self.complete_date - now).total_seconds() > 120:
                    # Reset complete_date values that are in the future
                    # 'complete_date' can be set automatically by the server. Allow some grace between local and server time
                    log.warning("'complete_date' must be in the past (%s vs %s). Resetting", self.complete_date, now)
                    self.complete_date = now
                if self.start_date and self.complete_date.date() < self.start_date:
                    log.warning(
                        "'complete_date' must be greater than 'start_date' (%s vs %s). Resetting",
                        self.complete_date,
                        self.start_date,
                    )
                    self.complete_date = EWSDateTime.combine(self.start_date, datetime.time(0, 0)).replace(tzinfo=UTC)
            if self.percent_complete is not None:
                if self.status == self.COMPLETED and self.percent_complete != Decimal(100):
                    # percent_complete must be 100% if task is complete
                    log.warning(
                        "'percent_complete' must be 100 when 'status' is '%s' (%s). Resetting",
                        self.COMPLETED,
                        self.percent_complete,
                    )
                    self.percent_complete = Decimal(100)
                elif self.status == self.NOT_STARTED and self.percent_complete != Decimal(0):
                    # percent_complete must be 0% if task is not started
                    log.warning(
                        "'percent_complete' must be 0 when 'status' is '%s' (%s). Resetting",
                        self.NOT_STARTED,
                        self.percent_complete,
                    )
                    self.percent_complete = Decimal(0)

  `def complete(self)`
    Expand source code

        def complete(self):
            # A helper method to mark a task as complete on the server
            self.status = Task.COMPLETED
            self.percent_complete = Decimal(100)
            self.save()

  ### Inherited members

  - `Item`:
    - `ID_ELEMENT_CLS`
    - `account`
    - `add_field`
    - `attach`
    - `deregister`
    - `detach`
    - `folder`
    - `register`
    - `remove_field`
    - `supported_fields`
    - `validate_field`