diff --git a/pyrightconfig.stricter.json b/pyrightconfig.stricter.json index 8080d32ae..04d956721 100644 --- a/pyrightconfig.stricter.json +++ b/pyrightconfig.stricter.json @@ -51,6 +51,7 @@ "stubs/httplib2", "stubs/humanfriendly", "stubs/hvac", + "stubs/icalendar", "stubs/influxdb-client", "stubs/jmespath", "stubs/jsonschema", diff --git a/stubs/icalendar/@tests/stubtest_allowlist.txt b/stubs/icalendar/@tests/stubtest_allowlist.txt new file mode 100644 index 000000000..ce84f2c48 --- /dev/null +++ b/stubs/icalendar/@tests/stubtest_allowlist.txt @@ -0,0 +1,9 @@ +# Command line app +icalendar\.cli + +# Tests +icalendar\.tests(\..*)? + +# Methods that use `int` to mean `bool`. +icalendar\.cal\.Component\.get_inline +icalendar\.cal\.Component\.set_inline diff --git a/stubs/icalendar/@tests/test_cases/check_cal.py b/stubs/icalendar/@tests/test_cases/check_cal.py new file mode 100644 index 000000000..639034b1d --- /dev/null +++ b/stubs/icalendar/@tests/test_cases/check_cal.py @@ -0,0 +1,9 @@ +from icalendar.cal import Component + +component = Component() +component.add("summary", "Test 1") +component.add("dtstart", "2022-01-01", encode=True) +component.add("dtend", "2022-01-02", encode=False) +component.add("location", "Test 3", {}) +component.add("dtstamp", "2022-01-03", parameters={}, encode=True) +component.add("description", "Test 2", parameters={}, encode=False) # type: ignore diff --git a/stubs/icalendar/METADATA.toml b/stubs/icalendar/METADATA.toml new file mode 100644 index 000000000..c987aedd4 --- /dev/null +++ b/stubs/icalendar/METADATA.toml @@ -0,0 +1,3 @@ +version = "5.0.*" +upstream_repository = "https://github.com/collective/icalendar" +requires = ["types-pytz"] diff --git a/stubs/icalendar/icalendar/__init__.pyi b/stubs/icalendar/icalendar/__init__.pyi new file mode 100644 index 000000000..24322cd08 --- /dev/null +++ b/stubs/icalendar/icalendar/__init__.pyi @@ -0,0 +1,40 @@ +from typing import Final + +from .cal import ( + Alarm as Alarm, + Calendar as Calendar, + ComponentFactory as ComponentFactory, + Event as Event, + FreeBusy as FreeBusy, + Journal as Journal, + Timezone as Timezone, + TimezoneDaylight as TimezoneDaylight, + TimezoneStandard as TimezoneStandard, + Todo as Todo, +) +from .parser import Parameters as Parameters, q_join as q_join, q_split as q_split +from .prop import ( + FixedOffset as FixedOffset, + LocalTimezone as LocalTimezone, + TypesFactory as TypesFactory, + vBinary as vBinary, + vBoolean as vBoolean, + vCalAddress as vCalAddress, + vDate as vDate, + vDatetime as vDatetime, + vDDDTypes as vDDDTypes, + vDuration as vDuration, + vFloat as vFloat, + vFrequency as vFrequency, + vGeo as vGeo, + vInt as vInt, + vPeriod as vPeriod, + vRecur as vRecur, + vText as vText, + vTime as vTime, + vUri as vUri, + vUTCOffset as vUTCOffset, + vWeekday as vWeekday, +) + +__version__: Final[str] diff --git a/stubs/icalendar/icalendar/cal.pyi b/stubs/icalendar/icalendar/cal.pyi new file mode 100644 index 000000000..8c0265d24 --- /dev/null +++ b/stubs/icalendar/icalendar/cal.pyi @@ -0,0 +1,86 @@ +from _typeshed import Incomplete, SupportsItems +from typing import Any, ClassVar, Final, Literal, overload + +from pytz.tzinfo import DstTzInfo + +from .caselessdict import CaselessDict +from .parser import Contentline, Contentlines +from .prop import TypesFactory + +class ComponentFactory(CaselessDict[Incomplete]): + def __init__(self, *args, **kwargs) -> None: ... + +INLINE: CaselessDict[int] + +class Component(CaselessDict[Incomplete]): + name: ClassVar[str | None] + required: ClassVar[tuple[str, ...]] + singletons: ClassVar[tuple[str, ...]] + multiple: ClassVar[tuple[str, ...]] + exclusive: ClassVar[tuple[str, ...]] + inclusive: ClassVar[tuple[tuple[str, ...], ...]] + ignore_exceptions: ClassVar[bool] + subcomponents: list[Incomplete] + errors: list[str] + + def __init__(self, *args, **kwargs) -> None: ... + def __bool__(self) -> bool: ... + __nonzero__ = __bool__ + def is_empty(self) -> bool: ... + @property + def is_broken(self) -> bool: ... + @overload + def add(self, name: str, value: Any, *, encode: Literal[False]) -> None: ... + @overload + def add(self, name: str, value: Any, parameters: None, encode: Literal[False]) -> None: ... + @overload + def add( + self, name: str, value: Any, parameters: SupportsItems[str, str | None] | None = None, encode: Literal[True] = True + ) -> None: ... + def decoded(self, name, default=[]): ... + def get_inline(self, name, decode: bool = True): ... + def set_inline(self, name, values, encode: bool = True) -> None: ... + def add_component(self, component: Component) -> None: ... + def walk(self, name: Incomplete | None = None): ... + def property_items(self, recursive: bool = True, sorted: bool = True): ... + @overload + @classmethod + def from_ical(cls, st: str, multiple: Literal[False] = False) -> Component: ... # or any of its subclasses + @overload + @classmethod + def from_ical(cls, st: str, multiple: Literal[True]) -> list[Component]: ... # or any of its subclasses + def content_line(self, name: str, value, sorted: bool = True) -> Contentline: ... + def content_lines(self, sorted: bool = True) -> Contentlines: ... + def to_ical(self, sorted: bool = True) -> bytes: ... + def __eq__(self, other: Component) -> bool: ... # type: ignore[override] + +class Event(Component): + name: ClassVar[Literal["VEVENT"]] + +class Todo(Component): + name: ClassVar[Literal["VTODO"]] + +class Journal(Component): + name: ClassVar[Literal["VJOURNAL"]] + +class FreeBusy(Component): + name: ClassVar[Literal["VFREEBUSY"]] + +class Timezone(Component): + name: ClassVar[Literal["VTIMEZONE"]] + def to_tz(self) -> DstTzInfo: ... + +class TimezoneStandard(Component): + name: ClassVar[Literal["STANDARD"]] + +class TimezoneDaylight(Component): + name: ClassVar[Literal["DAYLIGHT"]] + +class Alarm(Component): + name: ClassVar[Literal["VALARM"]] + +class Calendar(Component): + name: ClassVar[Literal["VCALENDAR"]] + +types_factory: Final[TypesFactory] +component_factory: Final[ComponentFactory] diff --git a/stubs/icalendar/icalendar/caselessdict.pyi b/stubs/icalendar/icalendar/caselessdict.pyi new file mode 100644 index 000000000..61fd04dd2 --- /dev/null +++ b/stubs/icalendar/icalendar/caselessdict.pyi @@ -0,0 +1,43 @@ +from _typeshed import SupportsItems +from collections import OrderedDict +from collections.abc import Iterable, Mapping +from typing import ClassVar, TypeVar, overload +from typing_extensions import Self + +_T = TypeVar("_T") +_VT = TypeVar("_VT") + +def canonsort_keys(keys: Iterable[str], canonical_order: Iterable[str] | None = None) -> list[str]: ... +def canonsort_items(dict1: Mapping[str, _VT], canonical_order: Iterable[str] | None = None) -> list[tuple[str, _VT]]: ... + +class CaselessDict(OrderedDict[str, _VT]): + # Inherit complex __init__ from dict. + def __getitem__(self, key: str | bytes) -> _VT: ... + def __setitem__(self, key: str | bytes, value: _VT) -> None: ... + def __delitem__(self, key: str | bytes) -> None: ... + def __contains__(self, key: str | bytes) -> bool: ... # type: ignore[override] + @overload + def get(self, key: str | bytes, default: None = None) -> _VT: ... + @overload + def get(self, key: str | bytes, default: _VT) -> _VT: ... + @overload + def get(self, key: str | bytes, default: _T) -> _VT | _T: ... + @overload + def setdefault(self: CaselessDict[_T | None], key: str | bytes, value: None = None) -> _T | None: ... + @overload + def setdefault(self, key: str | bytes, value: _VT) -> _VT: ... + @overload # type: ignore[override] + def pop(self, key: str | bytes, default: None = None) -> _VT | None: ... + @overload + def pop(self, key: str | bytes, default: _VT) -> _VT: ... + @overload + def pop(self, key: str | bytes, default: _T) -> _VT | _T: ... + def popitem(self) -> tuple[str, _VT]: ... # type: ignore[override] + def has_key(self, key: str | bytes) -> bool: ... + def update(self, *args: SupportsItems[str, _VT] | Iterable[tuple[str, _VT]], **kwargs: _VT) -> None: ... # type: ignore[override] + def copy(self) -> Self: ... + def __eq__(self, other: SupportsItems[str, _VT]) -> bool: ... # type: ignore[override] + def __ne__(self, other: SupportsItems[str, _VT]) -> bool: ... # type: ignore[override] + canonical_order: ClassVar[Iterable[str] | None] + def sorted_keys(self) -> list[str]: ... + def sorted_items(self) -> list[tuple[str, _VT]]: ... diff --git a/stubs/icalendar/icalendar/parser.pyi b/stubs/icalendar/icalendar/parser.pyi new file mode 100644 index 000000000..1484ecdf3 --- /dev/null +++ b/stubs/icalendar/icalendar/parser.pyi @@ -0,0 +1,58 @@ +from _collections_abc import dict_keys +from _typeshed import Incomplete +from collections.abc import Iterable +from re import Pattern +from typing import AnyStr, Final, overload +from typing_extensions import Self + +from .caselessdict import CaselessDict + +def escape_char(text: str) -> str: ... +def unescape_char(text: AnyStr) -> AnyStr: ... +def tzid_from_dt(dt): ... +def foldline(line: str, limit: int = 75, fold_sep: str = "\r\n ") -> str: ... +def param_value(value: str | list[str] | tuple[str, ...] | Incomplete) -> str: ... + +NAME: Final[Pattern[str]] +UNSAFE_CHAR: Final[Pattern[str]] +QUNSAFE_CHAR: Final[Pattern[str]] +FOLD: Final[Pattern[bytes]] +uFOLD: Final[Pattern[str]] +NEWLINE: Final[Pattern[str]] + +def validate_token(name: str) -> None: ... +def validate_param_value(value: str, quoted: bool = True) -> None: ... + +QUOTABLE: Final[Pattern[str]] + +def dquote(val: str) -> str: ... +def q_split(st: str, sep: str = ",", maxsplit: int = -1) -> list[str]: ... +def q_join(lst: Iterable[str], sep: str = ",") -> str: ... + +class Parameters(CaselessDict[str]): + def params(self) -> dict_keys[str, str]: ... + def to_ical(self, sorted: bool = True) -> bytes: ... + @classmethod + def from_ical(cls, st: str, strict: bool = False) -> Self: ... + +def escape_string(val: str) -> str: ... +def unescape_string(val: str) -> str: ... +@overload +def unescape_list_or_string(val: list[str]) -> list[str]: ... +@overload +def unescape_list_or_string(val: str) -> str: ... + +class Contentline(str): + strict: bool + def __new__(cls, value: str | bytes, strict: bool = False, encoding: str = ...) -> Self: ... + @classmethod + def from_parts(cls, name: str, params: Parameters, values, sorted: bool = True) -> Self: ... + def parts(self) -> tuple[str, Parameters, str]: ... + @classmethod + def from_ical(cls, ical: str | bytes, strict: bool = False) -> Self: ... + def to_ical(self) -> bytes: ... + +class Contentlines(list[Contentline]): + def to_ical(self) -> bytes: ... + @classmethod + def from_ical(cls, st: str | bytes) -> Self: ... diff --git a/stubs/icalendar/icalendar/parser_tools.pyi b/stubs/icalendar/icalendar/parser_tools.pyi new file mode 100644 index 000000000..5badc5621 --- /dev/null +++ b/stubs/icalendar/icalendar/parser_tools.pyi @@ -0,0 +1,17 @@ +from typing import Any, Final, TypeVar, overload + +_T = TypeVar("_T") + +SEQUENCE_TYPES: Final[tuple[type[Any], ...]] +DEFAULT_ENCODING: str + +def from_unicode(value: str | bytes, encoding: str = "utf-8") -> bytes: ... +def to_unicode(value: str | bytes, encoding: str = "utf-8") -> str: ... +@overload +def data_encode(data: str, encoding: str = ...) -> bytes: ... # type: ignore[misc] +@overload +def data_encode(data: dict[Any, Any], encoding: str = ...) -> dict[Any, Any]: ... +@overload +def data_encode(data: list[Any] | tuple[Any, ...], encoding: str = ...) -> list[Any]: ... # type: ignore[misc] +@overload +def data_encode(data: _T, encoding: str = ...) -> _T: ... diff --git a/stubs/icalendar/icalendar/prop.pyi b/stubs/icalendar/icalendar/prop.pyi new file mode 100644 index 000000000..efc333d69 --- /dev/null +++ b/stubs/icalendar/icalendar/prop.pyi @@ -0,0 +1,225 @@ +import datetime +from _typeshed import Incomplete +from datetime import tzinfo +from re import Pattern +from typing import Any, ClassVar, Final +from typing_extensions import TypeAlias + +from .caselessdict import CaselessDict +from .parser import Parameters + +_PropType: TypeAlias = type[Any] # any of the v* classes in this file + +DURATION_REGEX: Final[Pattern[str]] +WEEKDAY_RULE: Final[Pattern[str]] +ZERO: Final[datetime.timedelta] +HOUR: Final[datetime.timedelta] +STDOFFSET: Final[datetime.timedelta] +DSTOFFSET: Final[datetime.timedelta] +DSTDIFF: Final[datetime.timedelta] + +class FixedOffset(tzinfo): + def __init__(self, offset, name) -> None: ... + def utcoffset(self, dt): ... + def tzname(self, dt): ... + def dst(self, dt): ... + +class LocalTimezone(tzinfo): + def utcoffset(self, dt): ... + def dst(self, dt): ... + def tzname(self, dt): ... + +class vBinary: + obj: Incomplete + params: Incomplete + def __init__(self, obj) -> None: ... + def to_ical(self): ... + @staticmethod + def from_ical(ical): ... + def __eq__(self, other): ... + +class vBoolean(int): + BOOL_MAP: Incomplete + params: Incomplete + def __new__(cls, *args, **kwargs): ... + def to_ical(self): ... + @classmethod + def from_ical(cls, ical): ... + +class vCalAddress(str): + params: Incomplete + def __new__(cls, value, encoding="utf-8"): ... + def to_ical(self): ... + @classmethod + def from_ical(cls, ical): ... + +class vFloat(float): + params: Incomplete + def __new__(cls, *args, **kwargs): ... + def to_ical(self): ... + @classmethod + def from_ical(cls, ical): ... + +class vInt(int): + params: Incomplete + def __new__(cls, *args, **kwargs): ... + def to_ical(self): ... + @classmethod + def from_ical(cls, ical): ... + +class vDDDLists: + params: Incomplete + dts: Incomplete + def __init__(self, dt_list) -> None: ... + def to_ical(self): ... + @staticmethod + def from_ical(ical, timezone: Incomplete | None = None): ... + def __eq__(self, other): ... + +class vCategory: + cats: Incomplete + params: Incomplete + def __init__(self, c_list) -> None: ... + def to_ical(self): ... + @staticmethod + def from_ical(ical): ... + def __eq__(self, other): ... + +class TimeBase: + def __eq__(self, other): ... + def __hash__(self): ... + +class vDDDTypes(TimeBase): + params: Incomplete + dt: Incomplete + def __init__(self, dt) -> None: ... + def to_ical(self): ... + @classmethod + def from_ical(cls, ical, timezone: Incomplete | None = None): ... + +class vDate(TimeBase): + dt: Incomplete + params: Incomplete + def __init__(self, dt) -> None: ... + def to_ical(self): ... + @staticmethod + def from_ical(ical): ... + +class vDatetime(TimeBase): + dt: Incomplete + params: Incomplete + def __init__(self, dt) -> None: ... + def to_ical(self): ... + @staticmethod + def from_ical(ical, timezone: Incomplete | None = None): ... + +class vDuration(TimeBase): + td: Incomplete + params: Incomplete + def __init__(self, td) -> None: ... + def to_ical(self): ... + @staticmethod + def from_ical(ical): ... + @property + def dt(self): ... + +class vPeriod(TimeBase): + params: Incomplete + start: Incomplete + end: Incomplete + by_duration: Incomplete + duration: Incomplete + def __init__(self, per) -> None: ... + def overlaps(self, other): ... + def to_ical(self): ... + @staticmethod + def from_ical(ical, timezone: Incomplete | None = None): ... + @property + def dt(self): ... + +class vWeekday(str): + week_days: Incomplete + relative: Incomplete + params: Incomplete + def __new__(cls, value, encoding="utf-8"): ... + def to_ical(self): ... + @classmethod + def from_ical(cls, ical): ... + +class vFrequency(str): + frequencies: Incomplete + params: Incomplete + def __new__(cls, value, encoding="utf-8"): ... + def to_ical(self): ... + @classmethod + def from_ical(cls, ical): ... + +class vRecur(CaselessDict[Incomplete]): + frequencies: ClassVar[list[str]] + canonical_order: ClassVar[tuple[str, ...]] + types: ClassVar[CaselessDict[_PropType]] + params: Parameters + def __init__(self, *args, **kwargs) -> None: ... + def to_ical(self): ... + @classmethod + def parse_type(cls, key, values): ... + @classmethod + def from_ical(cls, ical) -> dict[str, Incomplete]: ... + +class vText(str): + encoding: Incomplete + params: Incomplete + def __new__(cls, value, encoding="utf-8"): ... + def to_ical(self): ... + @classmethod + def from_ical(cls, ical): ... + +class vTime(TimeBase): + dt: Incomplete + params: Incomplete + def __init__(self, *args) -> None: ... + def to_ical(self): ... + @staticmethod + def from_ical(ical): ... + +class vUri(str): + params: Incomplete + def __new__(cls, value, encoding="utf-8"): ... + def to_ical(self): ... + @classmethod + def from_ical(cls, ical): ... + +class vGeo: + latitude: Incomplete + longitude: Incomplete + params: Incomplete + def __init__(self, geo) -> None: ... + def to_ical(self): ... + @staticmethod + def from_ical(ical): ... + def __eq__(self, other): ... + +class vUTCOffset: + ignore_exceptions: bool + td: Incomplete + params: Incomplete + def __init__(self, td) -> None: ... + def to_ical(self): ... + @classmethod + def from_ical(cls, ical): ... + def __eq__(self, other): ... + +class vInline(str): + params: Incomplete + def __new__(cls, value, encoding="utf-8"): ... + def to_ical(self): ... + @classmethod + def from_ical(cls, ical): ... + +class TypesFactory(CaselessDict[_PropType]): + all_types: tuple[_PropType, ...] + def __init__(self, *args, **kwargs) -> None: ... + types_map: CaselessDict[str] + def for_property(self, name: str) -> _PropType: ... + def to_ical(self, name: str, value) -> bytes: ... + def from_ical(self, name: str, value): ... diff --git a/stubs/icalendar/icalendar/timezone_cache.pyi b/stubs/icalendar/icalendar/timezone_cache.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/icalendar/icalendar/tools.pyi b/stubs/icalendar/icalendar/tools.pyi new file mode 100644 index 000000000..2f3e28a6a --- /dev/null +++ b/stubs/icalendar/icalendar/tools.pyi @@ -0,0 +1,10 @@ +from typing import Final + +from .prop import vText + +class UIDGenerator: + chars: Final[list[str]] + @staticmethod + def rnd_string(length: int = 16) -> str: ... + @staticmethod + def uid(host_name: str = "example.com", unique: str = "") -> vText: ... diff --git a/stubs/icalendar/icalendar/windows_to_olson.pyi b/stubs/icalendar/icalendar/windows_to_olson.pyi new file mode 100644 index 000000000..7b8e1e881 --- /dev/null +++ b/stubs/icalendar/icalendar/windows_to_olson.pyi @@ -0,0 +1,3 @@ +from typing import Final + +WINDOWS_TO_OLSON: Final[dict[str, str]]