Skip to content

mv ui.py -> ui.pyi, use PIL stubs in photos.pyi, update README - #10

Merged
hbmartin merged 5 commits into
masterfrom
hm/3.4-release-prep
Aug 12, 2025
Merged

mv ui.py -> ui.pyi, use PIL stubs in photos.pyi, update README#10
hbmartin merged 5 commits into
masterfrom
hm/3.4-release-prep

Conversation

@hbmartin

@hbmartin hbmartin commented Aug 11, 2025

Copy link
Copy Markdown
Owner

There are a whole bunch of ruff formatting auto fixes I will commit separately (either here or in a new PR) since they are a large volume of trivial changes.

PR Type

Documentation, Enhancement


Description

  • Add Python Software Foundation Code of Conduct

  • Update README with improved badges and coverage status

  • Rename ui.py to ui.pyi for proper stub typing

  • Update photos module to use proper PIL and UI imports


Diagram Walkthrough

flowchart LR
  A["Code of Conduct"] --> B["Documentation Updates"]
  B --> C["Type Stub Improvements"]
  C --> D["Import Fixes"]
Loading

File Walkthrough

Relevant files
Documentation
CODE_OF_CONDUCT.md
Add Python Software Foundation Code of Conduct                     

CODE_OF_CONDUCT.md

  • Add complete Python Software Foundation Code of Conduct
  • Include community standards and enforcement procedures
  • Define scope for PSF events and online spaces
  • Provide contact information for incident reporting
+166/-0 
README.md
Update badges, installation, and API coverage                       

README.md

  • Replace Travis CI badge with GitHub Actions CI badge
  • Add Ruff linting badge and update installation to use uv
  • Update API coverage table with current module status
  • Remove detailed IDE integration section and code formatting details
+19/-39 
Configuration changes
pyproject.toml
Update project metadata and linting configuration               

pyproject.toml

  • Add email to Harold Martin's author information
  • Update Ruff configuration with comprehensive linting rules
  • Set Python 3.11 as target version and configure line length
+8/-6     
Enhancement
photos.pyi
Fix imports and modernize type hints                                         

stubs/pythonista_stubs/photos.pyi

  • Replace generic Image and ui_Image classes with proper PIL and UI
    imports
  • Update type hints to use PILImage and UIImage from actual modules
  • Change Tuple to tuple for modern Python typing syntax
+9/-9     


Important

Renamed ui.py to ui.pyi, updated photos.pyi imports, and enhanced documentation and configuration for type hinting and development tools.

  • Type Hinting and Stubs:
    • Renamed ui.py to ui.pyi for improved type hinting.
    • Updated photos.pyi to use proper PIL and UI imports.
  • Documentation:
    • Added CODE_OF_CONDUCT.md with Python Software Foundation Code of Conduct.
    • Updated README.md with new badges and coverage status.
  • Configuration:
    • Updated pyproject.toml to include black, mypy, and ruff in dev dependencies.
    • Updated uv.lock to reflect new package versions and dependencies.

This description was created by Ellipsis for d1166db. You can customize this summary. It will automatically update as commits are pushed.


Summary by CodeRabbit

  • New Features

    • Modernized typing across stubs for better editor hints and Python 3.10+ style.
    • Expanded Photos API: richer image types, asset editing/deletion, data access, and album helpers.
    • Added location helpers (start updates, authorization check) and richer UI surface (Image and View).
    • Improved Objective‑C interop with container semantics, typed structs, and convenience constructors.
  • Documentation

    • Added a CODE OF CONDUCT; README streamlined (badges, install instructions, API coverage, added author).
  • Chores

    • Tooling updates: Ruff reconfiguration, Black added, CI now checks Black formatting, author metadata updated.

@hbmartin
hbmartin requested a review from o-murphy August 11, 2025 12:59
@sourcery-ai

sourcery-ai Bot commented Aug 11, 2025

Copy link
Copy Markdown

Reviewer's Guide

This PR modernizes project documentation and configuration by overhauling the README, enhancing type stubs for photos with PIL and ui imports, configuring Ruff in pyproject.toml, and introducing a Code of Conduct file.

Class diagram for updated Asset class in photos.pyi

classDiagram
    class Asset {
        +get_image(original: bool = False) : PILImage
        +get_ui_image(size: Optional[tuple[int, int]] = None, crop: bool = False) : UIImage
    }
    PILImage <.. Asset : uses
    UIImage <.. Asset : uses
Loading

File-Level Changes

Change Details Files
Revamped README with updated badges, install workflow, and API status table
  • Replaced pip install instruction with ‘uv add’ and refreshed usage text
  • Swapped GitHub issues and Travis badges for Ruff and GitHub Actions badges
  • Updated API coverage table statuses and linked WIP items
  • Removed outdated editor integration and formatting sections
README.md
Improved photos.pyi type stubs using PIL and ui imports
  • Imported PILImage and UIImage instead of generic Image and ui_Image
  • Replaced List/Optional/Tuple typing with built-in tuple syntax and Sequence
  • Adjusted return annotations to PILImage and UIImage
  • Deleted unused typing imports
stubs/pythonista_stubs/photos.pyi
Enhanced pyproject.toml with author metadata and Ruff configuration
  • Added email for existing author and included new author entry
  • Defined Ruff settings: line-length, indent-width, target-version
  • Configured lint.select and lint.ignore rules
  • Removed old Ruff include list
pyproject.toml
Added a new Code of Conduct document
  • Introduced COMMUNITY guidelines based on Python Software Foundation template
  • Committed CODE_OF_CONDUCT.md at project root
CODE_OF_CONDUCT.md

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 11, 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.

Walkthrough

Adds a PSF Code of Conduct; updates README and project metadata/tooling; introduces Black in CI and Ruff reconfiguration; modernizes many Pythonista type stubs (appex, dialogs, location, photos, objc_util, ui), replacing legacy typing with modern builtins, unions, TypeAlias, overloads and adding new API surface elements.

Changes

Cohort / File(s) Summary of Changes
Policy & Docs
CODE_OF_CONDUCT.md, README.md
Add PSF Code of Conduct; update README badges, installation/usage text, API-coverage statuses, contributing notes, and add a new author.
Project Config & CI
pyproject.toml, .github/workflows/ci.yml, setup.py
Add author email; remove [project.optional-dependencies]; add black>=25.1.0 to dev group; replace Ruff include with explicit [tool.ruff] settings and per-file ignores; add Black check step to CI; add # noqa: D100 to setup.py.
UI API Restructure
stubs/pythonista_stubs/ui.py, stubs/pythonista_stubs/ui.pyi
Remove old ui.py View stub; add new ui.pyi exposing Image, View, and _RenderingMode with modern typed methods and properties.
Typing Modernization — appex
stubs/pythonista_stubs/appex.pyi
Modernize to built-in generics and PEP 604 unions; add _ImageType: TypeAlias, PILImage/UIImage/View aliases; add is_running_extension(); add overloads and tighten many function signatures and return types.
Typing Modernization — dialogs
stubs/pythonista_stubs/dialogs.pyi
Adopt Protocol/TypeAlias/TypeVar; make list_dialog generic; replace typing generics with builtins and `
Location API Updates
stubs/pythonista_stubs/location.pyi
Modernize types (builtins and `
Photos API Modernization & Additions
stubs/pythonista_stubs/photos.pyi
Introduce PILImage/UIImage aliases; modernize types and TypeAlias usage; change Asset/AssetCollection signatures/properties (add get_image_data, edit_content, modification_date, hidden, delete); add album helpers and overloads for pick_asset; update capture/get/batch APIs.
ObjC Interop Enhancements
stubs/pythonista_stubs/objc_util.pyi
Expand typing surface: container methods on ObjCInstance, stricter ObjCBlock typing, autoreleasepool()AbstractContextManager, overloaded ns, selctypes.c_void_p, add ctypes.Structure types (CGPoint, CGSize, CGRect, etc.), new ObjC wrapper classes and convenience constructors.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested labels

Review effort 4/5

Poem

In a burrow of bytes I nibble and hop,
Stubs wake to new types from bottom to top.
Views and images, albums and maps,
Signatures sharpen — no more old gaps.
I twitch my whiskers: hop, hop, hooray! 🐇✨


📜 Recent review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between cf944e1 and d1166db.

📒 Files selected for processing (3)
  • stubs/pythonista_stubs/appex.pyi (2 hunks)
  • stubs/pythonista_stubs/dialogs.pyi (15 hunks)
  • stubs/pythonista_stubs/photos.pyi (8 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (3)
stubs/pythonista_stubs/dialogs.pyi (2)
stubs/pythonista_stubs/ui.pyi (1)
  • Image (5-119)
stubs/pythonista_stubs/console.pyi (1)
  • alert (57-83)
stubs/pythonista_stubs/appex.pyi (4)
stubs/pythonista_stubs/ui.pyi (2)
  • Image (5-119)
  • View (121-130)
stubs/pythonista_stubs/editor.pyi (2)
  • View (9-9)
  • get_text (19-25)
stubs/pythonista_stubs/photos.pyi (2)
  • get_image (19-21)
  • get_image_data (23-25)
stubs/pythonista_stubs/clipboard.pyi (1)
  • get_image (32-46)
stubs/pythonista_stubs/photos.pyi (2)
stubs/pythonista_stubs/ui.pyi (2)
  • Image (5-119)
  • size (39-41)
stubs/pythonista_stubs/appex.pyi (4)
  • get_image (75-75)
  • get_image (77-77)
  • get_image (79-79)
  • get_image (80-91)
🔇 Additional comments (3)
stubs/pythonista_stubs/appex.pyi (2)

55-72: Excellent use of overloads for image type precision!

The overloaded signatures for get_images correctly express that the return type depends on the image_type parameter, providing better type safety and IDE support.


74-91: Well-structured overloads for get_image

The overloaded signatures properly handle both "pil" and "ui" image types, ensuring type-safe returns based on the input parameter.

stubs/pythonista_stubs/photos.pyi (1)

194-212: Good implementation of overloads for pick_asset

The overloaded signatures correctly express that when multi=True, the function returns a list of assets, and when multi=False, it returns a single asset. This provides better type precision for users of the API.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch hm/3.4-release-prep

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.
    • 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.
  • 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 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/Issue comments)

Type @coderabbitai help to get the list of available commands.

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

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • 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 @hbmartin, 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 focused on enhancing the project's foundational elements. This includes refining type stub definitions for better code analysis, modernizing the project's documentation and build configurations, and formally establishing a Code of Conduct to ensure a positive and inclusive development environment. These changes aim to improve maintainability, developer experience, and community engagement.

Highlights

  • Improved Type Stub Accuracy: I've updated the photos.pyi stub file to correctly utilize type hints from the PIL (Pillow) library and the ui module, ensuring more accurate type checking for image-related operations.
  • Community Guidelines: I've added a comprehensive CODE_OF_CONDUCT.md file, adopting the Python Software Foundation's guidelines to foster a welcoming and inclusive community environment.
  • Documentation and Build Tooling Updates: I've modernized the project's README.md to reflect current best practices, including updated badges, a switch to uv add for installation, and a clearer overview of API coverage. I also updated pyproject.toml to refine Ruff linting configurations.
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: 2 🔵🔵⚪⚪⚪
🧪 No relevant tests
🔒 No security concerns identified
⚡ Recommended focus areas for review

Import Stability

Using 'from ui import Image as UIImage' in a stub ties the typing to a concrete runtime import; ensure this module name is correct in consuming environments and that the stub package layout exposes 'ui.Image' to avoid ImportError during type checking or when editors resolve symbols.

from PIL.Image import Image as PILImage
from ui import Image as UIImage
Type Consistency

The docstrings reference 'ui.Image' while the return type is aliased as 'UIImage'; verify consistency across stubs and docs so downstream tools don’t display mixed type names.

def get_ui_image(
    self, size: Optional[tuple[int, int]] = None, crop: bool = False
) -> UIImage:
    """
    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:
        UIImage: The asset's image data as a ui.Image object.
    """

@qodo-code-review

Copy link
Copy Markdown

CI Feedback 🧐

A test triggered by this PR failed. Here is an AI-generated analysis of the failure:

Action: testing

Failed stage: Check code formatting with ruff [❌]

Failure summary:

The action failed because code style and typing lint checks reported numerous violations in stub
files, causing the linter to exit with a non-zero status.
Key issues reported (with file/line
references) include:
- COM812: Trailing comma missing in parameter lists (e.g., stubs/_cb.pyi:77:50,
stubs/_cb.pyi:92:50, stubs/pythonista_stubs/cb.pyi:70:50).
- UP045: Use X | None instead of
Optional[X] in type annotations (e.g., stubs/_cb.pyi:92:37, stubs/_cb.pyi:95:37,
stubs/pythonista_stubs/cb.pyi:67:37).
- RUF022: all not sorted isort-style (e.g., lines 55–61,
marker at line 61).
- D413/D411: Missing required blank lines around docstring sections like "Args",
"Returns", and "Raises" (e.g., stubs/pythonista_stubs/console.pyi:164:5,
stubs/pythonista_stubs/editor.pyi:114:5, stubs/pythonista_stubs/speech.pyi:49:5).
- PYI026: Use
typing.TypeAlias for type aliases (e.g., stubs/pythonista_stubs/console.pyi:177:1,
stubs/pythonista_stubs/editor.pyi:121:1).
- UP006: Replace Tuple[...] with tuple[...] (e.g.,
stubs/pythonista_stubs/ui.pyi:10:, column 45).
The run ended with "Found 582 errors. [*] 480 fixable
with the --fix option" and then exited with code 1, causing the GitHub Action to fail.

Relevant error logs:
1:  ##[group]Runner Image Provisioner
2:  Hosted Compute Agent
...

324:  79 |     def read_characteristic_value(self, characteristic: Characteristic) -> None: ...
325:  |
326:  stubs/_cb.pyi:77:50: COM812 [*] Trailing comma missing
327:  |
328:  75 |     ) -> None: ...
329:  76 |     def write_characteristic_value(
330:  77 |         self, characteristic, data, with_response
331:  |                                                  ^ COM812
332:  78 |     ) -> None: ...
333:  79 |     def read_characteristic_value(self, characteristic: Characteristic) -> None: ...
334:  |
335:  = help: Add trailing comma
336:  stubs/_cb.pyi:92:37: UP045 [*] Use `X | None` for type annotations
337:  |
338:  90 |     def did_connect_peripheral(self, p: Peripheral) -> None: ...
339:  91 |     def did_fail_to_connect_peripheral(
340:  92 |         self, p: Peripheral, error: Optional[str]
341:  |                                     ^^^^^^^^^^^^^ UP045
342:  93 |     ) -> None: ...
343:  94 |     def did_disconnect_peripheral(
344:  |
345:  = help: Convert to `X | None`
346:  stubs/_cb.pyi:92:50: COM812 [*] Trailing comma missing
347:  |
348:  90 |     def did_connect_peripheral(self, p: Peripheral) -> None: ...
349:  91 |     def did_fail_to_connect_peripheral(
350:  92 |         self, p: Peripheral, error: Optional[str]
351:  |                                                  ^ COM812
352:  93 |     ) -> None: ...
353:  94 |     def did_disconnect_peripheral(
354:  |
355:  = help: Add trailing comma
356:  stubs/_cb.pyi:95:37: UP045 [*] Use `X | None` for type annotations
357:  |
358:  93 |     ) -> None: ...
359:  94 |     def did_disconnect_peripheral(
360:  95 |         self, p: Peripheral, error: Optional[str]
361:  |                                     ^^^^^^^^^^^^^ UP045
362:  96 |     ) -> None: ...
363:  97 |     def did_discover_services(self, p: Peripheral, error: Optional[str]) -> None: ...
364:  |
365:  = help: Convert to `X | None`
366:  stubs/_cb.pyi:95:50: COM812 [*] Trailing comma missing
367:  |
368:  93 |     ) -> None: ...
369:  94 |     def did_disconnect_peripheral(
370:  95 |         self, p: Peripheral, error: Optional[str]
371:  |                                                  ^ COM812
372:  96 |     ) -> None: ...
373:  97 |     def did_discover_services(self, p: Peripheral, error: Optional[str]) -> None: ...
374:  |
375:  = help: Add trailing comma
376:  stubs/_cb.pyi:97:59: UP045 [*] Use `X | None` for type annotations
377:  |
378:  95 |         self, p: Peripheral, error: Optional[str]
379:  96 |     ) -> None: ...
380:  97 |     def did_discover_services(self, p: Peripheral, error: Optional[str]) -> None: ...
381:  |                                                           ^^^^^^^^^^^^^ UP045
382:  98 |     def did_discover_characteristics(
383:  99 |         self, s: Service, error: Optional[str]
384:  |
385:  = help: Convert to `X | None`
386:  stubs/_cb.pyi:99:34: UP045 [*] Use `X | None` for type annotations
387:  |
388:  97 |     def did_discover_services(self, p: Peripheral, error: Optional[str]) -> None: ...
389:  98 |     def did_discover_characteristics(
390:  99 |         self, s: Service, error: Optional[str]
391:  |                                  ^^^^^^^^^^^^^ UP045
392:  100 |     ) -> None: ...
393:  101 |     def did_write_value(self, c: Characteristic, error: Optional[str]) -> None: ...
394:  |
395:  = help: Convert to `X | None`
396:  stubs/_cb.pyi:99:47: COM812 [*] Trailing comma missing
397:  |
398:  97 |     def did_discover_services(self, p: Peripheral, error: Optional[str]) -> None: ...
399:  98 |     def did_discover_characteristics(
400:  99 |         self, s: Service, error: Optional[str]
401:  |                                               ^ COM812
402:  100 |     ) -> None: ...
403:  101 |     def did_write_value(self, c: Characteristic, error: Optional[str]) -> None: ...
404:  |
405:  = help: Add trailing comma
406:  stubs/_cb.pyi:101:57: UP045 [*] Use `X | None` for type annotations
407:  |
408:  99 |         self, s: Service, error: Optional[str]
409:  100 |     ) -> None: ...
410:  101 |     def did_write_value(self, c: Characteristic, error: Optional[str]) -> None: ...
411:  |                                                         ^^^^^^^^^^^^^ UP045
412:  102 |     def did_update_value(self, c: Characteristic, error: Optional[str]) -> None: ...
413:  103 |     def did_update_state(self) -> None: ...
414:  |
415:  = help: Convert to `X | None`
416:  stubs/_cb.pyi:102:58: UP045 [*] Use `X | None` for type annotations
417:  |
418:  100 |     ) -> None: ...
419:  101 |     def did_write_value(self, c: Characteristic, error: Optional[str]) -> None: ...
420:  102 |     def did_update_value(self, c: Characteristic, error: Optional[str]) -> None: ...
421:  |                                                          ^^^^^^^^^^^^^ UP045
...

1278:  55 | |     "scan_for_peripherals",
1279:  56 | |     "stop_scan",
1280:  57 | |     "connect_peripheral",
1281:  58 | |     "cancel_peripheral_connection",
1282:  59 | |     "get_state",
1283:  60 | |     "reset",
1284:  61 | | )
1285:  | |_^ RUF022
1286:  62 |
1287:  63 |   class _CentralManagerDelegate(Protocol):
1288:  |
1289:  = help: Apply an isort-style sorting to `__all__`
1290:  stubs/pythonista_stubs/cb.pyi:67:37: UP045 [*] Use `X | None` for type annotations
1291:  |
1292:  65 |     def did_connect_peripheral(self, p: Peripheral) -> None: ...
1293:  66 |     def did_fail_to_connect_peripheral(
1294:  67 |         self, p: Peripheral, error: Optional[str]
1295:  |                                     ^^^^^^^^^^^^^ UP045
1296:  68 |     ) -> None: ...
1297:  69 |     def did_disconnect_peripheral(
1298:  |
1299:  = help: Convert to `X | None`
1300:  stubs/pythonista_stubs/cb.pyi:67:50: COM812 [*] Trailing comma missing
1301:  |
1302:  65 |     def did_connect_peripheral(self, p: Peripheral) -> None: ...
1303:  66 |     def did_fail_to_connect_peripheral(
1304:  67 |         self, p: Peripheral, error: Optional[str]
1305:  |                                                  ^ COM812
1306:  68 |     ) -> None: ...
1307:  69 |     def did_disconnect_peripheral(
1308:  |
1309:  = help: Add trailing comma
1310:  stubs/pythonista_stubs/cb.pyi:70:37: UP045 [*] Use `X | None` for type annotations
1311:  |
1312:  68 |     ) -> None: ...
1313:  69 |     def did_disconnect_peripheral(
1314:  70 |         self, p: Peripheral, error: Optional[str]
1315:  |                                     ^^^^^^^^^^^^^ UP045
1316:  71 |     ) -> None: ...
1317:  72 |     def did_discover_services(self, p: Peripheral, error: Optional[str]) -> None: ...
1318:  |
1319:  = help: Convert to `X | None`
1320:  stubs/pythonista_stubs/cb.pyi:70:50: COM812 [*] Trailing comma missing
1321:  |
1322:  68 |     ) -> None: ...
1323:  69 |     def did_disconnect_peripheral(
1324:  70 |         self, p: Peripheral, error: Optional[str]
1325:  |                                                  ^ COM812
1326:  71 |     ) -> None: ...
1327:  72 |     def did_discover_services(self, p: Peripheral, error: Optional[str]) -> None: ...
1328:  |
1329:  = help: Add trailing comma
1330:  stubs/pythonista_stubs/cb.pyi:72:59: UP045 [*] Use `X | None` for type annotations
1331:  |
1332:  70 |         self, p: Peripheral, error: Optional[str]
1333:  71 |     ) -> None: ...
1334:  72 |     def did_discover_services(self, p: Peripheral, error: Optional[str]) -> None: ...
1335:  |                                                           ^^^^^^^^^^^^^ UP045
1336:  73 |     def did_discover_characteristics(
1337:  74 |         self, s: Service, error: Optional[str]
1338:  |
1339:  = help: Convert to `X | None`
1340:  stubs/pythonista_stubs/cb.pyi:74:34: UP045 [*] Use `X | None` for type annotations
1341:  |
1342:  72 |     def did_discover_services(self, p: Peripheral, error: Optional[str]) -> None: ...
1343:  73 |     def did_discover_characteristics(
1344:  74 |         self, s: Service, error: Optional[str]
1345:  |                                  ^^^^^^^^^^^^^ UP045
1346:  75 |     ) -> None: ...
1347:  76 |     def did_write_value(self, c: Characteristic, error: Optional[str]) -> None: ...
1348:  |
1349:  = help: Convert to `X | None`
1350:  stubs/pythonista_stubs/cb.pyi:74:47: COM812 [*] Trailing comma missing
1351:  |
1352:  72 |     def did_discover_services(self, p: Peripheral, error: Optional[str]) -> None: ...
1353:  73 |     def did_discover_characteristics(
1354:  74 |         self, s: Service, error: Optional[str]
1355:  |                                               ^ COM812
1356:  75 |     ) -> None: ...
1357:  76 |     def did_write_value(self, c: Characteristic, error: Optional[str]) -> None: ...
1358:  |
1359:  = help: Add trailing comma
1360:  stubs/pythonista_stubs/cb.pyi:76:57: UP045 [*] Use `X | None` for type annotations
1361:  |
1362:  74 |         self, s: Service, error: Optional[str]
1363:  75 |     ) -> None: ...
1364:  76 |     def did_write_value(self, c: Characteristic, error: Optional[str]) -> None: ...
1365:  |                                                         ^^^^^^^^^^^^^ UP045
1366:  77 |     def did_update_value(self, c: Characteristic, error: Optional[str]) -> None: ...
1367:  78 |     def did_update_state(self) -> None: ...
1368:  |
1369:  = help: Convert to `X | None`
1370:  stubs/pythonista_stubs/cb.pyi:77:58: UP045 [*] Use `X | None` for type annotations
1371:  |
1372:  75 |     ) -> None: ...
1373:  76 |     def did_write_value(self, c: Characteristic, error: Optional[str]) -> None: ...
1374:  77 |     def did_update_value(self, c: Characteristic, error: Optional[str]) -> None: ...
1375:  |                                                          ^^^^^^^^^^^^^ UP045
...

1790:  150 |     The text fields can be pre-filled with the `login` and `password` parameters.
1791:  151 |     Returns a tuple of the entered text as `(login, password)`. The ‘Cancel’
1792:  |                                                                            ^ RUF002
1793:  152 |     button sends a KeyboardInterrupt.
1794:  |
1795:  stubs/pythonista_stubs/console.pyi:164:5: D413 [*] Missing blank line after last section ("Returns")
1796:  |
1797:  162 |             Defaults to "OK".
1798:  163 |
1799:  164 |     Returns:
1800:  |     ^^^^^^^ D413
1801:  165 |         Tuple[str, str]: A tuple containing the entered login and password.
1802:  166 |     """
1803:  |
1804:  = help: Add blank line after "Returns"
1805:  stubs/pythonista_stubs/console.pyi:177:1: PYI026 [*] Use `typing.TypeAlias` for type alias, e.g., `_HudIcon: TypeAlias = Literal["success", "error"]`
1806:  |
1807:  175 |     ...
1808:  176 |
1809:  177 | _HudIcon = Literal["success", "error"]
1810:  | ^^^^^^^^ PYI026
...

3064:  107 |
3065:  108 | def present_themed(ui_view: View, theme_name: Optional[str] = None, **kwargs) -> None:
3066:  |                                                                     ^^^^^^^^ ANN003
3067:  109 |     """Styles a ui.View and presents it.
3068:  |
3069:  stubs/pythonista_stubs/editor.pyi:114:5: D413 [*] Missing blank line after last section ("Args")
3070:  |
3071:  112 |     Keyword arguments are passed on to `ui.View.present()`.
3072:  113 |
3073:  114 |     Args:
3074:  |     ^^^^ D413
3075:  115 |         ui_view (ui.View): The view to be styled and presented.
3076:  116 |         theme_name (Optional[str], optional): The name of the theme. If None,
3077:  |
3078:  = help: Add blank line after "Args"
3079:  stubs/pythonista_stubs/editor.pyi:121:1: PYI026 [*] Use `typing.TypeAlias` for type alias, e.g., `_AnnotationStyle: TypeAlias = Literal["success", "warning", "error"]`
3080:  |
3081:  119 |     ...
3082:  120 |
3083:  121 | _AnnotationStyle = Literal["success", "warning", "error"]
3084:  | ^^^^^^^^^^^^^^^^ PYI026
...

5793:  |
5794:  45 |         file_path (str): The path to the audio file.
5795:  46 |         language (str, optional): The locale identifier (e.g. 'en-US').
5796:  47 |     Returns:
5797:  |     ^^^^^^^ D411
5798:  48 |         List[Tuple[str, List[Dict]]]: A list of possible transcriptions.
5799:  49 |     Raises:
5800:  |
5801:  = help: Add blank line before "Returns"
5802:  stubs/pythonista_stubs/speech.pyi:49:5: D413 [*] Missing blank line after last section ("Raises")
5803:  |
5804:  47 |     Returns:
5805:  48 |         List[Tuple[str, List[Dict]]]: A list of possible transcriptions.
5806:  49 |     Raises:
5807:  |     ^^^^^^ D413
5808:  50 |         RuntimeError: If speech recognition fails.
5809:  51 |         ValueError: If the language parameter is invalid.
5810:  |
5811:  = help: Add blank line after "Raises"
5812:  stubs/pythonista_stubs/speech.pyi:49:5: D411 [*] Missing blank line before section ("Raises")
5813:  |
5814:  47 |     Returns:
5815:  48 |         List[Tuple[str, List[Dict]]]: A list of possible transcriptions.
5816:  49 |     Raises:
5817:  |     ^^^^^^ D411
5818:  50 |         RuntimeError: If speech recognition fails.
5819:  51 |         ValueError: If the language parameter is invalid.
5820:  |
...

