Skip to content

Compatible stubs for Pythonista 3.4+ - #5

Merged
hbmartin merged 3 commits into
hbmartin:masterfrom
o-murphy:master
Aug 11, 2025
Merged

Compatible stubs for Pythonista 3.4+#5
hbmartin merged 3 commits into
hbmartin:masterfrom
o-murphy:master

Conversation

@o-murphy

@o-murphy o-murphy commented Aug 9, 2025

Copy link
Copy Markdown
Collaborator

User description

  • some stubs updated
  • project tree changed to typeshed-like
  • switching to the pyproject.toml
  • updated CI
  • added publish.yml (allows build and 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)

PR Type

Enhancement


Description

  • Modernized project structure to typeshed-like organization

  • Migrated from setup.py to pyproject.toml configuration

  • Updated CI/CD with uv package manager and ruff linting

  • Added comprehensive type stubs for Pythonista modules


Diagram Walkthrough

flowchart LR
  A["Old setup.py"] -- "migrate to" --> B["pyproject.toml"]
  C["Basic stubs"] -- "expand to" --> D["Comprehensive .pyi files"]
  E["Black + mypy CI"] -- "upgrade to" --> F["uv + ruff + mypy CI"]
  G["Simple structure"] -- "reorganize to" --> H["Typeshed-like layout"]
Loading

File Walkthrough

Relevant files
Configuration changes
9 files
setup.py
Simplified to minimal setup() call                                             
+1/-37   
ci.yml
Updated CI to use uv and ruff                                                       
+15/-22 
publish.yml
Added automated publishing workflow                                           
+31/-0   
profiles_settings.xml
Added IDE inspection settings                                                       
+6/-0     
misc.xml
Updated IDE configuration                                                               
+3/-0     
MANIFEST.in
Added package manifest for stub files                                       
+2/-0     
VERSION
Added version file with 3.4.0                                                       
+1/-0     
mypy.ini
Removed old mypy configuration                                                     
+0/-5     
pyproject.toml
Added modern Python project configuration                               
+76/-0   
Miscellaneous
7 files
__init__.py
Removed Python implementation file                                             
+0/-65   
__init__.pyi
Removed old appex stub implementation                                       
+0/-16   
__init__.pyi
Removed old clipboard stub implementation                               
+0/-9     
__init__.pyi
Removed old console stub implementation                                   
+0/-48   
__init__.pyi
Removed old reminders stub implementation                               
+0/-31   
__init__.pyi
Removed old sound stub implementation                                       
+0/-50   
__init__.pyi
Removed old speech stub implementation                                     
+0/-13   
Formatting
1 files
ui.py
Minor formatting cleanup                                                                 
+1/-2     
Enhancement
22 files
_cb.pyi
Added Bluetooth Core module stubs                                               
+101/-0 
__init__.pyi
Added package version stub                                                             
+1/-0     
appex.pyi
Added comprehensive appex module stubs                                     
+161/-0 
canvas.pyi
Added canvas drawing module stubs                                               
+221/-0 
cb.pyi
Added Bluetooth module wrapper stubs                                         
+94/-0   
clipboard.pyi
Added comprehensive clipboard module stubs                             
+63/-0   
console.pyi
Added comprehensive console module stubs                                 
+244/-0 
contacts.pyi
Added contacts module stubs                                                           
+172/-0 
dialogs.pyi
Added dialogs module stubs                                                             
+280/-0 
editor.pyi
Added comprehensive editor module stubs                                   
+156/-0 
keyboard.pyi
Added keyboard module stubs                                                           
+82/-0   
keychain.pyi
Added keychain module stubs                                                           
+57/-0   
linguistictagger.pyi
Added linguistic tagger module stubs                                         
+45/-0   
location.pyi
Added location services module stubs                                         
+82/-0   
motion.pyi
Added motion sensors module stubs                                               
+33/-0   
notification.pyi
Added notification module stubs                                                   
+68/-0   
objc_util.pyi
Added Objective-C bridge module stubs                                       
+220/-0 
photos.pyi
Added photos library module stubs                                               
+200/-0 
reminders.pyi
Added comprehensive reminders module stubs                             
+121/-0 
shortcuts.pyi
Added shortcuts integration module stubs                                 
+44/-0   
sound.pyi
Added comprehensive sound module stubs                                     
+159/-0 
speech.pyi
Added speech synthesis module stubs                                           
+54/-0   
Additional files
3 files
LICENSE [link]   
py.typed [link]   
py.typed [link]   

* 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)
@o-murphy
o-murphy requested a review from hbmartin August 9, 2025 20:22
@sourcery-ai

sourcery-ai Bot commented Aug 9, 2025

Copy link
Copy Markdown

Reviewer's Guide

This PR refactors the project to a typeshed‐style layout, migrates build and package metadata to pyproject.toml, overhauls CI to use uv + ruff/mypy with a publish workflow, and replaces the old setup.py stub roster with comprehensive .pyi stubs for Pythonista 3.4+ APIs.

Entity relationship diagram for new Pythonista stub modules

