From 61ce8edc0d9c2a476d10c5847f6767ef35372800 Mon Sep 17 00:00:00 2001 From: o-murphy Date: Sat, 9 Aug 2025 23:12:20 +0300 Subject: [PATCH 1/3] Compatible stubs for Pythonista 3.4+ * some stubs updated * project tree changed to typeshed-like * switching to the pyproject.toml * updated CI (can publish to properly configured trusted publisher * version number changed to 3.4.0 (3.4.x is a minimal supported Pythonista version, the patch-number is a stubs version for a current pythonista version) --- .github/workflows/ci.yml | 65 +++-- .../inspectionProfiles/profiles_settings.xml | 6 + LICENSE.txt => LICENSE | 0 MANIFEST.in | 1 + VERSION | 1 + mypy.ini | 5 - pyproject.toml | 68 +++++ setup.py | 38 +-- stubs/_cb.pyi | 101 +++++++ stubs/appex/__init__.pyi | 16 -- stubs/clipboard/__init__.pyi | 9 - stubs/console/__init__.pyi | 48 ---- stubs/editor/__init__.py | 65 ----- stubs/py.typed | 0 stubs/pythonista_stubs/__init__.pyi | 1 + stubs/pythonista_stubs/appex.pyi | 161 +++++++++++ stubs/pythonista_stubs/canvas.pyi | 221 +++++++++++++++ stubs/pythonista_stubs/cb.pyi | 94 +++++++ stubs/pythonista_stubs/clipboard.pyi | 63 +++++ stubs/pythonista_stubs/console.pyi | 244 +++++++++++++++++ stubs/pythonista_stubs/contacts.pyi | 172 ++++++++++++ stubs/pythonista_stubs/dialogs.pyi | 255 ++++++++++++++++++ stubs/pythonista_stubs/editor.pyi | 156 +++++++++++ stubs/pythonista_stubs/keyboard.pyi | 82 ++++++ stubs/pythonista_stubs/keychain.pyi | 57 ++++ stubs/pythonista_stubs/linguistictagger.pyi | 45 ++++ stubs/pythonista_stubs/location.pyi | 82 ++++++ stubs/pythonista_stubs/motion.pyi | 33 +++ stubs/pythonista_stubs/notification.pyi | 68 +++++ stubs/pythonista_stubs/objc_util.pyi | 220 +++++++++++++++ stubs/pythonista_stubs/photos.pyi | 187 +++++++++++++ stubs/pythonista_stubs/py.typed | 0 stubs/pythonista_stubs/reminders.pyi | 121 +++++++++ stubs/pythonista_stubs/shortcuts.pyi | 44 +++ stubs/pythonista_stubs/sound.pyi | 158 +++++++++++ stubs/pythonista_stubs/speech.pyi | 54 ++++ .../__init__.py => pythonista_stubs/ui.py} | 3 +- stubs/reminders/__init__.pyi | 31 --- stubs/sound/__init__.pyi | 50 ---- stubs/speech/__init__.pyi | 13 - uv.lock | 174 ++++++++++++ 41 files changed, 2914 insertions(+), 298 deletions(-) create mode 100644 .idea/inspectionProfiles/profiles_settings.xml rename LICENSE.txt => LICENSE (100%) mode change 100755 => 100644 create mode 100644 MANIFEST.in create mode 100644 VERSION delete mode 100644 mypy.ini create mode 100644 pyproject.toml create mode 100644 stubs/_cb.pyi delete mode 100644 stubs/appex/__init__.pyi delete mode 100644 stubs/clipboard/__init__.pyi delete mode 100644 stubs/console/__init__.pyi delete mode 100644 stubs/editor/__init__.py create mode 100644 stubs/py.typed create mode 100644 stubs/pythonista_stubs/__init__.pyi create mode 100644 stubs/pythonista_stubs/appex.pyi create mode 100644 stubs/pythonista_stubs/canvas.pyi create mode 100644 stubs/pythonista_stubs/cb.pyi create mode 100644 stubs/pythonista_stubs/clipboard.pyi create mode 100644 stubs/pythonista_stubs/console.pyi create mode 100644 stubs/pythonista_stubs/contacts.pyi create mode 100644 stubs/pythonista_stubs/dialogs.pyi create mode 100644 stubs/pythonista_stubs/editor.pyi create mode 100644 stubs/pythonista_stubs/keyboard.pyi create mode 100644 stubs/pythonista_stubs/keychain.pyi create mode 100644 stubs/pythonista_stubs/linguistictagger.pyi create mode 100644 stubs/pythonista_stubs/location.pyi create mode 100644 stubs/pythonista_stubs/motion.pyi create mode 100644 stubs/pythonista_stubs/notification.pyi create mode 100644 stubs/pythonista_stubs/objc_util.pyi create mode 100644 stubs/pythonista_stubs/photos.pyi create mode 100644 stubs/pythonista_stubs/py.typed create mode 100644 stubs/pythonista_stubs/reminders.pyi create mode 100644 stubs/pythonista_stubs/shortcuts.pyi create mode 100644 stubs/pythonista_stubs/sound.pyi create mode 100644 stubs/pythonista_stubs/speech.pyi rename stubs/{ui/__init__.py => pythonista_stubs/ui.py} (92%) delete mode 100644 stubs/reminders/__init__.pyi delete mode 100644 stubs/sound/__init__.pyi delete mode 100644 stubs/speech/__init__.pyi create mode 100644 uv.lock diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 075e900..07b0853 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,30 +5,51 @@ on: branches: [ master ] pull_request: branches: [ master ] + release: + types: [ published ] + workflow_dispatch: jobs: - test: + testing: runs-on: ubuntu-latest - strategy: - matrix: - python-version: ["3.6"] + permissions: + id-token: write steps: - - uses: actions/checkout@v4 - - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 - with: - python-version: ${{ matrix.python-version }} - - - name: Install package - run: pip install . - - - name: Install black - run: pip install black - - - name: Check code formatting with black - run: black --check stubs/ - - - name: Type check with mypy - run: mypy stubs/ \ No newline at end of file + - uses: actions/checkout@v4 + + - name: Install uv + uses: astral-sh/setup-uv@v5 + + - name: Install the project + run: uv sync --locked --all-extras --dev + + - name: Check code formatting with ruff + run: uv run ruff check + + - name: Type check with mypy + run: uv run mypy + + publish: + runs-on: ubuntu-latest + environment: + name: pypi + needs: [testing] + permissions: + id-token: write + + steps: + - uses: actions/checkout@v4 + + - name: Install uv + uses: astral-sh/setup-uv@v5 + + - name: Install the project + run: uv sync --locked --all-extras --dev + + - name: Build + run: uv build + + - name: Publish + if: github.event_name == 'release' + run: uv publish --trusted-publishing always diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/LICENSE.txt b/LICENSE old mode 100755 new mode 100644 similarity index 100% rename from LICENSE.txt rename to LICENSE diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..a4d5857 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1 @@ +include pythonista_stubs/*.pyi diff --git a/VERSION b/VERSION new file mode 100644 index 0000000..fbcbf73 --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +3.4.0 \ No newline at end of file diff --git a/mypy.ini b/mypy.ini deleted file mode 100644 index 0d69f24..0000000 --- a/mypy.ini +++ /dev/null @@ -1,5 +0,0 @@ -[mypy] -python_version = 3.6 - -[mypy-PIL.*] -ignore_missing_imports = True diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..2bc2074 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,68 @@ +[build-system] +requires = ["setuptools>=80.1.0"] +build-backend = "setuptools.build_meta" + +[project] +name = "pythonista-stubs" +authors = [ + { name = "Harold Martin" }, + { name = "Dmytro Yaroshenko" } +] +description = "A collection of Pythonista stub files" +readme = "README.md" +requires-python = ">=3.10" +dependencies = [ + "types-pillow>=10.2.0.20240822", + "typing-extensions>=4.14.1", +] +license = { file = "LICENSE" } +keywords = ["pythonista", "stubs", "ios", "ide"] +classifiers = [ + "Intended Audience :: Developers", + "Natural Language :: English", + "Programming Language :: Python", + "Topic :: Software Development :: Libraries :: Python Modules", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: Implementation :: CPython", +] +dynamic = ['version'] + +[project.urls] +"Homepage" = "https://github.com/hbmartin/pythonista-stubs" +"Bug Reports" = "https://github.com/hbmartin/pythonista-stubs/issues" +"Source" = "https://github.com/hbmartin/pythonista-stubs" + + +[tool.setuptools.packages.find] +where = ["stubs"] +include = [ + "pythonista_stubs*", +] + +[tool.setuptools.package-data] +"*" = [ "**/*" ] # to include root-places .pyi stubs + +[tool.setuptools.dynamic] +version = {file = "VERSION"} + +[dependency-groups] +dev = [ + "mypy>=1.17.1", # as a dev dependency, Pythonista does not support mypy + "ruff>=0.12.8", +] + +[tool.mypy] +packages = ["stubs"] +ignore_missing_imports = true + +[tool.ruff] +include = [ + "pyproject.toml", + "stubs/**/*.py", + "stubs/**/*.pyi", +] diff --git a/setup.py b/setup.py index 1c221a7..6068493 100755 --- a/setup.py +++ b/setup.py @@ -1,39 +1,3 @@ from setuptools import setup -from os import path -here = path.abspath(path.dirname(__file__)) - -with open(path.join(here, "README.md"), encoding="utf-8") as f: - long_description = f.read() - -packages = ["appex", "clipboard", "console", "editor", "reminders", "sound", "speech", "ui"] -packages_stubs = [p + "-stubs" for p in packages] -package_dir = {p + "-stubs": path.join("stubs", p) for p in packages} -package_data = {ps: ["__init__.pyi"] for ps in packages_stubs} - -setup( - name="pythonista-stubs", - version="0.0.3", - description="A collection of Pythonista stub files", - long_description=long_description, - long_description_content_type="text/markdown", - url="https://github.com/hbmartin/pythonista-stubs", - package_dir=package_dir, - packages=packages_stubs, - package_data=package_data, - install_requires=["typing_extensions", "mypy", "Pillow"], - classifiers=[ - "Development Status :: 3 - Alpha", - "Intended Audience :: Developers", - "Intended Audience :: Information Technology", - "License :: OSI Approved :: Apache Software License", - "Operating System :: iOS", - "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.6", - "Topic :: Software Development :: Libraries :: Python Modules", - "Typing :: Typed", - ], - license="Apache License 2.0", - keywords="pythonista stubs ios ide", - project_urls={"Bug Reports": "https://github.com/hbmartin/pythonista-stubs/issues"}, -) +setup() diff --git a/stubs/_cb.pyi b/stubs/_cb.pyi new file mode 100644 index 0000000..569acb1 --- /dev/null +++ b/stubs/_cb.pyi @@ -0,0 +1,101 @@ +# Created on July, 07 2025 by o-murphy +""" +pythonista `_cb` module type annotations +according to [pythonista.cb docs](https://omz-software.com/pythonista/docs/ios/cb.html) +and references to pythonista built-in `_cb` module help +>>> import _cb +>>> help(_cb) +""" + +from typing import Optional, List + +__all__ = ( + "CM_STATE_UNKNOWN", + "CM_STATE_RESETTING", + "CM_STATE_UNSUPPORTED", + "CM_STATE_UNAUTHORIZED", + "CM_STATE_POWERED_OFF", + "CM_STATE_POWERED_ON", + "CH_PROP_BROADCAST", + "CH_PROP_READ", + "CH_PROP_WRITE_WITHOUT_RESPONSE", + "CH_PROP_WRITE", + "CH_PROP_NOTIFY", + "CH_PROP_INDICATE", + "CH_PROP_AUTHENTICATED_SIGNED_WRITES", + "CH_PROP_EXTENDED_PROPERTIES", + "CH_PROP_NOTIFY_ENCRYPTION_REQUIRED", + "CH_PROP_INDICATE_ENCRYPTION_REQUIRED", + "Characteristic", + "Service", + "Peripheral", + "CentralManager", +) + +CM_STATE_UNKNOWN: int = 0 +CM_STATE_RESETTING: int = 1 +CM_STATE_UNSUPPORTED: int = 2 +CM_STATE_UNAUTHORIZED: int = 3 +CM_STATE_POWERED_OFF: int = 4 +CM_STATE_POWERED_ON: int = 5 + +CH_PROP_BROADCAST: int = 1 +CH_PROP_READ: int = 2 +CH_PROP_WRITE_WITHOUT_RESPONSE: int = 4 +CH_PROP_WRITE: int = 8 +CH_PROP_NOTIFY: int = 16 +CH_PROP_INDICATE: int = 32 +CH_PROP_AUTHENTICATED_SIGNED_WRITES: int = 64 +CH_PROP_EXTENDED_PROPERTIES: int = 128 +CH_PROP_NOTIFY_ENCRYPTION_REQUIRED: int = 256 +CH_PROP_INDICATE_ENCRYPTION_REQUIRED: int = 512 + +class Characteristic: + properties: int + value: Optional[bytes] + uuid: str # hex + notifying: bool # of bool + +class Service: + characteristics: List[Characteristic] + primary: bool + uuid: str # hex + +class Peripheral: + manufacturer_data: bytes + name: Optional[str] + uuid: str # hex + state: int + services: List[Service] + + def discover_services(self) -> None: ... + def discover_characteristics(self, service) -> None: ... + def set_notify_value(self, characteristic, flag: bool = True) -> None: ... + def write_characteristic_value( + self, characteristic, data, with_response + ) -> None: ... + def read_characteristic_value(self, characteristic) -> None: ... + +class CentralManager: + state: int + + def __init__(self) -> None: ... + def scan_for_peripherals(self) -> None: ... + def stop_scan(self) -> None: ... + def connect_peripheral(self, p: Peripheral) -> None: ... + def cancel_peripheral_connection(self, p: Peripheral) -> None: ... + def did_discover_peripheral(self, p: Peripheral) -> None: ... + def did_connect_peripheral(self, p: Peripheral) -> None: ... + def did_fail_to_connect_peripheral( + self, p: Peripheral, error: Optional[str] + ) -> None: ... + def did_disconnect_peripheral( + self, p: Peripheral, error: Optional[str] + ) -> None: ... + def did_discover_services(self, p: Peripheral, error: Optional[str]) -> None: ... + def did_discover_characteristics( + self, s: Service, error: Optional[str] + ) -> None: ... + def did_write_value(self, c: Characteristic, error: Optional[str]) -> None: ... + def did_update_value(self, c: Characteristic, error: Optional[str]) -> None: ... + def did_update_state(self): ... diff --git a/stubs/appex/__init__.pyi b/stubs/appex/__init__.pyi deleted file mode 100644 index 7354014..0000000 --- a/stubs/appex/__init__.pyi +++ /dev/null @@ -1,16 +0,0 @@ -from typing import List, Any, ByteString, Optional -from typing_extensions import Literal - -def is_running_extension() -> bool: ... -def get_attachments(uti: str = "public.data") -> List[Any]: ... -def get_images(image_type: Literal["ui", "pil"] = "pil") -> List[Any]: ... -def get_image(image_type: Literal["ui", "pil"] = "pil") -> Any: ... -def get_image_data() -> Optional[ByteString]: ... -def get_images_data() -> List[ByteString]: ... -def get_text() -> str: ... -def get_urls() -> List[str]: ... -def get_url() -> Optional[str]: ... -def get_file_paths() -> List[str]: ... -def get_file_path() -> Optional[str]: ... -def get_vcard() -> Optional[Any]: ... -def get_vcards() -> List[Any]: ... diff --git a/stubs/clipboard/__init__.pyi b/stubs/clipboard/__init__.pyi deleted file mode 100644 index b745de1..0000000 --- a/stubs/clipboard/__init__.pyi +++ /dev/null @@ -1,9 +0,0 @@ -from PIL import Image -from typing_extensions import Literal - -def get() -> str: ... -def set(string: str) -> None: ... -def get_image(idx: int = 0) -> Image: ... -def set_image( - image: Image, format: Literal["jpeg", "png"] = "png", jpeg_quality: float = 0.75 -) -> None: ... diff --git a/stubs/console/__init__.pyi b/stubs/console/__init__.pyi deleted file mode 100644 index 116d393..0000000 --- a/stubs/console/__init__.pyi +++ /dev/null @@ -1,48 +0,0 @@ -from typing import Optional, Tuple -from typing_extensions import Literal - -def clear() -> None: ... -def set_font(name: Optional[str], size: Optional[float]) -> None: ... -def set_color(r: float, g: float, b: float) -> None: ... -def secure_input(prompt: Optional[str]) -> None: ... -def show_image(image_path: str) -> None: ... -def alert( - title: str, - message: Optional[str], - button1: Optional[str], - button2: Optional[str], - button3: Optional[str], - hide_cancel_button: bool = False, -) -> int: ... -def input_alert( - title: str, - message: Optional[str], - input: Optional[str], - ok_button_title: Optional[str], - hide_cancel_button: bool = False, -) -> str: ... -def password_alert( - title: str, - message: Optional[str], - password: Optional[str], - ok_button_title: Optional[str], - hide_cancel_button: bool = False, -) -> str: ... -def login_alert( - title: str, - message: Optional[str], - login: Optional[str], - password: Optional[str], - ok_button_title: Optional[str], -) -> Tuple[str, str]: ... -def show_activity() -> None: ... -def hide_activity() -> None: ... -def hud_alert( - message: str, icon: Literal["success", "error"] = "success", duration: float = 1.8 -) -> None: ... -def write_link(title: str, link_url: str) -> None: ... -def hide_output() -> None: ... -def quicklook(file_path: str) -> None: ... -def open_in(file_path) -> None: ... -def set_idle_timer_disabled(flag: bool) -> None: ... -def is_in_background() -> bool: ... diff --git a/stubs/editor/__init__.py b/stubs/editor/__init__.py deleted file mode 100644 index ef41acb..0000000 --- a/stubs/editor/__init__.py +++ /dev/null @@ -1,65 +0,0 @@ -from typing import Optional, Tuple -from typing_extensions import Literal - -from stubs import ui - - -def get_path() -> Optional[str]: - ... - - -def get_text() -> str: - ... - - -def get_selection() -> Optional[Tuple[int, int]]: - ... - - -def get_line_selection() -> Optional[Tuple[int, int]]: - ... - - -def set_selection(start: int, end: Optional[int] = None, scroll: bool = False) -> None: - ... - - -def replace_text(start: int, end: int, replacement: str) -> None: - ... - - -def make_new_file(name: str, content: Optional[str], new_tab: Optional[bool]) -> None: - ... - - -def open_file(name: str, new_tab: Optional[bool] = False) -> None: - ... - - -def reload_files() -> None: - ... # undocumented - - -def apply_ui_theme(ui_view: ui.View, theme_name: Optional[str] = None) -> None: - ... - - -def present_themed( - ui_view: ui.View, theme_name: Optional[str] = None, **kwargs -) -> None: - ... - - -def annotate_line( - lineno: int, - text: str = "", - style: Literal["success", "warning", "error"] = "warning", - expanded: bool = True, - filename: Optional[str] = None, - scroll: bool = False, -) -> None: - ... - - -def clear_annotations(filename: Optional[str] = None) -> None: - ... diff --git a/stubs/py.typed b/stubs/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/stubs/pythonista_stubs/__init__.pyi b/stubs/pythonista_stubs/__init__.pyi new file mode 100644 index 0000000..bda5b5a --- /dev/null +++ b/stubs/pythonista_stubs/__init__.pyi @@ -0,0 +1 @@ +__version__: str diff --git a/stubs/pythonista_stubs/appex.pyi b/stubs/pythonista_stubs/appex.pyi new file mode 100644 index 0000000..6714ba0 --- /dev/null +++ b/stubs/pythonista_stubs/appex.pyi @@ -0,0 +1,161 @@ +""" +This is a stub file for the `appex` module, providing type hints for its +functions and their parameters, to be used for static analysis and autocompletion. +""" + +from typing import Any, Dict, List, Optional, Literal, Union + +# These are imported from the `ui` module, which is part of Pythonista. +class View: ... +class Image: ... + +# Assuming 'PIL' is from the Pillow library. +try: + from PIL.Image import Image as PilImage +except ImportError: + PilImage: Any # type: ignore[no-redef] + +# ----------------------------------------------------------------------------- +# General Functions +# ----------------------------------------------------------------------------- +def is_running_extension() -> bool: + """Return True if the script is running within an app extension (share + extension or widget), False otherwise. + """ + ... + +def is_widget() -> bool: + """Return True if the script is running within the Today widget, False + otherwise. + """ + ... + +def finish(js: Optional[str] = None) -> None: + """Close the share sheet extension. + Args: + js (str, optional): A piece of JavaScript code to be evaluated in the + context of the current web page (only relevant in Safari). + """ + ... + +# ----------------------------------------------------------------------------- +# Share Extension Functions +# ----------------------------------------------------------------------------- +def get_attachments(uti: str = "public.data") -> List[Any]: + """Return a list of attachments that match the given type identifier. + Args: + uti (str, optional): The type identifier to match. Defaults to 'public.data'. + Returns: + List[Any]: A list of attachments. + """ + ... + +_ImageType = Literal["ui", "pil"] + +def get_images(image_type: _ImageType = "pil") -> List[Union[Image, PilImage]]: + """Return a list of images in the input of the share sheet. + Args: + image_type (Literal['ui', 'pil'], optional): The desired image type. + Defaults to 'pil'. + Returns: + List[Union[ui.Image, PIL.Image.Image]]: A list of images. + """ + ... + +def get_image(image_type: _ImageType = "pil") -> Optional[Union[Image, PilImage]]: + """Return the first image in the input of the share sheet. + Args: + image_type (Literal['ui', 'pil'], optional): The desired image type. + Defaults to 'pil'. + Returns: + Optional[Union[ui.Image, PIL.Image.Image]]: The first image, or None. + """ + ... + +def get_image_data() -> Optional[bytes]: + """Return raw image data for the first image in the share sheet’s input. + Returns: + Optional[bytes]: The raw image data as a byte string, or None. + """ + ... + +def get_images_data() -> List[bytes]: + """Return raw image data for all images in the share sheet’s input. + Returns: + List[bytes]: A list of byte strings, or an empty list. + """ + ... + +def get_text() -> Optional[str]: + """Return text input of the share sheet. + Returns: + Optional[str]: The text as a unicode string, or None. + """ + ... + +def get_urls() -> List[str]: + """Return a list of URLs in the share sheet’s input. + Returns: + List[str]: A list of URLs, or an empty list. + """ + ... + +def get_url() -> Optional[str]: + """Return the first URL in the share sheet’s input. + Returns: + Optional[str]: The first URL, or None. + """ + ... + +def get_file_paths() -> List[str]: + """Return a list of file paths in the share sheet’s input. + Returns: + List[str]: A list of file paths, or an empty list. + """ + ... + +def get_file_path() -> Optional[str]: + """Return the first file path in the share sheet’s input. + Returns: + Optional[str]: The first file path, or None. + """ + ... + +def get_vcards() -> List[str]: + """Return a list of VCard records in the share sheet’s input. + Returns: + List[str]: A list of VCard records as strings, or an empty list. + """ + ... + +def get_vcard() -> Optional[str]: + """Return the first VCard record in the share sheet’s input. + Returns: + Optional[str]: The first VCard record as a string, or None. + """ + ... + +def get_web_page_info() -> Dict[str, str]: + """When the share sheet is shown in Safari, return information about the + currently loaded page. + Returns: + Dict[str, str]: A dictionary with page information, or an empty dict. + """ + ... + +# ----------------------------------------------------------------------------- +# Today Widget Functions +# ----------------------------------------------------------------------------- +def get_widget_view() -> Optional[View]: + """Return the view that is currently shown in the Today widget. + Returns: + Optional[ui.View]: The current view, or None. + """ + ... + +def set_widget_view(view: Optional[View]) -> None: + """Set the widget’s view to a ui.View object. + Args: + view (Optional[ui.View]): The view to set, or None to remove the current view. + """ + ... diff --git a/stubs/pythonista_stubs/canvas.pyi b/stubs/pythonista_stubs/canvas.pyi new file mode 100644 index 0000000..3b32039 --- /dev/null +++ b/stubs/pythonista_stubs/canvas.pyi @@ -0,0 +1,221 @@ +""" +This is a stub file for the `canvas` module, providing type hints for its +functions and their parameters, to be used for static analysis and autocompletion. +""" + +from typing import Optional, Tuple + +# ----------------------------------------------------------------------------- +# Blend Modes (Constants) +# ----------------------------------------------------------------------------- +BLEND_NORMAL: int = ... +BLEND_MULTIPLY: int = ... +BLEND_SCREEN: int = ... +BLEND_OVERLAY: int = ... +BLEND_DARKEN: int = ... +BLEND_LIGHTEN: int = ... +BLEND_COLOR_DODGE: int = ... +BLEND_COLOR_BURN: int = ... +BLEND_SOFT_LIGHT: int = ... +BLEND_HARD_LIGHT: int = ... +BLEND_DIFFERENCE: int = ... +BLEND_EXCLUSION: int = ... +BLEND_HUE: int = ... +BLEND_SATURATION: int = ... +BLEND_COLOR: int = ... +BLEND_LUMINOSITY: int = ... +BLEND_CLEAR: int = ... +BLEND_COPY: int = ... +BLEND_SOURCE_IN: int = ... +BLEND_SOURCE_OUT: int = ... +BLEND_SOURCE_ATOP: int = ... +BLEND_DESTINATION_OVER: int = ... +BLEND_DESTINATION_ATOP: int = ... +BLEND_XOR: int = ... +BLEND_PLUS_DARKER: int = ... +BLEND_PLUS_LIGHTER: int = ... + +# ----------------------------------------------------------------------------- +# Functions +# ----------------------------------------------------------------------------- +# Configuration +def clear() -> None: + """Clears the canvas.""" + ... + +def get_size() -> Tuple[float, float]: + """Return the size of the canvas as a tuple of width and height.""" + ... + +def set_size(width: float, height: float) -> None: + """Set the size of the canvas and reset all graphics state.""" + ... + +def begin_updates() -> None: + """Begins a group of drawing operations to improve performance.""" + ... + +def end_updates() -> None: + """Forces all buffered drawing to be displayed on the screen.""" + ... + +def save_png(filename: str) -> None: + """Save the current content of the canvas to a PNG file.""" + ... + +# Setting Drawing Parameters +def set_aa_enabled(flag: bool) -> None: + """Enables or disables antialiasing.""" + ... + +def set_alpha(alpha: float) -> None: + """Sets the global alpha value.""" + ... + +def set_blend_mode(mode: int) -> None: + """Sets the active blend mode.""" + ... + +def set_fill_color(r: float, g: float, b: float, a: float = 1.0) -> None: + """Sets the fill color (RGB or RGBA).""" + ... + +def set_line_width(width: float) -> None: + """Sets the line width.""" + ... + +def set_stroke_color(r: float, g: float, b: float, a: float = 1.0) -> None: + """Sets the active stroke color (RGB or RGBA).""" + ... + +# Vector Drawing Functions +def add_curve( + cp1x: float, cp1y: float, cp2x: float, cp2y: float, x: float, y: float +) -> None: + """Adds a cubic bezier curve to the current path.""" + ... + +def add_ellipse(x: float, y: float, width: float, height: float) -> None: + """Adds an ellipse to the current path.""" + ... + +def add_line(x: float, y: float) -> None: + """Adds a straight line to the current path.""" + ... + +def add_quad_curve(cpx: float, cpy: float, x: float, y: float) -> None: + """Adds a quadratic bezier curve to the current path.""" + ... + +def add_rect(x: float, y: float, width: float, height: float) -> None: + """Adds a rectangle to the current path.""" + ... + +def begin_path() -> None: + """Begins a new path.""" + ... + +def clip() -> None: + """Clips subsequent drawing to the current path.""" + ... + +def close_path() -> None: + """Closes the current path.""" + ... + +def draw_ellipse(x: float, y: float, width: float, height: float) -> None: + """Draws an ellipse in a rectangle.""" + ... + +def draw_line(x1: float, y1: float, x2: float, y2: float) -> None: + """Draws a line between two points.""" + ... + +def draw_path() -> None: + """Draws the outline of the current path.""" + ... + +def draw_rect(x: float, y: float, width: float, height: float) -> None: + """Draws the outline of a rectangle.""" + ... + +def fill_ellipse(x: float, y: float, width: float, height: float) -> None: + """Fills an ellipse in a rectangle.""" + ... + +def fill_path() -> None: + """Fills the current path.""" + ... + +def fill_pixel(x: float, y: float) -> None: + """Fills a pixel with the current fill color.""" + ... + +def fill_rect(x: float, y: float, width: float, height: float) -> None: + """Fills a rectangle.""" + ... + +def move_to(x: float, y: float) -> None: + """Moves the 'pen' to a given point.""" + ... + +# Transforms +def restore_gstate() -> None: + """Restores the graphics state from the stack.""" + ... + +def rotate(angle: float) -> None: + """Rotates the current transformation matrix.""" + ... + +def save_gstate() -> None: + """Pushes a copy of the current graphics state onto the stack.""" + ... + +def scale(sx: float, sy: float) -> None: + """Scales the current transformation matrix.""" + ... + +def translate(tx: float, ty: float) -> None: + """Translates the current transformation matrix.""" + ... + +# Drawing Bitmap Images +def draw_image( + image_name: str, + x: float, + y: float, + width: Optional[float] = None, + height: Optional[float] = None, +) -> None: + """Draws the image with the given name in a rectangle.""" + ... + +def draw_clipboard(x: float, y: float, width: float, height: float) -> None: + """Draw the image in the clipboard in a given rectangle.""" + ... + +def get_clipboard_size() -> Tuple[float, float]: + """Return the size of the image in the clipboard in points.""" + ... + +def get_image_size(image_name: str) -> Tuple[float, float]: + """Returns the size of the image with the given name in points.""" + ... + +# Drawing Text +def draw_text( + text: str, + x: float, + y: float, + font_name: str = "Helvetica", + font_size: float = 16.0, +) -> None: + """Draw a single line of text at a given point.""" + ... + +def get_text_size( + text: str, font_name: str = "Helvetica", font_size: float = 16.0 +) -> Tuple[float, float]: + """Get the size of a line of text as a tuple of (width, height).""" + ... diff --git a/stubs/pythonista_stubs/cb.pyi b/stubs/pythonista_stubs/cb.pyi new file mode 100644 index 0000000..7b85722 --- /dev/null +++ b/stubs/pythonista_stubs/cb.pyi @@ -0,0 +1,94 @@ +""" +`pythonista.cb` module type annotations +according to [pythonista.cb docs](https://omz-software.com/pythonista/docs/ios/cb.html) +""" + +from typing import Optional, Protocol +from _cb import ( + CM_STATE_UNKNOWN, + CM_STATE_RESETTING, + CM_STATE_UNSUPPORTED, + CM_STATE_UNAUTHORIZED, + CM_STATE_POWERED_OFF, + CM_STATE_POWERED_ON, + CH_PROP_BROADCAST, + CH_PROP_READ, + CH_PROP_WRITE_WITHOUT_RESPONSE, + CH_PROP_WRITE, + CH_PROP_NOTIFY, + CH_PROP_INDICATE, + CH_PROP_AUTHENTICATED_SIGNED_WRITES, + CH_PROP_EXTENDED_PROPERTIES, + CH_PROP_NOTIFY_ENCRYPTION_REQUIRED, + CH_PROP_INDICATE_ENCRYPTION_REQUIRED, + Characteristic, + Service, + Peripheral, + CentralManager, +) + +__all__ = ( + "CM_STATE_UNKNOWN", + "CM_STATE_RESETTING", + "CM_STATE_UNSUPPORTED", + "CM_STATE_UNAUTHORIZED", + "CM_STATE_POWERED_OFF", + "CM_STATE_POWERED_ON", + "CH_PROP_BROADCAST", + "CH_PROP_READ", + "CH_PROP_WRITE_WITHOUT_RESPONSE", + "CH_PROP_WRITE", + "CH_PROP_NOTIFY", + "CH_PROP_INDICATE", + "CH_PROP_AUTHENTICATED_SIGNED_WRITES", + "CH_PROP_EXTENDED_PROPERTIES", + "CH_PROP_NOTIFY_ENCRYPTION_REQUIRED", + "CH_PROP_INDICATE_ENCRYPTION_REQUIRED", + "Characteristic", + "Service", + "Peripheral", + "CentralManager", + "SharedCentralManager", + "shared_manager", + "set_central_delegate", + "set_verbose", + "scan_for_peripherals", + "stop_scan", + "connect_peripheral", + "cancel_peripheral_connection", + "get_state", + "reset", +) + +class _CentralManagerDelegate(Protocol): + def did_discover_peripheral(self, p: Peripheral) -> None: ... + def did_connect_peripheral(self, p: Peripheral) -> None: ... + def did_fail_to_connect_peripheral( + self, p: Peripheral, error: Optional[str] + ) -> None: ... + def did_disconnect_peripheral( + self, p: Peripheral, error: Optional[str] + ) -> None: ... + def did_discover_services(self, p: Peripheral, error: Optional[str]) -> None: ... + def did_discover_characteristics( + self, s: Service, error: Optional[str] + ) -> None: ... + def did_write_value(self, c: Characteristic, error: Optional[str]) -> None: ... + def did_update_value(self, c: Characteristic, error: Optional[str]) -> None: ... + def did_update_state(self) -> None: ... + +class SharedCentralManager(CentralManager): + delegate: Optional[_CentralManagerDelegate] = None + verbose: bool = False + def verbose_log(self): ... + +shared_manager: Optional[SharedCentralManager] = SharedCentralManager() + +def set_central_delegate(delegate: _CentralManagerDelegate) -> None: ... +def set_verbose(flag: bool) -> None: ... +def scan_for_peripherals() -> None: ... +def stop_scan() -> None: ... +def connect_peripheral(p: Peripheral) -> None: ... +def cancel_peripheral_connection(p: Peripheral) -> None: ... +def get_state() -> int: ... +def reset() -> None: ... diff --git a/stubs/pythonista_stubs/clipboard.pyi b/stubs/pythonista_stubs/clipboard.pyi new file mode 100644 index 0000000..00f120f --- /dev/null +++ b/stubs/pythonista_stubs/clipboard.pyi @@ -0,0 +1,63 @@ +""" +This is a stub file for the `clipboard` module, providing type hints for its +functions and their parameters, to be used for static analysis and autocompletion. +""" + +from typing import Optional, Literal, Any + +# Assuming 'PIL' is from the Pillow library, which is not part of the standard library +# and might not be available in all Pythonista environments. +# We'll use `Any` as a fallback or assume a type alias exists. +try: + from PIL.Image import Image +except ImportError: + Image: Any # type: ignore[no-redef] + +def get() -> str: + """Returns the clipboard’s content as a Unicode string. + + Returns: + str: The content of the clipboard. + """ + ... + +def set(string: str) -> None: + """Sets the clipboard’s content to a new string. + + Args: + string (str): The new content for the clipboard. + """ + ... + +def get_image(idx: int = 0) -> Optional[Image]: + """Returns an image from the clipboard. + + If there are multiple images in the clipboard, the `idx` parameter can be + used to get an image at a given index. If the index is >= the number of + images in the clipboard, `None` is returned. + + Args: + idx (int, optional): The index of the image to retrieve. Defaults to 0. + + Returns: + Optional[Image]: The image from the clipboard, or None if no image + was found at the given index. + """ + ... + +_ImageFormat = Literal["png", "jpeg"] + +def set_image( + image: Image, format: _ImageFormat = "png", jpeg_quality: float = 0.75 +) -> None: + """Stores a given PIL Image in the clipboard. + + Args: + image (PIL.Image.Image): The image to store in the clipboard. + format (str, optional): The format to store the image in. Can be + 'png' or 'jpeg'. Defaults to 'png'. + jpeg_quality (float, optional): The quality for JPEG format. Should be + a float between 0.0 and 1.0. This is ignored if `format` is 'png'. + Defaults to 0.75. + """ + ... diff --git a/stubs/pythonista_stubs/console.pyi b/stubs/pythonista_stubs/console.pyi new file mode 100644 index 0000000..1c0cd7d --- /dev/null +++ b/stubs/pythonista_stubs/console.pyi @@ -0,0 +1,244 @@ +""" +This is a stub file for the `console` module, providing type hints for its +functions and their parameters, to be used for static analysis and autocompletion. +""" + +from typing import Optional, Union, Tuple, Sequence, Literal + +# These are simple utility functions. +def clear() -> None: + """Clears the console output.""" + ... + +def set_font(name: Optional[str] = None, size: Optional[int] = None) -> None: + """Sets the font and font size for the following output. + + Args: + name (str, optional): The font name (e.g. "Menlo"). If None, reset to default. + size (int, optional): The font size. If None, reset to default. + """ + ... + +def set_color(r: float, g: float, b: float) -> None: + """Sets the RGB colour for the following output. + + The components are floats between 0.0 and 1.0. + + Args: + r (float): The red component. + g (float): The green component. + b (float): The blue component. + """ + ... + +def secure_input(prompt: Optional[str] = None) -> str: + """Gets user input with hidden characters. + + This function is similar to the built-in raw_input function, but the user’s + input is hidden, so that it’s suitable to request passwords and other + sensitive information. + + Args: + prompt (str, optional): A prompt to display to the user. + + Returns: + str: The string entered by the user. + """ + ... + +def show_image(image_path: Union[str]) -> None: + """Shows an image in the console output area. + + Args: + image_path (str or Path): The path to the image file. + """ + ... + +def alert( + title: str, + message: str = "", + button1: str = "OK", + button2: Optional[str] = None, + button3: Optional[str] = None, + hide_cancel_button: bool = False, +) -> int: + """Shows an alert dialog with up to three custom buttons. + + The selected button is returned as an integer (button1 => 1, etc.). + Unless `hide_cancel_button` is True, all alert dialogs contain a ‘Cancel’ + button that sends a KeyboardInterrupt. + + Args: + title (str): The title of the alert. + message (str, optional): The message to display. Defaults to "". + button1 (str, optional): The title of the first button. Defaults to "OK". + button2 (str, optional): The title of the second button. + button3 (str, optional): The title of the third button. + hide_cancel_button (bool, optional): If True, hides the cancel button. + Defaults to False. + + Returns: + int: The integer corresponding to the selected button (1, 2, or 3). + """ + ... + +def input_alert( + title: str, + message: str = "", + input: str = "", + ok_button_title: str = "OK", + hide_cancel_button: bool = False, +) -> str: + """Shows a dialog with a single text field. + + The text field can be pre-filled with the `input` parameter. The text + that was entered by the user is returned. The ‘Cancel’ button sends a + KeyboardInterrupt. + + Args: + title (str): The title of the alert. + message (str, optional): The message to display. Defaults to "". + input (str, optional): Text to pre-fill the input field with. + Defaults to "". + ok_button_title (str, optional): The title of the OK button. + Defaults to "OK". + hide_cancel_button (bool, optional): If True, hides the cancel button. + Defaults to False. + + Returns: + str: The text entered by the user. + """ + ... + +def password_alert( + title: str, + message: str = "", + password: str = "", + ok_button_title: str = "OK", + hide_cancel_button: bool = False, +) -> str: + """Shows a dialog with a password entry text field. + + The password field can be pre-filled with the `password` parameter. + The password that was entered by the user is returned. The ‘Cancel’ button + sends a KeyboardInterrupt. + + Args: + title (str): The title of the alert. + message (str, optional): The message to display. Defaults to "". + password (str, optional): Text to pre-fill the password field with. + Defaults to "". + ok_button_title (str, optional): The title of the OK button. + Defaults to "OK". + hide_cancel_button (bool, optional): If True, hides the cancel button. + Defaults to False. + + Returns: + str: The password entered by the user. + """ + ... + +def login_alert( + title: str, + message: str = "", + login: str = "", + password: str = "", + ok_button_title: str = "OK", +) -> Tuple[str, str]: + """Shows a dialog with two text fields, one for login and one for a password. + + The text fields can be pre-filled with the `login` and `password` parameters. + Returns a tuple of the entered text as `(login, password)`. The ‘Cancel’ + button sends a KeyboardInterrupt. + + Args: + title (str): The title of the alert. + message (str, optional): The message to display. Defaults to "". + login (str, optional): Text to pre-fill the login field with. + Defaults to "". + password (str, optional): Text to pre-fill the password field with. + Defaults to "". + ok_button_title (str, optional): The title of the OK button. + Defaults to "OK". + + Returns: + Tuple[str, str]: A tuple containing the entered login and password. + """ + ... + +def show_activity() -> None: + """Shows the animated “network activity indicator” in the status bar.""" + ... + +def hide_activity() -> None: + """Hides the animated “network activity indicator” in the status bar.""" + ... + +_HudIcon = Literal["success", "error"] + +def hud_alert(message: str, icon: _HudIcon = "success", duration: float = 1.8) -> None: + """Shows a HUD-style alert with the given message. + + The function blocks until the alert is dismissed. + + Args: + message (str): The message to display. + icon (str, optional): The icon to show. It Can be 'success' (a checkmark + symbol) or 'error' (a cross symbol). Defaults to 'success'. + duration (float, optional): How long the alert is shown. It Can be + between 0.25 and 5.0 seconds. Defaults to 1.8 seconds. + """ + ... + +def write_link(title: str, link_url: str) -> None: + """Prints a tappable link to the console. + + Args: + title (str): The title of the link to display. + link_url (str): The URL link should open. + """ + ... + +def hide_output() -> None: + """Hides the console output area with a sliding animation.""" + ... + +def quicklook(file_path: Union[str, Sequence[str]]) -> None: + """Shows a full-screen preview of local files. + + The function returns when the preview is dismissed. + + Args: + file_path (str or Path or Sequence): The path to a single file, or + a sequence of paths to preview multiple files. + """ + ... + +def open_in(file_path: str) -> Optional[str]: + """Shows the iOS “Open in...” menu for the specified file. + + Args: + file_path (str or Path): The path to the file. + + Returns: + Optional[str]: The bundle identifier of the selected app, or None + if the menu was cancelled or no app can open the file. + """ + ... + +def set_idle_timer_disabled(flag: bool) -> None: + """Disables or enables the idle timer. + + Args: + flag (bool): If True, the idle timer is disabled (a device won't go to + sleep). If False, the idle timer is re-enabled. + """ + ... + +def is_in_background() -> bool: + """Returns whether the app is currently running in the background. + + Returns: + bool: True if the app is in the background, False otherwise. + """ + ... diff --git a/stubs/pythonista_stubs/contacts.pyi b/stubs/pythonista_stubs/contacts.pyi new file mode 100644 index 0000000..e9b8d96 --- /dev/null +++ b/stubs/pythonista_stubs/contacts.pyi @@ -0,0 +1,172 @@ +""" +This is a stub file for the `contacts` module, providing type hints for its +functions and their parameters, to be used for static analysis and autocompletion. +""" + +import datetime +from typing import Dict, List, Optional, Tuple + +# ----------------------------------------------------------------------------- +# Constants for multi-value attributes +# ----------------------------------------------------------------------------- +HOME: str = ... +WORK: str = ... +OTHER: str = ... +IPHONE: str = ... +MAIN_PHONE: str = ... +HOME_FAX: str = ... +WORK_FAX: str = ... +OTHER_FAX: str = ... +PAGER: str = ... +FATHER: str = ... +MOTHER: str = ... +PARENT: str = ... +BROTHER: str = ... +SISTER: str = ... +CHILD: str = ... +FRIEND: str = ... +SPOUSE: str = ... +PARTNER: str = ... +ASSISTANT: str = ... +MANAGER: str = ... +HOMEPAGE: str = ... +STREET: str = ... +CITY: str = ... +STATE: str = ... +ZIP: str = ... +COUNTRY: str = ... +COUNTRY_CODE: str = ... + +# ----------------------------------------------------------------------------- +# Person Objects +# ----------------------------------------------------------------------------- +class Person: + """Person objects represent people in the address book.""" + + address: List[Tuple[str, Dict[str, str]]] + """Street address(es). The inner dictionary uses keys from the constants + section (e.g., STREET, CITY). + """ + birthday: Optional[datetime.datetime] + """Birthday as a datetime object.""" + creation_date: datetime.datetime + """When the person was added (readonly).""" + department: str + """Department name.""" + email: List[Tuple[str, str]] + """Email address(es).""" + first_name: str + """First name.""" + first_name_phonetic: str + """Phonetic first name.""" + full_name: str + """The person’s full name (readonly).""" + id: int + """The persistent identifier of the person record (readonly).""" + image_data: Optional[bytes] + """The person’s image data (e.g., PNG or JPEG) or None.""" + instant_message: List[Tuple[str, Dict[str, str]]] + """Instant message accounts.""" + job_title: str + """Job title.""" + kind: int + """The kind of address book record (0 for person, 1 for organization).""" + last_name: str + """Last name.""" + last_name_phonetic: str + """Phonetic last name.""" + middle_name: str + """Middle name.""" + middle_name_phonetic: str + """Phonetic middle name.""" + modification_date: datetime.datetime + """When the person was last modified (readonly).""" + nickname: str + """Nickname.""" + note: str + """Additional notes.""" + organization: str + """Organization name.""" + phone: List[Tuple[str, str]] + """Phone number(s).""" + prefix: str + """Prefix (e.g., 'Sir').""" + related_names: List[Tuple[str, str]] + """Related names.""" + social_profile: List[Tuple[str, Dict[str, str]]] + """Social profile(s).""" + suffix: str + """Suffix (e.g., 'Jr.').""" + url: List[Tuple[str, str]] + """URL(s).""" + vcard: str + """VCard representation of the person's data (readonly).""" + +# ----------------------------------------------------------------------------- +# Group Objects +# ----------------------------------------------------------------------------- +class Group: + """A Group object represents a group in the address book.""" + + name: str + """The group’s name.""" + id: int + """The persistent identifier of the group (readonly).""" + +# ----------------------------------------------------------------------------- +# Functions +# ----------------------------------------------------------------------------- +def get_group(group_id: int) -> Optional[Group]: + """Return the Group with the given id.""" + ... + +def get_all_groups() -> List[Group]: + """Return a list of all Group objects in the address book.""" + ... + +def add_group() -> Group: + """Add a new Group to the address book. + Returns: + Group: The newly created Group object. + """ + ... + +def remove_group(group: Group) -> None: + """Remove a Group from the address book.""" + ... + +def add_person(person: Person) -> None: + """Add a Person to the address book.""" + ... + +def remove_person(person: Person) -> None: + """Remove a Person from the address book.""" + ... + +def find(name: str) -> List[Person]: + """Do a prefix search for the given name and return a list of matches.""" + ... + +def get_all_people() -> List[Person]: + """Return a list of all people in the address book.""" + ... + +def get_person(person_id: int) -> Optional[Person]: + """Return the Person with the given id.""" + ... + +def save() -> None: + """Save all pending changes in the contacts database.""" + ... + +def revert() -> None: + """Revert all pending changes in the contacts database.""" + ... + +def localized_label(label: str) -> str: + """Return a localized version of a label.""" + ... + +def is_authorized() -> bool: + """Returns True if access to the address book is currently allowed.""" + ... diff --git a/stubs/pythonista_stubs/dialogs.pyi b/stubs/pythonista_stubs/dialogs.pyi new file mode 100644 index 0000000..e9dbe53 --- /dev/null +++ b/stubs/pythonista_stubs/dialogs.pyi @@ -0,0 +1,255 @@ +""" +This is a stub file for the `dialogs` module, providing type hints for its +functions and their parameters, to be used for static analysis and autocompletion. +""" + +import datetime +from typing import Any, Dict, List, Optional, Sequence, Tuple, Union, Literal + +# These are imported from the `console` module for convenience. +# We'll alias the types for clarity. +from . import console as _console + +# These are imported from the `ui` module, which is part of Pythonista. +# We'll provide a minimal stub for the types used. +class Image: ... + +class TextField: + AUTOCAPITALIZE_SENTENCES: int = ... + # ... other autocapitalization types + +class ListDataSource: + items: List[Dict[str, Any]] = ... + +def alert(*args, **kwargs) -> int: + """See console.alert()""" + return _console.alert(*args, **kwargs) + +def input_alert(*args, **kwargs) -> str: + """See console.input_alert()""" + return _console.input_alert(*args, **kwargs) + +def login_alert(*args, **kwargs) -> Tuple[str, str]: + """See console.login_alert()""" + return _console.login_alert(*args, **kwargs) + +def password_alert(*args, **kwargs) -> str: + """See console.password_alert()""" + return _console.password_alert(*args, **kwargs) + +def hud_alert(*args, **kwargs) -> None: + """See console.hud_alert()""" + return _console.hud_alert(*args, **kwargs) + +# ----------------------------------------------------------------------------- +# Dialog Functions +# ----------------------------------------------------------------------------- + +def list_dialog( + title: str = "", + items: Optional[Union[Sequence[Any], List[Dict[str, Any]]]] = None, + multiple: bool = False, +) -> Optional[Union[Any, List[Any]]]: + """Presents a list of items and returns the one(s) that were selected. + + When the dialog is cancelled, None is returned. The `items` list can + contain any kind of object that can be converted to a string. To get more + control over how each item is displayed in the list, you can also use a + list of dictionaries (see ui.ListDataSource.items for details). + + Args: + title (str, optional): The title of the dialog. Defaults to "". + items (Union[Sequence[Any], List[Dict[str, Any]]], optional): + The list of items to display. Defaults to None. + multiple (bool, optional): If True, allows multiple selections. + Defaults to False. + + Returns: + Optional[Union[Any, List[Any]]]: The selected item(s), or None if the + dialog was canceled. + """ + ... + +def edit_list_dialog( + title: str = "", + items: Optional[Sequence[Any]] = None, + move: bool = True, + delete: bool = True, +) -> Optional[List[Any]]: + """Presents a list of items that can be edited by the user. + + By default, the user can both rearrange the list and remove items; this + behavior can be controlled with the `move` and `delete` parameters. + + Args: + title (str, optional): The title of the dialog. Defaults to "". + items (Sequence[Any], optional): The list of items to display. + Defaults to None. + move (bool, optional): If True, allows items to be rearranged. + Defaults to True. + delete (bool, optional): If True, allows items to be deleted. + Defaults to True. + + Returns: + Optional[List[Any]]: The modified list of items, or None if the + dialog was cancelled. + """ + ... + +# Field dictionaries are complex, so we'll type-hint them with a specific type alias. +_FieldType = Literal[ + "switch", + "text", + "url", + "email", + "password", + "number", + "check", + "datetime", + "date", + "time", +] +_FieldDict = Dict[str, Any] +_SectionTuple = Tuple[str, List[_FieldDict], Optional[str]] + +def form_dialog( + title: str = "", + fields: Optional[List[_FieldDict]] = None, + sections: Optional[List[_SectionTuple]] = None, +) -> Optional[Dict[str, Any]]: + """Presents a form dialog with customizable data input fields. + + Args: + title (str, optional): The title of the dialog. Defaults to "". + fields (List[Dict[str, Any]], optional): A list of field dictionaries for + a single-section form. Use `sections` for multiple sections. + Defaults to None. + sections (List[Tuple[str, List[Dict[str, Any]], Optional[str]]], optional): + A list of tuples, where each tuple represents a section. + Defaults to None. + + Returns: + Optional[Dict[str, Any]]: A dictionary of values for each field, + or None if the dialog was cancelled. + """ + ... + +def text_dialog( + title: str = "", + text: str = "", + font: Union[Tuple[str, int], Tuple[str], str] = ("", 16), + autocorrection: Optional[bool] = None, + autocapitalization: int = TextField.AUTOCAPITALIZE_SENTENCES, + spellchecking: Optional[bool] = None, +) -> Optional[str]: + """Shows a multi-line text editor sheet. + + Args: + title (str, optional): The title of the dialog. Defaults to "". + text (str, optional): The initial text in the editor. Defaults to "". + font (Union[Tuple[str, int], Tuple[str], str], optional): + The font and size. Defaults to ('', 16). + autocorrection (Optional[bool], optional): Whether auto-correction + should be enabled. Defaults to None. + autocapitalization (int, optional): The auto-capitalization behavior. + Defaults to ui.AUTOCAPITALIZE_SENTENCES. + spellchecking (Optional[bool], optional): Whether spell checking + should be enabled. Defaults to None. + + Returns: + Optional[str]: The edited text, or None if the dialog was cancelled. + """ + ... + +def date_dialog(title: str = "") -> Optional[datetime.datetime]: + """Shows a date picker dialog. + + Args: + title (str, optional): The title of the dialog. Defaults to "". + + Returns: + Optional[datetime.datetime]: A datetime.datetime object with the selected + date, or None if the dialog was cancelled. + """ + ... + +def time_dialog(title: str = "") -> Optional[datetime.datetime]: + """Shows a time picker dialog. + + Args: + title (str, optional): The title of the dialog. Defaults to "". + + Returns: + Optional[datetime.datetime]: A datetime.datetime object with the selected + time, or None if the dialog was cancelled. + """ + ... + +def datetime_dialog(title: str = "") -> Optional[datetime.datetime]: + """Shows a date and time picker dialog. + + Args: + title (str, optional): The title of the dialog. Defaults to "". + + Returns: + Optional[datetime.datetime]: A datetime.datetime object with the selected + date and time, or None if the dialog was cancelled. + """ + ... + +def duration_dialog(title: str = "") -> Optional[float]: + """Shows a duration picker dialog (e.g. for a countdown timer). + + Args: + title (str, optional): The title of the dialog. Defaults to "". + + Returns: + Optional[float]: The selected duration in seconds, or None if the + dialog was cancelled. + """ + ... + +# ----------------------------------------------------------------------------- +# Sharing Functions +# ----------------------------------------------------------------------------- + +def share_image(img: Union[Image, Any]) -> None: + """Shows the system sharing dialog for a given image. + + Args: + img (Union[ui.Image, PIL.Image.Image]): The image to share. + """ + ... + +def share_text(text: str) -> None: + """Shows the system sharing dialog for a given string. + + Args: + text (str): The text to share. + """ + ... + +def share_url(url: str) -> None: + """Shows the system sharing dialog for a given URL. + + Args: + url (str): The URL to share. + """ + ... + +# ----------------------------------------------------------------------------- +# Importing Files +# ----------------------------------------------------------------------------- + +def pick_document(types: List[str] = ["public.data"]) -> Optional[str]: + """Shows the system’s document picker for importing a file. + + Args: + types (List[str], optional): Universal Type Identifiers (UTIs) for + file types that should be selectable. Defaults to ['public.data']. + + Returns: + Optional[str]: The path to the selected temporary file, or None if + the dialog was cancelled. + """ + ... diff --git a/stubs/pythonista_stubs/editor.pyi b/stubs/pythonista_stubs/editor.pyi new file mode 100644 index 0000000..5d8ab7f --- /dev/null +++ b/stubs/pythonista_stubs/editor.pyi @@ -0,0 +1,156 @@ +""" +This is a stub file for the `editor` module, providing type hints for its +functions and their parameters, to be used for static analysis and autocompletion. +""" + +from typing import Optional, Tuple, Literal + +# We'll use a minimal stub for the ui.View type from the ui module. +class View: ... + +def get_path() -> Optional[str]: + """Returns the absolute file path of the script that is currently open in the editor. + + Returns: + Optional[str]: The absolute file path, or None if no script is open. + """ + ... + +def get_text() -> str: + """Returns the entire text of the script that is currently being edited. + + Returns: + str: The full text content of the editor. + """ + ... + +def get_selection() -> Optional[Tuple[int, int]]: + """Returns the selected range as a tuple of the form (start, end). + + The `start` and `end` values are character indices. + + Returns: + Optional[Tuple[int, int]]: The start and end indices of the selection, + or None if no file is currently open. + """ + ... + +def get_line_selection() -> Optional[Tuple[int, int]]: + """Returns the range of all lines that are part of the current selection. + + Returns: + Optional[Tuple[int, int]]: The start and end indices of the line selection, + or None if no file is currently open. + """ + ... + +def set_selection(start: int, end: Optional[int] = None, scroll: bool = False) -> None: + """Sets the selected range in the editor. + + Args: + start (int): The starting character index of the selection. + end (Optional[int], optional): The ending character index of the selection. + If None, the caret is positioned at `start` with no text selected. + scroll (bool, optional): If True, scrolls the view to make the selection + visible. Defaults to False. + """ + ... + +def replace_text(start: int, end: int, replacement: str) -> None: + """Replaces the text in the given range with a new string. + + To insert/append text, a zero-length range can be used. All changes can be + undone by the user (using the regular undo key). + + Args: + start (int): The starting character index of the range to replace. + end (int): The ending character index of the range to replace. + replacement (str): The new text to insert. + """ + ... + +def make_new_file(name: Optional[str] = None, content: Optional[str] = None) -> None: + """Creates a new file and opens it in the editor. + + If a file with the given name already exists, a numeric suffix is + automatically appended. + + Args: + name (Optional[str], optional): The desired name for the new file. + Defaults to None. + content (Optional[str], optional): The initial content of the new file. + If omitted, an empty file is created. Defaults to None. + """ + ... + +def open_file(name: str, new_tab: bool = False) -> None: + """Opens the file with the given name in the editor. + + Args: + name (str): The path to the file. It can be relative to the script + library’s root directory or an absolute path. The .py extension + can be omitted. + new_tab (bool, optional): If True, the file is opened in a new tab. + Defaults to False. + """ + ... + +def apply_ui_theme(ui_view: View, theme_name: Optional[str] = None) -> None: + """Styles a ui.View (and its descendents) with the given UI theme. + + Args: + ui_view (ui.View): The view to be styled. + theme_name (Optional[str], optional): The name of the theme. If None, + the currently selected theme is used. Defaults to None. + """ + ... + +def present_themed(ui_view: View, theme_name: Optional[str] = None, **kwargs) -> None: + """Styles a ui.View and presents it. + + This function combines `apply_ui_theme()` and `ui.View.present()`. + Keyword arguments are passed on to `ui.View.present()`. + + Args: + ui_view (ui.View): The view to be styled and presented. + theme_name (Optional[str], optional): The name of the theme. If None, + the currently selected theme is used. Defaults to None. + """ + ... + +_AnnotationStyle = Literal["success", "warning", "error"] + +def annotate_line( + lineno: int, + text: str = "", + style: _AnnotationStyle = "warning", + expanded: bool = True, + filename: Optional[str] = None, + scroll: bool = False, +) -> None: + """Annotates a line of code in the editor with a label. + + Args: + lineno (int): The 1-based line number to annotate. + text (str, optional): The text of the annotation. Defaults to ''. + style (Literal['success', 'warning', 'error'], optional): The style of + the annotation. Defaults to 'warning'. + expanded (bool, optional): If False, only an icon is shown; tapping + shows the text. Defaults to True. + filename (Optional[str], optional): The path to the file to annotate. + If None, the file currently open in the editor is used. + Defaults to None. + scroll (bool, optional): If True, scrolls to the annotated line. + Defaults to False. + """ + ... + +def clear_annotations(filename: Optional[str] = None) -> None: + """Removes all annotations that were added via `annotate_line()`. + + Args: + filename (Optional[str], optional): The path to the file from which to + clear annotations. If None, the file currently open is used. + Defaults to None. + """ + ... diff --git a/stubs/pythonista_stubs/keyboard.pyi b/stubs/pythonista_stubs/keyboard.pyi new file mode 100644 index 0000000..c3d4cf8 --- /dev/null +++ b/stubs/pythonista_stubs/keyboard.pyi @@ -0,0 +1,82 @@ +""" +This is a stub file for the `keyboard` module, providing type hints for its +functions and their parameters, to be used for static analysis and autocompletion. +""" + +from typing import List, Literal, Optional, Tuple + +# These are imported from the `ui` module, which is part of Pythonista. +class View: + def __init__(self, *args, **kwargs): ... + def add_subview(self, view: "View") -> None: ... + def remove_subview(self, view: "View") -> None: ... + def present(self, style: str = "sheet", animated: bool = True) -> None: ... + +# ----------------------------------------------------------------------------- +# Functions +# ----------------------------------------------------------------------------- +_Appearance = Literal["dark", "light"] +_Mode = Literal["current", "minimized", "expanded"] + +def backspace(times: int = 1) -> None: + """Delete backwards in the current document. + Args: + times (int, optional): The number of characters to delete. Defaults to 1. + """ + ... + +def get_appearance() -> _Appearance: + """Return the current appearance of the keyboard ('dark' or 'light').""" + ... + +def get_document_id() -> str: + """Return a unique identifier (UUID) for the current document.""" + ... + +def get_input_context() -> Tuple[str, str]: + """Return a 2-tuple with the text immediately before and after the cursor.""" + ... + +def get_selected_text() -> str: + """Return the currently selected text or an empty string.""" + ... + +def get_text_replacements() -> Optional[List[Tuple[str, str]]]: + """Return a list of text replacements. + Returns: + Optional[List[Tuple[str, str]]]: A list of (phrase, shortcut) tuples, + or None if not running in the keyboard. + """ + ... + +def has_full_access() -> bool: + """Return True if 'Full Access' is enabled for the keyboard.""" + ... + +def has_text() -> bool: + """Return True if the document being edited contains any text.""" + ... + +def insert_text(text: str) -> None: + """Insert text in the current document.""" + ... + +def is_keyboard() -> bool: + """Return True if the script is running in the custom Pythonista keyboard.""" + ... + +def move_cursor(offset: int) -> None: + """Move the cursor by a specified offset.""" + ... + +def play_input_click() -> None: + """Play an input click sound.""" + ... + +def set_view(view: Optional[View] = None, mode: _Mode = "current") -> None: + """Sets a custom ui.View as the keyboard's UI. + Args: + view (ui.View, optional): The view to display. Pass None to close. + mode (str, optional): The presentation mode ('minimized', 'expanded', or 'current'). + """ + ... diff --git a/stubs/pythonista_stubs/keychain.pyi b/stubs/pythonista_stubs/keychain.pyi new file mode 100644 index 0000000..bbee4fc --- /dev/null +++ b/stubs/pythonista_stubs/keychain.pyi @@ -0,0 +1,57 @@ +"""Secure Password Storage. + +This module provides simple access to secure password storage. + +Note: + The keychain is not shared between apps, so you cannot use this to + access passwords stored in Safari's keychain, for example. +""" + +from typing import Optional, List, Tuple, Any + +def get_password(service: str, account: str) -> Optional[str]: + """Get a password from the keychain. + + Args: + service: The name of the service associated with the password. + account: The name of the user account associated with the password. + + Returns: + The password as a string, or `None` if no password is found + for the given service and account. + """ + ... + +def set_password(service: str, account: str, password: str) -> None: + """Save a password to the keychain. + + This saves a password for the given service and account. If a password + already exists for this service/account pair, it will be overwritten. + + Args: + service: The name of the service to associate with the password. + account: The name of the user account. + password: The password to be stored. + """ + ... + +def delete_password(service: str, account: str) -> None: + """Delete a password from the keychain. + + This deletes the password for the given service and account. + + Args: + service: The name of the service. + account: The name of the user account. + """ + ... + +def reset_keychain() -> None: + """Delete all data from the keychain. + + This is a destructive operation that removes all passwords + stored by the current application. + """ + ... + +def get_services() -> List[Tuple[Any, Any]]: ... diff --git a/stubs/pythonista_stubs/linguistictagger.pyi b/stubs/pythonista_stubs/linguistictagger.pyi new file mode 100644 index 0000000..5393eac --- /dev/null +++ b/stubs/pythonista_stubs/linguistictagger.pyi @@ -0,0 +1,45 @@ +""" +This is a stub file for the `linguistictagger` module, providing type hints for +its functions and their parameters, to be used for static analysis and +autocompletion. +""" + +from typing import List, Literal, Tuple + +# ----------------------------------------------------------------------------- +# Constants +# ----------------------------------------------------------------------------- +SCHEME_TOKEN_TYPE: str = ... +SCHEME_LEXICAL_CLASS: str = ... +SCHEME_NAME_TYPE: str = ... +SCHEME_NAME_TYPE_OR_LEXICAL_CLASS: str = ... +SCHEME_LEMMA: str = ... +SCHEME_LANGUAGE: str = ... +SCHEME_SCRIPT: str = ... + +# ----------------------------------------------------------------------------- +# Functions +# ----------------------------------------------------------------------------- +_Scheme = Literal[ + "Token Type", + "Lexical Class", + "Name Type", + "Name Type or Lexical Class", + "Lemma", + "Language", + "Script", +] + +def tag_string( + string: str, + scheme: _Scheme, +) -> List[Tuple[str, str, Tuple[int, int]]]: + """Tag a given string according to the scheme. + Args: + string (str): The text to be tagged. + scheme (str): The tagging scheme to use. + Returns: + List[Tuple[str, str, Tuple[int, int]]]: A list of (tag, substring, range) + tuples. + """ + ... diff --git a/stubs/pythonista_stubs/location.pyi b/stubs/pythonista_stubs/location.pyi new file mode 100644 index 0000000..50594b5 --- /dev/null +++ b/stubs/pythonista_stubs/location.pyi @@ -0,0 +1,82 @@ +""" +This is a stub file for the `location` module, providing type hints for its +functions and their parameters, to be used for static analysis and autocompletion. +""" + +from typing import Dict, List, Optional, Literal + +# These are imported from the `ui` module, which is part of Pythonista. +class Image: ... + +# ----------------------------------------------------------------------------- +# Functions +# ----------------------------------------------------------------------------- +_MapType = Literal["standard", "satellite", "hybrid"] + +def get_location() -> Optional[Dict[str, float]]: + """Return the most recently obtained location data. + Returns: + Optional[Dict[str, float]]: A dictionary with 'longitude', 'latitude', + and 'timestamp' keys, or None. + """ + ... + +def start_updates() -> None: + """Start updating location data.""" + ... + +def stop_updates() -> None: + """Stop updating location data.""" + ... + +def geocode(address: Dict[str, str]) -> List[Dict[str, float]]: + """Convert an address dictionary to geo-coordinates. + Args: + address (Dict[str, str]): A dictionary with address components (e.g., + 'Street', 'City', 'Country'). + Returns: + List[Dict[str, float]]: A list of dictionaries with 'longitude' and + 'latitude' keys. + """ + ... + +def render_map_snapshot( + lat: float, + lng: float, + width: float = 1000.0, + height: float = 1000.0, + map_type: _MapType = "standard", + show_poi: bool = True, + img_width: int = 240, + img_height: int = 240, + img_scale: int = 0, +) -> Image: + """Render a snapshot image of the given map region. + Args: + lat (float): Latitude of the map's center. + lng (float): Longitude of the map's center. + width (float, optional): Width of the map region in meters. + height (float, optional): Height of the map region in meters. + map_type (str, optional): Map type ('standard', 'satellite', or 'hybrid'). + show_poi (bool, optional): Whether to show points of interest. + img_width (int, optional): Width of the returned image in points. + img_height (int, optional): Height of the returned image in points. + img_scale (int, optional): Scale factor of the image (0 for device scale). + Returns: + ui.Image: The rendered map snapshot. + """ + ... + +def reverse_geocode(location: Dict[str, float]) -> List[Dict[str, str]]: + """Convert geo-coordinates to a human-readable address. + Args: + location (Dict[str, float]): A dictionary with 'longitude' and + 'latitude' keys. + Returns: + List[Dict[str, str]]: A list of possible address dictionaries. + """ + ... + +def is_authorized() -> bool: + """Returns True if access to location data is currently allowed.""" + ... diff --git a/stubs/pythonista_stubs/motion.pyi b/stubs/pythonista_stubs/motion.pyi new file mode 100644 index 0000000..883b058 --- /dev/null +++ b/stubs/pythonista_stubs/motion.pyi @@ -0,0 +1,33 @@ +""" +This is a stub file for the `motion` module, providing type hints for its +functions and their parameters, to be used for static analysis and autocompletion. +""" + +from typing import Tuple + +# ----------------------------------------------------------------------------- +# Functions +# ----------------------------------------------------------------------------- +def start_updates() -> None: + """Start monitoring the device's motion sensors.""" + ... + +def stop_updates() -> None: + """Stop monitoring the device's motion sensors.""" + ... + +def get_gravity() -> Tuple[float, float, float]: + """Return the gravity vector (x, y, z).""" + ... + +def get_user_acceleration() -> Tuple[float, float, float]: + """Return the acceleration the user is giving to the device.""" + ... + +def get_attitude() -> Tuple[float, float, float]: + """Return the attitude of the device (roll, pitch, yaw).""" + ... + +def get_magnetic_field() -> Tuple[float, float, float, float]: + """Return the magnetic field vector with respect to the device (x, y, z, accuracy).""" + ... diff --git a/stubs/pythonista_stubs/notification.pyi b/stubs/pythonista_stubs/notification.pyi new file mode 100644 index 0000000..07a6a55 --- /dev/null +++ b/stubs/pythonista_stubs/notification.pyi @@ -0,0 +1,68 @@ +""" +This is a stub file for the `notification` module, providing type hints for its +functions and their parameters, to be used for static analysis and autocompletion. +""" + +from typing import Dict, List, Optional, Union + +# ----------------------------------------------------------------------------- +# Functions +# ----------------------------------------------------------------------------- +_Action = Dict[str, Union[str, bool]] +_Trigger = Dict[str, Union[int, float, bool]] + +def schedule( + message: Optional[str] = None, + delay: float = 0, + sound_name: Optional[str] = None, + action_url: Optional[str] = None, + title: Optional[str] = None, + subtitle: Optional[str] = None, + attachments: Optional[List[str]] = None, + trigger: Optional[_Trigger] = None, + actions: Optional[List[_Action]] = None, + identifier: Optional[str] = None, +) -> str: + """Schedule a notification. + Args: + message (str, optional): The main text of the notification. + delay (float, optional): The time in seconds until delivery. Defaults to 0. + sound_name (str, optional): The sound to play. Use 'default' for the + default sound or None for silent. + action_url (str, optional): The URL to launch when the notification is tapped. + title (str, optional): The title of the notification. + subtitle (str, optional): The subtitle of the notification. + attachments (List[str], optional): A list of file paths to attach. + trigger (dict, optional): A dictionary for more complex triggers. + actions (List[dict], optional): Definitions for custom action buttons. + identifier (str, optional): An optional identifier for the notification. + Returns: + str: The identifier of the scheduled notification. + """ + ... + +def cancel(identifier: str) -> None: + """Cancel a previously scheduled notification. + Args: + identifier (str): The identifier of the notification to cancel. + """ + ... + +def cancel_all() -> None: + """Cancel all previously scheduled notifications.""" + ... + +def get_scheduled() -> List[str]: + """Return a list of scheduled notification identifiers.""" + ... + +def remove_delivered(identifier: str) -> None: + """Remove a specific delivered notification from Notification Center. + Args: + identifier (str): The identifier of the notification to remove. + """ + ... + +def remove_all_delivered() -> None: + """Remove all delivered notifications from Notification Center.""" + ... diff --git a/stubs/pythonista_stubs/objc_util.pyi b/stubs/pythonista_stubs/objc_util.pyi new file mode 100644 index 0000000..c8daa00 --- /dev/null +++ b/stubs/pythonista_stubs/objc_util.pyi @@ -0,0 +1,220 @@ +"""Utilities for bridging Objective-C APIs. + +This module provides a "bridge" for using Objective-C APIs from Python. +Based on ctypes and the Objective-C runtime library, objc_util allows +you to "wrap" existing Objective-C classes in a way that automatically +converts Python method calls to corresponding Objective-C messages. +""" + +from typing import ( + Any, + Callable, + List, + Optional, + TypeVar, +) + +# A type variable for the decorator to preserve function signatures. +F = TypeVar("F", bound=Callable) + +class ObjCClass: + """Wrapper for an Objective-C class. + + Acts as a proxy for calling Objective-C class methods. Method calls are + converted to Objective-C messages on-the-fly. This is done by replacing + underscores in the method name with colons in the selector name, and + using the selector and arguments for a call to the low-level objc_msgSend() + function. + + Example: + Calling `NSDictionary.dictionaryWithObject_forKey_(obj, key)` in Python is + translated to `[NSDictionary dictionaryWithObject:obj forKey:key]` + in Objective-C. + + Args: + name: The name of the Objective-C class as a string. + """ + + def __init__(self, name: str) -> None: + pass + +class ObjCInstance: + """Wrapper for a pointer to an Objective-C object. + + Acts as a proxy for sending messages to the object. Method calls are converted + to Objective-C messages on-the-fly. + + Example: + Calling `obj.setFoo_withBar_(foo, bar)` in Python is translated to + `[obj setFoo:foo withBar:bar]` in Objective-C. + + Args: + ptr: A pointer to the Objective-C object. + """ + + def __init__(self, ptr: Any) -> None: + pass + +class ObjCBlock: + """Wrapper for Objective-C blocks (closures). + + Note: + Block support is experimental. + + Args: + func: The Python function to wrap as a block. + restype: The return type of the block (e.g., `NSInteger`). + argtypes: A list of argument types for the block. + """ + + def __init__( + self, func: Callable, restype: Any = None, argtypes: Optional[List[Any]] = None + ) -> None: + pass + +def autoreleasepool() -> Any: + """A context manager for NSAutoreleasePool. + + This acts as a wrapper for `NSAutoreleasePool` (similar to + `@autoreleasepool {...}` in Objective-C). + + Usage: + with objc_util.autoreleasepool(): + # do stuff... + + Returns: + A context manager for an autorelease pool. + """ + ... + +def create_objc_class( + name: str, + superclass: ObjCClass = ..., + methods: Optional[List[Callable]] = None, + classmethods: Optional[List[Callable]] = None, + protocols: Optional[List[str]] = None, + debug: bool = True, +) -> ObjCClass: + """Create and return a new ObjCClass. + + The selector name is derived from the name of the function. The return and + argument types are inferred automatically from the superclass or protocols + if possible. + + Args: + name: The name of the class to create. + superclass: The ObjCClass object from which the new class inherits. + methods: A list of functions for instance methods. + classmethods: A list of functions for class methods. + protocols: A list of protocol names (strings) for type hinting. + debug: If `True`, a new name will be chosen automatically if a class + with `name` already exists. + + Returns: + A new ObjCClass object. + """ + ... + +def load_framework(name: str) -> None: + """Load the system framework with the given name. + + Args: + name: The name of the framework (e.g., 'SceneKit'). + """ + ... + +def ns(obj: Any) -> Any: + """Convert a Python object to its Objective-C equivalent. + + Converts `str` to `NSString`, `list` to `NSMutableArray`, `dict` to + `NSMutableDictionary`, etc. Nested structures are supported. + + Args: + obj: The Python object to convert. + + Returns: + The Objective-C equivalent of the input object, wrapped in an + ObjCInstance if applicable. + """ + ... + +def nsurl(url_or_path: str) -> ObjCInstance: + """Convert a Python string to an NSURL object. + + Args: + url_or_path: A string representing a URL or a file path. + + Returns: + An `NSURL` object wrapped in an `ObjCInstance`. + """ + ... + +def nsdata_to_bytes(data: ObjCInstance) -> bytes: + """Convert an NSData object to a Python byte string. + + Args: + data: An `NSData` object wrapped in an `ObjCInstance`. + + Returns: + A Python byte string. + """ + ... + +def uiimage_to_png(img: ObjCInstance) -> bytes: + """Convert a UIImage object to a Python byte string with PNG data. + + Args: + img: A `UIImage` object wrapped in an `ObjCInstance`. + + Returns: + A Python byte string containing PNG data. + """ + ... + +def on_main_thread(func: F) -> F: + """Decorator to call a function on the UIKit main thread. + + This is typically used to decorate another function, but can also be used + ad-hoc for dispatching a function call to the main thread. + + Args: + func: The function to be executed on the main thread. + + Returns: + The decorated function. + """ + ... + +def sel(name: str) -> Any: + """Convert a Python string to an Objective-C selector. + + Args: + name: The name of the selector as a string. + + Returns: + An Objective-C selector object. + """ + ... + +# Convenience class wrappers for common Objective-C types +# These are included as module-level objects for convenience. +class CGPoint: ... +class CGSize: ... +class CGVector: ... +class CGRect: ... +class CGAffineTransform: ... +class UIEdgeInsets: ... +class NSRange: ... +class NSDictionary(ObjCClass): ... +class NSMutableDictionary(ObjCClass): ... +class NSArray(ObjCClass): ... +class NSMutableArray(ObjCClass): ... +class NSSet(ObjCClass): ... +class NSMutableSet(ObjCClass): ... +class NSString(ObjCClass): ... +class NSMutableString(ObjCClass): ... +class NSData(ObjCClass): ... +class NSMutableData(ObjCClass): ... +class NSNumber(ObjCClass): ... +class NSURL(ObjCClass): ... +class NSEnumerator(ObjCClass): ... diff --git a/stubs/pythonista_stubs/photos.pyi b/stubs/pythonista_stubs/photos.pyi new file mode 100644 index 0000000..0974df5 --- /dev/null +++ b/stubs/pythonista_stubs/photos.pyi @@ -0,0 +1,187 @@ +""" +This is a stub file for the `photos` module, providing type hints for its +functions and their parameters, to be used for static analysis and autocompletion. +""" + +import datetime +import io +from typing import List, Optional, Tuple, Literal, Union + +# These are imported from the `PIL` and `ui` modules. +class Image: ... +class ui_Image: ... + +# ----------------------------------------------------------------------------- +# Asset Class +# ----------------------------------------------------------------------------- +class Asset: + """Represents a single media item in the photo library.""" + + def get_image(self, original: bool = False) -> Image: + """Fetch the asset's image data as a PIL.Image object.""" + ... + + def get_image_data(self, original: bool = False) -> io.BytesIO: + """Fetch the asset's image data as an io.BytesIO object.""" + ... + + def get_ui_image( + self, size: Optional[Tuple[int, int]] = None, crop: bool = False + ) -> ui_Image: + """Fetch the asset's image data as a ui.Image object.""" + ... + + def edit_content(self, jpeg_path: str) -> None: + """Replace the asset's image content with the given JPEG file.""" + ... + + def delete(self) -> None: + """Delete the asset from the photo library.""" + ... + + def revert(self) -> None: + """Revert the asset to its original state.""" + ... + + local_id: str + """A unique identifier of this asset (read-only).""" + pixel_width: int + """The width of the asset in pixels (read-only).""" + pixel_height: int + """The height of the asset in pixels (read-only).""" + media_type: Literal["image", "video"] + """The asset's media type (read-only).""" + media_subtypes: List[str] + """The asset's media subtypes (read-only).""" + creation_date: datetime.datetime + """The asset's creation date (read-write).""" + modification_date: datetime.datetime + """The asset's modification date (read-write).""" + hidden: bool + """Whether the asset is hidden (read-write).""" + favorite: bool + """Whether the asset is a favorite (read-write).""" + duration: float + """The duration of a video asset in seconds (read-only).""" + location: Optional[dict] + """The geo-location where the media was taken (read-write).""" + can_edit_content: bool + """Whether the asset's content can be modified (read-only).""" + can_edit_properties: bool + """Whether the asset's metadata can be modified (read-only).""" + can_delete: bool + """Whether the asset can be deleted (read-only).""" + +# ----------------------------------------------------------------------------- +# AssetCollection Class +# ----------------------------------------------------------------------------- +class AssetCollection: + """Represents a collection in the photo library (album or smart album).""" + + def delete(self) -> None: + """Delete the asset collection from the photo library.""" + ... + + def add_assets(self, assets: List[Asset]) -> None: + """Add a list of Asset objects to the album.""" + ... + + def remove_assets(self, assets: List[Asset]) -> None: + """Remove a list of Asset objects from the album.""" + ... + + assets: List[Asset] + """The assets that the collection contains (read-only).""" + local_id: str + """A unique identifier of this asset collection (read-only).""" + title: str + """The title of the asset collection (read-write).""" + type: Literal["album", "smart_album", "moment"] + """The type of the asset collection (read-only).""" + subtype: str + """The subtype of the asset collection (read-only).""" + start_date: datetime.datetime + """The earliest creation date of an asset in the collection (read-only).""" + end_date: datetime.datetime + """The latest creation date of an asset in the collection (read-only).""" + can_delete: bool + """Whether the collection can be deleted (read-only).""" + can_add_assets: bool + """Whether the collection allows adding assets (read-only).""" + can_remove_assets: bool + """Whether the collection allows removing assets (read-only).""" + can_rename: bool + """Whether the collection's title can be changed (read-only).""" + +# ----------------------------------------------------------------------------- +# Functions +# ----------------------------------------------------------------------------- +_MediaType = Literal["image", "video"] +_CameraType = Literal["rear", "front"] +_MapType = Literal["standard", "satellite", "hybrid"] + +def capture_image(camera: _CameraType = "rear") -> Optional[Image]: + """Show a standard camera interface and return the captured image.""" + ... + +def get_assets( + media_type: _MediaType = "image", include_hidden: bool = False +) -> List[Asset]: + """Fetch and return a list of all assets in the library.""" + ... + +def get_asset_with_local_id(local_id: str) -> Asset: + """Fetch and return the asset with the given local identifier.""" + ... + +def get_albums() -> List[AssetCollection]: + """Return a list of all regular albums in the photo library.""" + ... + +def get_smart_albums() -> List[AssetCollection]: + """Return a list of all smart albums in the photo library.""" + ... + +def get_moments() -> List[AssetCollection]: + """Return a list of all 'moments' in the photo library.""" + ... + +def get_favorites_album() -> AssetCollection: + """Return the smart album containing all favorite assets.""" + ... + +def get_recently_added_album() -> AssetCollection: + """Return the smart album containing recently added assets.""" + ... + +def get_selfies_album() -> AssetCollection: + """Return the smart album containing all assets taken with the front camera.""" + ... + +def get_screenshots_album() -> AssetCollection: + """Return the smart album containing all screenshots.""" + ... + +def batch_delete(assets: List[Asset]) -> None: + """Delete multiple assets from the photo library.""" + ... + +def batch_revert(assets: List[Asset]) -> None: + """Revert multiple assets to their original state.""" + ... + +def create_album(title: str) -> AssetCollection: + """Create and return a new album in the photo library.""" + ... + +def create_image_asset(image_path: str) -> Asset: + """Create and return a new image asset from a file.""" + ... + +def pick_asset( + assets: Optional[Union[List[Asset], AssetCollection]] = None, + title: str = "", + multi: bool = False, +) -> Union[Optional[Asset], Optional[List[Asset]]]: + """Show a dialog with a grid of thumbnails for the given assets.""" + ... diff --git a/stubs/pythonista_stubs/py.typed b/stubs/pythonista_stubs/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/stubs/pythonista_stubs/reminders.pyi b/stubs/pythonista_stubs/reminders.pyi new file mode 100644 index 0000000..db9a0cd --- /dev/null +++ b/stubs/pythonista_stubs/reminders.pyi @@ -0,0 +1,121 @@ +""" +This is a stub file for the `reminders` module, providing type hints for its +functions and their parameters, to be used for static analysis and autocompletion. +""" + +from typing import List, Optional, Tuple, Literal, Union +import datetime + +# ----------------------------------------------------------------------------- +# Alarm Objects +# ----------------------------------------------------------------------------- +class Alarm: + """Alarm objects represent an alarm associated with a reminder.""" + + date: Optional[datetime.datetime] + """The absolute date when the alarm is triggered.""" + location: Optional[Union[Tuple[str, float, float], Tuple[str, float, float, float]]] + """The title, coordinates, and radius for a geo-location-based alarm. + Represented as a 3- or 4-tuple: (title, latitude, longitude[, radius]). + """ + proximity: Literal["enter", "leave", "none"] + """Determines if a location-based alarm is triggered when entering or + leaving the specified area. + """ + +# ----------------------------------------------------------------------------- +# Reminder Objects +# ----------------------------------------------------------------------------- +class Reminder: + """Reminder objects represent a single reminder in a list.""" + + def __init__(self, calendar: Optional["Calendar"] = None): ... + + alarms: List[Alarm] + """A list of Alarm objects associated with this reminder.""" + completed: bool + """Whether the reminder has been completed (checked off) yet.""" + completion_date: Optional[datetime.datetime] + """The date when the reminder was completed, or None if not completed.""" + due_date: Optional[datetime.datetime] + """The due date of the reminder.""" + notes: str + """Additional notes for the reminder.""" + priority: int + """Priority of the reminder (0 = no priority, 1 = highest, 9 = lowest).""" + title: str + """The title of the reminder.""" + url: str + """A URL associated with the reminder.""" + + def save(self) -> None: + """Save changes to the database.""" + ... + +# ----------------------------------------------------------------------------- +# Calendar Objects +# ----------------------------------------------------------------------------- +class Calendar: + """Calendar objects represent lists of reminders.""" + + title: str + """The title of the list of reminders.""" + identifier: str + """The unique identifier of the calendar (readonly).""" + + def save(self) -> None: + """Save changes to the database.""" + ... + +# ----------------------------------------------------------------------------- +# Functions +# ----------------------------------------------------------------------------- +def get_reminders( + calendar: Optional[Calendar] = None, + completed: Optional[bool] = None, +) -> List[Reminder]: + """Return all reminders in the given Calendar (or all calendars). + Args: + calendar (Calendar, optional): The calendar to get reminders from. + Defaults to None. + completed (bool, optional): Filters reminders by completion status. + Defaults to None (all reminders). + Returns: + List[Reminder]: A list of Reminder objects. + """ + ... + +def get_all_calendars() -> List[Calendar]: + """Return a list of all available Calendar objects.""" + ... + +def get_default_calendar() -> Calendar: + """Return the Calendar that is used for new reminders by default.""" + ... + +def get_calendar(calendar_id: str) -> Optional[Calendar]: + """Return a specific Calendar by its unique identifier. + Args: + calendar_id (str): The unique identifier of the calendar. + Returns: + Optional[Calendar]: The Calendar object, or None if not found. + """ + ... + +def delete_reminder(reminder: Reminder) -> bool: + """Remove a Reminder from the database. + Args: + reminder (Reminder): The Reminder object to remove. + Returns: + bool: True if the removal was successful, False otherwise. + """ + ... + +def delete_calendar(calendar: Calendar) -> bool: + """Remove a Calendar from the database. + Args: + calendar (Calendar): The Calendar object to remove. + Returns: + bool: True if the removal was successful, False otherwise. + """ + ... diff --git a/stubs/pythonista_stubs/shortcuts.pyi b/stubs/pythonista_stubs/shortcuts.pyi new file mode 100644 index 0000000..e939662 --- /dev/null +++ b/stubs/pythonista_stubs/shortcuts.pyi @@ -0,0 +1,44 @@ +""" +This is a stub file for the `shortcuts` module, providing type hints for its +functions and their parameters, to be used for static analysis and autocompletion. +""" + +from typing import List, Literal, Optional + +# ----------------------------------------------------------------------------- +# Functions +# ----------------------------------------------------------------------------- +_Action = Literal["run", "open", "exec"] + +def open_url(url: str) -> None: + """Open a given URL using the system's default app. + Args: + url (str): The URL to open. + """ + ... + +def pythonista_url( + path: str = "", + action: _Action = "run", + args: Optional[str] = None, + argv: Optional[List[str]] = None, +) -> str: + """Generates a pythonista3://... URL from a file name/path. + Args: + path (str, optional): Path to the script. Defaults to ''. + action (_Action, optional): The action to perform ('run', 'open', 'exec'). + Defaults to 'run'. + args (str, optional): A string of arguments to pass to the script. + argv (List[str], optional): A list of arguments to pass to the script. + Returns: + str: The generated Pythonista URL. + """ + ... + +def open_shortcuts_app(name: Optional[str] = None, shortcut_input: str = "") -> None: + """Open the Apple Shortcuts app and optionally run a named shortcut. + Args: + name (str, optional): The name of the shortcut to run. + shortcut_input (str, optional): Text input to pass to the shortcut. + """ + ... diff --git a/stubs/pythonista_stubs/sound.pyi b/stubs/pythonista_stubs/sound.pyi new file mode 100644 index 0000000..a20743a --- /dev/null +++ b/stubs/pythonista_stubs/sound.pyi @@ -0,0 +1,158 @@ +""" +This is a stub file for the `sound` module, providing type hints for its +functions and their parameters, to be used for static analysis and autocompletion. +""" + +from typing import Callable, Optional, Tuple + +# ----------------------------------------------------------------------------- +# Functions +# ----------------------------------------------------------------------------- +def play_effect( + name: str, + volume: float = 1.0, + pitch: float = 1.0, + pan: float = 0.0, + looping: bool = False, +) -> Optional["Effect"]: + """Play the sound effect with the given name. + Args: + name (str): The name of the sound effect or a file path. + volume (float, optional): The volume of the effect (0.0-1.0). + pitch (float, optional): The pitch of the effect. Defaults to 1.0. + pan (float, optional): The stereo position (-1.0 to 1.0). Defaults to 0.0. + looping (bool, optional): Whether the effect should loop. Defaults to False. + Returns: + Optional[Effect]: An Effect object, or None if too many effects are playing. + """ + ... + +def stop_all_effects() -> None: + """Stop all sound effects that are currently playing.""" + ... + +def stop_effect(effect: "Effect") -> None: + """Stop playback of the given sound effect.""" + ... + +def set_volume(vol: float) -> None: + """Sets the default volume for all sound effects (0.0 to 1.0).""" + ... + +def set_honors_silent_switch(flag: bool) -> None: + """Determines whether the silent switch is honored when playing sounds.""" + ... + +# ----------------------------------------------------------------------------- +# Effect Class +# ----------------------------------------------------------------------------- +class Effect: + """Represents a sound effect that is currently playing. + Effect objects are returned from `play_effect()`. + """ + def stop(self) -> None: + """Stop playback of the sound effect.""" + ... + + @property + def looping(self) -> bool: ... + @looping.setter + def looping(self, value: bool) -> None: ... + @property + def pan(self) -> float: ... + @pan.setter + def pan(self, value: float) -> None: ... + @property + def pitch(self) -> float: ... + @pitch.setter + def pitch(self, value: float) -> None: ... + @property + def position(self) -> Tuple[float, float, float]: ... + @position.setter + def position(self, value: Tuple[float, float, float]) -> None: ... + @property + def volume(self) -> float: ... + @volume.setter + def volume(self, value: float) -> None: ... + +# ----------------------------------------------------------------------------- +# Player Class +# ----------------------------------------------------------------------------- +class Player: + """Provides an interface for playing audio files from disk.""" + def __init__(self, file_path: str): ... + def play(self) -> None: + """Start playing audio.""" + ... + + def stop(self) -> None: + """Stop playing audio and reset the playback position.""" + ... + + def pause(self) -> None: + """Stop playing audio, but keep the current playback position.""" + ... + + current_time: float + """The current playback position in seconds.""" + duration: float + """The duration of the audio track (read-only).""" + finished_handler: Optional[Callable[[], None]] + """A function that is called when the player finishes playing.""" + number_of_loops: int + """The number of times the audio track should be repeated.""" + playing: bool + """A boolean indicating whether the audio player is playing.""" + pan: float + """The stereo positioning of the played sound (-1.0 to 1.0).""" + +# ----------------------------------------------------------------------------- +# Recorder Class +# ----------------------------------------------------------------------------- +class Recorder: + """High-level methods for recording audio files from the microphone.""" + def __init__(self, file_path: str): ... + def record(self, duration: Optional[float] = None) -> None: + """Start recording audio from the microphone. + Args: + duration (float, optional): The number of seconds to record. + """ + ... + + def stop(self) -> None: + """Stop recording audio.""" + ... + + def pause(self) -> None: + """Pause recording audio.""" + ... + + current_time: float + """The current duration of the active recording.""" + recording: bool + """Whether the recorder is currently recording.""" + meters: dict + """The current average and peak power (read-only). + Example: {'average': (-35.3, -30.1), 'peak': (-5.2, -8.2)} + """ + +# ----------------------------------------------------------------------------- +# MIDIPlayer Class +# ----------------------------------------------------------------------------- +class MIDIPlayer: + """Simple playback functions for MIDI (.mid) files.""" + def __init__(self, file_path: str, sound_bank_path: Optional[str] = None): ... + def play(self) -> None: + """Start playback.""" + ... + + def stop(self) -> None: + """Stop playback.""" + ... + + current_time: float + """The current playback position.""" + duration: float + """The duration of the loaded MIDI file.""" + rate: float + """The playback rate.""" diff --git a/stubs/pythonista_stubs/speech.pyi b/stubs/pythonista_stubs/speech.pyi new file mode 100644 index 0000000..9721d4f --- /dev/null +++ b/stubs/pythonista_stubs/speech.pyi @@ -0,0 +1,54 @@ +""" +This is a stub file for the `speech` module, providing type hints for its +functions and their parameters, to be used for static analysis and autocompletion. +""" + +from typing import Dict, List, Optional, Tuple + +# ----------------------------------------------------------------------------- +# Functions +# ----------------------------------------------------------------------------- +def get_synthesis_languages() -> List[str]: + """Return a list of all language/locale identifiers available for + speech synthesis. + """ + ... + +def get_recognition_languages() -> List[str]: + """Return a list of all language/locale identifiers available for + speech recognition. + """ + ... + +def say(text: str, language: Optional[str] = None, rate: float = 0.5) -> None: + """Speak the given text. + Args: + text (str): The text to be spoken. + language (str, optional): The language as a BCP-47 code (e.g. 'en-US'). + rate (float, optional): The speech rate (0.0 slowest, 1.0 fastest). + """ + ... + +def stop() -> None: + """Stop any speech synthesis currently in progress.""" + ... + +def is_speaking() -> bool: + """Return True if the synthesizer is currently speaking, False otherwise.""" + ... + +def recognize( + file_path: str, language: Optional[str] = None +) -> List[Tuple[str, List[Dict]]]: + """Transcribe spoken text in the given audio file. + Args: + file_path (str): The path to the audio file. + language (str, optional): The locale identifier (e.g. 'en-US'). + Returns: + List[Tuple[str, List[Dict]]]: A list of possible transcriptions. + Raises: + RuntimeError: If speech recognition fails. + ValueError: If the language parameter is invalid. + IOError: If the audio file cannot be read. + """ + ... diff --git a/stubs/ui/__init__.py b/stubs/pythonista_stubs/ui.py similarity index 92% rename from stubs/ui/__init__.py rename to stubs/pythonista_stubs/ui.py index 3e43aa8..6ea6658 100644 --- a/stubs/ui/__init__.py +++ b/stubs/pythonista_stubs/ui.py @@ -10,5 +10,4 @@ def __init__( Union[str, Tuple[int, int, int], Tuple[int, int, int, int], float] ] = None, name: Optional[str] = None, - ) -> None: - ... + ) -> None: ... diff --git a/stubs/reminders/__init__.pyi b/stubs/reminders/__init__.pyi deleted file mode 100644 index 47ac951..0000000 --- a/stubs/reminders/__init__.pyi +++ /dev/null @@ -1,31 +0,0 @@ -from typing import Optional, List, Tuple -from datetime import datetime - -def get_reminders( - calendar: Optional[Calendar], completed=Optional[bool] -) -> List[Reminder]: ... -def get_all_calendars() -> List[Calendar]: ... -def get_default_calendar() -> Calendar: ... -def get_calendar(calendar_id: str) -> Optional[Calendar]: ... -def delete_reminder(reminder: Reminder) -> bool: ... -def delete_calendar(calendar: Calendar) -> bool: ... - -class Alarm: - date: datetime - location: Tuple[str, float, float, Optional[float]] - proximity: str - -class Calendar: - title: str - identifier: str - def save(self) -> None: ... - -class Reminder: - title: str - notes: str - completed: bool - completion_date: Optional[datetime] - due_date: Optional[datetime] - alarms: List[Alarm] - def __init__(self, calendar: Optional[Calendar]) -> None: ... - def save(self) -> None: ... diff --git a/stubs/sound/__init__.pyi b/stubs/sound/__init__.pyi deleted file mode 100644 index e70126f..0000000 --- a/stubs/sound/__init__.pyi +++ /dev/null @@ -1,50 +0,0 @@ -from typing import Dict, Optional, Tuple, Callable - -def play_effect( - name: str, - volume: Optional[float] = None, - pitch: Optional[float] = 1.0, - pan: Optional[float] = 0.0, - looping: Optional[bool] = False, -) -> Optional[Effect]: ... -def stop_all_effects() -> None: ... -def stop_effect(effect: Effect) -> None: ... -def set_volume(vol: float) -> None: ... -def set_honors_silent_switch(flag: bool) -> None: ... - -class Effect: - looping: bool - pan: float - pitch: float = 1.0 - position: Tuple[float, float, float] - volume: float - def stop(self) -> None: ... - -class Player: - current_time: float - duration: float - finished_handler: Callable - number_of_loops: int - playing: bool - pan: float - def __init__(self, file_path: str) -> None: ... - def play(self): ... - def stop(self): ... - def pause(self): ... - -class Recorder: - current_time: float - recording: bool - meters: Dict[str, Tuple[float, float]] - def __init__(self, file_path: str) -> None: ... - def record(self, duration: Optional[int] = None) -> None: ... - def stop(self) -> None: ... - def pause(self) -> None: ... - -class MIDIPlayer: - current_time: float - duration: float - rate: float - def __init__(self, file_path: str, sound_bank_path: Optional[str]) -> None: ... - def play(self) -> None: ... - def stop(self) -> None: ... diff --git a/stubs/speech/__init__.pyi b/stubs/speech/__init__.pyi deleted file mode 100644 index 641ee13..0000000 --- a/stubs/speech/__init__.pyi +++ /dev/null @@ -1,13 +0,0 @@ -from typing import Optional, List, Tuple, Dict - -def get_languages() -> List[str]: ... -def get_synthesis_languages() -> List[str]: ... -def get_recognition_languages() -> List[str]: ... -def say( - text: str, language: Optional[str] = None, rate: Optional[float] = 0.5 -) -> None: ... -def stop() -> None: ... -def is_speaking() -> bool: ... -def recognize( - file_path: str, language: Optional[str] = None -) -> List[Tuple[str, List[Dict]]]: ... diff --git a/uv.lock b/uv.lock new file mode 100644 index 0000000..fc82db6 --- /dev/null +++ b/uv.lock @@ -0,0 +1,174 @@ +version = 1 +revision = 1 +requires-python = ">=3.10" + +[[package]] +name = "mypy" +version = "1.17.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mypy-extensions" }, + { name = "pathspec" }, + { name = "tomli", marker = "python_full_version < '3.11'" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/8e/22/ea637422dedf0bf36f3ef238eab4e455e2a0dcc3082b5cc067615347ab8e/mypy-1.17.1.tar.gz", hash = "sha256:25e01ec741ab5bb3eec8ba9cdb0f769230368a22c959c4937360efb89b7e9f01", size = 3352570 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/77/a9/3d7aa83955617cdf02f94e50aab5c830d205cfa4320cf124ff64acce3a8e/mypy-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3fbe6d5555bf608c47203baa3e72dbc6ec9965b3d7c318aa9a4ca76f465bd972", size = 11003299 }, + { url = "https://files.pythonhosted.org/packages/83/e8/72e62ff837dd5caaac2b4a5c07ce769c8e808a00a65e5d8f94ea9c6f20ab/mypy-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:80ef5c058b7bce08c83cac668158cb7edea692e458d21098c7d3bce35a5d43e7", size = 10125451 }, + { url = "https://files.pythonhosted.org/packages/7d/10/f3f3543f6448db11881776f26a0ed079865926b0c841818ee22de2c6bbab/mypy-1.17.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c4a580f8a70c69e4a75587bd925d298434057fe2a428faaf927ffe6e4b9a98df", size = 11916211 }, + { url = "https://files.pythonhosted.org/packages/06/bf/63e83ed551282d67bb3f7fea2cd5561b08d2bb6eb287c096539feb5ddbc5/mypy-1.17.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dd86bb649299f09d987a2eebb4d52d10603224500792e1bee18303bbcc1ce390", size = 12652687 }, + { url = "https://files.pythonhosted.org/packages/69/66/68f2eeef11facf597143e85b694a161868b3b006a5fbad50e09ea117ef24/mypy-1.17.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:a76906f26bd8d51ea9504966a9c25419f2e668f012e0bdf3da4ea1526c534d94", size = 12896322 }, + { url = "https://files.pythonhosted.org/packages/a3/87/8e3e9c2c8bd0d7e071a89c71be28ad088aaecbadf0454f46a540bda7bca6/mypy-1.17.1-cp310-cp310-win_amd64.whl", hash = "sha256:e79311f2d904ccb59787477b7bd5d26f3347789c06fcd7656fa500875290264b", size = 9507962 }, + { url = "https://files.pythonhosted.org/packages/46/cf/eadc80c4e0a70db1c08921dcc220357ba8ab2faecb4392e3cebeb10edbfa/mypy-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ad37544be07c5d7fba814eb370e006df58fed8ad1ef33ed1649cb1889ba6ff58", size = 10921009 }, + { url = "https://files.pythonhosted.org/packages/5d/c1/c869d8c067829ad30d9bdae051046561552516cfb3a14f7f0347b7d973ee/mypy-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:064e2ff508e5464b4bd807a7c1625bc5047c5022b85c70f030680e18f37273a5", size = 10047482 }, + { url = "https://files.pythonhosted.org/packages/98/b9/803672bab3fe03cee2e14786ca056efda4bb511ea02dadcedde6176d06d0/mypy-1.17.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:70401bbabd2fa1aa7c43bb358f54037baf0586f41e83b0ae67dd0534fc64edfd", size = 11832883 }, + { url = "https://files.pythonhosted.org/packages/88/fb/fcdac695beca66800918c18697b48833a9a6701de288452b6715a98cfee1/mypy-1.17.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e92bdc656b7757c438660f775f872a669b8ff374edc4d18277d86b63edba6b8b", size = 12566215 }, + { url = "https://files.pythonhosted.org/packages/7f/37/a932da3d3dace99ee8eb2043b6ab03b6768c36eb29a02f98f46c18c0da0e/mypy-1.17.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c1fdf4abb29ed1cb091cf432979e162c208a5ac676ce35010373ff29247bcad5", size = 12751956 }, + { url = "https://files.pythonhosted.org/packages/8c/cf/6438a429e0f2f5cab8bc83e53dbebfa666476f40ee322e13cac5e64b79e7/mypy-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:ff2933428516ab63f961644bc49bc4cbe42bbffb2cd3b71cc7277c07d16b1a8b", size = 9507307 }, + { url = "https://files.pythonhosted.org/packages/17/a2/7034d0d61af8098ec47902108553122baa0f438df8a713be860f7407c9e6/mypy-1.17.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:69e83ea6553a3ba79c08c6e15dbd9bfa912ec1e493bf75489ef93beb65209aeb", size = 11086295 }, + { url = "https://files.pythonhosted.org/packages/14/1f/19e7e44b594d4b12f6ba8064dbe136505cec813549ca3e5191e40b1d3cc2/mypy-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1b16708a66d38abb1e6b5702f5c2c87e133289da36f6a1d15f6a5221085c6403", size = 10112355 }, + { url = "https://files.pythonhosted.org/packages/5b/69/baa33927e29e6b4c55d798a9d44db5d394072eef2bdc18c3e2048c9ed1e9/mypy-1.17.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:89e972c0035e9e05823907ad5398c5a73b9f47a002b22359b177d40bdaee7056", size = 11875285 }, + { url = "https://files.pythonhosted.org/packages/90/13/f3a89c76b0a41e19490b01e7069713a30949d9a6c147289ee1521bcea245/mypy-1.17.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:03b6d0ed2b188e35ee6d5c36b5580cffd6da23319991c49ab5556c023ccf1341", size = 12737895 }, + { url = "https://files.pythonhosted.org/packages/23/a1/c4ee79ac484241301564072e6476c5a5be2590bc2e7bfd28220033d2ef8f/mypy-1.17.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c837b896b37cd103570d776bda106eabb8737aa6dd4f248451aecf53030cdbeb", size = 12931025 }, + { url = "https://files.pythonhosted.org/packages/89/b8/7409477be7919a0608900e6320b155c72caab4fef46427c5cc75f85edadd/mypy-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:665afab0963a4b39dff7c1fa563cc8b11ecff7910206db4b2e64dd1ba25aed19", size = 9584664 }, + { url = "https://files.pythonhosted.org/packages/5b/82/aec2fc9b9b149f372850291827537a508d6c4d3664b1750a324b91f71355/mypy-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:93378d3203a5c0800c6b6d850ad2f19f7a3cdf1a3701d3416dbf128805c6a6a7", size = 11075338 }, + { url = "https://files.pythonhosted.org/packages/07/ac/ee93fbde9d2242657128af8c86f5d917cd2887584cf948a8e3663d0cd737/mypy-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:15d54056f7fe7a826d897789f53dd6377ec2ea8ba6f776dc83c2902b899fee81", size = 10113066 }, + { url = "https://files.pythonhosted.org/packages/5a/68/946a1e0be93f17f7caa56c45844ec691ca153ee8b62f21eddda336a2d203/mypy-1.17.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:209a58fed9987eccc20f2ca94afe7257a8f46eb5df1fb69958650973230f91e6", size = 11875473 }, + { url = "https://files.pythonhosted.org/packages/9f/0f/478b4dce1cb4f43cf0f0d00fba3030b21ca04a01b74d1cd272a528cf446f/mypy-1.17.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:099b9a5da47de9e2cb5165e581f158e854d9e19d2e96b6698c0d64de911dd849", size = 12744296 }, + { url = "https://files.pythonhosted.org/packages/ca/70/afa5850176379d1b303f992a828de95fc14487429a7139a4e0bdd17a8279/mypy-1.17.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fa6ffadfbe6994d724c5a1bb6123a7d27dd68fc9c059561cd33b664a79578e14", size = 12914657 }, + { url = "https://files.pythonhosted.org/packages/53/f9/4a83e1c856a3d9c8f6edaa4749a4864ee98486e9b9dbfbc93842891029c2/mypy-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:9a2b7d9180aed171f033c9f2fc6c204c1245cf60b0cb61cf2e7acc24eea78e0a", size = 9593320 }, + { url = "https://files.pythonhosted.org/packages/38/56/79c2fac86da57c7d8c48622a05873eaab40b905096c33597462713f5af90/mypy-1.17.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:15a83369400454c41ed3a118e0cc58bd8123921a602f385cb6d6ea5df050c733", size = 11040037 }, + { url = "https://files.pythonhosted.org/packages/4d/c3/adabe6ff53638e3cad19e3547268482408323b1e68bf082c9119000cd049/mypy-1.17.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:55b918670f692fc9fba55c3298d8a3beae295c5cded0a55dccdc5bbead814acd", size = 10131550 }, + { url = "https://files.pythonhosted.org/packages/b8/c5/2e234c22c3bdeb23a7817af57a58865a39753bde52c74e2c661ee0cfc640/mypy-1.17.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:62761474061feef6f720149d7ba876122007ddc64adff5ba6f374fda35a018a0", size = 11872963 }, + { url = "https://files.pythonhosted.org/packages/ab/26/c13c130f35ca8caa5f2ceab68a247775648fdcd6c9a18f158825f2bc2410/mypy-1.17.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c49562d3d908fd49ed0938e5423daed8d407774a479b595b143a3d7f87cdae6a", size = 12710189 }, + { url = "https://files.pythonhosted.org/packages/82/df/c7d79d09f6de8383fe800521d066d877e54d30b4fb94281c262be2df84ef/mypy-1.17.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:397fba5d7616a5bc60b45c7ed204717eaddc38f826e3645402c426057ead9a91", size = 12900322 }, + { url = "https://files.pythonhosted.org/packages/b8/98/3d5a48978b4f708c55ae832619addc66d677f6dc59f3ebad71bae8285ca6/mypy-1.17.1-cp314-cp314-win_amd64.whl", hash = "sha256:9d6b20b97d373f41617bd0708fd46aa656059af57f2ef72aa8c7d6a2b73b74ed", size = 9751879 }, + { url = "https://files.pythonhosted.org/packages/1d/f3/8fcd2af0f5b806f6cf463efaffd3c9548a28f84220493ecd38d127b6b66d/mypy-1.17.1-py3-none-any.whl", hash = "sha256:a9f52c0351c21fe24c21d8c0eb1f62967b262d6729393397b6f443c3b773c3b9", size = 2283411 }, +] + +[[package]] +name = "mypy-extensions" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/6e/371856a3fb9d31ca8dac321cda606860fa4548858c0cc45d9d1d4ca2628b/mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558", size = 6343 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", size = 4963 }, +] + +[[package]] +name = "pathspec" +version = "0.12.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ca/bc/f35b8446f4531a7cb215605d100cd88b7ac6f44ab3fc94870c120ab3adbf/pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712", size = 51043 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cc/20/ff623b09d963f88bfde16306a54e12ee5ea43e9b597108672ff3a408aad6/pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", size = 31191 }, +] + +[[package]] +name = "pythonista-stubs" +source = { editable = "." } +dependencies = [ + { name = "types-pillow" }, + { name = "typing-extensions" }, +] + +[package.dev-dependencies] +dev = [ + { name = "mypy" }, + { name = "ruff" }, +] + +[package.metadata] +requires-dist = [ + { name = "types-pillow", specifier = ">=10.2.0.20240822" }, + { name = "typing-extensions", specifier = ">=4.14.1" }, +] + +[package.metadata.requires-dev] +dev = [ + { name = "mypy", specifier = ">=1.17.1" }, + { name = "ruff", specifier = ">=0.12.8" }, +] + +[[package]] +name = "ruff" +version = "0.12.8" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4b/da/5bd7565be729e86e1442dad2c9a364ceeff82227c2dece7c29697a9795eb/ruff-0.12.8.tar.gz", hash = "sha256:4cb3a45525176e1009b2b64126acf5f9444ea59066262791febf55e40493a033", size = 5242373 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c9/1e/c843bfa8ad1114fab3eb2b78235dda76acd66384c663a4e0415ecc13aa1e/ruff-0.12.8-py3-none-linux_armv6l.whl", hash = "sha256:63cb5a5e933fc913e5823a0dfdc3c99add73f52d139d6cd5cc8639d0e0465513", size = 11675315 }, + { url = "https://files.pythonhosted.org/packages/24/ee/af6e5c2a8ca3a81676d5480a1025494fd104b8896266502bb4de2a0e8388/ruff-0.12.8-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:9a9bbe28f9f551accf84a24c366c1aa8774d6748438b47174f8e8565ab9dedbc", size = 12456653 }, + { url = "https://files.pythonhosted.org/packages/99/9d/e91f84dfe3866fa648c10512904991ecc326fd0b66578b324ee6ecb8f725/ruff-0.12.8-py3-none-macosx_11_0_arm64.whl", hash = "sha256:2fae54e752a3150f7ee0e09bce2e133caf10ce9d971510a9b925392dc98d2fec", size = 11659690 }, + { url = "https://files.pythonhosted.org/packages/fe/ac/a363d25ec53040408ebdd4efcee929d48547665858ede0505d1d8041b2e5/ruff-0.12.8-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c0acbcf01206df963d9331b5838fb31f3b44fa979ee7fa368b9b9057d89f4a53", size = 11896923 }, + { url = "https://files.pythonhosted.org/packages/58/9f/ea356cd87c395f6ade9bb81365bd909ff60860975ca1bc39f0e59de3da37/ruff-0.12.8-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ae3e7504666ad4c62f9ac8eedb52a93f9ebdeb34742b8b71cd3cccd24912719f", size = 11477612 }, + { url = "https://files.pythonhosted.org/packages/1a/46/92e8fa3c9dcfd49175225c09053916cb97bb7204f9f899c2f2baca69e450/ruff-0.12.8-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cb82efb5d35d07497813a1c5647867390a7d83304562607f3579602fa3d7d46f", size = 13182745 }, + { url = "https://files.pythonhosted.org/packages/5e/c4/f2176a310f26e6160deaf661ef60db6c3bb62b7a35e57ae28f27a09a7d63/ruff-0.12.8-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:dbea798fc0065ad0b84a2947b0aff4233f0cb30f226f00a2c5850ca4393de609", size = 14206885 }, + { url = "https://files.pythonhosted.org/packages/87/9d/98e162f3eeeb6689acbedbae5050b4b3220754554526c50c292b611d3a63/ruff-0.12.8-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:49ebcaccc2bdad86fd51b7864e3d808aad404aab8df33d469b6e65584656263a", size = 13639381 }, + { url = "https://files.pythonhosted.org/packages/81/4e/1b7478b072fcde5161b48f64774d6edd59d6d198e4ba8918d9f4702b8043/ruff-0.12.8-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ac9c570634b98c71c88cb17badd90f13fc076a472ba6ef1d113d8ed3df109fb", size = 12613271 }, + { url = "https://files.pythonhosted.org/packages/e8/67/0c3c9179a3ad19791ef1b8f7138aa27d4578c78700551c60d9260b2c660d/ruff-0.12.8-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:560e0cd641e45591a3e42cb50ef61ce07162b9c233786663fdce2d8557d99818", size = 12847783 }, + { url = "https://files.pythonhosted.org/packages/4e/2a/0b6ac3dd045acf8aa229b12c9c17bb35508191b71a14904baf99573a21bd/ruff-0.12.8-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:71c83121512e7743fba5a8848c261dcc454cafb3ef2934a43f1b7a4eb5a447ea", size = 11702672 }, + { url = "https://files.pythonhosted.org/packages/9d/ee/f9fdc9f341b0430110de8b39a6ee5fa68c5706dc7c0aa940817947d6937e/ruff-0.12.8-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:de4429ef2ba091ecddedd300f4c3f24bca875d3d8b23340728c3cb0da81072c3", size = 11440626 }, + { url = "https://files.pythonhosted.org/packages/89/fb/b3aa2d482d05f44e4d197d1de5e3863feb13067b22c571b9561085c999dc/ruff-0.12.8-py3-none-musllinux_1_2_i686.whl", hash = "sha256:a2cab5f60d5b65b50fba39a8950c8746df1627d54ba1197f970763917184b161", size = 12462162 }, + { url = "https://files.pythonhosted.org/packages/18/9f/5c5d93e1d00d854d5013c96e1a92c33b703a0332707a7cdbd0a4880a84fb/ruff-0.12.8-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:45c32487e14f60b88aad6be9fd5da5093dbefb0e3e1224131cb1d441d7cb7d46", size = 12913212 }, + { url = "https://files.pythonhosted.org/packages/71/13/ab9120add1c0e4604c71bfc2e4ef7d63bebece0cfe617013da289539cef8/ruff-0.12.8-py3-none-win32.whl", hash = "sha256:daf3475060a617fd5bc80638aeaf2f5937f10af3ec44464e280a9d2218e720d3", size = 11694382 }, + { url = "https://files.pythonhosted.org/packages/f6/dc/a2873b7c5001c62f46266685863bee2888caf469d1edac84bf3242074be2/ruff-0.12.8-py3-none-win_amd64.whl", hash = "sha256:7209531f1a1fcfbe8e46bcd7ab30e2f43604d8ba1c49029bb420b103d0b5f76e", size = 12740482 }, + { url = "https://files.pythonhosted.org/packages/cb/5c/799a1efb8b5abab56e8a9f2a0b72d12bd64bb55815e9476c7d0a2887d2f7/ruff-0.12.8-py3-none-win_arm64.whl", hash = "sha256:c90e1a334683ce41b0e7a04f41790c429bf5073b62c1ae701c9dc5b3d14f0749", size = 11884718 }, +] + +[[package]] +name = "tomli" +version = "2.2.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/18/87/302344fed471e44a87289cf4967697d07e532f2421fdaf868a303cbae4ff/tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff", size = 17175 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/43/ca/75707e6efa2b37c77dadb324ae7d9571cb424e61ea73fad7c56c2d14527f/tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249", size = 131077 }, + { url = "https://files.pythonhosted.org/packages/c7/16/51ae563a8615d472fdbffc43a3f3d46588c264ac4f024f63f01283becfbb/tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6", size = 123429 }, + { url = "https://files.pythonhosted.org/packages/f1/dd/4f6cd1e7b160041db83c694abc78e100473c15d54620083dbd5aae7b990e/tomli-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a", size = 226067 }, + { url = "https://files.pythonhosted.org/packages/a9/6b/c54ede5dc70d648cc6361eaf429304b02f2871a345bbdd51e993d6cdf550/tomli-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee", size = 236030 }, + { url = "https://files.pythonhosted.org/packages/1f/47/999514fa49cfaf7a92c805a86c3c43f4215621855d151b61c602abb38091/tomli-2.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e", size = 240898 }, + { url = "https://files.pythonhosted.org/packages/73/41/0a01279a7ae09ee1573b423318e7934674ce06eb33f50936655071d81a24/tomli-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4", size = 229894 }, + { url = "https://files.pythonhosted.org/packages/55/18/5d8bc5b0a0362311ce4d18830a5d28943667599a60d20118074ea1b01bb7/tomli-2.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106", size = 245319 }, + { url = "https://files.pythonhosted.org/packages/92/a3/7ade0576d17f3cdf5ff44d61390d4b3febb8a9fc2b480c75c47ea048c646/tomli-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8", size = 238273 }, + { url = "https://files.pythonhosted.org/packages/72/6f/fa64ef058ac1446a1e51110c375339b3ec6be245af9d14c87c4a6412dd32/tomli-2.2.1-cp311-cp311-win32.whl", hash = "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff", size = 98310 }, + { url = "https://files.pythonhosted.org/packages/6a/1c/4a2dcde4a51b81be3530565e92eda625d94dafb46dbeb15069df4caffc34/tomli-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b", size = 108309 }, + { url = "https://files.pythonhosted.org/packages/52/e1/f8af4c2fcde17500422858155aeb0d7e93477a0d59a98e56cbfe75070fd0/tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea", size = 132762 }, + { url = "https://files.pythonhosted.org/packages/03/b8/152c68bb84fc00396b83e7bbddd5ec0bd3dd409db4195e2a9b3e398ad2e3/tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8", size = 123453 }, + { url = "https://files.pythonhosted.org/packages/c8/d6/fc9267af9166f79ac528ff7e8c55c8181ded34eb4b0e93daa767b8841573/tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192", size = 233486 }, + { url = "https://files.pythonhosted.org/packages/5c/51/51c3f2884d7bab89af25f678447ea7d297b53b5a3b5730a7cb2ef6069f07/tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222", size = 242349 }, + { url = "https://files.pythonhosted.org/packages/ab/df/bfa89627d13a5cc22402e441e8a931ef2108403db390ff3345c05253935e/tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77", size = 252159 }, + { url = "https://files.pythonhosted.org/packages/9e/6e/fa2b916dced65763a5168c6ccb91066f7639bdc88b48adda990db10c8c0b/tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6", size = 237243 }, + { url = "https://files.pythonhosted.org/packages/b4/04/885d3b1f650e1153cbb93a6a9782c58a972b94ea4483ae4ac5cedd5e4a09/tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd", size = 259645 }, + { url = "https://files.pythonhosted.org/packages/9c/de/6b432d66e986e501586da298e28ebeefd3edc2c780f3ad73d22566034239/tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e", size = 244584 }, + { url = "https://files.pythonhosted.org/packages/1c/9a/47c0449b98e6e7d1be6cbac02f93dd79003234ddc4aaab6ba07a9a7482e2/tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98", size = 98875 }, + { url = "https://files.pythonhosted.org/packages/ef/60/9b9638f081c6f1261e2688bd487625cd1e660d0a85bd469e91d8db969734/tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4", size = 109418 }, + { url = "https://files.pythonhosted.org/packages/04/90/2ee5f2e0362cb8a0b6499dc44f4d7d48f8fff06d28ba46e6f1eaa61a1388/tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7", size = 132708 }, + { url = "https://files.pythonhosted.org/packages/c0/ec/46b4108816de6b385141f082ba99e315501ccd0a2ea23db4a100dd3990ea/tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c", size = 123582 }, + { url = "https://files.pythonhosted.org/packages/a0/bd/b470466d0137b37b68d24556c38a0cc819e8febe392d5b199dcd7f578365/tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13", size = 232543 }, + { url = "https://files.pythonhosted.org/packages/d9/e5/82e80ff3b751373f7cead2815bcbe2d51c895b3c990686741a8e56ec42ab/tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281", size = 241691 }, + { url = "https://files.pythonhosted.org/packages/05/7e/2a110bc2713557d6a1bfb06af23dd01e7dde52b6ee7dadc589868f9abfac/tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272", size = 251170 }, + { url = "https://files.pythonhosted.org/packages/64/7b/22d713946efe00e0adbcdfd6d1aa119ae03fd0b60ebed51ebb3fa9f5a2e5/tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140", size = 236530 }, + { url = "https://files.pythonhosted.org/packages/38/31/3a76f67da4b0cf37b742ca76beaf819dca0ebef26d78fc794a576e08accf/tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2", size = 258666 }, + { url = "https://files.pythonhosted.org/packages/07/10/5af1293da642aded87e8a988753945d0cf7e00a9452d3911dd3bb354c9e2/tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744", size = 243954 }, + { url = "https://files.pythonhosted.org/packages/5b/b9/1ed31d167be802da0fc95020d04cd27b7d7065cc6fbefdd2f9186f60d7bd/tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec", size = 98724 }, + { url = "https://files.pythonhosted.org/packages/c7/32/b0963458706accd9afcfeb867c0f9175a741bf7b19cd424230714d722198/tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69", size = 109383 }, + { url = "https://files.pythonhosted.org/packages/6e/c2/61d3e0f47e2b74ef40a68b9e6ad5984f6241a942f7cd3bbfbdbd03861ea9/tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc", size = 14257 }, +] + +[[package]] +name = "types-pillow" +version = "10.2.0.20240822" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/18/4a/4495264dddaa600d65d68bcedb64dcccf9d9da61adff51f7d2ffd8e4c9ce/types-Pillow-10.2.0.20240822.tar.gz", hash = "sha256:559fb52a2ef991c326e4a0d20accb3bb63a7ba8d40eb493e0ecb0310ba52f0d3", size = 35389 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/66/23/e81a5354859831fcf54d488d33b80ba6133ea84f874a9c0ec40a4881e133/types_Pillow-10.2.0.20240822-py3-none-any.whl", hash = "sha256:d9dab025aba07aeb12fd50a6799d4eac52a9603488eca09d7662543983f16c5d", size = 54354 }, +] + +[[package]] +name = "typing-extensions" +version = "4.14.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/98/5a/da40306b885cc8c09109dc2e1abd358d5684b1425678151cdaed4731c822/typing_extensions-4.14.1.tar.gz", hash = "sha256:38b39f4aeeab64884ce9f74c94263ef78f3c22467c8724005483154c26648d36", size = 107673 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b5/00/d631e67a838026495268c2f6884f3711a15a9a2a96cd244fdaea53b823fb/typing_extensions-4.14.1-py3-none-any.whl", hash = "sha256:d1e1e3b58374dc93031d6eda2420a48ea44a36c2b4766a4fdeb3710755731d76", size = 43906 }, +] From 52858ce67c2fab5dece9d03e4393e47c554c13e8 Mon Sep 17 00:00:00 2001 From: o-murphy Date: Mon, 11 Aug 2025 00:18:17 +0300 Subject: [PATCH 2/3] Resolved review problems --- .github/workflows/ci.yml | 28 ------------------ .github/workflows/publish.yml | 31 ++++++++++++++++++++ .idea/misc.xml | 3 ++ MANIFEST.in | 1 + pyproject.toml | 12 ++++++-- stubs/_cb.pyi | 8 ++--- stubs/pythonista_stubs/dialogs.pyi | 47 +++++++++++++++++++++++------- stubs/pythonista_stubs/photos.pyi | 15 +++++++++- stubs/pythonista_stubs/sound.pyi | 5 ++-- uv.lock | 9 ++++++ 10 files changed, 111 insertions(+), 48 deletions(-) create mode 100644 .github/workflows/publish.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 07b0853..3626196 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,15 +5,11 @@ on: branches: [ master ] pull_request: branches: [ master ] - release: - types: [ published ] workflow_dispatch: jobs: testing: runs-on: ubuntu-latest - permissions: - id-token: write steps: - uses: actions/checkout@v4 @@ -29,27 +25,3 @@ jobs: - name: Type check with mypy run: uv run mypy - - publish: - runs-on: ubuntu-latest - environment: - name: pypi - needs: [testing] - permissions: - id-token: write - - steps: - - uses: actions/checkout@v4 - - - name: Install uv - uses: astral-sh/setup-uv@v5 - - - name: Install the project - run: uv sync --locked --all-extras --dev - - - name: Build - run: uv build - - - name: Publish - if: github.event_name == 'release' - run: uv publish --trusted-publishing always diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..a145fb5 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,31 @@ +name: Publish + +on: + release: + types: [ published ] + workflow_dispatch: + +jobs: + + publish: + runs-on: ubuntu-latest + environment: + name: pypi + permissions: + id-token: write + + steps: + - uses: actions/checkout@v4 + + - name: Install uv + uses: astral-sh/setup-uv@v5 + + - name: Install the project + run: uv sync --locked --all-extras --dev + + - name: Build + run: uv build + + - name: Publish + if: github.event_name == 'release' + run: uv publish --trusted-publishing always diff --git a/.idea/misc.xml b/.idea/misc.xml index a2e120d..c54cb59 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,4 +1,7 @@ + + \ No newline at end of file diff --git a/MANIFEST.in b/MANIFEST.in index a4d5857..2c9a355 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1 +1,2 @@ include pythonista_stubs/*.pyi +include VERSION \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index 2bc2074..c5ac17a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -37,6 +37,14 @@ dynamic = ['version'] "Bug Reports" = "https://github.com/hbmartin/pythonista-stubs/issues" "Source" = "https://github.com/hbmartin/pythonista-stubs" +[project.optional-dependencies] +dev = [ + "mypy>=1.17.1", + "ruff>=0.12.8", +] + +[tool.setuptools.package-dir] +"pythonista_stubs" = "stubs" [tool.setuptools.packages.find] where = ["stubs"] @@ -45,10 +53,10 @@ include = [ ] [tool.setuptools.package-data] -"*" = [ "**/*" ] # to include root-places .pyi stubs +"*" = ["**/*"] # to include root-places .pyi stubs [tool.setuptools.dynamic] -version = {file = "VERSION"} +version = { file = "VERSION" } [dependency-groups] dev = [ diff --git a/stubs/_cb.pyi b/stubs/_cb.pyi index 569acb1..67a09f5 100644 --- a/stubs/_cb.pyi +++ b/stubs/_cb.pyi @@ -69,12 +69,12 @@ class Peripheral: services: List[Service] def discover_services(self) -> None: ... - def discover_characteristics(self, service) -> None: ... - def set_notify_value(self, characteristic, flag: bool = True) -> None: ... + def discover_characteristics(self, service: Service) -> None: ... + def set_notify_value(self, characteristic: Characteristic, flag: bool = True) -> None: ... def write_characteristic_value( self, characteristic, data, with_response ) -> None: ... - def read_characteristic_value(self, characteristic) -> None: ... + def read_characteristic_value(self, characteristic: Characteristic) -> None: ... class CentralManager: state: int @@ -98,4 +98,4 @@ class CentralManager: ) -> None: ... def did_write_value(self, c: Characteristic, error: Optional[str]) -> None: ... def did_update_value(self, c: Characteristic, error: Optional[str]) -> None: ... - def did_update_state(self): ... + def did_update_state(self) -> None: ... diff --git a/stubs/pythonista_stubs/dialogs.pyi b/stubs/pythonista_stubs/dialogs.pyi index e9dbe53..72d61c1 100644 --- a/stubs/pythonista_stubs/dialogs.pyi +++ b/stubs/pythonista_stubs/dialogs.pyi @@ -8,7 +8,7 @@ from typing import Any, Dict, List, Optional, Sequence, Tuple, Union, Literal # These are imported from the `console` module for convenience. # We'll alias the types for clarity. -from . import console as _console +from .console import _HudIcon # These are imported from the `ui` module, which is part of Pythonista. # We'll provide a minimal stub for the types used. @@ -21,25 +21,50 @@ class TextField: class ListDataSource: items: List[Dict[str, Any]] = ... -def alert(*args, **kwargs) -> int: +def alert( + title: str, + message: str = "", + button1: str = "OK", + button2: Optional[str] = None, + button3: Optional[str] = None, + hide_cancel_button: bool = False, +) -> int: """See console.alert()""" - return _console.alert(*args, **kwargs) + ... -def input_alert(*args, **kwargs) -> str: +def input_alert( + title: str, + message: str = "", + input: str = "", + ok_button_title: str = "OK", + hide_cancel_button: bool = False, +) -> str: """See console.input_alert()""" - return _console.input_alert(*args, **kwargs) + ... -def login_alert(*args, **kwargs) -> Tuple[str, str]: +def password_alert( + title: str, + message: str = "", + password: str = "", + ok_button_title: str = "OK", + hide_cancel_button: bool = False, +) -> str: """See console.login_alert()""" - return _console.login_alert(*args, **kwargs) + ... -def password_alert(*args, **kwargs) -> str: +def login_alert( + title: str, + message: str = "", + login: str = "", + password: str = "", + ok_button_title: str = "OK", +) -> Tuple[str, str]: """See console.password_alert()""" - return _console.password_alert(*args, **kwargs) + ... -def hud_alert(*args, **kwargs) -> None: +def hud_alert(message: str, icon: _HudIcon = "success", duration: float = 1.8) -> None: """See console.hud_alert()""" - return _console.hud_alert(*args, **kwargs) + ... # ----------------------------------------------------------------------------- # Dialog Functions diff --git a/stubs/pythonista_stubs/photos.pyi b/stubs/pythonista_stubs/photos.pyi index 0974df5..a9c6e62 100644 --- a/stubs/pythonista_stubs/photos.pyi +++ b/stubs/pythonista_stubs/photos.pyi @@ -28,7 +28,20 @@ class Asset: def get_ui_image( self, size: Optional[Tuple[int, int]] = None, crop: bool = False ) -> ui_Image: - """Fetch the asset's image data as a ui.Image object.""" + """ + Fetch the asset's image data as a ui.Image object. + + Args: + size (Optional[Tuple[int, int]]): The desired size of the returned image, + specified as a tuple of (width, height). If None, the original + image dimensions are used. + crop (bool): If True, the image will be cropped to fit the specified + size while maintaining its aspect ratio. If False, the image will + be resized and may be distorted. Defaults to False. + + Returns: + ui_Image: The asset's image data as a ui.Image object. + """ ... def edit_content(self, jpeg_path: str) -> None: diff --git a/stubs/pythonista_stubs/sound.pyi b/stubs/pythonista_stubs/sound.pyi index a20743a..ac24f1f 100644 --- a/stubs/pythonista_stubs/sound.pyi +++ b/stubs/pythonista_stubs/sound.pyi @@ -3,7 +3,8 @@ This is a stub file for the `sound` module, providing type hints for its functions and their parameters, to be used for static analysis and autocompletion. """ -from typing import Callable, Optional, Tuple +from typing import Callable, Optional, Tuple, Mapping + # ----------------------------------------------------------------------------- # Functions @@ -131,7 +132,7 @@ class Recorder: """The current duration of the active recording.""" recording: bool """Whether the recorder is currently recording.""" - meters: dict + meters: Mapping[str, Tuple[float, float]] """The current average and peak power (read-only). Example: {'average': (-35.3, -30.1), 'peak': (-5.2, -8.2)} """ diff --git a/uv.lock b/uv.lock index fc82db6..6900664 100644 --- a/uv.lock +++ b/uv.lock @@ -73,6 +73,12 @@ dependencies = [ { name = "typing-extensions" }, ] +[package.optional-dependencies] +dev = [ + { name = "mypy" }, + { name = "ruff" }, +] + [package.dev-dependencies] dev = [ { name = "mypy" }, @@ -81,9 +87,12 @@ dev = [ [package.metadata] requires-dist = [ + { name = "mypy", marker = "extra == 'dev'", specifier = ">=1.17.1" }, + { name = "ruff", marker = "extra == 'dev'", specifier = ">=0.12.8" }, { name = "types-pillow", specifier = ">=10.2.0.20240822" }, { name = "typing-extensions", specifier = ">=4.14.1" }, ] +provides-extras = ["dev"] [package.metadata.requires-dev] dev = [ From 47542890868fb0e6d6308a77447d5d260cecc5b4 Mon Sep 17 00:00:00 2001 From: o-murphy Date: Mon, 11 Aug 2025 00:28:20 +0300 Subject: [PATCH 3/3] Typo and formatting fix --- stubs/_cb.pyi | 6 ++++-- stubs/pythonista_stubs/dialogs.pyi | 4 ++-- stubs/pythonista_stubs/editor.pyi | 2 +- stubs/pythonista_stubs/sound.pyi | 1 - 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/stubs/_cb.pyi b/stubs/_cb.pyi index 67a09f5..0d8240f 100644 --- a/stubs/_cb.pyi +++ b/stubs/_cb.pyi @@ -54,7 +54,7 @@ class Characteristic: properties: int value: Optional[bytes] uuid: str # hex - notifying: bool # of bool + notifying: bool class Service: characteristics: List[Characteristic] @@ -70,7 +70,9 @@ class Peripheral: def discover_services(self) -> None: ... def discover_characteristics(self, service: Service) -> None: ... - def set_notify_value(self, characteristic: Characteristic, flag: bool = True) -> None: ... + def set_notify_value( + self, characteristic: Characteristic, flag: bool = True + ) -> None: ... def write_characteristic_value( self, characteristic, data, with_response ) -> None: ... diff --git a/stubs/pythonista_stubs/dialogs.pyi b/stubs/pythonista_stubs/dialogs.pyi index 72d61c1..95c7711 100644 --- a/stubs/pythonista_stubs/dialogs.pyi +++ b/stubs/pythonista_stubs/dialogs.pyi @@ -49,7 +49,7 @@ def password_alert( ok_button_title: str = "OK", hide_cancel_button: bool = False, ) -> str: - """See console.login_alert()""" + """See console.password_alert()""" ... def login_alert( @@ -59,7 +59,7 @@ def login_alert( password: str = "", ok_button_title: str = "OK", ) -> Tuple[str, str]: - """See console.password_alert()""" + """See console.login_alert()""" ... def hud_alert(message: str, icon: _HudIcon = "success", duration: float = 1.8) -> None: diff --git a/stubs/pythonista_stubs/editor.pyi b/stubs/pythonista_stubs/editor.pyi index 5d8ab7f..952506e 100644 --- a/stubs/pythonista_stubs/editor.pyi +++ b/stubs/pythonista_stubs/editor.pyi @@ -96,7 +96,7 @@ def open_file(name: str, new_tab: bool = False) -> None: ... def apply_ui_theme(ui_view: View, theme_name: Optional[str] = None) -> None: - """Styles a ui.View (and its descendents) with the given UI theme. + """Styles a ui.View (and its descendants) with the given UI theme. Args: ui_view (ui.View): The view to be styled. diff --git a/stubs/pythonista_stubs/sound.pyi b/stubs/pythonista_stubs/sound.pyi index ac24f1f..94d7ddc 100644 --- a/stubs/pythonista_stubs/sound.pyi +++ b/stubs/pythonista_stubs/sound.pyi @@ -5,7 +5,6 @@ functions and their parameters, to be used for static analysis and autocompletio from typing import Callable, Optional, Tuple, Mapping - # ----------------------------------------------------------------------------- # Functions # -----------------------------------------------------------------------------