5880:  10 |             Union[str, Tuple[int, int, int], Tuple[int, int, int, int], float]
5881:  |                                              ^^^^^ UP006
5882:  11 |         ] = None,
5883:  12 |         name: Optional[str] = None,
5884:  |
5885:  = help: Replace with `tuple`
5886:  stubs/pythonista_stubs/ui.pyi:12:15: UP045 [*] Use `X | None` for type annotations
5887:  |
5888:  10 |             Union[str, Tuple[int, int, int], Tuple[int, int, int, int], float]
5889:  11 |         ] = None,
5890:  12 |         name: Optional[str] = None,
5891:  |               ^^^^^^^^^^^^^ UP045
5892:  13 |     ) -> None: ...
5893:  |
5894:  = help: Convert to `X | None`
5895:  Found 582 errors.
5896:  [*] 480 fixable with the `--fix` option (5 hidden fixes can be enabled with the `--unsafe-fixes` option).
5897:  ##[error]Process completed with exit code 1.
5898:  Post job cleanup.

@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 @hbmartin - I've reviewed your changes and they look great!

Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments

### Comment 1
<location> `stubs/pythonista_stubs/photos.pyi:28` </location>
<code_context>
         ...

     def get_ui_image(
-        self, size: Optional[Tuple[int, int]] = None, crop: bool = False
-    ) -> ui_Image:
+        self, size: Optional[tuple[int, int]] = None, crop: bool = False
+    ) -> UIImage:
         """
</code_context>

<issue_to_address>
Using 'tuple[int, int]' in type hints may reduce compatibility with older Python versions.

If you need to support Python versions earlier than 3.9, use 'Tuple[int, int]' from the 'typing' module instead.
</issue_to_address>

### Comment 2
<location> `README.md:17` </location>
<code_context>
-* flake8: [flake8-mypy](https://github.com/ambv/flake8-mypy)
-
-See also: [mypy integrations](https://github.com/python/mypy#ide--linter-integrations)
+You can now develop from your computer editor with proper typing and completinos.

 ## API Coverage
</code_context>

<issue_to_address>
Typo: 'completinos' should be 'completions'.

Update the spelling to 'completions'.
</issue_to_address>

<suggested_fix>
<<<<<<< SEARCH
You can now develop from your computer editor with proper typing and completinos.
=======
You can now develop from your computer editor with proper typing and completions.
>>>>>>> REPLACE

</suggested_fix>

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.

Comment thread stubs/pythonista_stubs/photos.pyi
Comment thread README.md Outdated
@qodo-code-review

qodo-code-review Bot commented Aug 11, 2025

Copy link
Copy Markdown

PR Code Suggestions ✨

Latest suggestions up to d1166db

CategorySuggestion                                                                                                                                    Impact
Incremental [*]
Fix YAML indentation

Align the Black step with the other steps by removing the extra indentation
before the dash; otherwise, the workflow will be invalid YAML and fail to parse

.github/workflows/ci.yml [26-30]

 - name: Type check with mypy
   run: uv run mypy
 
-  - name: Check code formatting with black
-    run: uv run black --check
+- name: Check code formatting with black
+  run: uv run black --check
  • Apply / Chat
Suggestion importance[1-10]: 9

__

Why: The suggestion correctly identifies a YAML syntax error due to incorrect indentation, which would cause the CI workflow to fail.

High
Possible issue
Use forward reference annotations

The magic methods reference ObjCInstance before it is fully defined, which can
cause evaluation issues in type checkers. Use a forward reference string for the
return annotations to avoid recursive type resolution problems. This keeps the
stub valid and prevents mypy/pyright errors.

stubs/pythonista_stubs/objc_util.pyi [42-64]

 class ObjCInstance:
     """Wrapper for a pointer to an Objective-C object.
 ...
     def __init__(self, ptr: int | ctypes.c_void_p | None) -> None: ...
 
     # Collection-like behavior for NSArray, NSDictionary, NSSet
     def __len__(self) -> int: ...
-    def __getitem__(self, key: Any) -> ObjCInstance: ...
+    def __getitem__(self, key: Any) -> "ObjCInstance": ...
     def __setitem__(self, key: Any, value: Any) -> None: ...
     def __iter__(self) -> Any: ...
     def __contains__(self, item: Any) -> bool: ...

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 5

__

Why: The suggestion correctly identifies the need for a forward reference for the ObjCInstance type hint within its own class definition to ensure compatibility with all type checkers.

Low
General
Quote self-referential return types

Methods returning Image within the class body should use forward references to
avoid NameError in some type checkers evaluating annotations at runtime. Quote
the return annotation "Image" for classmethods and instance methods returning
the same type.

stubs/pythonista_stubs/ui.pyi [4-119]

 class Image:
     """Represents an image that can be displayed in the user interface."""
     
     @classmethod
-    def from_data(cls, image_data: bytes, scale: float | None = None) -> Image:
+    def from_data(cls, image_data: bytes, scale: float | None = None) -> "Image":
         """Create an image from binary image data.
+        """
+        ...
+    
+    @classmethod
+    def named(cls, image_name: str) -> "Image" | None:
+        """Create an image from a built-in or local image file.
+        """
+        ...
 ...
     def resizable_image(
         self, top: float, left: float, bottom: float, right: float
-    ) -> Image:
+    ) -> "Image":
         """Create a 9-patch resizable version of this image.
+        """
+        ...
 ...
-    def with_rendering_mode(self, mode: _RenderingMode) -> Image:
+    def with_rendering_mode(self, mode: _RenderingMode) -> "Image":
         """Create a new image with the specified rendering mode.
+        """
+        ...

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 5

__

Why: The suggestion correctly recommends using forward references for methods returning an instance of the class they are defined in, which is a good practice for type hint robustness.

Low
  • More

Previous suggestions

Suggestions up to commit 3740993
CategorySuggestion                                                                                                                                    Impact
High-level
Avoid runtime imports in stubs

In stubs, importing runtime modules like PIL.Image and ui can break type
checking environments where those packages aren’t installed; prefer typing-only
imports with TYPE_CHECKING and string annotations or Protocols. Replace from
PIL.Image import Image and from ui import Image with forward-referenced types or
minimal Protocols to keep stubs self-contained and usable without requiring
optional dependencies.

Examples:

stubs/pythonista_stubs/photos.pyi [11-12]
from PIL.Image import Image as PILImage
from ui import Image as UIImage
stubs/pythonista_stubs/photos.pyi [20-21]
def get_image(self, original: bool = False) -> PILImage:
    """Fetch the asset's image data as a PIL.Image object."""

Solution Walkthrough:

Before:

# stubs/pythonista_stubs/photos.pyi
from PIL.Image import Image as PILImage
from ui import Image as UIImage

class Asset:
    def get_image(...) -> PILImage:
        ...
    def get_ui_image(...) -> UIImage:
        ...

After:

# stubs/pythonista_stubs/photos.pyi
from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from PIL.Image import Image as PILImage
    from ui import Image as UIImage

class Asset:
    def get_image(...) -> "PILImage":
        ...
    def get_ui_image(...) -> "UIImage":
        ...
Suggestion importance[1-10]: 9

__

Why: This suggestion correctly identifies a critical design flaw in the stub file that would make it unusable in standard type-checking environments, thus defeating the purpose of the library.

High

@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 updates the project's stub files, documentation, and tooling configuration. The changes to use specific PIL and UI types in photos.pyi are a great improvement for type safety. The documentation and project configuration updates are also welcome modernizations.

I've found a critical issue in photos.pyi where a necessary type import was removed, which would break static analysis. I've also pointed out a typo in the updated README.md and suggested restoring some helpful information that was removed.

Comment thread stubs/pythonista_stubs/photos.pyi Outdated
Comment thread README.md Outdated

@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 3740993 in 2 minutes and 0 seconds. Click for details.
  • Reviewed 365 lines of code in 5 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. README.md:15
  • Draft comment:
    Consider providing pip install instructions in addition to 'uv add' for wider user clarity.
  • Reason this comment was not posted:
    Confidence changes required: 50% <= threshold 50% None
2. stubs/pythonista_stubs/photos.pyi:67
  • Draft comment:
    The type 'List' is used (e.g. in 'media_subtypes: List[str]') without being imported. Either import List from typing or use the built-in 'list[str]' since the target is Python 3.10+.
  • Reason this comment was not posted:
    Comment was not on a location in the diff, so it can't be submitted as a review comment.
3. stubs/pythonista_stubs/photos.pyi:136
  • Draft comment:
    The return type of 'capture_image' is declared as 'Optional[Image]', but 'Image' is not imported. Clarify whether this should be 'PILImage' or 'UIImage'.
  • Reason this comment was not posted:
    Comment was not on a location in the diff, so it can't be submitted as a review comment.
4. README.md:17
  • Draft comment:
    Typographical error: 'completinos' should be corrected to 'completions'.
  • Reason this comment was not posted:
    Marked as duplicate.

Workflow ID: wflow_gxEL6549cIhAFhxT

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

Comment thread README.md Outdated

@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.

Important

Looks good to me! 👍

Reviewed 73730df in 2 minutes and 10 seconds. Click for details.
  • Reviewed 1241 lines of code in 8 files
  • Skipped 0 files when reviewing.
  • Skipped posting 8 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. README.md:17
  • Draft comment:
    Fixed typo: 'completinos' corrected to 'completions'.
  • Reason this comment was not posted:
    Comment did not seem useful. Confidence is useful = 0% <= threshold 50% This comment is purely informative, as it only points out a typo correction without suggesting any changes or improvements. It doesn't provide any actionable feedback or raise any concerns about the code.
2. pyproject.toml:2
  • Draft comment:
    The setuptools requirement is set to '>=80.1.0'; please ensure this high version is supported in all target environments.
  • Reason this comment was not posted:
    Comment was not on a location in the diff, so it can't be submitted as a review comment.
3. stubs/pythonista_stubs/appex.pyi:11
  • Draft comment:
    The try/except block for importing PIL.Image is handled correctly with a fallback type of Any.
  • Reason this comment was not posted:
    Confidence changes required: 0% <= threshold 50% None
4. stubs/pythonista_stubs/dialogs.pyi:126
  • Draft comment:
    Type aliases _FieldType, _FieldDict, and _SectionTuple use modern syntax and look correct.
  • Reason this comment was not posted:
    Confidence changes required: 0% <= threshold 50% None
5. stubs/pythonista_stubs/location.pyi:15
  • Draft comment:
    Location stubs use built-in generics (dict[str, float] | None, list[...]) and type aliases appropriately.
  • Reason this comment was not posted:
    Confidence changes required: 0% <= threshold 50% None
6. stubs/pythonista_stubs/photos.pyi:78
  • Draft comment:
    Photos stubs use modern type annotations; consider refining the 'location' attribute type to be more specific (e.g. dict with defined key types) if possible.
  • Reason this comment was not posted:
    Confidence changes required: 50% <= threshold 50% None
7. stubs/pythonista_stubs/ui.pyi:1
  • Draft comment:
    UI stubs look well structured; methods in the Image class (e.g. from_data, named, draw, to_png) are clearly annotated with proper types.
  • Reason this comment was not posted:
    Confidence changes required: 0% <= threshold 50% None
8. uv.lock:2
  • Draft comment:
    The uv.lock file has been updated with the latest package versions and future upload timestamps (2025). Verify these future dates are intentional and acceptable for your release process.
  • 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 verify future dates in a lock file, which is not a specific code suggestion or a request for a test. It falls under the category of asking for confirmation of intention, which is against the rules.

Workflow ID: wflow_WrxreFtFK91tQ1kX

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

@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: 5

♻️ Duplicate comments (2)
README.md (1)

17-17: Fix typo: 'completinos' should be 'completions'.

-You can now develop from your computer editor with proper typing and completinos.
+You can now develop from your computer editor with proper typing and completions.
stubs/pythonista_stubs/photos.pyi (1)

28-29: OK to use tuple[int, int] (Python 3.11 target)

Given the project targets Python 3.11, using built-in generics like tuple[int, int] is correct. Prior concern about Tuple[...] compatibility (older Python) no longer applies.

🧹 Nitpick comments (8)
stubs/pythonista_stubs/ui.pyi (1)

121-130: Consider adding a type alias for the background_color union.

The background_color parameter has a complex union type that could benefit from a type alias for better readability and reusability.

+_Color: TypeAlias = str | tuple[int, int, int] | tuple[int, int, int, int] | float | None
+
 class View:
     def __init__(
         self,
         frame: tuple[int, int, int, int] = (0, 0, 100, 100),
         flex: str = "",
-        background_color: (
-            str | tuple[int, int, int] | tuple[int, int, int, int] | float | None
-        ) = None,
+        background_color: _Color = None,
         name: str | None = None,
     ) -> None: ...
stubs/pythonista_stubs/appex.pyi (4)

12-14: Nice: PIL import with graceful fallback

The try/except around PIL.Image prevents import-time failures when Pillow isn’t installed. Consider mirroring this pattern in photos.pyi for consistency.


65-67: Docstring style: align with built-in generics

Docstrings still use Optional/List/Union. For consistency with 3.11 types used in signatures, consider updating to built-in generics.

Example edits:

  • Returns: list[Image | PilImage]
  • Returns: Image | PilImage | None

Also applies to: 79-80


165-171: Docstring style: use built-in generics for dict

To match code style, prefer dict[str, str] over Dict[str, str] in docstrings.


178-193: Docstrings: reference imported types directly

Docstrings say Optional[ui.View]; in this stub you import View directly. Suggest “View | None” or just “View”.

stubs/pythonista_stubs/dialogs.pyi (2)

177-184: Docstring constant reference is misleading

The default for autocapitalization mentions ui.AUTOCAPITALIZE_SENTENCES, but the constants are defined here on TextField. Suggest updating the docstring accordingly.

Proposed text: “Defaults to TextField.AUTOCAPITALIZE_SENTENCES.”


279-286: Mutable default argument in a stub — prefer ellipsis to reflect default exists

While stubs aren’t executed, list defaults can be confusing. Using ... is idiomatic in .pyi to indicate a default exists without specifying the value.

Apply this diff:

-def pick_document(types: list[str] = ["public.data"]) -> str | None:
+def pick_document(types: list[str] = ...) -> str | None:
stubs/pythonista_stubs/photos.pyi (1)

28-31: Docstrings: modernize types to match signatures

Docstrings still use Optional[...] and ui.Image; prefer built-ins and the local alias name.

Suggested edits:

  • size: tuple[int, int] | None
  • Returns: UIImage
  • Remove “Optional[...]” usages and use “X | None”.

Also applies to: 34-44

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 271b53c and 73730df.

⛔ Files ignored due to path filters (1)
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (9)
  • CODE_OF_CONDUCT.md (1 hunks)
  • README.md (2 hunks)
  • pyproject.toml (3 hunks)
  • stubs/pythonista_stubs/appex.pyi (2 hunks)
  • stubs/pythonista_stubs/dialogs.pyi (15 hunks)
  • stubs/pythonista_stubs/location.pyi (4 hunks)
  • stubs/pythonista_stubs/photos.pyi (8 hunks)
  • stubs/pythonista_stubs/ui.py (0 hunks)
  • stubs/pythonista_stubs/ui.pyi (1 hunks)
💤 Files with no reviewable changes (1)
  • stubs/pythonista_stubs/ui.py
🧰 Additional context used
🧬 Code Graph Analysis (5)
stubs/pythonista_stubs/ui.pyi (1)
stubs/pythonista_stubs/canvas.pyi (7)
  • begin_updates (54-56)
  • clear (42-44)
  • draw_path (134-136)
  • clip (118-120)
  • set_blend_mode (75-77)
  • fill_path (146-148)
  • set_alpha (71-73)
stubs/pythonista_stubs/appex.pyi (2)
stubs/pythonista_stubs/ui.pyi (2)
  • View (121-130)
  • Image (5-119)
stubs/pythonista_stubs/photos.pyi (1)
  • get_image (18-20)
stubs/pythonista_stubs/location.pyi (1)
stubs/pythonista_stubs/ui.pyi (1)
  • Image (5-119)
stubs/pythonista_stubs/dialogs.pyi (1)
stubs/pythonista_stubs/ui.pyi (1)
  • Image (5-119)
stubs/pythonista_stubs/photos.pyi (3)
stubs/pythonista_stubs/ui.pyi (2)
  • Image (5-119)
  • size (39-41)
stubs/pythonista_stubs/clipboard.pyi (1)
  • get_image (32-46)
stubs/pythonista_stubs/appex.pyi (1)
  • get_image (71-82)
🪛 LanguageTool
CODE_OF_CONDUCT.md

[style] ~40-~40: Consider a more concise word here.
Context: ... * Creating additional online accounts in order to harass another person or circumvent a b...

(IN_ORDER_TO_PREMIUM)

🪛 markdownlint-cli2 (0.17.2)
README.md

13-13: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)


14-14: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)


15-15: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)


16-16: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)


17-17: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)


18-18: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)


19-19: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)


20-20: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)


21-21: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)


34-34: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)


35-35: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)


36-36: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)


37-37: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)


38-38: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)


39-39: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)


40-40: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)


41-41: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)


42-42: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)


43-43: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)


85-85: Unordered list indentation
Expected: 0; Actual: 2

(MD007, ul-indent)

🔇 Additional comments (14)
CODE_OF_CONDUCT.md (1)

1-167: Good addition of the PSF Code of Conduct.

Adding a formal Code of Conduct helps establish community guidelines and expectations for contributors.

pyproject.toml (3)

8-8: LGTM! Author email added.

Adding author contact information improves project metadata.


55-60: Good migration to dependency-groups.

Using [dependency-groups] follows modern Python packaging standards (PEP 735) for better dependency management.


66-73: Well-configured Ruff settings.

The explicit Ruff configuration with Python 3.11 target and appropriate stub-specific lint ignores (PYI021, PYI048) is suitable for a type stubs project.

README.md (2)

4-6: Good badge updates.

Replacing Travis CI with GitHub Actions and adding the Ruff badge accurately reflects the project's current tooling.


24-43: Excellent progress on API coverage.

The updated table shows substantial completion of stub implementations, with appropriate issue tracking for work in progress.

stubs/pythonista_stubs/location.pyi (3)

5-13: Good typing modernization.

Using TypeAlias and Literal for the map type definition improves type safety and readability.


15-88: Consistent typing modernization across all functions.

All function signatures properly use built-in generics (dict, list) and PEP 604 union syntax (|), aligning with the Python 3.11 target.


25-27: Good API additions for location management.

Adding start_updates() and is_authorized() provides better control over location services and permission handling.

Also applies to: 90-92

stubs/pythonista_stubs/ui.pyi (1)

1-119: Well-structured Image class with comprehensive API.

The Image class provides a complete interface with proper type hints, class methods for construction, properties for metadata, and methods for drawing operations. The _RenderingMode TypeAlias appropriately defines the allowed rendering modes.

stubs/pythonista_stubs/appex.pyi (2)

8-8: Good: reuse UI types from ui stubs

Importing View and Image from .ui keeps types consistent across modules.


56-56: TypeAlias for _ImageType is correct and future-proof

Literal union as a named alias is a clear improvement.

stubs/pythonista_stubs/dialogs.pyi (1)

21-21: LGTM: narrowed ListDataSource.items type

items: list[dict[str, Any]] matches how ListDataSource is commonly used and improves static checking.

stubs/pythonista_stubs/photos.pyi (1)

134-137: LGTM: API typing improvements

  • capture_image returns PILImage | None
  • get_assets and album getters return list[...] with built-ins
  • batch_delete/batch_revert use list[Asset]
    These align with the broader modernization.

Also applies to: 139-142, 149-160, 177-184

Comment thread stubs/pythonista_stubs/appex.pyi Outdated
Comment thread stubs/pythonista_stubs/dialogs.pyi
Comment thread stubs/pythonista_stubs/dialogs.pyi
Comment thread stubs/pythonista_stubs/photos.pyi Outdated
Comment thread stubs/pythonista_stubs/photos.pyi Outdated

@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.

Important

Looks good to me! 👍

Reviewed db38197 in 2 minutes and 45 seconds. Click for details.
  • Reviewed 296 lines of code in 1 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/pythonista_stubs/objc_util.pyi:10
  • Draft comment:
    Consider importing Callable from 'typing' for consistency with other type imports.
  • Reason this comment was not posted:
    Confidence changes required: 33% <= threshold 50% None
2. stubs/pythonista_stubs/objc_util.pyi:63
  • Draft comment:
    Specify a more precise return type for iter (e.g. Iterator[ObjCInstance]) instead of Any.
  • Reason this comment was not posted:
    Confidence changes required: 33% <= threshold 50% None
3. stubs/pythonista_stubs/objc_util.pyi:104
  • Draft comment:
    Using '...' as the default for 'superclass' in create_objc_class may be unclear; consider a more explicit default or document this behavior.
  • Reason this comment was not posted:
    Confidence changes required: 33% <= threshold 50% None