erDiagram
    "pythonista_stubs" ||--o{ "appex" : contains
    "pythonista_stubs" ||--o{ "clipboard" : contains
    "pythonista_stubs" ||--o{ "console" : contains
    "pythonista_stubs" ||--o{ "editor" : contains
    "pythonista_stubs" ||--o{ "reminders" : contains
    "pythonista_stubs" ||--o{ "sound" : contains
    "pythonista_stubs" ||--o{ "speech" : contains
    "pythonista_stubs" ||--o{ "ui" : contains
    "pythonista_stubs" ||--o{ "canvas" : contains
    "pythonista_stubs" ||--o{ "contacts" : contains
    "pythonista_stubs" ||--o{ "dialogs" : contains
    "pythonista_stubs" ||--o{ "keychain" : contains
    "pythonista_stubs" ||--o{ "linguistictagger" : contains
    "pythonista_stubs" ||--o{ "location" : contains
    "pythonista_stubs" ||--o{ "motion" : contains
    "pythonista_stubs" ||--o{ "notification" : contains
    "pythonista_stubs" ||--o{ "objc_util" : contains
    "pythonista_stubs" ||--o{ "photos" : contains
    "pythonista_stubs" ||--o{ "shortcuts" : contains
    "pythonista_stubs" ||--o{ "cb" : contains
    "pythonista_stubs" ||--o{ "keyboard" : contains
    "pythonista_stubs" ||--o{ "__init__" : contains
    "pythonista_stubs" ||--o{ "_cb" : contains
    "cb" }o--|| "_cb" : imports
    "dialogs" }o--|| "console" : imports
    "dialogs" }o--|| "ui" : imports
    "appex" }o--|| "ui" : imports
    "appex" }o--|| "PIL.Image" : imports
    "clipboard" }o--|| "PIL.Image" : imports
    "photos" }o--|| "PIL.Image" : imports
    "photos" }o--|| "ui" : imports
Loading

Class diagram for new and refactored Pythonista stub types

classDiagram
    class Asset {
        +get_image(original: bool)
        +get_image_data(original: bool)
        +get_ui_image(size, crop)
        +edit_content(jpeg_path)
        +delete()
        +revert()
        local_id: str
        pixel_width: int
        pixel_height: int
        media_type: "image"|"video"
        media_subtypes: List[str]
        creation_date: datetime
        modification_date: datetime
        hidden: bool
        favorite: bool
        duration: float
        location: dict
        can_edit_content: bool
        can_edit_properties: bool
        can_delete: bool
    }
    class AssetCollection {
        +delete()
        +add_assets(assets)
        +remove_assets(assets)
        assets: List[Asset]
        local_id: str
        title: str
        type: "album"|"smart_album"|"moment"
        subtype: str
        start_date: datetime
        end_date: datetime
        can_delete: bool
        can_add_assets: bool
        can_remove_assets: bool
        can_rename: bool
    }
    AssetCollection "1" o-- "*" Asset

    class Reminder {
        +save()
        alarms: List[Alarm]
        completed: bool
        completion_date: datetime
        due_date: datetime
        notes: str
        priority: int
        title: str
        url: str
    }
    class Alarm {
        date: datetime
        location: tuple
        proximity: "enter"|"leave"|"none"
    }
    Reminder "*" o-- "*" Alarm

    class Calendar {
        +save()
        title: str
        identifier: str
    }
    Calendar "1" o-- "*" Reminder

    class Person {
        address: List[Tuple[str, Dict[str, str]]]
        birthday: datetime
        creation_date: datetime
        department: str
        email: List[Tuple[str, str]]
        first_name: str
        full_name: str
        id: int
        image_data: bytes
        job_title: str
        last_name: str
        middle_name: str
        modification_date: datetime
        nickname: str
        note: str
        organization: str
        phone: List[Tuple[str, str]]
        related_names: List[Tuple[str, str]]
        social_profile: List[Tuple[str, Dict[str, str]]]
        url: List[Tuple[str, str]]
        vcard: str
    }
    class Group {
        name: str
        id: int
    }
    Group "1" o-- "*" Person

    class Effect {
        +stop()
        looping: bool
        pan: float
        pitch: float
        position: tuple
        volume: float
    }
    class Player {
        +play()
        +stop()
        +pause()
        current_time: float
        duration: float
        finished_handler: Callable
        number_of_loops: int
        playing: bool
        pan: float
    }
    class Recorder {
        +record(duration)
        +stop()
        +pause()
        current_time: float
        recording: bool
        meters: dict
    }
    class MIDIPlayer {
        +play()
        +stop()
        current_time: float
        duration: float
        rate: float
    }
    class ObjCClass {
        +__init__(name: str)
    }
    class ObjCInstance {
        +__init__(ptr)
    }
    class ObjCBlock {
        +__init__(func, restype, argtypes)
    }
    class CentralManager {
        +scan_for_peripherals()
        +stop_scan()
        +connect_peripheral(p)
        +cancel_peripheral_connection(p)
        state: int
    }
    class Peripheral {
        manufacturer_data: bytes
        name: str
        uuid: str
        state: int
        services: List[Service]
        +discover_services()
        +discover_characteristics(service)
        +set_notify_value(characteristic, flag)
        +write_characteristic_value(characteristic, data, with_response)
        +read_characteristic_value(characteristic)
    }
    class Service {
        characteristics: List[Characteristic]
        primary: bool
        uuid: str
    }
    class Characteristic {
        properties: int
        value: bytes
        uuid: str
        notifying: bool
    }
    CentralManager "1" o-- "*" Peripheral
    Peripheral "1" o-- "*" Service
    Service "1" o-- "*" Characteristic
Loading

File-Level Changes

Change Details Files
Migrate build configuration to PEP 621 pyproject.toml
  • Replaced detailed setup.py calls with a minimal setup() invocation
  • Added pyproject.toml specifying project metadata, dependencies, dynamic version, and build-system
  • Included MANIFEST.in to include all stub files in distributions
setup.py
pyproject.toml
MANIFEST.in
Overhaul CI pipeline and add publish job
  • Renamed test job to ‘testing’ and added id-token permissions
  • Switched from pip install/black to astral-sh UV sync with ruff and mypy checks
  • Introduced a separate publish job triggered on releases, with uv build and pypi publish steps
.github/workflows/ci.yml
Reorganize project tree to typeshed-like layout
  • Removed legacy mypy.ini in favor of tooling config in pyproject.toml
  • Configured setuptools to find packages under stubs/pythonista_stubs
  • Rearranged stub files into a dedicated pythonista_stubs namespace
mypy.ini
pyproject.toml
Add comprehensive Pythonista API .pyi stubs
  • Implemented type stubs for core modules (dialogs, console, canvas)
  • Added stubs for system services (photos, contacts, reminders, notifications)
  • Included bridging APIs (objc_util), UI widgets, and utility modules (clipboard, keychain, etc.)
stubs/pythonista_stubs/dialogs.pyi
stubs/pythonista_stubs/console.pyi
stubs/pythonista_stubs/canvas.pyi
stubs/pythonista_stubs/objc_util.pyi
stubs/pythonista_stubs/photos.pyi
stubs/pythonista_stubs/contacts.pyi
stubs/pythonista_stubs/appex.pyi
stubs/pythonista_stubs/editor.pyi
stubs/pythonista_stubs/reminders.pyi
stubs/pythonista_stubs/notification.pyi
stubs/pythonista_stubs/clipboard.pyi
stubs/pythonista_stubs/keychain.pyi
stubs/pythonista_stubs/speech.pyi
stubs/pythonista_stubs/linguistictagger.pyi
stubs/pythonista_stubs/shortcuts.pyi
stubs/pythonista_stubs/motion.pyi
Bump project version to 3.4.0
  • Updated the minimal supported Pythonista version in metadata
  • Incremented VERSION file to reflect stubs versioning
VERSION

Possibly linked issues

  • #123: The PR delivers updated and new mypy compatible stub files for Pythonista, directly addressing the issue's focus on compatible stubs.

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@coderabbitai

coderabbitai Bot commented Aug 9, 2025

Copy link
Copy Markdown

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Warning

Rate limit exceeded

@o-murphy has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 23 minutes and 26 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 9106cde and 4754289.

⛔ Files ignored due to path filters (1)
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (39)
  • .github/workflows/ci.yml (1 hunks)
  • .github/workflows/publish.yml (1 hunks)
  • .idea/inspectionProfiles/profiles_settings.xml (1 hunks)
  • .idea/misc.xml (1 hunks)
  • MANIFEST.in (1 hunks)
  • VERSION (1 hunks)
  • mypy.ini (0 hunks)
  • pyproject.toml (1 hunks)
  • setup.py (1 hunks)
  • stubs/_cb.pyi (1 hunks)
  • stubs/appex/__init__.pyi (0 hunks)
  • stubs/clipboard/__init__.pyi (0 hunks)
  • stubs/console/__init__.pyi (0 hunks)
  • stubs/editor/__init__.py (0 hunks)
  • stubs/pythonista_stubs/__init__.pyi (1 hunks)
  • stubs/pythonista_stubs/appex.pyi (1 hunks)
  • stubs/pythonista_stubs/canvas.pyi (1 hunks)
  • stubs/pythonista_stubs/cb.pyi (1 hunks)
  • stubs/pythonista_stubs/clipboard.pyi (1 hunks)
  • stubs/pythonista_stubs/console.pyi (1 hunks)
  • stubs/pythonista_stubs/contacts.pyi (1 hunks)
  • stubs/pythonista_stubs/dialogs.pyi (1 hunks)
  • stubs/pythonista_stubs/editor.pyi (1 hunks)
  • stubs/pythonista_stubs/keyboard.pyi (1 hunks)
  • stubs/pythonista_stubs/keychain.pyi (1 hunks)
  • stubs/pythonista_stubs/linguistictagger.pyi (1 hunks)
  • stubs/pythonista_stubs/location.pyi (1 hunks)
  • stubs/pythonista_stubs/motion.pyi (1 hunks)
  • stubs/pythonista_stubs/notification.pyi (1 hunks)
  • stubs/pythonista_stubs/objc_util.pyi (1 hunks)
  • stubs/pythonista_stubs/photos.pyi (1 hunks)
  • stubs/pythonista_stubs/reminders.pyi (1 hunks)
  • stubs/pythonista_stubs/shortcuts.pyi (1 hunks)
  • stubs/pythonista_stubs/sound.pyi (1 hunks)
  • stubs/pythonista_stubs/speech.pyi (1 hunks)
  • stubs/pythonista_stubs/ui.py (1 hunks)
  • stubs/reminders/__init__.pyi (0 hunks)
  • stubs/sound/__init__.pyi (0 hunks)
  • stubs/speech/__init__.pyi (0 hunks)

Walkthrough

This update restructures the Pythonista stubs package, replacing legacy stub files with a new, unified set under pythonista_stubs, and introduces a modernized build system using pyproject.toml. The workflow is overhauled for improved CI/CD, new type stubs are added for many modules, and several obsolete or duplicate stubs are removed. The package metadata, versioning, and distribution configuration are revised for clarity and maintainability.

Changes

Cohort / File(s) Change Summary
CI/CD Workflow Overhaul
.github/workflows/ci.yml, .github/workflows/publish.yml
Added manual trigger to CI workflow; renamed test job to testing; removed Python 3.6 matrix; switched to uv tool for setup, linting, and type checking; added explicit id-token: write permission; introduced new publish workflow triggered on release or manual dispatch for build and conditional PyPI publishing.
Project Metadata & Build System
pyproject.toml, setup.py, VERSION, MANIFEST.in, mypy.ini
Added comprehensive pyproject.toml with project metadata, dependencies, and tooling configuration; simplified setup.py by removing detailed metadata; added VERSION file with version number; updated MANIFEST.in to include .pyi stub files and VERSION; removed legacy mypy.ini configuration.
IDE Configuration
.idea/inspectionProfiles/profiles_settings.xml, .idea/misc.xml
Added new IntelliJ inspection profile settings; updated Python SDK version from 3.7 to 3.10 and set SDK name to "Python 3.10 (pythonista-stubs)"; added Black formatter component with SDK configuration.
Removed Legacy Stubs
stubs/appex/__init__.pyi, stubs/clipboard/__init__.pyi, stubs/console/__init__.pyi, stubs/editor/__init__.py, stubs/reminders/__init__.pyi, stubs/sound/__init__.pyi, stubs/speech/__init__.pyi
Deleted old stub files for modules now replaced by new unified stubs under pythonista_stubs.
Formatting-Only Change
stubs/pythonista_stubs/ui.py
Adjusted ellipsis formatting in __init__ method for consistency; no functional change.
New and Modernized Stubs
stubs/pythonista_stubs/__init__.pyi, stubs/pythonista_stubs/appex.pyi, stubs/pythonista_stubs/canvas.pyi, stubs/pythonista_stubs/cb.pyi, stubs/pythonista_stubs/clipboard.pyi, stubs/pythonista_stubs/console.pyi, stubs/pythonista_stubs/contacts.pyi, stubs/pythonista_stubs/dialogs.pyi, stubs/pythonista_stubs/editor.pyi, stubs/pythonista_stubs/keyboard.pyi, stubs/pythonista_stubs/keychain.pyi, stubs/pythonista_stubs/linguistictagger.pyi, stubs/pythonista_stubs/location.pyi, stubs/pythonista_stubs/motion.pyi, stubs/pythonista_stubs/notification.pyi, stubs/pythonista_stubs/objc_util.pyi, stubs/pythonista_stubs/photos.pyi, stubs/pythonista_stubs/reminders.pyi, stubs/pythonista_stubs/shortcuts.pyi, stubs/pythonista_stubs/sound.pyi, stubs/pythonista_stubs/speech.pyi, stubs/_cb.pyi
Added extensive new type stub files with detailed type annotations, docstrings, and modern typing constructs for many Pythonista modules, providing improved static analysis and autocompletion support.
Stub Modernization: Module Renames/Unification
(see above for new stubs)
Unified and replaced old stubs with new pythonista_stubs-prefixed stubs, improving consistency, coverage, and maintainability.

Sequence Diagram(s)

sequenceDiagram
    participant Developer
    participant GitHub Actions
    participant PyPI

    Developer->>GitHub Actions: Push, PR, Release, or Manual Trigger
    GitHub Actions->>GitHub Actions: Run 'testing' job (setup, lint, type-check)
    GitHub Actions->>GitHub Actions: On release, run 'publish' job (build, publish)
    GitHub Actions->>PyPI: Publish package (on release event)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~35 minutes

Poem

🐇 A hop, a skip, new stubs abound,
With pyproject’s song, the builds resound.
Old files retired, new types in place,
CI now leaps with elegant grace.
Versioned and tidy, the stubs align—
Pythonista’s future is looking divine!
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary of Changes

Hello @o-murphy, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

I've refactored the Pythonista stubs project to enhance compatibility with Pythonista 3.4+ and modernize its build and dependency management. This involved restructuring the stub files into a more organized, typeshed-like layout and migrating the project configuration to pyproject.toml. These changes aim to improve the development experience by providing clearer type hints and a more standardized project setup, while also updating the version and CI processes for better release management.

Highlights

  • Stub File Restructuring and Updates: The project's stub files have been updated and reorganized into a typeshed-like structure under a new pythonista_stubs directory. This improves consistency and maintainability for type hints.
  • Modernized Project Configuration with pyproject.toml: The project has transitioned from setup.py and mypy.ini to a modern pyproject.toml for all project configuration, including build system, dependencies, and tool settings. This streamlines development and dependency management.
  • Version Compatibility Update: The version number has been updated to 3.4.0, indicating compatibility with Pythonista 3.4 and newer versions.
  • CI/CD Enhancements: The Continuous Integration (CI) setup has been updated to support publishing to a properly configured trusted publisher, enhancing the release process.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in issue comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments or fill out our survey to provide feedback.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@qodo-code-review

Copy link
Copy Markdown

PR Reviewer Guide 🔍

Here are some key observations to aid the review process:

⏱️ Estimated effort to review: 4 🔵🔵🔵🔵⚪
🧪 No relevant tests
🔒 No security concerns identified
⚡ Recommended focus areas for review

Packaging Inconsistency

Minimal setup.py with setup() only may conflict with pyproject-based build; consider removing the file entirely to avoid legacy invocation or sdist behavior mismatches.

from setuptools import setup

setup()
Publish Guard

The publish step runs on release events only, but job has broad permissions and prepares build on all triggers; ensure conditions prevent unintended publishes and consider restricting workflow to tag patterns or environment protections.

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
Python Version Requirement

requires-python is set to >=3.10 while stubs target Pythonista 3.4+; verify this constraint matches intended consumer environments and mypy/types packages compatibility.

requires-python = ">=3.10"
dependencies = [
    "types-pillow>=10.2.0.20240822",
    "typing-extensions>=4.14.1",
]

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @o-murphy - I've reviewed your changes - here's some feedback:

  • The requires-python >=3.10 in pyproject.toml conflicts with the stated support for Pythonista 3.4+; please adjust the Python requirement or clarify the supported versions.
  • Some stubs use relative imports (e.g. from . import console as _console)—verify those import paths resolve correctly under the pythonista_stubs package for both mypy and IDE tooling.
  • Since you switched to a dynamic version in pyproject.toml, ensure the VERSION file is updated to 3.4.0 so the published package reflects the intended stub version.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The `requires-python >=3.10` in pyproject.toml conflicts with the stated support for Pythonista 3.4+; please adjust the Python requirement or clarify the supported versions.
- Some stubs use relative imports (e.g. `from . import console as _console`)—verify those import paths resolve correctly under the `pythonista_stubs` package for both mypy and IDE tooling.
- Since you switched to a dynamic version in pyproject.toml, ensure the `VERSION` file is updated to `3.4.0` so the published package reflects the intended stub version.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@qodo-code-review

qodo-code-review Bot commented Aug 9, 2025

Copy link
Copy Markdown

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
Security
Remove unnecessary OIDC permission
Suggestion Impact:The commit removed a job section that included permissions with id-token: write, thereby eliminating the unnecessary OIDC permission.

code diff:

-  publish:
-    runs-on: ubuntu-latest
-    environment:
-      name: pypi
-    needs: [testing]
-    permissions:
-      id-token: write
-

The testing job doesn't require OIDC and granting id-token: write broadens
permissions unnecessarily. Remove this permission to follow GitHub's
least-privilege guidance and avoid potential token misuse.

.github/workflows/ci.yml [13-16]

 testing:
   runs-on: ubuntu-latest
-  permissions:
-    id-token: write

[Suggestion processed]

Suggestion importance[1-10]: 7

__

Why: The suggestion correctly identifies that the testing job does not require OIDC permissions, and removing the id-token: write permission aligns with the principle of least privilege, improving security.

Medium
Possible issue
Fix incorrect optional typing

Declaring shared_manager as Optional while initializing it defeats type checking
and may mislead consumers to handle None. Type it as SharedCentralManager to
match the initialization and avoid unnecessary None-guards.

stubs/pythonista_stubs/cb.pyi [80-85]

 class SharedCentralManager(CentralManager):
   delegate: Optional[_CentralManagerDelegate] = None
   verbose: bool = False
   def verbose_log(self): ...
 
-shared_manager: Optional[SharedCentralManager] = SharedCentralManager()
+shared_manager: SharedCentralManager = SharedCentralManager()

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 5

__

Why: The suggestion correctly points out that typing shared_manager as Optional is misleading since it's initialized with a non-None value, and the proposed change improves type hint accuracy.

Low
  • Update

@ellipsis-dev ellipsis-dev Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Changes requested ❌

Reviewed everything up to 5fb7267 in 1 minute and 44 seconds. Click for details.
  • Reviewed 3468 lines of code in 41 files
  • Skipped 0 files when reviewing.
  • Skipped posting 4 draft comments. View those below.
  • Modify your settings and rules to customize what types of comments Ellipsis leaves. And don't forget to react with 👍 or 👎 to teach Ellipsis.
1. pyproject.toml:13
  • Draft comment:
    The 'requires-python = ">=3.10"' setting may need review. The PR description notes minimal support for Pythonista 3.4+, so please confirm that requiring Python 3.10 for static analysis doesn’t inadvertently exclude users running older versions when using the stubs.
  • Reason this comment was not posted:
    Comment did not seem useful. Confidence is useful = 0% <= threshold 50% The comment is asking the PR author to confirm their intention regarding the Python version requirement. It suggests a potential issue with excluding users running older versions, but it doesn't provide a specific code suggestion or ask for a test. It violates the rule against asking the author to confirm their intention.
2. pyproject.toml:48
  • Draft comment:
    Typographical suggestion: In the comment '# to include root-places .pyi stubs', 'root-places' might be a typo. Consider changing it to 'root-level' or a similar phrase if that is what was intended.
  • Reason this comment was not posted:
    Decided after close inspection that this draft comment was likely wrong and/or not actionable: usefulness confidence = 10% vs. threshold = 50% While "root-places" is an unusual term, this is just about wording in a comment. Comments are meant to help developers understand the code, but this suggestion is very minor and doesn't affect functionality. The existing comment, while using unusual wording, still conveys its basic meaning about including .pyi stubs. The unusual term might genuinely confuse future developers. The comment is part of a configuration file where clarity is important. However, this is still just a stylistic suggestion about comment wording. Per the rules, we should not make purely informative comments or ones that don't require clear code changes. The comment should be deleted as it's a minor stylistic suggestion about documentation that doesn't affect functionality or require actual code changes.
3. stubs/_cb.pyi:1
  • Draft comment:
    Typo suggestion: The header on line 1 reads "Created on July, 07 2025...". The comma after "July" looks out of place. Consider revising it (e.g., "Created on July 07, 2025...").
  • Reason this comment was not posted:
    Decided after close inspection that this draft comment was likely wrong and/or not actionable: usefulness confidence = 10% vs. threshold = 50% While this is technically about changed code since it's a new file, the comment is about an extremely minor formatting issue in a header comment that doesn't affect functionality or code quality. The rules state not to make comments that are obvious or unimportant. Date formatting in a header comment is very low importance. The date format with the comma is technically incorrect, and having consistent date formatting could be considered a code quality issue. While correct, this is an extremely minor stylistic issue in a comment that doesn't impact code functionality or maintainability. The rules specifically say not to make unimportant comments. This comment should be deleted as it addresses an extremely minor formatting issue that doesn't meaningfully impact code quality.
4. stubs/pythonista_stubs/editor.pyi:102
  • Draft comment:
    Typo: In the apply_ui_theme docstring, consider replacing "descendents" with "descendants".
  • Reason this comment was not posted:
    Decided after close inspection that this draft comment was likely wrong and/or not actionable: usefulness confidence = 10% vs. threshold = 50% While this is a spelling error, it's in a docstring and is a very minor issue. The meaning is still completely clear. The rules state we should not make purely informative comments or unimportant changes. This feels like a very low-priority issue that doesn't materially affect the code quality or functionality. The spelling error could propagate if other developers copy this docstring as a template. Documentation quality is important for maintainability. While documentation quality matters, this particular spelling variation is so minor and still completely understandable that fixing it provides negligible value. Delete the comment as it points out an extremely minor spelling issue that doesn't materially affect code quality or understanding.

Workflow ID: wflow_HMXMl4uL7eETLgNf

You can customize Ellipsis by changing your verbosity settings, reacting with 👍 or 👎, replying to comments, or adding code review rules.

Comment thread MANIFEST.in
Comment thread stubs/_cb.pyi Outdated

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request is a significant improvement, modernizing the project's packaging by migrating to pyproject.toml and adopting a typeshed-like structure for stubs. My review focuses on refining the packaging configuration to ensure all stubs are correctly included, correcting some syntax in the stub files, and enhancing type hint completeness for better static analysis.

Comment thread stubs/pythonista_stubs/dialogs.pyi Outdated
Comment thread pyproject.toml Outdated
Comment thread pyproject.toml
Comment thread MANIFEST.in
Comment thread stubs/_cb.pyi Outdated
Comment thread stubs/pythonista_stubs/console.pyi
@o-murphy

o-murphy commented Aug 9, 2025

Copy link
Copy Markdown
Collaborator Author

@hbmartin If you approve it I will megre. Also please setup trusted publisher to pypi to able publish to pypi on github release action
There are example how can it be configured
image

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 20

🧹 Nitpick comments (22)
.idea/inspectionProfiles/profiles_settings.xml (1)

1-6: Avoid committing IDE-specific files (.idea).

Recommend excluding JetBrains project files from VCS to reduce noise and accidental config drift. Add to .gitignore:

.idea/

If you intentionally track IDE settings, consider documenting that in CONTRIBUTING.md.

stubs/pythonista_stubs/__init__.pyi (1)

1-1: Consider marking version as Final for clarity.

Marking as Final helps type checkers treat it as a constant. Use typing_extensions for broader compatibility.

+from typing_extensions import Final
-__version__: str
+__version__: Final[str]
setup.py (1)

3-3: Remove or justify the no-op setup() call

With a PEP 517 build (pyproject.toml + setuptools.build_meta) this file is no longer used for builds or editable installs (PEP 660).
Keeping a dummy setup.py can confuse tooling and duplicate metadata maintenance. Either delete the file or add a short comment explaining that it is retained only for legacy pip (< 21.3) compatibility.

stubs/pythonista_stubs/clipboard.pyi (1)

11-15: Simplify the PIL import in stubs

.pyi files are not executed at runtime, so the try/except fallback is unnecessary.
Prefer the canonical pattern:

from typing import TYPE_CHECKING, Any

if TYPE_CHECKING:
    from PIL.Image import Image
else:
    Image = Any  # type: ignore[assignment]

This avoids redef-warnings and expresses intent cleanly.

stubs/pythonista_stubs/linguistictagger.pyi (1)

12-31: Reuse declared constants in _Scheme to avoid drift

The Literal list hard-codes the scheme strings, which risks diverging from the constants above. Build it from the constants instead:

_Scheme = Literal[
    SCHEME_TOKEN_TYPE,
    SCHEME_LEXICAL_CLASS,
    SCHEME_NAME_TYPE,
    SCHEME_NAME_TYPE_OR_LEXICAL_CLASS,
    SCHEME_LEMMA,
    SCHEME_LANGUAGE,
    SCHEME_SCRIPT,
]

One source of truth improves maintainability.

stubs/pythonista_stubs/motion.pyi (1)

6-34: Consider introducing a Vector3/Vector4 alias.

All value-returning helpers repeatedly declare Tuple[float, float, float] (and once four floats). Defining

from typing import Tuple, TypeAlias

Vector3: TypeAlias = Tuple[float, float, float]
Vector4: TypeAlias = Tuple[float, float, float, float]

once at the top and re-using the aliases cuts duplication and improves readability without affecting callers.

stubs/pythonista_stubs/speech.pyi (2)

23-30: Tighten the rate parameter typing.

If the underlying API clamps values between 0.0 – 1.0, consider

from typing import Annotated
Rate = Annotated[float, "0.0 ≤ rate ≤ 1.0"]
def say(text: str, language: Optional[str] = None, rate: Rate = 0.5) -> None: ...

(or a Literal[0.25, 0.5, 1.0] set if only discrete steps are accepted).


40-54: Provide a shaped type for the recognition result.

List[Tuple[str, List[Dict]]] hides the structure of the dicts. A small TypedDict, e.g.

class Alt(TypedDict):
    confidence: float
    words: List[str]

makes static analysis far more useful and self-documenting.

stubs/pythonista_stubs/appex.pyi (2)

14-16: Use a TYPE_CHECKING gate for the optional Pillow import

The fallback assignment PilImage: Any is only needed at runtime, not during type-checking.
A cleaner pattern:

from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from PIL.Image import Image as PilImage
else:
    PilImage = Any  # type: ignore[assignment]

Reduces unnecessary import attempts at runtime and keeps the type checker happy.


55-63: Synchronise annotations with the doc-string

The return annotation is List[Union[Image, PilImage]], but the doc-string mentions ui.Image.
Once the real ui.Image alias is imported (see previous note), update either the annotations or the doc-string so both mention the same concrete types to avoid confusion.

stubs/pythonista_stubs/contacts.pyi (1)

12-39: Mark constants as Final for stronger type safety

-from typing import Dict, List, Optional, Tuple
+from typing import Dict, List, Optional, Tuple, Final
 ...
-HOME: str = ...
+HOME: Final[str] = ...

Applying Final prevents accidental reassignment and gives static analysers better guarantees.

stubs/pythonista_stubs/editor.pyi (1)

98-106: Doc-string refers to ui.View but the annotation is plain View

Once the real ui.View is imported, make the annotation explicit:

-def apply_ui_theme(ui_view: View, ...
+def apply_ui_theme(ui_view: ui.View, ...

Keeps annotation and documentation in lock-step.

stubs/pythonista_stubs/notification.pyi (1)

11-13: Model _Action and _Trigger with TypedDict for richer checking

from typing import TypedDict, Literal

class _Action(TypedDict, total=False):
    title: str
    identifier: str
    foreground: bool

class _Trigger(TypedDict, total=False):
    date: float
    repeats: bool

TypedDicts let users discover valid keys and value types during code completion.

stubs/pythonista_stubs/reminders.pyi (1)

17-24: Consider a named structure for location-based alarms

Anonymous Tuple[str, float, float, float] provides little clarity.
A small NamedTuple or TypedDict (title, lat, lon, radius) would make the API self-documenting and safer.

stubs/pythonista_stubs/location.pyi (2)

65-67: Align return type name in docstring with signature

After importing Image from ui, update the docstring to avoid the misleading ui.Image reference.

-        ui.Image: The rendered map snapshot.
+        Image: The rendered map snapshot.

16-23: Widen container types (or consider TypedDicts) to avoid over-constraining return payloads

Pythonista location APIs often return additional keys. Current typing may be too strict (e.g., geocode results may include non-float fields). Either:

  • minimally widen to Mapping[...] for inputs/outputs, or
  • introduce TypedDicts with optional keys.

Minimal widening:

-from typing import Dict, List, Optional, Literal
+from typing import Dict, List, Optional, Literal, Mapping
@@
-def get_location() -> Optional[Dict[str, float]]:
+def get_location() -> Optional[Mapping[str, float]]:
@@
-def geocode(address: Dict[str, str]) -> List[Dict[str, float]]:
+def geocode(address: Mapping[str, str]) -> List[Mapping[str, float]]:
@@
-def reverse_geocode(location: Dict[str, float]) -> List[Dict[str, str]]:
+def reverse_geocode(location: Mapping[str, float]) -> List[Mapping[str, str]]:

If you prefer precision, I can draft TypedDicts for Location/Geocode/Address with optional fields.

Also applies to: 32-41, 70-78

stubs/pythonista_stubs/console.pyi (1)

34-47: Update docstring to reference input (not raw_input)

In Python 3, input superseded raw_input.

-    This function is similar to the built-in raw_input function, but the user’s
+    This function is similar to the built-in input function, but the user’s
stubs/_cb.pyi (1)

57-58: Fix typo in comment for notifying

Minor nit: “of bool” looks accidental.

-    notifying: bool  # of bool
+    notifying: bool
stubs/pythonista_stubs/photos.pyi (1)

181-186: Redundant Union[Optional[…]]

Union[Optional[Asset], Optional[List[Asset]]] expands to Union[Asset, List[Asset], None].
Simplify to improve readability:

-) -> Union[Optional[Asset], Optional[List[Asset]]]:
+) -> Optional[Union[Asset, List[Asset]]]:
stubs/pythonista_stubs/dialogs.pyi (1)

244-250: Avoid mutable default in stub signature

Even in stubs, using a list literal as a default (types: List[str] = ["public.data"]) is frowned upon because it leaks a shared mutable object to type-checkers.

-def pick_document(types: List[str] = ["public.data"]) -> Optional[str]:
+def pick_document(types: List[str] | None = None) -> Optional[str]:

Inside the runtime implementation you’d substitute the default.

stubs/pythonista_stubs/objc_util.pyi (1)

91-97: Default for superclass should be None

Using ... as a default value for a parameter annotated ObjCClass is misleading and forces callers to pass an ObjCClass anyway. A clearer contract is:

-superclass: ObjCClass = ...,
+superclass: ObjCClass | None = None,
stubs/pythonista_stubs/canvas.pyi (1)

194-196: Minor docstring typo

draw_clipboard() docstring is missing a verb:

-"""Draw the image in the clipboard in a given rectangle."""
+"""Draws the image in the clipboard in a given rectangle."""
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1283877 and 5fb7267.

⛔ Files ignored due to path filters (1)
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (37)
  • .github/workflows/ci.yml (1 hunks)
  • .idea/inspectionProfiles/profiles_settings.xml (1 hunks)
  • MANIFEST.in (1 hunks)
  • VERSION (1 hunks)
  • mypy.ini (0 hunks)
  • pyproject.toml (1 hunks)
  • setup.py (1 hunks)
  • stubs/_cb.pyi (1 hunks)
  • stubs/appex/__init__.pyi (0 hunks)
  • stubs/clipboard/__init__.pyi (0 hunks)
  • stubs/console/__init__.pyi (0 hunks)
  • stubs/editor/__init__.py (0 hunks)
  • stubs/pythonista_stubs/__init__.pyi (1 hunks)
  • stubs/pythonista_stubs/appex.pyi (1 hunks)
  • stubs/pythonista_stubs/canvas.pyi (1 hunks)
  • stubs/pythonista_stubs/cb.pyi (1 hunks)
  • stubs/pythonista_stubs/clipboard.pyi (1 hunks)
  • stubs/pythonista_stubs/console.pyi (1 hunks)
  • stubs/pythonista_stubs/contacts.pyi (1 hunks)
  • stubs/pythonista_stubs/dialogs.pyi (1 hunks)
  • stubs/pythonista_stubs/editor.pyi (1 hunks)
  • stubs/pythonista_stubs/keyboard.pyi (1 hunks)
  • stubs/pythonista_stubs/keychain.pyi (1 hunks)
  • stubs/pythonista_stubs/linguistictagger.pyi (1 hunks)
  • stubs/pythonista_stubs/location.pyi (1 hunks)
  • stubs/pythonista_stubs/motion.pyi (1 hunks)
  • stubs/pythonista_stubs/notification.pyi (1 hunks)
  • stubs/pythonista_stubs/objc_util.pyi (1 hunks)
  • stubs/pythonista_stubs/photos.pyi (1 hunks)
  • stubs/pythonista_stubs/reminders.pyi (1 hunks)
  • stubs/pythonista_stubs/shortcuts.pyi (1 hunks)
  • stubs/pythonista_stubs/sound.pyi (1 hunks)
  • stubs/pythonista_stubs/speech.pyi (1 hunks)
  • stubs/pythonista_stubs/ui.py (1 hunks)
  • stubs/reminders/__init__.pyi (0 hunks)
  • stubs/sound/__init__.pyi (0 hunks)
  • stubs/speech/__init__.pyi (0 hunks)
💤 Files with no reviewable changes (8)
  • mypy.ini
  • stubs/speech/init.pyi
  • stubs/reminders/init.pyi
  • stubs/clipboard/init.pyi
  • stubs/console/init.pyi
  • stubs/appex/init.pyi
  • stubs/sound/init.pyi
  • stubs/editor/init.py
🧰 Additional context used
🧬 Code Graph Analysis (10)
stubs/pythonista_stubs/motion.pyi (1)
stubs/pythonista_stubs/location.pyi (2)
  • start_updates (24-26)
  • stop_updates (28-30)
stubs/pythonista_stubs/clipboard.pyi (2)
stubs/pythonista_stubs/appex.pyi (2)
  • Image (10-10)
  • get_image (65-73)
stubs/pythonista_stubs/photos.pyi (2)
  • Image (11-11)
  • get_image (20-22)
stubs/pythonista_stubs/cb.pyi (1)
stubs/_cb.pyi (17)
  • Characteristic (53-57)
  • Service (59-62)
  • Peripheral (64-77)
  • CentralManager (79-101)
  • did_discover_peripheral (87-87)
  • did_connect_peripheral (88-88)
  • did_fail_to_connect_peripheral (89-91)
  • did_disconnect_peripheral (92-94)
  • did_discover_services (95-95)
  • did_discover_characteristics (96-98)
  • did_write_value (99-99)
  • did_update_value (100-100)
  • did_update_state (101-101)
  • scan_for_peripherals (83-83)
  • stop_scan (84-84)
  • connect_peripheral (85-85)
  • cancel_peripheral_connection (86-86)
stubs/pythonista_stubs/appex.pyi (6)
stubs/pythonista_stubs/editor.pyi (2)
  • View (9-9)
  • get_text (19-25)
stubs/pythonista_stubs/ui.py (1)
  • View (4-13)
stubs/pythonista_stubs/dialogs.pyi (1)
  • Image (15-15)
stubs/pythonista_stubs/location.pyi (1)
  • Image (9-9)
stubs/pythonista_stubs/photos.pyi (3)
  • Image (11-11)
  • get_image (20-22)
  • get_image_data (24-26)
stubs/pythonista_stubs/clipboard.pyi (1)
  • get_image (32-46)
stubs/pythonista_stubs/dialogs.pyi (4)
stubs/pythonista_stubs/appex.pyi (1)
  • Image (10-10)
stubs/pythonista_stubs/location.pyi (1)
  • Image (9-9)
stubs/pythonista_stubs/photos.pyi (1)
  • Image (11-11)
stubs/pythonista_stubs/console.pyi (5)
  • alert (57-83)
  • input_alert (85-111)
  • login_alert (141-167)
  • password_alert (113-139)
  • hud_alert (179-191)
stubs/pythonista_stubs/reminders.pyi (1)
stubs/pythonista_stubs/contacts.pyi (1)
  • save (158-160)
stubs/pythonista_stubs/editor.pyi (1)
stubs/pythonista_stubs/ui.py (1)
  • View (4-13)
stubs/pythonista_stubs/location.pyi (5)
stubs/pythonista_stubs/appex.pyi (1)
  • Image (10-10)
stubs/pythonista_stubs/dialogs.pyi (1)
  • Image (15-15)
stubs/pythonista_stubs/photos.pyi (1)
  • Image (11-11)
stubs/pythonista_stubs/motion.pyi (2)
  • start_updates (11-13)
  • stop_updates (15-17)
stubs/pythonista_stubs/contacts.pyi (1)
  • is_authorized (170-172)
stubs/pythonista_stubs/keyboard.pyi (1)
stubs/pythonista_stubs/ui.py (1)
  • View (4-13)
stubs/pythonista_stubs/canvas.pyi (1)
stubs/pythonista_stubs/console.pyi (1)
  • clear (9-11)
🔇 Additional comments (4)
stubs/pythonista_stubs/ui.py (1)

13-13: LGTM: stub formatting change is fine.

Single-line ellipsis for the constructor is clear and consistent with stubs style. No functional/signature change.

stubs/pythonista_stubs/shortcuts.pyi (1)

11-44: Stub looks good

Types and doc-strings are clear, and parameter defaults match real-world usage. Nice work.

.github/workflows/ci.yml (1)

54-55: Guard publishing with a tag instead of event name alone.

github.event_name == 'release' fires for any release action (including edits). Using
if: github.event.action == 'published' (you already filter the workflow trigger) or checking github.ref for a refs/tags/* pattern avoids accidental re-publishes.

stubs/_cb.pyi (1)

65-66: Confirm manufacturer_data nullability

Some peripherals may not include manufacturer data. Consider Optional[bytes] if the runtime can emit None or omit the field.

Please verify via the Pythonista _cb help or quick runtime probe:

import _cb
# After discovering a peripheral without manufacturer data:
# Check attribute value on Peripheral instance:
# print(repr(p.manufacturer_data))  # Is it b'' or None?

If None is possible, update:

-    manufacturer_data: bytes
+    manufacturer_data: Optional[bytes]

Comment thread .github/workflows/ci.yml Outdated
Comment thread MANIFEST.in
Comment thread pyproject.toml
Comment thread pyproject.toml
Comment thread stubs/_cb.pyi
Comment on lines +8 to +10
# These are imported from the `ui` module, which is part of Pythonista.
class Image: ...

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Use the canonical ui.Image type instead of redefining Image locally

Redefining Image here creates inconsistencies across stubs. Import it from the ui stub to keep types unified.

Apply:

-from typing import Dict, List, Optional, Literal
+from typing import Dict, List, Optional, Literal
+from .ui import Image
-
-# These are imported from the `ui` module, which is part of Pythonista.
-class Image: ...
+# Image is provided by the `ui` module.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# These are imported from the `ui` module, which is part of Pythonista.
class Image: ...
from typing import Dict, List, Optional, Literal
from .ui import Image
# Image is provided by the `ui` module.
🤖 Prompt for AI Agents
In stubs/pythonista_stubs/location.pyi around lines 8 to 10, the Image class is
redefined locally which causes inconsistencies. Remove the local Image class
definition and instead import the canonical Image type from the ui module stub
to unify the type usage across stubs.

Comment thread stubs/pythonista_stubs/photos.pyi
Comment thread stubs/pythonista_stubs/photos.pyi
Comment thread stubs/pythonista_stubs/sound.pyi Outdated
Comment thread VERSION

@hbmartin hbmartin left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome stuff 🚀
Take a look at the comments and let me know what you think

Comment thread .github/workflows/ci.yml Outdated
Comment thread MANIFEST.in
Comment thread pyproject.toml
Comment thread pyproject.toml
Comment thread stubs/_cb.pyi
Comment thread stubs/pythonista_stubs/console.pyi
Comment thread stubs/pythonista_stubs/dialogs.pyi Outdated
Comment thread stubs/pythonista_stubs/photos.pyi
Comment thread stubs/pythonista_stubs/photos.pyi
@o-murphy

Copy link
Copy Markdown
Collaborator Author

Awesome stuff 🚀

Take a look at the comments and let me know what you think

I will fix few things I'm agreed with

@o-murphy

Copy link
Copy Markdown
Collaborator Author

Awesome shitt, somehow I deleted changes

@o-murphy o-murphy reopened this Aug 10, 2025
@qodo-code-review

Copy link
Copy Markdown

PR Reviewer Guide 🔍

Here are some key observations to aid the review process:

⏱️ Estimated effort to review: 4 🔵🔵🔵🔵⚪
🧪 No relevant tests
🔒 No security concerns identified
⚡ Recommended focus areas for review

Packaging Behavior

Replacing the previous rich setup configuration with a bare setup() may unintentionally publish an empty or incorrect distribution unless pyproject.toml fully supersedes packaging needs; consider removing setup.py entirely to avoid ambiguity or ensure parity with old metadata.

from setuptools import setup

setup()
Python Version Floor

Raising requires-python to >=3.10 drops support for older Python versions previously targeted (e.g., 3.6); validate this aligns with the stated minimal supported Pythonista version and downstream tooling (mypy types, runtime of stubs consumers).

requires-python = ">=3.10"
dependencies = [
Type Specificity

Several attributes use broad types (e.g., manufacturer_data: bytes non-optional, uuid: str as hex) and some method args lack precise types; verify against actual Pythonista API to ensure optionality and signatures (e.g., write/read characteristic typing, notifying comment).

    manufacturer_data: bytes
    name: Optional[str]
    uuid: str  # hex
    state: int
    services: List[Service]

    def discover_services(self) -> 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: 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) -> None: ...

@qodo-code-review

Copy link
Copy Markdown

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
Possible issue
Fix invalid MANIFEST include

The bare 'include' line is invalid and will cause build errors. Replace it with
explicit include patterns or remove it. Ensure all package data (like py.typed
and nested stubs) are included with correct globs.

MANIFEST.in [1-2]

 include pythonista_stubs/*.pyi
-include
+include stubs/pythonista_stubs/py.typed
+recursive-include stubs/pythonista_stubs *.pyi
  • Apply / Chat
Suggestion importance[1-10]: 8

__

Why: The suggestion correctly identifies that a bare include in MANIFEST.in is invalid and would cause build errors for source distributions, fixing a definite bug.

Medium
General
Align variable type with initialization

Declaring a module-level variable as Optional but initializing it to an instance
is inconsistent and can mislead type checkers. Make the type non-optional to
reflect the actual initialization.

stubs/pythonista_stubs/cb.pyi [80-85]

 class SharedCentralManager(CentralManager):
   delegate: Optional[_CentralManagerDelegate] = None
   verbose: bool = False
-  def verbose_log(self): ...
+  def verbose_log(self) -> None: ...
 
-shared_manager: Optional[SharedCentralManager] = SharedCentralManager()
+shared_manager: SharedCentralManager = SharedCentralManager()

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 5

__

Why: The suggestion correctly points out an inconsistency between the type hint and the initialization of shared_manager, improving type safety and code clarity.

Low
  • More

@qodo-code-review

Copy link
Copy Markdown

PR Reviewer Guide 🔍

Here are some key observations to aid the review process:

⏱️ Estimated effort to review: 3 🔵🔵🔵⚪⚪
🧪 No relevant tests
🔒 No security concerns identified
⚡ Recommended focus areas for review

Packaging Change

The minimal setup() call without metadata may be redundant or misleading now that the project is migrated to pyproject.toml; consider removing setup.py entirely to avoid confusion or ensure it cannot be invoked to produce an unintended distribution.

from setuptools import setup

setup()
Manifest Syntax

MANIFEST.in ends with a bare include directive without a path or pattern, which is invalid and can break source distribution builds; verify and remove or complete this line.

include pythonista_stubs/*.pyi
include
Typing Accuracy

Some attributes like Peripheral.manufacturer_data likely can be absent; consider Optional typing and verify method parameter types (e.g., untyped characteristic, data, with_response) for better static checking and parity with actual API.

    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: 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: Characteristic) -> None: ...

@qodo-code-review

Copy link
Copy Markdown

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
Possible issue
Fix invalid MANIFEST include

The bare 'include' line is invalid and will cause sdist build failures. Remove
it or replace it with an explicit pattern for files you intend to ship (e.g.,
LICENSE, VERSION, py.typed). Ensure stub package markers are included.

MANIFEST.in [1-2]

 include pythonista_stubs/*.pyi
-include
+include stubs/pythonista_stubs/py.typed
+include stubs/py.typed
+include VERSION
+include LICENSE
  • Apply / Chat
Suggestion importance[1-10]: 9

__

Why: The suggestion correctly identifies that a bare include in MANIFEST.in is a syntax error that will break the packaging process, making this a critical fix.

High
General
Align optionality with default value

Annotating a variable as Optional while assigning a non-None default is
contradictory and can mislead type checkers. Align the annotation with the value
by removing Optional, or initialize with None if it can be absent.

stubs/pythonista_stubs/cb.pyi [85]

-shared_manager: Optional[SharedCentralManager] = SharedCentralManager()
+shared_manager: SharedCentralManager = SharedCentralManager()
  • Apply / Chat
Suggestion importance[1-10]: 5

__

Why: The suggestion correctly points out a type hint inconsistency where a variable is declared Optional but assigned a non-None value, improving type safety and clarity.

Low
  • More

@ellipsis-dev ellipsis-dev Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Changes requested ❌

Reviewed everything up to 9e6abdc in 1 minute and 42 seconds. Click for details.
  • Reviewed 3548 lines of code in 43 files
  • Skipped 0 files when reviewing.
  • Skipped posting 5 draft comments. View those below.
  • Modify your settings and rules to customize what types of comments Ellipsis leaves. And don't forget to react with 👍 or 👎 to teach Ellipsis.
1. .idea/misc.xml:6
  • Draft comment:
    The ProjectRootManager configuration still uses 'Python 3.7', which conflicts with the project’s requirement of Python >=3.10 (as specified in pyproject.toml). Consider updating the project JDK version in the IDE settings for consistency.
  • Reason this comment was not posted:
    Comment was on unchanged code.
2. MANIFEST.in:2
  • Draft comment:
    Typographical note: The second line just has "include" and appears incomplete. Please verify if this was intended or if a file pattern is missing.
  • Reason this comment was not posted:
    Marked as duplicate.
3. stubs/_cb.pyi:1
  • Draft comment:
    Minor typographical suggestion: In the header, consider revising the date format to remove the comma after "July" (e.g., "Created on July 07, 2025 by ...").
  • Reason this comment was not posted:
    Decided after close inspection that this draft comment was likely wrong and/or not actionable: usefulness confidence = 10% vs. threshold = 50% This is an extremely minor stylistic suggestion about punctuation in a comment. While technically correct that dates are usually written without that comma, this kind of nitpicking about comment formatting doesn't improve code quality or functionality. The current format is perfectly readable and understandable. The comma removal would make the date format more standard. Header comments are the first thing users see, so maintaining professional formatting could be important. While proper formatting is good, this level of nitpicking about punctuation in comments doesn't meet the bar for a necessary code change and violates the rule about not making purely informative comments. Delete this comment as it's an extremely minor stylistic suggestion about comment formatting that doesn't warrant a code change.
4. stubs/pythonista_stubs/dialogs.pyi:55
  • Draft comment:
    Typographical note: In the docstring for login_alert, the reference to console.password_alert() appears to be swapped. Should this reference be console.login_alert() instead?
  • Reason this comment was not posted:
    Marked as duplicate.
5. stubs/pythonista_stubs/dialogs.pyi:78
  • Draft comment:
    Minor inconsistency: The docstring uses both 'cancelled' and 'canceled' in different parts. Consider making the spelling consistent.
  • Reason this comment was not posted:
    Decided after close inspection that this draft comment was likely wrong and/or not actionable: usefulness confidence = 10% vs. threshold = 50% This is a type stub file whose primary purpose is to provide type hints for static analysis and autocompletion. The spelling inconsistency doesn't affect functionality or type checking. While consistency is good, this is a very minor cosmetic issue that doesn't impact the file's main purpose. The rules say not to make purely informative comments or obvious/unimportant ones. The inconsistency could be confusing to users reading the documentation. Both spellings are technically correct (British vs American English). While both spellings are valid, this cosmetic documentation issue is too minor to warrant a comment in a type stub file review. The focus should be on type correctness and functionality. Delete this comment as it's a minor documentation consistency issue that doesn't affect the primary purpose of type stub files.

Workflow ID: wflow_076PdGcHYM76KBsQ

You can customize Ellipsis by changing your verbosity settings, reacting with 👍 or 👎, replying to comments, or adding code review rules.

Comment thread MANIFEST.in Outdated
Comment thread stubs/_cb.pyi Outdated
Comment thread stubs/pythonista_stubs/dialogs.pyi Outdated
Comment thread stubs/pythonista_stubs/editor.pyi Outdated
@o-murphy o-murphy closed this Aug 10, 2025
@o-murphy o-murphy reopened this Aug 10, 2025
@qodo-code-review

Copy link
Copy Markdown

PR Reviewer Guide 🔍

Here are some key observations to aid the review process:

⏱️ Estimated effort to review: 4 🔵🔵🔵🔵⚪
🧪 No relevant tests
🔒 No security concerns identified
⚡ Recommended focus areas for review

Type Accuracy

Several attributes in the BLE stubs are typed too strictly or with minor inaccuracies (e.g., manufacturer_data: bytes could be optional; comments like "of bool"), and parameter types like write_characteristic_value(self, characteristic, data, with_response) lack annotations. Verify against Pythonista's actual _cb API to ensure correct Optional usage and argument typing.

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: 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: 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) -> None: ...
Fallback Typing

The conditional import for PIL assigns PilImage: Any on ImportError, which can shadow the imported type and weaken type checking. Consider using a typing.TYPE_CHECKING guard or if typing.TYPE_CHECKING import with a Protocol to retain type safety.

try:
    from PIL.Image import Image as PilImage
except ImportError:
    PilImage: Any  # type: ignore[no-redef]
Package Data Inclusion

The combination of package-dir, packages.find where=["stubs"], and package-data as "*": ["**/*"] may include unintended files (e.g., .idea) or miss top-level .pyi if layout changes. Validate sdist/wheel contents and ensure only intended stubs are packaged; consider explicit include/exclude.

[tool.setuptools.package-dir]
"pythonista_stubs" = "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",
]

@ellipsis-dev ellipsis-dev Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Changes requested ❌

Reviewed everything up to 52858ce in 1 minute and 30 seconds. Click for details.
  • Reviewed 3548 lines of code in 43 files
  • Skipped 0 files when reviewing.
  • Skipped posting 6 draft comments. View those below.
  • Modify your settings and rules to customize what types of comments Ellipsis leaves. And don't forget to react with 👍 or 👎 to teach Ellipsis.
1. stubs/_cb.pyi:1
  • Draft comment:
    The header states 'Created on July, 07 2025' – please verify if this future date is intentional or a typo.
  • Reason this comment was not posted:
    Decided after close inspection that this draft comment was likely wrong and/or not actionable: usefulness confidence = 10% vs. threshold = 50% According to the rules, we should not ask authors to verify or confirm things. The date, while unusual, is just metadata in a comment and doesn't affect the actual code functionality. This is not a critical issue requiring code changes. The rules specifically say not to make comments that start with "verify that..." which this does. The future date could indicate confusion or a mistake that might affect documentation accuracy. Documentation correctness could be important for maintainability. While documentation accuracy is good, this is just a metadata comment that doesn't affect code functionality. The rules explicitly state not to ask for verifications or make purely informative comments. Delete the comment as it violates the rule against asking for verification and doesn't require any actual code changes.
2. pyproject.toml:46
  • Draft comment:
    The package configuration maps 'pythonista_stubs' to the 'stubs' directory. Please ensure that all stub files are correctly located so that they are discovered by the package finder.
  • Reason this comment was not posted:
    Comment did not seem useful. Confidence is useful = 0% <= threshold 50% This comment is asking the PR author to ensure that stub files are correctly located, which falls under the rule of not asking the author to ensure or verify things. It doesn't provide a specific suggestion or point out a specific issue with the code.
3. setup.py:1
  • Draft comment:
    The minimal setup.py (just 'setup()') is acceptable given the move to pyproject.toml, but consider adding a brief comment noting its purpose for backwards compatibility.
  • Reason this comment was not posted:
    Comment did not seem useful. Confidence is useful = 30% <= threshold 50% The comment is suggesting adding a comment for clarity, which is not strictly necessary for functionality or correctness. It doesn't ask for a specific code change or test, and it doesn't point out a potential issue with the code. Therefore, it seems to be more of an informative suggestion rather than a necessary action.
4. stubs/pythonista_stubs/__init__.pyi:1
  • Draft comment:
    Currently, this file only annotates version; adding a module docstring could improve readability and clarify the module’s purpose.
  • Reason this comment was not posted:
    Comment was on unchanged code.
5. stubs/pythonista_stubs/console.pyi:186
  • Draft comment:
    Typographical error: In the hud_alert docstring, consider changing "It Can be 'success'" to "It can be 'success'" (with a lowercase 'c').
  • Reason this comment was not posted:
    Decided after close inspection that this draft comment was likely wrong and/or not actionable: usefulness confidence = 10% vs. threshold = 50% While this is technically correct and the file is new, docstring capitalization issues are very minor and don't affect functionality. The comment is about a purely cosmetic issue. According to the rules, we should not make purely informative comments or comments about obvious/unimportant issues. The file is new so all content is technically "changed". And consistent capitalization could be considered part of code quality. While consistency is good, this is too minor of an issue to warrant a PR comment. It doesn't affect functionality or readability significantly. Delete this comment as it addresses a trivial capitalization issue that doesn't meaningfully impact code quality or functionality.
6. stubs/pythonista_stubs/console.pyi:188
  • Draft comment:
    Typographical error: In the hud_alert docstring, change "It Can be between 0.25 and 5.0 seconds" to "It can be between 0.25 and 5.0 seconds" (use lowercase 'c').
  • Reason this comment was not posted:
    Decided after close inspection that this draft comment was likely wrong and/or not actionable: usefulness confidence = 10% vs. threshold = 50% While this is technically correct and the file is new, this is an extremely minor stylistic issue in a docstring. It doesn't affect functionality, code quality, or even documentation clarity. The rules state not to make comments that are obvious or unimportant. This seems to fall into that category. The capitalization inconsistency could be seen as unprofessional in documentation. Multiple instances of the same error might indicate a pattern worth fixing. While consistency is good, this is too minor of an issue to warrant a PR comment. Documentation polish can be handled through other means. Delete this comment as it's too minor and doesn't materially improve the code or documentation quality enough to warrant a PR comment.

Workflow ID: wflow_j05XrjItozZPKsTF

You can customize Ellipsis by changing your verbosity settings, reacting with 👍 or 👎, replying to comments, or adding code review rules.

Comment thread stubs/pythonista_stubs/editor.pyi Outdated
@qodo-code-review

Copy link
Copy Markdown

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
High-level
Packaging and CI misalignment

The pyproject declares Python >=3.10 and uses uv sync --locked, but there is no
committed lockfile (uv.lock) and the stubs target Pythonista 3.4, which embeds
Python 3.10/3.11 depending on device; this risks CI nondeterminism and excludes
users on older Pythonista minor versions. Either commit a lockfile or drop
--locked, and clearly align the required Python version and dependency pins with
the actual Pythonista runtime(s) you intend to support to avoid
installation/typing incompatibilities.

Examples:

.github/workflows/ci.yml [21]
run: uv sync --locked --all-extras --dev
pyproject.toml [13]
requires-python = ">=3.10"

Solution Walkthrough:

Before:

# .github/workflows/ci.yml
...
steps:
  - uses: actions/checkout@v4
  - uses: astral-sh/setup-uv@v5
  - run: uv sync --locked --all-extras --dev
  - run: uv run ruff check
  - run: uv run mypy

# pyproject.toml
requires-python = ">=3.10"
# No uv.lock file is committed

After:

# .github/workflows/ci.yml
...
steps:
  - uses: actions/checkout@v4
  - uses: astral-sh/setup-uv@v5
  # Option 1 (recommended): Use the lock file
  - run: uv sync --locked --all-extras --dev
  # Option 2: Remove --locked if no lock file is intended
  # - run: uv sync --all-extras --dev
  ...

# pyproject.toml
requires-python = ">=3.10, <3.12" # Or align with supported Pythonista versions

# A uv.lock file should be generated and committed to the repository
Suggestion importance[1-10]: 9

__

Why: This suggestion correctly identifies a critical flaw in the CI configuration (uv sync --locked without a lockfile) which will cause workflows to fail, and it raises an important point about aligning the project's supported Python versions with its target environment (Pythonista).

High
General
Enforce format and scope type check

The ruff step only runs lint, but your pyproject uses ruff as a linter, not
formatter. Add a format check to catch formatting violations in CI. Also, mypy
is invoked without paths and may scan the whole repo unintentionally; restrict
it to the stubs package for consistent results.

.github/workflows/ci.yml [10-27]

 jobs:
   testing:
     runs-on: ubuntu-latest
 
     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: Check code formatting with ruff
+      - name: Lint with ruff
         run: uv run ruff check
 
+      - name: Check formatting with ruff
+        run: uv run ruff format --check
+
       - name: Type check with mypy
-        run: uv run mypy
+        run: uv run mypy stubs
  • Apply / Chat
Suggestion importance[1-10]: 7

__

Why: The suggestion correctly identifies that the CI is missing a format check and adds ruff format --check, which improves code quality enforcement.

Medium
Target mypy to paths explicitly

Using the 'packages' option with mypy expects importable packages, but your
stubs live under a directory that isn't necessarily a Python package root.
Switch to 'files' to explicitly point to paths, avoiding mypy skipping checks or
mis-discovering modules.

pyproject.toml [67-69]

 [tool.mypy]
-packages = ["stubs"]
+files = ["stubs"]
 ignore_missing_imports = true
  • Apply / Chat
Suggestion importance[1-10]: 6

__

Why: The suggestion correctly points out that using files instead of packages is more appropriate for mypy when checking a directory of stub files, improving configuration clarity and robustness.

Low
Possible issue
Fix mismatched Optional annotation

Declaring shared_manager as Optional but initializing it to an instance makes
types inconsistent and forces unnecessary Optional handling by users. Align the
annotation with the actual value to prevent type confusion in consumers.

stubs/pythonista_stubs/cb.pyi [80-94]

 class SharedCentralManager(CentralManager):
   delegate: Optional[_CentralManagerDelegate] = None
   verbose: bool = False
-  def verbose_log(self): ...
+  def verbose_log(self) -> None: ...
 
-shared_manager: Optional[SharedCentralManager] = SharedCentralManager()
+shared_manager: 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: ...

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 7

__

Why: The suggestion correctly identifies that shared_manager is always initialized, so removing the Optional from its type hint makes the type annotation more accurate and improves type safety for consumers.

Medium
  • More

@o-murphy

Copy link
Copy Markdown
Collaborator Author

My VCS was broken. Now looks ok. I think it's done

@o-murphy
o-murphy requested a review from hbmartin August 10, 2025 21:30
@o-murphy o-murphy linked an issue Aug 10, 2025 that may be closed by this pull request

@hbmartin hbmartin left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:shipit:

@hbmartin
hbmartin merged commit 271b53c into hbmartin:master Aug 11, 2025
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Some mypy compatible stubs

2 participants