Skip to content

Conversation

@aatle
Copy link
Contributor

@aatle aatle commented Aug 30, 2025

Revert the changes of #1942 (which initializes rect and image to None, and turns those attributes into properties).

Reasons:
The None values aren't actually compatible with the sprite functions and methods; they will error for a None sprite rect or image. It isn't really useful to initialize them to None.
By having them uninitialized instead, the remaining sprite stub issues involving optionals can be solved. -> makes sprite module comfortably usable and safe with typing.
The property accessors for these attributes seem to be redundant. Also, they are slightly slower than normal attributes.
The revert will also make sprite behavior in line with upstream pygame, as #1942 didn't apply to it.

Additionally, this PR fixes typing for DirtySprite.source_rect and LayeredDirty.get_clip().

@aatle aatle requested a review from MyreMylar August 30, 2025 02:29
@aatle aatle requested a review from a team as a code owner August 30, 2025 02:29
@aatle aatle added the sprite pygame.sprite label Aug 30, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Aug 30, 2025

📝 Walkthrough

Walkthrough

Sprite runtime API changed from property-backed private storage to public attributes image: Surface and rect: FRect | Rect; stub typings tightened for image/rect (non-Optional) and adjusted several return types to allow None where appropriate.

Changes

Cohort / File(s) Summary
Stub typings update
buildconfig/stubs/pygame/sprite.pyi
Narrowed _HasRect.rect to `FRect
Runtime Sprite API
src_py/sprite.py
Removed private __image/__rect fields and property getters/setters; added public attributes image: Surface and rect: Union[Rect, FRect]; updated imports and type hints (added Surface, FRect; replaced Optional with Union).

Sequence Diagram(s)

sequenceDiagram
    participant Code as Caller
    participant Sprite as Sprite (object)
    rect rgb(240,248,255)
    Note over Sprite: Previous (property-backed)
    end
    Code->>Sprite: access sprite.image (property)
    Sprite-->Code: property getter -> internal __image
    Code->>Sprite: assign sprite.image = surf
    Sprite-->Sprite: property setter -> set __image
    rect rgb(245,255,240)
    Note over Sprite: New (public attributes)
    end
    Code->>Sprite: access sprite.image
    Sprite-->Code: direct attribute read
    Code->>Sprite: assign sprite.image = surf
    Sprite-->Sprite: direct attribute write
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Pay attention to src_py/sprite.py for runtime behavioral changes (absence of defaults, potential AttributeError risks).
  • Verify stub/runtime parity in buildconfig/stubs/pygame/sprite.pyi vs src_py/sprite.py.
  • Check callers/groups (drawing, blitting) for assumptions about None vs non-None image/rect.

Possibly related PRs

  • Improve sprite stubs #3525 — Overlapping edits to buildconfig/stubs/pygame/sprite.pyi altering image/rect declarations and related return types.

Suggested labels

type hints

Suggested reviewers

  • MyreMylar
  • ankith26

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title Check ✅ Passed The pull request title "Remove property accessors and None initialization of Sprite.rect, Sprite.image" is fully related to the main changes in the changeset. The title accurately and specifically describes the primary modifications: removal of property accessors and elimination of None initialization for the Sprite.rect and Sprite.image attributes. The title is clear, concise, and directly reflects the core intent of reverting changes from PR #1942 while maintaining the main focus, even though secondary fixes to DirtySprite.source_rect and LayeredDirty.get_clip() are not mentioned.
Description Check ✅ Passed The pull request description is clearly related to the changeset and provides substantive context about the changes. It explains the reversion of PR #1942's changes, provides specific technical reasons (incompatibility of None values with sprite functions, typing safety improvements, redundancy of property accessors), aligns the changes with upstream pygame behavior, and mentions the additional typing fixes for DirtySprite.source_rect and LayeredDirty.get_clip(). The description is detailed and directly relevant to the modifications made in the PR without being vague or off-topic.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0a8311e and fe34f01.

📒 Files selected for processing (2)
  • buildconfig/stubs/pygame/sprite.pyi (3 hunks)
  • src_py/sprite.py (3 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: Starbuck5
Repo: pygame-community/pygame-ce PR: 3573
File: src_c/_pygame.h:108-133
Timestamp: 2025-09-01T20:18:57.500Z
Learning: In pygame-ce PR #3573, PG_SURF_BitsPerPixel was changed from a simple macro to a static inline function to handle SDL2/SDL3 differences. SDL2's BitsPerPixel includes padding bits (e.g., RGBX => 32) while SDL3's SDL_BITSPERPIXEL excludes padding (e.g., RGBX => 24). The new implementation bridges this gap rather than removing the helper entirely.
📚 Learning: 2025-09-01T20:18:57.500Z
Learnt from: Starbuck5
Repo: pygame-community/pygame-ce PR: 3573
File: src_c/_pygame.h:108-133
Timestamp: 2025-09-01T20:18:57.500Z
Learning: In pygame-ce PR #3573, PG_SURF_BitsPerPixel was changed from a simple macro to a static inline function to handle SDL2/SDL3 differences. SDL2's BitsPerPixel includes padding bits (e.g., RGBX => 32) while SDL3's SDL_BITSPERPIXEL excludes padding (e.g., RGBX => 24). The new implementation bridges this gap rather than removing the helper entirely.

Applied to files:

  • buildconfig/stubs/pygame/sprite.pyi
🧬 Code graph analysis (2)
src_py/sprite.py (2)
buildconfig/stubs/pygame/sprite.pyi (2)
  • rect (32-32)
  • image (37-37)
buildconfig/stubs/pygame/surface.pyi (1)
  • Surface (42-1054)
buildconfig/stubs/pygame/sprite.pyi (3)
buildconfig/stubs/pygame/rect.pyi (2)
  • FRect (301-301)
  • Rect (300-300)
buildconfig/stubs/pygame/surface.pyi (2)
  • Surface (42-1054)
  • get_clip (668-675)
src_py/sprite.py (2)
  • Sprite (97-249)
  • get_clip (1322-1328)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (20)
  • GitHub Check: Debian (Bookworm - 12) [s390x]
  • GitHub Check: msys2 (clang64, clang-x86_64)
  • GitHub Check: msys2 (ucrt64, ucrt-x86_64)
  • GitHub Check: debug_coverage (ubuntu-24.04, 3.10.17)
  • GitHub Check: debug_coverage (ubuntu-24.04, 3.14.0)
  • GitHub Check: Debian (Bookworm - 12) [armv6]
  • GitHub Check: Debian (Bookworm - 12) [armv7]
  • GitHub Check: msys2 (mingw64, x86_64)
  • GitHub Check: Debian (Bookworm - 12) [ppc64le]
  • GitHub Check: build (macos-14)
  • GitHub Check: build (ubuntu-24.04)
  • GitHub Check: build (windows-latest)
  • GitHub Check: AMD64
  • GitHub Check: aarch64
  • GitHub Check: x86
  • GitHub Check: dev-check
  • GitHub Check: Pyodide build
  • GitHub Check: i686
  • GitHub Check: build (ubuntu-22.04)
  • GitHub Check: x86_64
🔇 Additional comments (7)
buildconfig/stubs/pygame/sprite.pyi (4)

31-37: LGTM! Protocol typing correctly tightened.

The return types for rect and image in the protocols now correctly reflect that these attributes are non-optional in implementations. This aligns with the PR objective to remove None initialization and improve type safety.


45-46: LGTM! Stub correctly reflects runtime attribute changes.

The attribute annotations properly replace the previous property-based approach and accurately match the implementation in src_py/sprite.py. The comment helpfully documents why this approach was chosen.


64-64: LGTM! Type correctly widened to include None.

The type annotation for source_rect accurately reflects its initialization to None in the DirtySprite.__init__ method (line 293 of src_py/sprite.py).


146-146: LGTM! Return type accurately reflects implementation.

The return type correctly includes None since LayeredDirty.get_clip() returns self._clip which is initialized to None in line 1087 of src_py/sprite.py.

src_py/sprite.py (3)

92-93: LGTM! Imports correctly updated for type annotations.

The additions of FRect and Surface imports are necessary to support the type annotations added to the Sprite class.


112-114: LGTM! Attribute annotations correctly replace property-based approach.

The public attribute declarations with no initialization correctly implement the PR's intent to remove None initialization and property accessors. This improves type safety by making it clear that image and rect must be assigned before use, aligning with the existing documentation expectations.


1325-1325: LGTM! Docstring accurately updated.

The docstring now correctly documents that get_clip() can return None, matching both the implementation (which returns self._clip initialized to None) and the stub typing.


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

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

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 (3)
src_py/sprite.py (1)

294-294: Annotate DirtySprite.source_rect at runtime to match stubs

Add a concrete runtime type to aid tooling without reintroducing Optional elsewhere.

-        self.source_rect = None
+        self.source_rect: Union[Rect, FRect, None] = None
buildconfig/stubs/pygame/sprite.pyi (2)

46-53: Prefer attributes over properties in stubs to mirror runtime

Runtime Sprite now exposes plain attributes; stubs should reflect that for accuracy and simpler tooling.

 class Sprite(_HasImageAndRect):
-    @property
-    def image(self) -> Surface: ...
-    @image.setter
-    def image(self, value: Surface) -> None: ...
-    @property
-    def rect(self) -> Union[FRect, Rect]: ...
-    @rect.setter
-    def rect(self, value: Union[FRect, Rect]) -> None: ...
+    image: Surface
+    rect: Union[FRect, Rect]

153-154: get_clip return type should be Optional

LayeredDirty.get_clip can return None until set; adjust stub to avoid type mismatches.

-    def get_clip(self) -> Union[FRect, Rect]: ...
+    def get_clip(self) -> Optional[Union[FRect, Rect]]: ...
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 8d13367 and 4607af4.

📒 Files selected for processing (2)
  • buildconfig/stubs/pygame/sprite.pyi (3 hunks)
  • src_py/sprite.py (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
src_py/sprite.py (2)
buildconfig/stubs/pygame/sprite.pyi (7)
  • mask (43-43)
  • rect (33-33)
  • rect (51-51)
  • rect (53-53)
  • image (38-38)
  • image (47-47)
  • image (49-49)
buildconfig/stubs/pygame/rect.pyi (2)
  • FRect (304-304)
  • Rect (303-303)
buildconfig/stubs/pygame/sprite.pyi (2)
buildconfig/stubs/pygame/rect.pyi (2)
  • FRect (304-304)
  • Rect (303-303)
buildconfig/stubs/pygame/surface.pyi (1)
  • Surface (42-1051)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (20)
  • GitHub Check: arm64
  • GitHub Check: Debian (Bookworm - 12) [armv6]
  • GitHub Check: aarch64
  • GitHub Check: i686
  • GitHub Check: x86_64
  • GitHub Check: debug_coverage (ubuntu-24.04, 3.14.0rc1)
  • GitHub Check: debug_coverage (ubuntu-24.04, 3.13.5)
  • GitHub Check: x86
  • GitHub Check: debug_coverage (ubuntu-24.04, 3.9.23)
  • GitHub Check: AMD64
  • GitHub Check: dev-check
  • GitHub Check: Debian (Bookworm - 12) [s390x]
  • GitHub Check: Debian (Bookworm - 12) [armv7]
  • GitHub Check: Debian (Bookworm - 12) [ppc64le]
  • GitHub Check: msys2 (ucrt64, ucrt-x86_64)
  • GitHub Check: msys2 (mingw64, x86_64)
  • GitHub Check: msys2 (clang64, clang-x86_64)
  • GitHub Check: build (windows-latest)
  • GitHub Check: build (ubuntu-24.04)
  • GitHub Check: build (macos-14)
🔇 Additional comments (5)
src_py/sprite.py (3)

88-88: Typing import change is fine

Using Union keeps compatibility with supported Python versions.


93-94: Imports aligned with new annotations

Rect/FRect/Surface imports match usage.


113-115: Restoring public attributes for image/rect looks good

Matches upstream expectations and removes accessor overhead.

buildconfig/stubs/pygame/sprite.pyi (2)

31-39: Non-optional rect/image in Protocols — LGTM

These tighten contracts for collision/draw helpers appropriately.


71-71: DirtySprite.source_rect -> Optional — LGTM

Matches runtime default None and LayeredDirty usage.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

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 (3)
buildconfig/stubs/pygame/sprite.pyi (3)

32-34: Non-Optional rect is correct; prefer attribute over property in the protocol.

Tightening to Union[FRect, Rect] matches runtime expectations. To better align with structural typing and the runtime (which exposes a plain attribute), consider declaring rect as a plain attribute on the protocol instead of a read-only property.

Apply:

 class _HasRect(Protocol):
-    @property
-    def rect(self) -> Union[FRect, Rect]: ...
+    rect: Union[FRect, Rect]

37-39: Non-Optional image is correct; prefer attribute over property in the protocol.

As above, switching to a simple attribute on the protocol avoids unnecessary read-only semantics and matches the runtime Sprite API.

Apply:

 class _HasImageAndRect(_HasRect, Protocol):
-    @property
-    def image(self) -> Surface: ...
+    image: Surface

46-47: Minor DRY: introduce a local alias for Rect/FRect.

You repeat Union[FRect, Rect] several times. A small alias improves readability and future edits.

Apply (add alias near existing imports), then use it on these lines:

@@
-from pygame.rect import FRect, Rect
+from pygame.rect import FRect, Rect
+Rectish = Union[FRect, Rect]
@@
-    rect: Union[FRect, Rect]  # Same as image, see above
+    rect: Rectish  # Same as image, see above
@@
-    source_rect: Optional[Union[FRect, Rect]]
+    source_rect: Optional[Rectish]

Also applies to: 65-65

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 4607af4 and d1c7a63.

📒 Files selected for processing (1)
  • buildconfig/stubs/pygame/sprite.pyi (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
buildconfig/stubs/pygame/sprite.pyi (4)
buildconfig/stubs/pygame/rect.pyi (2)
  • FRect (304-304)
  • Rect (303-303)
buildconfig/stubs/pygame/surface.pyi (1)
  • Surface (42-1051)
buildconfig/stubs/pygame/mask.pyi (1)
  • Mask (18-60)
src_py/sprite.py (1)
  • Sprite (98-250)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: Debian (Bookworm - 12) [armv7]
  • GitHub Check: dev-check
  • GitHub Check: debug_coverage (ubuntu-24.04, 3.13.5)
  • GitHub Check: build (macos-14)
  • GitHub Check: build (windows-latest)
🔇 Additional comments (2)
buildconfig/stubs/pygame/sprite.pyi (2)

65-65: DirtySprite.source_rect now Optional: LGTM.

Matches typical usage where None signifies a full redraw region. No further changes needed.


46-47: Verify stubtest for Sprite.image/rect on Python 3.8–3.13
No @property accessors exist at runtime, so the stub’s attribute annotations are correct; run mypy.stubtest (or Pyright’s stub test) against Python 3.8, 3.9, 3.10, 3.11, 3.12, and 3.13 to confirm no false positives on missing instance attributes.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

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 (2)
src_py/sprite.py (2)

88-88: Avoid importing pygame.surface at import-time; use TYPE_CHECKING + quoted annotation.

Prevents importing the C extension on module import and keeps runtime lean. Safe because Surface is only used for typing here.

-from typing import Union
+from typing import TYPE_CHECKING, Union
@@
-from pygame.surface import Surface
+if TYPE_CHECKING:
+    from pygame.surface import Surface
@@
-    image: Surface
+    image: "Surface"

Also applies to: 93-95, 113-113


114-114: Use PEP 604 unions when supported.

If minimum Python is 3.10+, this is cleaner.

-    rect: Union[Rect, FRect]
+    rect: Rect | FRect
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between d1c7a63 and 0a8311e.

📒 Files selected for processing (2)
  • buildconfig/stubs/pygame/sprite.pyi (3 hunks)
  • src_py/sprite.py (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • buildconfig/stubs/pygame/sprite.pyi
🧰 Additional context used
🧬 Code graph analysis (1)
src_py/sprite.py (3)
src_py/__init__.py (1)
  • Surface (227-228)
buildconfig/stubs/pygame/sprite.pyi (3)
  • mask (43-43)
  • rect (33-33)
  • image (38-38)
buildconfig/stubs/pygame/rect.pyi (2)
  • FRect (304-304)
  • Rect (303-303)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (18)
  • GitHub Check: arm64
  • GitHub Check: x86_64
  • GitHub Check: debug_coverage (ubuntu-24.04, 3.14.0rc1)
  • GitHub Check: debug_coverage (ubuntu-24.04, 3.13.5)
  • GitHub Check: debug_coverage (ubuntu-24.04, 3.9.23)
  • GitHub Check: dev-check
  • GitHub Check: Debian (Bookworm - 12) [armv7]
  • GitHub Check: Debian (Bookworm - 12) [ppc64le]
  • GitHub Check: Debian (Bookworm - 12) [armv6]
  • GitHub Check: Debian (Bookworm - 12) [s390x]
  • GitHub Check: build (windows-latest)
  • GitHub Check: build (macos-14)
  • GitHub Check: msys2 (ucrt64, ucrt-x86_64)
  • GitHub Check: i686
  • GitHub Check: aarch64
  • GitHub Check: x86_64
  • GitHub Check: x86
  • GitHub Check: AMD64
🔇 Additional comments (2)
src_py/sprite.py (2)

113-115: Direct attributes for image/rect: LGTM.

This aligns with upstream pygame, removes property overhead, and tightens typing.


1326-1326: Docstring fix matches behavior.

Returning “Rect or None” reflects self._clip initialization and usage.

@aatle aatle changed the title Remove None initialization of Sprite.rect and Sprite.image, and remove property accessors Remove property accessors and None initialization of Sprite.rect, Sprite.image Sep 1, 2025
Copy link
Member

@damusss damusss left a comment

Choose a reason for hiding this comment

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

I don't see issues with it so I will approve it

Copy link
Member

@ankith26 ankith26 left a comment

Choose a reason for hiding this comment

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

I would like to request @MyreMylar to review this PR given that this PR is reverting a change they had done.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

sprite pygame.sprite

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants