Skip to content

Conversation

@flimsyhat
Copy link
Contributor

The PR proposes slimming down final app size by (1) reducing the size of the bundled python framework and (2) only importing the essential frameworks from PyObjC.

Optimizing bundled python framework

By removing the test suite, gui frameworks and other unnecessary modules from the stdlib, we can save ~32MB. We can shave off another ~19MB by removing the cache dirs (this does mean that python needs to rebuild the cache on startup, but this should only add a few seconds the first time PlotDevice is opened).

Total change: 204.7MB → 154.0MB, a savings of 50.7MB (24.8%).

Selective PyObjC imports

By only importing what we use from PyObjC, we go from 35.1MB (full PyObjC) to 19.5MB, a savings of 15.6MB (44.4%).

After testing, this results in a final app bundle of ~115MB, down from ~172MB (~57MB or 33% saved).

flimsyhat added 2 commits June 3, 2025 09:08
reduce framework size by removing unused stdlib modules and cache
@samizdatco
Copy link
Member

Thanks so much for taking a look at this!

The bundle is definitely a lot larger now that it's embedding its own Python framework than it was for older versions that just used the system's copy. Now that it's supplying the whole environment though I'd like to be careful about removing anything from it that existing code might depend on—in particular it would be a bummer for anyone who'd been using some of the more 'obscure' pyobjc modules to have to figure out how to install just the missing libraries (and at the correct version) to keep things running.

The other reason I'd been leaning towards including more rather than less is that the app bundle has to be effectively read-only due to code-signing, so things like the cache files really do need to be pre-generated or else they'll invalidate the app's signatures as they are created (breaking the app for anyone who downloaded it rather than building it locally).

Ultimately I'm not that worried about occupying a couple hundred megabytes on disk (cf. VS Code's 600mb bundle or even Spotify's 350mb)—it's more about the size of the download. And on that front it feels like the reductions (though real!) are pretty modest compared to the potential for breakage. It looks like the size of the zipped app would go from the current 55mb to 37.5mb.

What do you think though—am I missing some module deletions that might be a good idea on their own, separate from the space savings?

@flimsyhat
Copy link
Contributor Author

flimsyhat commented Jun 6, 2025

Thanks for taking a look and for explaining your reasoning! The philosophy of including more vs. less makes sense. I also didn't realize that re-generating the cache would invalidate the signatures, thanks for pointing that out.

I was mainly concerned with the eventual size of the download as well, so if it's just a reduction of 10-20mb for the zipped app it's not a huge difference in the end.

That said, I think we could still delete/avoid importing some modules:

Python framework

The bulk of the savings from the Python framework came from removing the internal test suite (test) which is ~27.6MB. I think this could still be safely removed without affecting any potential end use, since it's intended for internal use only during python development. What do you think?

PyObjC

I may be overthinking this, but there is maybe a case from a security pov for limiting the number of PyObjC modules that are imported. This could reduce the risk of inadvertently exposing sensitive system APIs in the (admittedly unlikely) case someone runs a malicious script.

I also think it's nice when reading the imports to see what's explicitly being imported and used. This also emphasizes the fact that PlotDevice is essentially wrapping Quartz.

By default, PlotDevice could ship only the necessary frameworks...

  • pyobjc-core
  • pyobjc-framework-Cocoa
  • pyobjc-framework-Quartz
  • pyobjc-framework-WebKit
  • pyobjc-framework-LaunchServices

...and it could be noted somewhere that users needing specialized system access can import additional PyObjC frameworks themselves, with maybe a brief guide on how to do that. Additional frameworks could be added back in progressively if concerns are raised.

I'll gladly defer to whatever you think is best.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants