Skip to content

Conversation

cherez
Copy link
Contributor

@cherez cherez commented Oct 1, 2025

This is my first 'meaty' PR, so let me know if I missed anything.

Adds wrappers for TTF_SetFontOutline and TTF_GetFontOutline. As-is I don't believe there's a clean way to outline fonts in pygame.

Visual demo of the outline effect:
image

@cherez cherez requested a review from a team as a code owner October 1, 2025 22:52
Copy link
Contributor

coderabbitai bot commented Oct 1, 2025

📝 Walkthrough

Walkthrough

Adds SDL_ttf-backed outline support to Font: new outline property with getter/setter, explicit get_outline()/set_outline() methods, C implementation with validation and SDL_ttf version gating, updated stubs and docs, and unit/interactive tests covering behavior and error cases.

Changes

Cohort / File(s) Summary
Public API stubs
buildconfig/stubs/pygame/font.pyi
Adds outline property (getter/setter) and methods get_outline() and set_outline(val: int, /) -> None to Font stub.
Documentation
docs/reST/ref/font.rst
Documents Font.outline (int), Font.get_outline() and Font.set_outline(size, /) -> None; notes behavior (0 = normal, >0 = outline) and marks as versionadded 2.5.6.
C core implementation
src_c/font.c
Adds font_getter_outline, font_setter_outline, font_get_outline, font_set_outline; registers outline getset and get_outline/set_outline methods; validates integer ≥ 0; checks font generation and requires SDL_ttf ≥ 2.0.12 (raises SDLError when unsupported).
Tests
test/font_test.py
Adds unit and interactive tests covering property/method behavior, type/value validation, SDL_ttf version gating, post-quit error cases, and interactive outlined rendering flow.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor PyUser as Python code
  participant FontObj as Font (Python)
  participant CAPI as src_c/font.c
  participant SDLTTF as SDL_ttf

  PyUser->>FontObj: font.get_outline() / font.outline
  FontObj->>CAPI: font_get_outline / font_getter_outline
  alt Font not generated
    CAPI-->>PyUser: raise pygame.error
  else SDL_ttf < 2.0.12
    CAPI-->>PyUser: raise SDLError (unsupported)
  else Supported
    CAPI->>SDLTTF: TTF_GetFontOutline(font)
    SDLTTF-->>CAPI: outline (int)
    CAPI-->>PyUser: return int
  end

  PyUser->>FontObj: font.set_outline(n) / font.outline = n
  FontObj->>CAPI: font_set_outline / font_setter_outline(n)
  alt invalid type or n < 0
    CAPI-->>PyUser: TypeError / ValueError
  else Font not generated
    CAPI-->>PyUser: raise pygame.error
  else SDL_ttf < 2.0.12
    CAPI-->>PyUser: raise SDLError (unsupported)
  else Supported
    CAPI->>SDLTTF: TTF_SetFontOutline(font, n)
    SDLTTF-->>CAPI: status
    CAPI-->>PyUser: None
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested reviewers

  • MightyJosip
  • ankith26

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% 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 title concisely and accurately summarizes the main change by stating that an outline property was added to pygame.font.Font, matching the core additions in the PR.
Description Check ✅ Passed The description explains that wrappers for TTF_SetFontOutline and TTF_GetFontOutline were added to enable font outlines in pygame and includes a visual demo, which aligns directly with the code changes.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • 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 75b90d8 and 01aacde.

📒 Files selected for processing (1)
  • src_c/font.c (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src_c/font.c
⏰ 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: x86_64
  • GitHub Check: x86_64
  • GitHub Check: i686
  • GitHub Check: aarch64
  • GitHub Check: dev-check
  • GitHub Check: debug_coverage (ubuntu-24.04, 3.14.0rc1)
  • GitHub Check: debug_coverage (ubuntu-24.04, 3.9.23)
  • GitHub Check: debug_coverage (ubuntu-24.04, 3.13.5)
  • GitHub Check: x86
  • GitHub Check: AMD64
  • GitHub Check: Debian (Bookworm - 12) [armv6]
  • GitHub Check: Debian (Bookworm - 12) [ppc64le]
  • GitHub Check: build (macos-14)
  • GitHub Check: build (ubuntu-24.04)
  • GitHub Check: Debian (Bookworm - 12) [s390x]
  • GitHub Check: Debian (Bookworm - 12) [armv7]
  • GitHub Check: build (ubuntu-22.04)
  • GitHub Check: msys2 (mingw64, x86_64)
  • GitHub Check: msys2 (ucrt64, ucrt-x86_64)
  • GitHub Check: msys2 (clang64, clang-x86_64)

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: 2

📜 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 f572e93 and 0feebd5.

⛔ Files ignored due to path filters (1)
  • src_c/doc/font_doc.h is excluded by !src_c/doc/*
📒 Files selected for processing (4)
  • buildconfig/stubs/pygame/font.pyi (2 hunks)
  • docs/reST/ref/font.rst (2 hunks)
  • src_c/font.c (3 hunks)
  • test/font_test.py (7 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
buildconfig/stubs/pygame/font.pyi (1)
buildconfig/stubs/pygame/mask.pyi (1)
  • outline (38-38)
test/font_test.py (1)
buildconfig/stubs/pygame/font.pyi (21)
  • init (12-12)
  • get_default_font (16-16)
  • Font (31-95)
  • get_sdl_ttf_version (15-15)
  • outline (61-61)
  • outline (63-63)
  • get_outline (94-94)
  • set_outline (95-95)
  • bold (37-37)
  • bold (39-39)
  • italic (41-41)
  • italic (43-43)
  • underline (45-45)
  • underline (47-47)
  • strikethrough (49-49)
  • strikethrough (51-51)
  • set_bold (78-78)
  • set_italic (80-80)
  • set_underline (74-74)
  • set_strikethrough (76-76)
  • render (65-72)
🪛 GitHub Actions: python3 dev.py all
test/font_test.py

[error] 1-1: clang-format reformatted file. Run 'clang-format -i test/font_test.py' and commit changes.

src_c/font.c

[error] 1-1: clang-format reformatted file. Run 'clang-format -i src_c/font.c' and commit changes.

⏰ 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: x86_64
  • GitHub Check: aarch64
  • GitHub Check: i686
  • GitHub Check: x86_64
  • GitHub Check: Debian (Bookworm - 12) [armv6]
  • GitHub Check: Debian (Bookworm - 12) [armv7]
  • GitHub Check: Debian (Bookworm - 12) [s390x]
  • GitHub Check: x86
  • GitHub Check: AMD64
  • GitHub Check: Debian (Bookworm - 12) [ppc64le]
  • GitHub Check: msys2 (mingw64, x86_64)
  • GitHub Check: msys2 (clang64, clang-x86_64)
  • GitHub Check: msys2 (ucrt64, ucrt-x86_64)
  • GitHub Check: debug_coverage (ubuntu-24.04, 3.14.0rc1)
  • GitHub Check: debug_coverage (ubuntu-24.04, 3.9.23)
  • GitHub Check: debug_coverage (ubuntu-24.04, 3.13.5)
  • GitHub Check: build (ubuntu-24.04)
  • GitHub Check: build (windows-latest)
  • GitHub Check: build (macos-14)
  • GitHub Check: build (ubuntu-22.04)
🔇 Additional comments (14)
docs/reST/ref/font.rst (1)

310-323: LGTM!

The outline attribute documentation is clear and follows the established pattern for other font attributes.

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

60-63: LGTM!

The outline property stubs are correctly typed and follow the established pattern for other Font properties.


94-95: LGTM!

The get_outline and set_outline method stubs have correct signatures matching the implementation.

test/font_test.py (5)

688-726: LGTM!

The test_outline_property test correctly validates outline property behavior with appropriate SDL_ttf version guards (2.0.12+), type checks, and boundary conditions.


727-751: LGTM!

The test_outline_method test properly validates get_outline and set_outline methods with version guards and error handling for invalid inputs.


1000-1006: LGTM!

Correctly adds outline methods to the post-quit exception test with appropriate version gating.


1107-1110: LGTM!

Correctly adds outline property to the post-quit exception test with appropriate version gating.


1169-1259: LGTM — outline tests added

Interactive tests correctly incorporate the outline parameter and demonstrate its effect.
CI is failing on formatting in test/font_test.py; format that file (e.g. run clang-format) to satisfy the pipeline.

src_c/font.c (6)

904-919: LGTM!

The font_getter_outline implementation correctly checks font generation, uses appropriate SDL_ttf version guards (2.0.12+), and returns the outline value via TTF_GetFontOutline.


921-951: LGTM!

The font_setter_outline implementation has proper:

  • Generation checks
  • Input validation (type check, non-negative constraint)
  • SDL_ttf version gating (2.0.12+)
  • Error messages matching other attribute setters

953-967: LGTM!

The font_get_outline method correctly mirrors the getter with generation checks and version guards.


969-991: LGTM!

The font_set_outline method properly validates input and applies the outline value with appropriate error handling.


1261-1262: LGTM!

Correctly adds outline property to font_getsets table with getter/setter and appropriate docstring placeholder.


1287-1288: Formatting Verification Required
Unable to run clang-format in this environment. Please manually format src_c/font.c using clang-format and re-run CI to resolve the pipeline failure.

Copy link
Member

@oddbookworm oddbookworm left a comment

Choose a reason for hiding this comment

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

Overall, excellent add! I do have some comments, but they're all nice and simple. Thanks for the contribution! 🎉

Comment on lines 312 to 321
| :sl:`Gets or sets the font's outline value`
| :sg:`outline -> int`
The outline value of the font.

When set to 0, the font will be drawn normally. When positive,
the text will be drawn as a hollow outline. This can be drawn
underneath unoutlined text to create a text outline effect.

.. versionadded:: 2.5.6
Copy link
Member

Choose a reason for hiding this comment

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

You don't describe how setting it to different values affects it. How would 2 differ from 1? You also specifically call out positive as opposed to nonzero, so what about setting it to a negative number?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That's a fair point. The upstream docs are quite vague about what the value does, and I didn't want to offer a more specific explanation that isn't accurate.

Copy link
Member

Choose a reason for hiding this comment

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

I think I'd like for it to at least mention that negative values are disallowed and larger values mean a thicker outline

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fair points, I expanded the explanation with 0c1d1ca.

src_c/font.c Outdated
Comment on lines 953 to 990
static PyObject *
font_get_outline(PyObject *self, PyObject *_null)
{
if (!PgFont_GenerationCheck(self)) {
return RAISE_FONT_QUIT_ERROR();
}
#if SDL_TTF_VERSION_ATLEAST(2, 0, 12)
TTF_Font *font = PyFont_AsFont(self);
return PyLong_FromLong(TTF_GetFontOutline(font));
#else
return RAISE(pgExc_SDLError,
"pygame.font not compiled with a new enough SDL_ttf version. "
"Needs SDL_ttf 2.0.12 or above.");
#endif
}

static PyObject *
font_set_outline(PyObject *self, PyObject *arg)
{
if (!PgFont_GenerationCheck(self)) {
return RAISE_FONT_QUIT_ERROR();
}
#if SDL_TTF_VERSION_ATLEAST(2, 0, 12)
TTF_Font *font = PyFont_AsFont(self);
long val = PyLong_AsLong(arg);
if (val == -1 && PyErr_Occurred()) {
return NULL;
}
if (val < 0) {
return RAISE(PyExc_ValueError, "outline must be >= 0");
}
TTF_SetFontOutline(font, (int)val);
Py_RETURN_NONE;
#else
return RAISE(pgExc_SDLError,
"pygame.font not compiled with a new enough SDL_ttf version. "
"Needs SDL_ttf 2.0.12 or above.");
#endif
Copy link
Member

Choose a reason for hiding this comment

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

You've got code duplication. I suggest moving the common code into a helper function that gets called by both the dedicated setter and the property setter

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I concur; I considered deduplicating the functions, but since the rest of the file seemed to use this sort of duplication I erred toward consistency. Is there a convention for this kind of deduplication elsewhere in the project?

Copy link
Member

Choose a reason for hiding this comment

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

It's scattered from what I remember. Personally, I'm a huge advocate for not duplicating code when possible

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I rewrote font_get_outline to just call font_getter_outline (We could probably even tell python to call font_getter_outline instead with a type cast?), and font_set_outline to call font_setter_outline and massage the return value.

Common helper functions would work too, but I don't see a reason to define 6 functions when 4 (3?) will give the same result.

Comment on lines 699 to 704
if ttf_version < (2, 0, 12):
with self.assertRaises(pygame.error):
f.outline = 0
with self.assertRaises(pygame.error):
_ = f.outline
return
Copy link
Member

Choose a reason for hiding this comment

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

I think it would be cleaner to just skip this test in this case using unittest.skipIf

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That would be cleaner, but that would also mean the case of trying to use the property on an unsupported version is not being tested. Is that a concern?

Copy link
Member

Choose a reason for hiding this comment

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

You can have a dedicated test for it that skips if the SDL_ttf version is too new. I'm not a huge fan of having this weird logic in the middle of the test

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Changed to use skipIf, and added tests for the stubs with 935ab5c.

Comment on lines 1208 to 1216
f.set_outline(outline)
s = f.render(text, antialiase, (0, 0, 0))
screen.blit(s, (offset, y))
y += s.get_size()[1] + spacing
f.set_bold(False)
f.set_italic(False)
f.set_underline(False)
f.set_strikethrough(False)
f.set_outline(0)
Copy link
Member

Choose a reason for hiding this comment

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

This seems like it needs to guard against SDL_ttf version as well

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added guards with 935ab5c.

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

♻️ Duplicate comments (2)
test/font_test.py (2)

1258-1259: Add version guard for SDL_ttf 2.0.12+.

This test will fail on SDL_ttf < 2.0.12 since outline support is not available. Consider adding a skipIf decorator.

Apply this diff:

+    @unittest.skipIf(
+        pygame.font.get_sdl_ttf_version() < (2, 0, 12),
+        "outline requires SDL_ttf 2.0.12+",
+    )
     def test_outline(self):
         self.assertTrue(self.query(outline=1))

1208-1208: Version-gate the set_outline call.

The set_outline call will raise a pygame.error on SDL_ttf < 2.0.12. Since test_outline (line 1258) calls query(outline=1), it could fail on older SDL_ttf versions.

Apply this diff to guard the call:

         f.set_underline(underline)
         f.set_strikethrough(strikethrough)
-        f.set_outline(outline)
+        if pygame_font.get_sdl_ttf_version() >= (2, 0, 12):
+            f.set_outline(outline)
         s = f.render(text, antialiase, (0, 0, 0))

Also guard the reset:

         f.set_underline(False)
         f.set_strikethrough(False)
-        f.set_outline(0)
+        if pygame_font.get_sdl_ttf_version() >= (2, 0, 12):
+            f.set_outline(0)
         s = f.render("(some comparison text)", False, (0, 0, 0))
🧹 Nitpick comments (2)
test/font_test.py (2)

698-704: Consider using unittest.skipIf for version gating.

The previous review suggested using unittest.skipIf instead of the if/return pattern for cleaner test skipping. This approach is more idiomatic and provides better test reporting.

Apply this pattern:

+    @unittest.skipIf(
+        pygame.font.get_sdl_ttf_version() < (2, 0, 12),
+        "outline requires SDL_ttf 2.0.12+",
+    )
     def test_outline_property(self):
         if pygame_font.__name__ == "pygame.ftfont":
             return  # not a pygame.ftfont feature
 
         pygame_font.init()
         font_path = os.path.join(
             os.path.split(pygame.__file__)[0], pygame_font.get_default_font()
         )
         f = pygame_font.Font(pathlib.Path(font_path), 25)
 
-        ttf_version = pygame_font.get_sdl_ttf_version()
-        if ttf_version < (2, 0, 12):
-            with self.assertRaises(pygame.error):
-                f.outline = 0
-            with self.assertRaises(pygame.error):
-                _ = f.outline
-            return
-
         # Default outline should be an integer >= 0 (typically 0)

Based on past review comments.


737-741: Consider using unittest.skipIf for version gating.

For consistency with the suggestion on test_outline_property, consider using the unittest.skipIf decorator here as well.

Apply this pattern:

+    @unittest.skipIf(
+        pygame.font.get_sdl_ttf_version() < (2, 0, 12),
+        "outline requires SDL_ttf 2.0.12+",
+    )
     def test_outline_method(self):
         if pygame_font.__name__ == "pygame.ftfont":
             return  # not a pygame.ftfont feature
 
         pygame_font.init()
         font_path = os.path.join(
             os.path.split(pygame.__file__)[0], pygame_font.get_default_font()
         )
         f = pygame_font.Font(pathlib.Path(font_path), 25)
 
-        ttf_version = pygame_font.get_sdl_ttf_version()
-        if ttf_version < (2, 0, 12):
-            self.assertRaises(pygame.error, f.get_outline)
-            self.assertRaises(pygame.error, f.set_outline, 1)
-            return
-
         val0 = f.get_outline()
📜 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 8c13923 and 5749c32.

⛔ Files ignored due to path filters (1)
  • src_c/doc/font_doc.h is excluded by !src_c/doc/*
📒 Files selected for processing (2)
  • src_c/font.c (3 hunks)
  • test/font_test.py (7 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src_c/font.c
🧰 Additional context used
🧬 Code graph analysis (1)
test/font_test.py (1)
buildconfig/stubs/pygame/font.pyi (21)
  • init (12-12)
  • get_default_font (16-16)
  • Font (31-95)
  • get_sdl_ttf_version (15-15)
  • outline (61-61)
  • outline (63-63)
  • get_outline (94-94)
  • set_outline (95-95)
  • bold (37-37)
  • bold (39-39)
  • italic (41-41)
  • italic (43-43)
  • underline (45-45)
  • underline (47-47)
  • strikethrough (49-49)
  • strikethrough (51-51)
  • set_bold (78-78)
  • set_italic (80-80)
  • set_underline (74-74)
  • set_strikethrough (76-76)
  • render (65-72)
⏰ 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: x86_64
  • GitHub Check: Debian (Bookworm - 12) [ppc64le]
  • GitHub Check: Debian (Bookworm - 12) [armv6]
  • GitHub Check: Debian (Bookworm - 12) [armv7]
  • GitHub Check: Debian (Bookworm - 12) [s390x]
  • GitHub Check: AMD64
  • GitHub Check: x86
  • GitHub Check: build (macos-14)
  • GitHub Check: build (ubuntu-24.04)
  • GitHub Check: msys2 (ucrt64, ucrt-x86_64)
  • GitHub Check: msys2 (clang64, clang-x86_64)
  • GitHub Check: build (ubuntu-22.04)
  • GitHub Check: msys2 (mingw64, x86_64)
  • GitHub Check: aarch64
  • GitHub Check: debug_coverage (ubuntu-24.04, 3.14.0rc1)
  • GitHub Check: dev-check
  • GitHub Check: x86_64
  • GitHub Check: debug_coverage (ubuntu-24.04, 3.13.5)
  • GitHub Check: i686
  • GitHub Check: debug_coverage (ubuntu-24.04, 3.9.23)
🔇 Additional comments (2)
test/font_test.py (2)

1001-1006: LGTM! Version gating correctly implemented.

The outline methods are now properly gated based on SDL_ttf version, matching the pattern used for other version-dependent features like point_size. This addresses the previous review feedback about needing SDL_ttf version guards.

Based on past review comments.


1107-1110: LGTM! Property version gating correctly implemented.

The outline property is appropriately version-gated, consistent with the pattern used for other version-dependent properties.

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: 1

🧹 Nitpick comments (1)
src_c/font.c (1)

954-971: Consider helper function to reduce duplication (optional).

As noted in past review comments, font_get_outline and font_set_outline duplicate logic from font_getter_outline and font_setter_outline. While the current implementation is consistent with other attributes in this file (e.g., point_size), consider introducing a helper function pattern to reduce duplication if this becomes a maintenance burden.

For example, you could define:

  • A helper that wraps the getter logic
  • A helper that wraps the setter logic and marshals the return type

This is a codebase-wide pattern rather than specific to outline, so defer to maintainer preference on whether to address this now or separately.

📜 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 5749c32 and df3f9e5.

📒 Files selected for processing (3)
  • docs/reST/ref/font.rst (2 hunks)
  • src_c/font.c (3 hunks)
  • test/font_test.py (7 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • docs/reST/ref/font.rst
🧰 Additional context used
🧬 Code graph analysis (1)
test/font_test.py (2)
src_c/font.c (1)
  • font (1497-1572)
buildconfig/stubs/pygame/font.pyi (20)
  • get_sdl_ttf_version (15-15)
  • init (12-12)
  • Font (31-95)
  • outline (61-61)
  • outline (63-63)
  • get_outline (94-94)
  • set_outline (95-95)
  • bold (37-37)
  • bold (39-39)
  • italic (41-41)
  • italic (43-43)
  • underline (45-45)
  • underline (47-47)
  • strikethrough (49-49)
  • strikethrough (51-51)
  • set_bold (78-78)
  • set_italic (80-80)
  • set_underline (74-74)
  • set_strikethrough (76-76)
  • render (65-72)
⏰ 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). (16)
  • GitHub Check: x86_64
  • GitHub Check: arm64
  • GitHub Check: i686
  • GitHub Check: x86_64
  • GitHub Check: aarch64
  • GitHub Check: dev-check
  • GitHub Check: debug_coverage (ubuntu-24.04, 3.9.23)
  • GitHub Check: debug_coverage (ubuntu-24.04, 3.14.0rc1)
  • GitHub Check: debug_coverage (ubuntu-24.04, 3.13.5)
  • GitHub Check: msys2 (mingw64, x86_64)
  • GitHub Check: AMD64
  • GitHub Check: x86
  • GitHub Check: Debian (Bookworm - 12) [s390x]
  • GitHub Check: Debian (Bookworm - 12) [armv6]
  • GitHub Check: Debian (Bookworm - 12) [ppc64le]
  • GitHub Check: Debian (Bookworm - 12) [armv7]
🔇 Additional comments (12)
test/font_test.py (7)

688-722: LGTM!

The test comprehensively validates the outline property behavior: default value checks, get/set operations, increment/decrement, and error handling for negative values and incorrect types.


723-741: LGTM!

The stub test correctly validates that accessing the outline property raises pygame.error on SDL_TTF versions older than 2.0.12, ensuring proper error handling for unsupported versions.


742-764: LGTM!

The test validates get_outline and set_outline methods, including default value checks, setting operations, and error handling for negative values and incorrect types.


765-781: LGTM!

The stub test correctly validates that calling get_outline and set_outline raises pygame.error on SDL_TTF versions older than 2.0.12.


1030-1037: LGTM!

The changes correctly add get_outline and set_outline to the test coverage for method exception checks after font module quit, with proper version gating for SDL_TTF >= 2.0.12.


1137-1141: LGTM!

The changes correctly add the outline property to the test coverage for property exception checks after font module quit, with proper version gating for SDL_TTF >= 2.0.12.


1206-1206: LGTM!

The interactive test changes correctly integrate outline support into the visual test suite:

  • Adds outline parameter to query method signature
  • Includes outline in mode construction and rendering
  • Properly guards outline operations with SDL_TTF version checks
  • Adds dedicated test_outline test case with proper version gating

Also applies to: 1217-1217, 1231-1232, 1238-1239, 1247-1248, 1290-1296

src_c/font.c (5)

904-919: LGTM!

The getter implementation correctly follows existing patterns:

  • Performs generation check
  • Guards SDL_ttf calls with version check
  • Returns descriptive error for unsupported versions
  • Uses TTF_GetFontOutline API correctly

921-952: LGTM!

The setter implementation correctly validates input and follows existing patterns:

  • Performs generation check
  • Guards SDL_ttf calls with version check
  • Validates type (must be integer)
  • Validates value (must be >= 0)
  • Uses TTF_SetFontOutline API correctly
  • Provides descriptive error messages

954-960: LGTM!

The method implementation correctly delegates to the property getter, following the existing pattern used by other font attributes.


1240-1241: LGTM!

The outline property is correctly registered in the font_getsets array with proper getter, setter, and documentation reference.


1266-1267: LGTM!

The get_outline and set_outline methods are correctly registered in the font_methods array with proper signatures (METH_NOARGS and METH_O) and documentation references.

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: 1

♻️ Duplicate comments (1)
src_c/font.c (1)

970-970: Use Py_RETURN_NONE macro for consistency.

Line 970 returns Py_None directly, which is inconsistent with the codebase pattern. For example, font_set_bold (line 341) and other setters use Py_RETURN_NONE to ensure proper reference counting.

Apply this diff:

-    Py_RETURN_NONE;
+    Py_RETURN_NONE;

Wait, that's the same. Let me re-read line 970...

Actually, looking at the code again:

The code already shows Py_RETURN_NONE at line 970. The past review comment mentioned line 970 had return Py_None; but the current code shows Py_RETURN_NONE. This means the issue was already fixed.

Let me reconsider. The past review comment from coderabbitai[bot] stated:
"Line 970 returns Py_None directly which is inconsistent with project patterns; replace the direct return with the Py_RETURN_NONE macro"

But the current code at line 970 shows:

This indicates the past issue was already addressed. I should not flag this as a duplicate or an issue.

[actions]

  • Approve this segment since the past issue was already fixed.
    -->
📜 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 df3f9e5 and 60ab8eb.

📒 Files selected for processing (1)
  • src_c/font.c (3 hunks)
⏰ 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). (19)
  • GitHub Check: x86
  • GitHub Check: AMD64
  • GitHub Check: Debian (Bookworm - 12) [armv7]
  • GitHub Check: Debian (Bookworm - 12) [s390x]
  • GitHub Check: Debian (Bookworm - 12) [armv6]
  • GitHub Check: Debian (Bookworm - 12) [ppc64le]
  • GitHub Check: dev-check
  • GitHub Check: build (ubuntu-22.04)
  • GitHub Check: msys2 (mingw64, x86_64)
  • GitHub Check: build (ubuntu-24.04)
  • GitHub Check: i686
  • GitHub Check: debug_coverage (ubuntu-24.04, 3.9.23)
  • GitHub Check: build (windows-latest)
  • GitHub Check: debug_coverage (ubuntu-24.04, 3.14.0rc1)
  • GitHub Check: x86_64
  • GitHub Check: debug_coverage (ubuntu-24.04, 3.13.5)
  • GitHub Check: aarch64
  • GitHub Check: msys2 (ucrt64, ucrt-x86_64)
  • GitHub Check: msys2 (clang64, clang-x86_64)
🔇 Additional comments (5)
src_c/font.c (5)

904-919: LGTM!

The getter implementation follows the established pattern for font properties: generation check, version gating for SDL_ttf 2.0.12+, and appropriate error handling.


954-960: LGTM!

The method implementation correctly delegates to the property getter, following the established pattern used by other get_* methods in the file.


962-971: LGTM!

The method implementation correctly delegates to the property setter and uses Py_RETURN_NONE, following the established pattern used by other set_* methods in the file. The past review concern about using Py_RETURN_NONE has been addressed.


1240-1241: LGTM!

The property registration follows the established pattern for other font properties, correctly linking the getter, setter, and documentation.


1266-1267: LGTM!

The method registration follows the established pattern for other font methods, with appropriate flags and documentation references.

@Starbuck5 Starbuck5 added New API This pull request may need extra debate as it adds a new class or function to pygame font pygame.font labels Oct 3, 2025
@Starbuck5
Copy link
Member

I haven't looked through the code, but just reading for interface I see you've added this functionality as a getter/setter and as a property. While most things in font are duplicated in this way, it's because things are being off boarded from being getter/setters. So I see no reason to add getter/setters in a new API, if it's going to be available as a property too.

Although, in the SDL3 documentation for this function it specifies that this can clear a cache of generated glyphs: https://wiki.libsdl.org/SDL3_ttf/TTF_SetFontOutline. So maybe a getter/setter is better because it implies more action taken by the backend?

My thought is we should only support 1 modern thing with a new API, and that it should be a property instead of getter/setter.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
font pygame.font New API This pull request may need extra debate as it adds a new class or function to pygame
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants