Source code for PyXA.apps.Fantastical

""".. versionadded:: 0.0.9

Control Fantastical using JXA-like syntax.
"""

from datetime import datetime
from typing import Union

import AppKit

from PyXA import XABase
from PyXA import XABaseScriptable
from ..XAProtocols import XAClipboardCodable, XACloseable, XADeletable, XAPrintable


[docs] class XAFantasticalApplication(XABaseScriptable.XASBApplication): """A class for managing and interacting with Fantastical.app. .. versionadded:: 0.0.9 """ def __init__(self, properties): super().__init__(properties) self.xa_wcls = XAFantasticalWindow @property def name(self) -> str: """The name of the application.""" return self.xa_scel.name() @property def frontmost(self) -> bool: """Whether Fantastical is the active application.""" return self.xa_scel.frontmost() @frontmost.setter def frontmost(self, frontmost: frontmost): self.set_property("frontmost", frontmost) @property def version(self) -> str: """The version of Fantastical.app.""" return self.xa_scel.version()
[docs] def parse_sentence( self, sentence: str, notes: str = "", calendar: Union[str, "XAFantasticalCalendar", None] = None, add_immediately: bool = True, add_attendees: bool = False, ): """Parses the given sentences and creates a corresponding calendar item based on the parsing result. :param sentence: The sentence to parse :type sentence: str :param notes: Notes to attach to the calendar item, defaults to "" :type notes: str, optional :param calendar: The calendar to add the item to, defaults to None :type calendar: Union[str, XAFantasticalCalendar, None], optional :param add_immediately: Whether to add the item without displaying an event editing dialog, defaults to True :type add_immediately: bool, optional :param add_attendees: Whether to invite attendees parsed from the sentence, defaults to False :type add_attendees: bool, optional :Example 1: Add simple events to calendars >>> # Create an event on the default calendar >>> import PyXA >>> app = PyXA.Application("Fantastical") >>> app.parse_sentence("Event 1") >>> >>> # Create an event on a calendar specified by a calendar object >>> cal = app.calendars().by_title("PyXA Development") >>> app.parse_sentence("Event 2", calendar = cal) >>> >>> # Create an event on a calendar specified by a string >>> app.parse_sentence("Event 3", calendar = "Testing") :Example 2: Use Fantastical's query parsing to adjust calendar item settings >>> # Automatically set the time of a task to 8am, show event editing dialog >>> app.parse_sentence("Wake up at 8am", add_immediately = False) >>> >>> # Create a todo >>> app.parse_sentence("todo today Learn PyXA") >>> >>> # Create an event at a location, with an alert, repeating weekly >>> app.parse_sentence("Meet with Example Person at 10am at 1 Infinite Loop, Cupertino, CA with alert 30 minutes before repeat weekly") >>> >>> # Create an event spanning a week >>> app.parse_sentence("PyXA stuff August 22 to August 29") .. versionadded:: 0.0.9 """ if isinstance(calendar, XAFantasticalCalendar): self.xa_scel.parseSentence_notes_calendar_calendarName_addImmediately_addAttendees_( sentence, notes, calendar.xa_elem, None, add_immediately, add_attendees ) elif isinstance(calendar, str): self.xa_scel.parseSentence_notes_calendar_calendarName_addImmediately_addAttendees_( sentence, notes, None, calendar, add_immediately, add_attendees ) else: self.xa_scel.parseSentence_notes_calendar_calendarName_addImmediately_addAttendees_( sentence, notes, None, None, add_immediately, add_attendees )
[docs] def show_mini_view(self, date: Union[str, datetime, None] = None): """Shows the mini calendar view, optionally showing a specific date. :param date: The date to display, defaults to None :type date: Union[str, datetime, None], optional .. versionadded:: 0.0.9 """ if date is None: date = "" if isinstance(date, datetime): date = date.strftime("%Y-%m-%d") print(date) XABase.XAURL(f"x-fantastical3://show/mini/{date}").open()
[docs] def show_calendar_view(self, date: Union[str, datetime, None] = None): """Shows the (large) calendar view, optionally showing a specific date. :param date: The date to display, defaults to None :type date: Union[str, datetime, None], optional .. versionadded:: 0.0.9 """ if date is None: date = "" if isinstance(date, datetime): date = date.strftime("%Y-%m-%d") print(date) XABase.XAURL(f"x-fantastical3://show/calendar/{date}").open()
[docs] def documents(self, filter: dict = None) -> "XAFantasticalDocumentList": """Returns a list of documents, as PyXA objects, matching the given filter. .. versionadded:: 0.0.9 """ return self._new_element( self.xa_scel.documents(), XAFantasticalDocumentList, filter )
[docs] def calendars(self, filter: dict = None) -> "XAFantasticalCalendarList": """Returns a list of calendars, as PyXA objects, matching the given filter. .. versionadded:: 0.0.9 """ return self._new_element( self.xa_scel.calendars(), XAFantasticalCalendarList, filter )
[docs] def selected_calendar_items( self, filter: dict = None ) -> "XAFantasticalSelectedCalendarItemList": """Returns a list of selected calendar items, as PyXA objects, matching the given filter. .. versionadded:: 0.0.9 """ return self._new_element( self.xa_scel.selectedCalendarItems(), XAFantasticalSelectedCalendarItemList, filter, )
[docs] class XAFantasticalDocumentList(XABase.XAList): """A wrapper around lists of Fantastical documents that employs fast enumeration techniques. All properties of documents can be called as methods on the wrapped list, returning a list containing each document's value for the property. .. versionadded:: 0.0.9 """ def __init__(self, properties: dict, filter: Union[dict, None] = None): super().__init__(properties, XAFantasticalDocument, filter)
[docs] def name(self) -> list[str]: return list(self.xa_elem.arrayByApplyingSelector_("name") or [])
[docs] def modified(self) -> list[bool]: return list(self.xa_elem.arrayByApplyingSelector_("modified") or [])
[docs] def file(self) -> list[XABase.XAPath]: ls = self.xa_elem.arrayByApplyingSelector_("file") or [] return [XABase.XAPath(x) for x in ls]
[docs] def by_name(self, name: str) -> "XAFantasticalDocument": return self.by_property("name", name)
[docs] def by_modified(self, modified: bool) -> "XAFantasticalDocument": return self.by_property("modified", modified)
[docs] def by_file(self, file: XABase.XAPath) -> "XAFantasticalDocument": return self.by_property("file", file.xa_elem)
def __repr__(self): return "<" + str(type(self)) + str(self.name()) + ">"
[docs] class XAFantasticalDocument( XABase.XAObject, XACloseable, XADeletable, XAPrintable, XAClipboardCodable ): """A document in Fantastical.app. .. versionadded:: 0.0.9 """ def __init__(self, properties): super().__init__(properties) @property def name(self) -> str: return self.xa_elem.name() @name.setter def name(self, name: str): """The document's name.""" self.set_property("name", name) @property def modified(self) -> bool: """Whether the document has been modified since it was last saved.""" return self.xa_elem.modified() @property def file(self) -> XABase.XAPath: """The document's path.""" return XABase.XAPath(self.xa_elem.file()) @file.setter def file(self, file: Union[str, XABase.XAPath]): if isinstance(file, str): file = XABase.XAPath(file) self.set_property("file", file.xa_elem)
[docs] def print( self, print_properties: Union[dict, None] = None, show_dialog: bool = True ) -> "XAPrintable": """Prints the object. Child classes of XAPrintable should override this method as necessary. :param show_dialog: Whether to show the print dialog, defaults to True :type show_dialog: bool, optional :param print_properties: Properties to set for printing, defaults to None :type print_properties: Union[dict, None], optional :return: A reference to the PyXA object that called this method. :rtype: XACanPrintPath .. versionadded:: 0.0.9 """ if print_properties is None: print_properties = {} self.xa_elem.print_printDialog_withProperties_( self.xa_elem, show_dialog, print_properties ) return self
[docs] def get_clipboard_representation(self) -> list[Union[AppKit.NSURL, str]]: """Gets a clipboard-codable representation of the document. When the clipboard content is set to a Fantastical document, the document's URL and source code are added to the clipboard. :return: The document's path and text content :rtype: list[Union[AppKit.NSURL, str]] .. versionadded:: 0.0.9 """ return [self.path.xa_elem, str(self.text)]
def __repr__(self): return "<" + str(type(self)) + str(self.name) + ">"
[docs] class XAFantasticalWindow(XABaseScriptable.XASBWindow, XAPrintable, XACloseable): """A window of Fantastical.app.""" def __init__(self, properties): super().__init__(properties) @property def document(self) -> XAFantasticalDocument: """The document currently displayed in the window.""" return self._new_element(self.xa_elem.document(), XAFantasticalDocument) @document.setter def document(self, document: XAFantasticalDocument): self.set_property("document", document.xa_elem)
[docs] class XAFantasticalCalendarList(XABase.XAList): """A wrapper around lists of Fantastical calendars that employs fast enumeration techniques. All properties of calendars can be called as methods on the wrapped list, returning a list containing each calendar's value for the property. .. versionadded:: 0.0.9 """ def __init__(self, properties: dict, filter: Union[dict, None] = None): super().__init__(properties, XAFantasticalCalendar, filter)
[docs] def title(self) -> list[str]: return list(self.xa_elem.arrayByApplyingSelector_("title") or [])
[docs] def id(self) -> list[str]: return list(self.xa_elem.arrayByApplyingSelector_("id") or [])
[docs] def by_title(self, title: str) -> "XAFantasticalCalendar": return self.by_property("title", title)
[docs] def by_id(self, id: str) -> "XAFantasticalCalendar": return self.by_property("id", id)
def __repr__(self): return "<" + str(type(self)) + str(self.title()) + ">"
[docs] class XAFantasticalCalendar(XABase.XAObject): """A class in Fantastical.app. .. versionadded:: 0.0.9 """ def __init__(self, properties): super().__init__(properties) @property def title(self) -> str: """The calendar's title.""" return self.xa_elem.title() @title.setter def title(self, title: str): self.set_property("title", title) @property def id(self) -> str: """The unique identifier for the calendar.""" return self.xa_elem.id() def __repr__(self): return "<" + str(type(self)) + str(self.title) + ">"
[docs] class XAFantasticalCalendarItemList(XABase.XAList): """A wrapper around lists of Fantastical calendar items that employs fast enumeration techniques. All properties of calendar items can be called as methods on the wrapped list, returning a list containing each calendar item's value for the property. .. versionadded:: 0.0.9 """ def __init__( self, properties: dict, filter: Union[dict, None] = None, obj_class=None ): if obj_class is None: obj_class = XAFantasticalCalendarItem super().__init__(properties, obj_class, filter)
[docs] def id(self) -> list[str]: return list(self.xa_elem.arrayByApplyingSelector_("id") or [])
[docs] def title(self) -> list[str]: return list(self.xa_elem.arrayByApplyingSelector_("title") or [])
[docs] def start_date(self) -> list[datetime]: return list(self.xa_elem.arrayByApplyingSelector_("startDate") or [])
[docs] def end_date(self) -> list[datetime]: return list(self.xa_elem.arrayByApplyingSelector_("endDate") or [])
[docs] def notes(self) -> list[str]: return list(self.xa_elem.arrayByApplyingSelector_("notes") or [])
[docs] def url(self) -> list[XABase.XAURL]: ls = self.xa_elem.arrayByApplyingSelector_("URL") or [] return [XABase.XAURL(x) for x in ls]
[docs] def show_url(self) -> list[XABase.XAURL]: return list(self.xa_elem.arrayByApplyingSelector_("showURL") or [])
[docs] def is_recurring(self) -> list[bool]: return list(self.xa_elem.arrayByApplyingSelector_("isRecurring") or [])
[docs] def is_all_day(self) -> list[bool]: return list(self.xa_elem.arrayByApplyingSelector_("isAllDay") or [])
[docs] def by_id(self, id: str) -> "XAFantasticalCalendarItem": return self.by_property("id", id)
[docs] def by_title(self, title: str) -> "XAFantasticalCalendarItem": return self.by_property("title", title)
[docs] def by_start_date(self, start_date: datetime) -> "XAFantasticalCalendarItem": return self.by_property("startDate", start_date)
[docs] def by_end_date(self, end_date: datetime) -> "XAFantasticalCalendarItem": return self.by_property("endDate", end_date)
[docs] def by_notes(self, notes: str) -> "XAFantasticalCalendarItem": return self.by_property("notes", notes)
[docs] def by_url(self, url: XABase.XAURL) -> "XAFantasticalCalendarItem": return self.by_property("URL", url.xa_elem)
[docs] def by_show_url(self, show_url: XABase.XAURL) -> "XAFantasticalCalendarItem": return self.by_property("showURL", show_url.xa_elem)
[docs] def by_is_recurring(self, is_recurring: bool) -> "XAFantasticalCalendarItem": return self.by_property("isRecurring", is_recurring)
[docs] def by_is_all_day(self, is_all_day: bool) -> "XAFantasticalCalendarItem": return self.by_property("isAllDay", is_all_day)
def __repr__(self): return "<" + str(type(self)) + str(self.title()) + ">"
[docs] class XAFantasticalCalendarItem(XABase.XAObject): """An insertion point between two objects in Fantastical.app. .. versionadded:: 0.0.9 """ def __init__(self, properties): super().__init__(properties) @property def id(self) -> str: """The unique identifier for the item.""" return self.xa_elem.id() @property def title(self) -> str: """The event title.""" return self.xa_elem.title() @property def start_date(self) -> datetime: """The start date of the event.""" return self.xa_elem.startDate() @property def end_date(self) -> datetime: """The end date of the event.""" return self.xa_elem.endDate() @property def notes(self) -> str: """The notes for the event.""" return self.xa_elem.notes() or "" @property def url(self) -> XABase.XAURL: """The related URL for the event.""" return XABase.XAURL(self.xa_elem.URL()) @property def show_url(self) -> XABase.XAURL: """The show URL for the event.""" return XABase.XAURL(self.xa_elem.showURL()) @property def is_recurring(self) -> bool: """True if the item is a recurring item.""" return self.xa_elem.isRecurring() @property def is_all_day(self) -> bool: """True if the item spans an entire day.""" return self.xa_elem.isAllDay()
[docs] def save(self): self.xa_elem.saveIn_as_(None, 0)
def __repr__(self): return "<" + str(type(self)) + str(self.title) + ">"
[docs] class XAFantasticalSelectedCalendarItemList(XAFantasticalCalendarItemList): """A wrapper around lists of Fantastical selected calendar items that employs fast enumeration techniques. All properties of selected calendar items can be called as methods on the wrapped list, returning a list containing each items's value for the property. .. versionadded:: 0.0.9 """ def __init__(self, properties: dict, filter: Union[dict, None] = None): super().__init__(properties, filter, XAFantasticalSelectedCalendarItem)
[docs] class XAFantasticalSelectedCalendarItem(XAFantasticalCalendarItem): def __init__(self, properties): super().__init__(properties)
[docs] class XAFantasticalCalendarEvent(XAFantasticalCalendarItem): def __init__(self, properties): super().__init__(properties) @property def location(self) -> str: """The event location.""" return self.xa_elem.location() @location.setter def location(self, location: str): self.set_property("location", location)
[docs] class XAFantasticalTaskItem(XAFantasticalCalendarItem): def __init__(self, properties): super().__init__(properties) @property def priority(self) -> int: """The event priority; higher number means lower priority.""" return self.xa_elem.priority() @priority.setter def priority(self, priority: int): self.set_property("priority", priority)