Source code for ics.attendee

from typing import Any, Dict, Generic, Iterable, List, TypeVar

import attr

from ics.utils import check_is_instance
from ics.valuetype.base import ValueConverter
from ics.valuetype.generic import BooleanConverter, URIConverter
from ics.valuetype.text import RawTextConverter

T = TypeVar("T")


@attr.s(frozen=True)
class PersonProperty(Generic[T]):
    name: str = attr.ib()
    converter: ValueConverter[T] = attr.ib(default=RawTextConverter)
    default: Any = attr.ib(default=None)

    def __get__(self, instance: "Person", owner) -> T:
        if self.name not in instance.extra:
            return self.default
        value = instance.extra[self.name]
        if len(value) == 0:
            return self.default
        elif len(value) == 1:
            return self.converter.parse(value[0])
        else:
            raise ValueError(
                f"Expected at most one value for property {self.name!r}, got {value!r}!"
            )

    def __set__(self, instance: "Person", value: T):
        instance.extra[self.name] = [self.converter.serialize(value)]

    def __delete__(self, instance: "Person"):
        instance.extra.pop(self.name, None)


@attr.s(frozen=True)
class PersonMultiProperty(Generic[T]):
    name: str = attr.ib()
    converter: ValueConverter[T] = attr.ib(default=RawTextConverter)
    default: Any = attr.ib(default=None)

    def __get__(self, instance: "Person", owner) -> List[T]:
        if self.name not in instance.extra:
            return self.default
        return [self.converter.parse(v) for v in instance.extra[self.name]]

    def __set__(self, instance: "Person", value: Iterable[T]):
        instance.extra[self.name] = [self.converter.serialize(v) for v in value]

    def __delete__(self, instance: "Person"):
        instance.extra.pop(self.name, None)


@attr.s
class PersonAttrs:
    email: str = attr.ib()
    extra: Dict[str, List[str]] = attr.ib(factory=dict)


class Person(PersonAttrs):
    """Abstract class for Attendee and Organizer."""

    NAME = "ABSTRACT-PERSON"

    def __init__(self, email, extra=None, **kwargs):
        if extra is None:
            extra = dict()
        else:
            check_is_instance("extra", extra, dict)
        super().__init__(email, extra)
        for key, val in kwargs.items():
            setattr(self, key, val)

    sent_by = PersonProperty("SENT-BY", URIConverter)
    common_name = PersonProperty[str]("CN")
    directory = PersonProperty("DIR", URIConverter)


class Organizer(Person):
    """Organizer of an event or todo."""

    NAME = "ORGANIZER"


[docs] class Attendee(Person): """Attendee of an event or todo. Possible values according to iCalendar standard, first value is default: user_type = INDIVIDUAL | GROUP | RESOURCE | ROOM | UNKNOWN member = Person role = REQ-PARTICIPANT | CHAIR | OPT-PARTICIPANT | NON-PARTICIPANT rsvp = False | True delegated_to = Person delegated_from = Person Depending on the Component, different status are possible. Event: status = NEEDS-ACTION | ACCEPTED | DECLINED | TENTATIVE | DELEGATED Todo: status = NEEDS-ACTION | ACCEPTED | DECLINED | TENTATIVE | DELEGATED | COMPLETED | IN-PROCESS """ NAME = "ATTENDEE" user_type = PersonProperty[str]("CUTYPE", default="INDIVIDUAL") member = PersonMultiProperty("MEMBER", converter=URIConverter) role = PersonProperty[str]("ROLE", default="REQ-PARTICIPANT") status = PersonProperty[str]("PARTSTAT", default="NEEDS-ACTION") rsvp = PersonProperty("RSVP", converter=BooleanConverter, default=False) delegated_to = PersonMultiProperty("DELEGATED-TO", converter=URIConverter) delegated_from = PersonMultiProperty("DELEGATED-FROM", converter=URIConverter)