Module exchangelib.items.task

Classes

class Task (**kwargs)
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()

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.

Ancestors

Class variables

var COMPLETED

The type of the None singleton.

var NOT_STARTED

The type of the None singleton.

var unique_body_idx

The type of the None singleton.

Instance variables

var actual_work

The type of the None singleton.

var assigned_time

The type of the None singleton.

var billing_information

The type of the None singleton.

var change_count

The type of the None singleton.

var companies

The type of the None singleton.

var complete_date

The type of the None singleton.

var contacts

The type of the None singleton.

var delegation_state

The type of the None singleton.

var delegator

The type of the None singleton.

var due_date

The type of the None singleton.

var is_complete

The type of the None singleton.

var is_editable

The type of the None singleton.

var is_recurring

The type of the None singleton.

var is_team_task

The type of the None singleton.

var mileage

The type of the None singleton.

var owner

The type of the None singleton.

var percent_complete

The type of the None singleton.

var recurrence

The type of the None singleton.

var start_date

The type of the None singleton.

var status

The type of the None singleton.

var status_description

The type of the None singleton.

var total_work

The type of the None singleton.

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