GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — Use CoreText to find macOS fonts by iccir · Pull Request #31977 · matplotlib/matplotlib

Conversation

@iccir

@iccir iccir commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Closes #28249
Closes #31965

Why is this change necessary?

Prior to this change, findSystemFonts() in font_manager.py called system_profiler -xml SPFontsDataType. This subprocess would load 1000+ font files in order to parse localized names. As we only need font paths, we can instead query CoreText directly. This finishes in ~63ms on my machine instead of ~7 seconds.

Differences in found fonts

system_profiler uses the private kCTFontCollectionIncludeInvisibleFontsOption option to find "invisible" fonts. These are fonts with names starting with '.'. These fonts are typically unavailable using the standard macOS font APIs. On my machine (macOS 14.8), the following fonts are "invisible":

  /System/Library/Fonts/ADTNumeric.ttc
  /System/Library/Fonts/AquaKana.ttc
  /System/Library/Fonts/HelveLTMM
  /System/Library/Fonts/Keyboard.ttf
  /System/Library/Fonts/LastResort.otf
  /System/Library/Fonts/NewYork.ttf
  /System/Library/Fonts/NewYorkItalic.ttf
  /System/Library/Fonts/SFArabic.ttf
  /System/Library/Fonts/SFArabicRounded.ttf
  /System/Library/Fonts/SFArmenian.ttf
  /System/Library/Fonts/SFArmenianRounded.ttf
  /System/Library/Fonts/SFCamera.ttf
  /System/Library/Fonts/SFCompact.ttf
  /System/Library/Fonts/SFCompactItalic.ttf
  /System/Library/Fonts/SFCompactRounded.ttf
  /System/Library/Fonts/SFGeorgian.ttf
  /System/Library/Fonts/SFGeorgianRounded.ttf
  /System/Library/Fonts/SFHebrew.ttf
  /System/Library/Fonts/SFHebrewRounded.ttf
  /System/Library/Fonts/SFNS.ttf
  /System/Library/Fonts/SFNSItalic.ttf
  /System/Library/Fonts/SFNSMono.ttf
  /System/Library/Fonts/SFNSMonoItalic.ttf
  /System/Library/Fonts/SFNSRounded.ttf
  /System/Library/Fonts/ThonburiUI.ttc
  /System/Library/Fonts/TimesLTMM

My change uses the CTFontCollectionCreateFromAvailableFonts() without this private option; hence, these fonts will be missing from the list returned by _get_macos_fonts().

However, font_manager.py later re-scans the "/System/Library/Fonts" path, so it should discover these invisible fonts at that time.

I tested this change on macOS Mojave (10.14) and macOS Sonoma (14.8). I was unable to test on 10.12 or 10.13 as I updated my 10.12 test device to 10.14. The CoreText API used has been available since 10.5, so I do not foresee any compatibility issues.

AI Disclosure

The original C-based implementation in #31965 is my own without any usage of AI. I used AI to help me convert it to C++ and return a py::set (my original implementation printed the paths). I used AI to check the resulting files and verify that I was following the correct formatting guidelines.

PR checklist

  • "closes #0000" is in the body of the PR description to link the related issue
  • new and changed code is tested
  • [N/A] Plotting related features are demonstrated in an example
  • [N/A] New Features and API Changes are noted with a directive and release note
  • Documentation complies with general and docstring guidelines

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
iccir added 2 commits July 1, 2026 11:00
@iccir
Use CoreText to find macOS fonts
50cbd1e
@iccir
Fix mypy-stubtest failure
aa947c8
@melissawm melissawm added GUI: MacOSX topic: text/fonts labels Jul 9, 2026
@QuLogic QuLogic mentioned this pull request Jul 16, 2026
[MNT]: findSystemFonts - Use system API instead to look into folder #24001
Closed
@QuLogic QuLogic linked an issue Jul 16, 2026 that may be closed by this pull request
[MNT]: findSystemFonts - Use system API instead to look into folder #24001
Closed
greglucas
greglucas reviewed Jul 24, 2026
View reviewed changes
Comment thread lib/matplotlib/tests/test_font_manager.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread lib/matplotlib/_c_internal_utils.pyi Outdated
@@ -1,5 +1,6 @@
def display_is_valid() -> bool: ...
def xdisplay_is_valid() -> bool: ...
def find_available_fonts() -> set[str] | None: ...

@greglucas greglucas Jul 24, 2026

Copy link
Copy Markdown
Contributor

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

Suggested change
def find_available_fonts() -> set[str] | None: ...
def get_available_fonts() -> set[str] | None: ...

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread src/_c_internal_utils.cpp
}
return fonts;
#else
return py::none();

@greglucas greglucas Jul 24, 2026

Copy link
Copy Markdown
Contributor

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

should this be a py::set() call so that you can iterate it on the returning item even on a non macos platform? It is private, so probably not a big deal either way, but you are calling it as for x in None in the _get_macos helper above which would raise instead of returning empty.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@iccir iccir Jul 24, 2026

Copy link
Copy Markdown
Contributor Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

I was trying to mimic the "on other platforms, returns None" in Win32_GetCurrentProcessExplicitAppUserModelID and Win32_GetForegroundWindow.

I think _get_macos_fonts() should be changed to check for None rather than returning an empty set. To me, an empty set would indicate that the platform-specific code ran but found no fonts.

I think raising NotImplementedError might be the proper solution if the other functions in that file would do the same? I'm not sure (still learning!) :)

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@iccir
Changes based on feedback
0122e2d
@github-actions github-actions Bot removed GUI: MacOSX topic: text/fonts labels Jul 24, 2026
greglucas
greglucas approved these changes Jul 24, 2026
View reviewed changes
Comment thread lib/matplotlib/tests/test_font_manager.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

@iccir @greglucas
Update lib/matplotlib/tests/test_font_manager.py
dbbcd59
Co-authored-by: Greg Lucas <[email protected]>
QuLogic
QuLogic reviewed Jul 28, 2026
View reviewed changes
Comment thread lib/matplotlib/tests/test_font_manager.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread lib/matplotlib/tests/test_font_manager.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread lib/matplotlib/tests/test_font_manager.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread src/_c_internal_utils.cpp Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread src/_c_internal_utils.cpp Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread src/_c_internal_utils.cpp Resolved

Uh oh!

There was an error while loading. Please reload this page.

iccir and others added 6 commits July 27, 2026 19:42
@iccir @QuLogic
Update lib/matplotlib/tests/test_font_manager.py
058dfc0
Co-authored-by: Elliott Sales de Andrade <[email protected]>
@iccir @QuLogic
Update lib/matplotlib/tests/test_font_manager.py
a592719
Co-authored-by: Elliott Sales de Andrade <[email protected]>
@iccir @QuLogic
Update lib/matplotlib/tests/test_font_manager.py
a980e73
Co-authored-by: Elliott Sales de Andrade <[email protected]>
@iccir @QuLogic
Update src/_c_internal_utils.cpp
aca9614
Co-authored-by: Elliott Sales de Andrade <[email protected]>
@iccir
Use snake_case
22e92ce
@iccir
Use std::make_unique instead of new
f76a6ed
@melissawm melissawm added the OS: Apple label Jul 28, 2026
@QuLogic

QuLogic commented Jul 29, 2026

Copy link
Copy Markdown
Member

I happened across foliojs/font-manager#19 while looking at these functions. Is that also a problem in this implementation (and was it something that we supported before)?

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@iccir

iccir commented Jul 29, 2026 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor Author

I happened across foliojs/font-manager#19 while looking at these functions. Is that also a problem in this implementation (and was it something that we supported before)?

I'm not sure what is going on in the linked bug. ~/Library/Fonts is being checked on my test devices:

>>> pprint.pp([x for x in _c_internal_utils.get_available_fonts() if "iccir" in x])
['/Users/iccir/Library/Fonts/SF-Mono-Light.otf',
 '/Users/iccir/Library/Fonts/SF-Mono-Bold.otf',
 '/Users/iccir/Library/Fonts/DINishCondensed-Heavy.ttf',
 '/Users/iccir/Library/Fonts/DINish-Italic.otf',
…

My suspicion is one of the following:

  1. There was a bug circa-2017 with CoreText.
  2. The node process didn't have access to ~/Library/Fonts. I wouldn't expect this back in 2017. It would be more common nowadays with all of the additional macOS restrictions.
  3. The user was placing fonts in ~/Library/Fonts without actually registering them with macOS via Font Book. Although the user mentions that they are available in TextEdit so I wouldn't expect this to be the case.

I'm leaning towards 1.

In any case, our previous implemented ran system_profiler as a subprocess, which also uses CTFontCollectionCreateFromAvailableFonts() internally. It's possible that ~/Library/Fonts isn't being accessed on some versions of macOS, but I wouldn't expect that to be a regression from the previous implementation.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

QuLogic
QuLogic approved these changes Jul 29, 2026
View reviewed changes
@iccir

iccir commented Jul 29, 2026

Copy link
Copy Markdown
Contributor Author

I did some more digging last night.

system_profiler calls CTFontCollectionCreateFromAvailableFonts() with kCTFontCollectionIncludeDisabledFontsOption turned on. This means that fonts explicitly deactivated/disabled by the user were being included in _get_macos_fonts().

The new code calls CTFontCollectionCreateFromAvailableFonts() with NULL, so deactivated/disabled fonts will not be included.

This is a subtle change of behavior, but I'm not sure if the old behavior is correct. There are situations where a user may have multiple user-level fonts installed with the same name and wants to deactivate one of them.

Assuming we want to change this behavior, should the version number of the font cache be bumped in font_manager.py? It's currently:

    __version__ = '3.11.0'
All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@QuLogic

QuLogic commented Aug 6, 2026

Copy link
Copy Markdown
Member

Hmm, yes, I think that is correct, as we did the same thing for Windows: #22859

You can bump the cache key to 3.12.0a1 or similar.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@iccir
Bump font manager version due to macOS CoreText change
7a279ce
@QuLogic
QuLogic merged commit 8aedfd2 into matplotlib:main Aug 6, 2026
42 checks passed

Uh oh!

There was an error while loading. Please reload this page.

@QuLogic QuLogic added this to the v3.12.0 milestone Aug 6, 2026
@iccir
iccir deleted the coretext-find-fonts branch September 7, 2026 16:57
@iccir iccir mentioned this pull request Sep 9, 2026
[Bug]: macOS font discovery raises KeyError('_items') for an incomplete system_profiler font record #32328
Open
@happyarts happyarts mentioned this pull request Sep 17, 2026
Keep matplotlib off the system fonts in the diarization worker, so a broken font record on macOS no longer kills speaker detection kaixxx/noScribe#346
Merged
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@QuLogic QuLogic QuLogic approved these changes
@greglucas greglucas greglucas approved these changes

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

OS: Apple

Projects

None yet

Milestone

v3.12.0

Development

Successfully merging this pull request may close these issues.

[MNT]: Possibly use CoreText to find fonts for faster performance font finding in OSX produces 200+ lines of warnings [MNT]: findSystemFonts - Use system API instead to look into folder

Uh oh!

There was an error while loading. Please reload this page.

4 participants

@iccir @QuLogic @greglucas @melissawm
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.