4. stubs/pythonista_stubs/objc_util.pyi:82
  • Draft comment:
    Using the internal type 'ctypes._SimpleCData' for restype/argtypes may be fragile; consider a public alternative if available.
  • Reason this comment was not posted:
    Decided after close inspection that this draft comment was likely wrong and/or not actionable: usefulness confidence = 30% vs. threshold = 50% This is a valid concern about API stability since internal types like _SimpleCData could change. However, looking at ctypes docs, there doesn't seem to be a good public alternative - this is the actual type that represents simple C data types. The comment suggests finding an alternative but doesn't propose one, making it not very actionable. Maybe there is a public alternative I'm not aware of? Or maybe using Any would be better than exposing internal types? While using Any would hide the internal type, it would also hide useful type information. The _SimpleCData type, despite being internal, is the most accurate way to type these parameters. The comment raises a valid concern but doesn't provide an actionable solution, and the current approach may be the best available option given ctypes' public API.
5. stubs/pythonista_stubs/objc_util.pyi:237
  • Draft comment:
    The 'fields' placeholder in CGPoint is acceptable for stubs, but consider adding a comment or concrete definitions to aid tooling if possible.
  • Reason this comment was not posted:
    Confidence changes required: 33% <= threshold 50% None
6. stubs/pythonista_stubs/objc_util.pyi:152
  • Draft comment:
    Consider adding an ns() overload for int if integer inputs are common.
  • Reason this comment was not posted:
    Confidence changes required: 33% <= threshold 50% None

Workflow ID: wflow_3dS7QFnKvAA9Ho51

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

@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.

Important

Looks good to me! 👍

Reviewed cf944e1 in 1 minute and 30 seconds. Click for details.
  • Reviewed 33 lines of code in 3 files
  • Skipped 0 files when reviewing.
  • Skipped posting 3 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. .github/workflows/ci.yml:29
  • Draft comment:
    Added Black check step is a good improvement. Ensure that Black and Ruff checks are aligned to avoid overlapping responsibilities.
  • 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% The comment starts with praise but then asks to "ensure" something, which violates our rules. It's asking the author to verify/check something rather than pointing out a specific issue. While tool alignment is important, this is more of a discussion point than a concrete code change request. The comment does raise a valid concern about potential conflicts between formatting tools. Maybe there's a real issue here that needs addressing? While tool conflicts could be an issue, the comment doesn't point out any specific conflict or problem. It's just asking for verification, which our rules explicitly say to avoid. The comment should be deleted because it's asking for verification rather than pointing out a specific issue that needs fixing.
2. pyproject.toml:73
  • Draft comment:
    The lint.ignore list now includes 'A002' and a per-file-ignore is added for objc_util.pyi. Confirm these ignores are intentional to suppress false positives and document them if necessary.
  • Reason this comment was not posted:
    Comment did not seem useful. Confidence is useful = 30% <= threshold 50% The comment is asking the PR author to confirm their intention regarding the lint.ignore list and per-file-ignore. This violates the rule against asking the author to confirm their intention. However, it also suggests documenting the ignores if necessary, which is a specific action. Overall, the comment leans more towards asking for confirmation, which is not allowed.
3. setup.py:1
  • Draft comment:
    Suppressing the missing module docstring (D100) for setup.py is acceptable given its minimal content.
  • Reason this comment was not posted:
    Comment did not seem useful. Confidence is useful = 0% <= threshold 50% This comment is purely informative and does not provide any actionable feedback or suggestions for improvement. It simply states that suppressing a warning is acceptable, which does not align with the rules for useful comments.

Workflow ID: wflow_mx8aJKnmV98H9tbx

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

@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: 0

🧹 Nitpick comments (1)
.github/workflows/ci.yml (1)

29-30: Enhance Black check output and scope

Recommend adding --diff (clearer CI feedback) and an explicit path '.' for clarity.

-      - name: Check code formatting with black
-        run: uv run black --check
+      - name: Check code formatting with black
+        run: uv run black --check --diff .
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between db38197 and cf944e1.

📒 Files selected for processing (3)
  • .github/workflows/ci.yml (1 hunks)
  • pyproject.toml (3 hunks)
  • setup.py (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • setup.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • pyproject.toml
🔇 Additional comments (1)
.github/workflows/ci.yml (1)

28-30: Black integration verified

  • pyproject.toml declares Black as a dev dependency ("black>=25.1.0" on line 57).
  • uv.lock pins Black (version 25.1.0 and wheels present).
  • No [tool.black] section found in pyproject.toml – Black will use defaults. If you need custom settings (line length, exclusions, etc.), add a [tool.black] table.

No further action required unless you want non-default Black options.

@openhands-ai

openhands-ai Bot commented Aug 12, 2025

Copy link
Copy Markdown

Looks like there are a few issues preventing this PR from being merged!

  • GitHub Actions are failing:
    • CI

If you'd like me to help, just leave a comment, like

@OpenHands please fix the failing actions on PR #10

Feel free to include any additional details that might help me get this PR into a better state.

You can manage your notification settings

@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.

Important

Looks good to me! 👍

Reviewed d1166db in 1 minute and 38 seconds. Click for details.
  • Reviewed 239 lines of code in 3 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. stubs/pythonista_stubs/appex.pyi:55
  • Draft comment:
    Good use of @overload decorators on get_images; the multiple overloads clarify the return type based on the 'image_type' parameter.
  • Reason this comment was not posted:
    Confidence changes required: 0% <= threshold 50% None
2. stubs/pythonista_stubs/appex.pyi:75
  • Draft comment:
    The overloaded get_image function is clearly defined with distinct overloads for 'pil' and 'ui'; this improves type inference and IDE support.
  • Reason this comment was not posted:
    Confidence changes required: 0% <= threshold 50% None
3. stubs/pythonista_stubs/dialogs.pyi:71
  • Draft comment:
    Introducing the StrConvertible protocol and the type variable T in list_dialog boosts type safety. Consider using a more flexible type (e.g. Sequence[T]) for the items parameter if non-list iterables should be supported.
  • Reason this comment was not posted:
    Confidence changes required: 0% <= threshold 50% None
4. stubs/pythonista_stubs/dialogs.pyi:252
  • Draft comment:
    The updated share_image function signature accepting both UIImage and PILImage ensures consistency with related modules.
  • Reason this comment was not posted:
    Confidence changes required: 0% <= threshold 50% None
5. stubs/pythonista_stubs/photos.pyi:194
  • Draft comment:
    The overloads for pick_asset differentiate return types based on the 'multi' parameter, providing clearer type expectations for API consumers.
  • Reason this comment was not posted:
    Confidence changes required: 0% <= threshold 50% None

Workflow ID: wflow_FeJ2UjcpNXONLqrx

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

@hbmartin

Copy link
Copy Markdown
Owner Author

@o-murphy merging this now so I can make a follow up formatting PR but happy to continue discussing these changes.

@hbmartin
hbmartin merged commit 4e5bdcc into master Aug 12, 2025
1 of 2 checks passed
@hbmartin
hbmartin deleted the hm/3.4-release-prep branch August 12, 2025 15:02
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.

1 participant