Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

crash #23

Open
justanotherfoundry opened this issue Jun 24, 2024 · 15 comments
Open

crash #23

justanotherfoundry opened this issue Jun 24, 2024 · 15 comments

Comments

@justanotherfoundry
Copy link

Details:
Traceback (most recent call last):

File "plugin.py", line 48, in openWindow_
from TalkingLeaves import TalkingLeaves

File "init.py", line 19, in
import TalkingLeaves.data as data

File "data.py", line 2, in
import pandas as pd

ModuleNotFoundError: No module named 'pandas'

App:3.3-3311 Plugin:0.1-2 System:14.5.0

@justinpenner
Copy link
Owner

Did you install pandas? It's a new dependency since I implemented the new TalkingLeaves.data module. You can just run the pip command from the README to install it.

The roadmap for TalkingLeaves includes eventually handling dependency installs automatically via the GUI (see #2), but it's complicated at the moment because GlyphsPython doesn't have pip built-in.

@justanotherfoundry
Copy link
Author

I just installed pip install pandas via Terminal and re-started Glyphs and now I am getting a similar (but not identical) error:

Details:
Traceback (most recent call last):

  File "plugin.py", line 48, in openWindow_
    from TalkingLeaves import TalkingLeaves

  File "__init__.py", line 19, in <module>
    import TalkingLeaves.data as data

  File "data.py", line 2, in <module>
    import pandas as pd

ModuleNotFoundError: No module named 'pandas'

App:3.3-3311 Plugin:0.1-2 System:14.5.0


@justanotherfoundry
Copy link
Author

After messing with things I’d rather not want to mess with (a.k.a. dependency hell), I got it to work. I doubt that most users of TalkingLeaves would be willing to spend the time and effort on this.

I installed pandas using this snippet from within Glyphs and now it works again. Not sure whether this is the expert way of doing things, I’m a dummy at handling multiple Python versions and installing dependencies.

@justinpenner
Copy link
Owner

I just installed pip install pandas via Terminal and re-started Glyphs and now I am getting a similar (but not identical) error:

That error is in fact identical to the earlier one you posted. pip install pandas installed pandas for your command line Python, but GlyphsApp is using GlyphsPython, so the pandas module couldn't be found. I'll eventually fix this so that instead of crashing, it will fail gracefully like it does if Hyperglot is missing.

I installed pandas using this snippet from within Glyphs and now it works again.

That's a clever way to do it, but you installed it to a site-packages folder buried deep inside of ~/Library/Application Support/Glyphs 3/Repositories/GlyphsPythonPlugin/…. Anytime GlyphsPython gets updated, the pandas module you installed there will vanish and you'll have to reinstall it again. That's why we use the long pip command from the README which tells pip to target ~/Library/Application Support/Glyphs 3/Scripts/site-packages. This is the recommended location to install dependencies for Glyphs plugins. If you have any issues with dependencies you can just delete the entire contents of that folder and install your dependencies again. pip caches downloads, so reinstalling dependencies is usually very quick.

I spent a lot of time in dependency hell when I was working out the best way to install dependencies for TalkingLeaves. The best pointer I can give you is to understand how module names work and where Python searches for them. Module names are just folder and/or file names, so import hyperglot will try to find a match like ./hyperglot.py, ./hyperglot.pyc, or ./hyperglot/__init__.py. It just searches a list of paths until it finds a matching module, and you can see (and modify) the list of paths that will be searched by looking at sys.path like this:

import sys
for p in sys.path:
    print(p)

If I run that in Glyphs, I get a list like this:

# All plugins get added to sys.path, so plugin developers should avoid generic 
# module names like "utils" so that one plugin doesn't mistakenly import a 
# module from the other plugin.
/Users/justinpenner/Library/Application Support/Glyphs 3/Plugins/TalkingLeaves/TalkingLeaves.glyphsPlugin/Contents/Resources

# If you `import GlyphsApp` in your plugin, this is where it comes from.
/Applications/Glyphs 3.app/Contents/Scripts311

# This is where the modules from the Plugin Manager reside (vanilla, fonttools)
/Users/justinpenner/Library/Application Support/Glyphs 3/Scripts

# This is where dependencies for plugins should usually be installed
# (hyperglot, pandas, and all of their respective dependencies)
/Users/justinpenner/Library/Application Support/Glyphs 3/Scripts/site-packages

# The next few paths are where the Python standard library modules reside
/Users/justinpenner/Library/Application Support/Glyphs 3/Repositories/GlyphsPythonPlugin/Python.framework/Versions/3.11/lib/python311.zip
/Users/justinpenner/Library/Application Support/Glyphs 3/Repositories/GlyphsPythonPlugin/Python.framework/Versions/3.11/lib/python3.11
/Users/justinpenner/Library/Application Support/Glyphs 3/Repositories/GlyphsPythonPlugin/Python.framework/Versions/3.11/lib/python3.11/lib-dynload

# This is where the GlyphsPython `pip` installs to by default, but you 
# shouldn't add anything to it. pyobjc is preinstalled here.
/Users/justinpenner/Library/Application Support/Glyphs 3/Repositories/GlyphsPythonPlugin/Python.framework/Versions/3.11/lib/python3.11/site-packages

@jpt
Copy link

jpt commented Jul 14, 2024

I'm also getting a crash. Nothing in output though. I suspect it happened after upgrading to Sonoma. I tried re-running the command in the readme to no avail. Will keep poking at it trying to get it to throw an error..

@justinpenner
Copy link
Owner

I'm also getting a crash. Nothing in output though. I suspect it happened after upgrading to Sonoma. I tried re-running the command in the readme to no avail. Will keep poking at it trying to get it to throw an error..

So there isn't a popup window with an error message, or anything in the Glyphs macro window? That would be hard to diagnose unless I can reproduce it on my machine, but I'm running Monterey right now. Let me know if you come up with any details or error messages that might be useful.

Just double-checking, but make sure to use the pip command from the latest readme, which installs both pandas rand hyperglot. Also, for troubleshooting any possible problems with dependencies that are installed in your ~/Library/Application Support/Glyphs 3/Scripts/site-packages folder, it's generally safe to delete the contents of that folder and then run the pip command again to reinstall dependencies. If any warnings or errors come up while installing pandas, hyperglot, and their respective dependencies, they might be useful to post here.

@jpt
Copy link

jpt commented Jul 17, 2024

No output unfortunately... maybe on a system level somewhere but not sure when it's Glyphs python.
In any case, it's a bit wacky, but it resolved itself. I believe it happened after uninstalling and reinstalling an unrelated plugin. Can't explain it, but that's the only thing that changed I can think of that might have had an effect 🤔

@justanotherfoundry
Copy link
Author

Not sure whether this helps but apparently you can specify dependencies in the Plugin Manager.
Just saw this example yesterday: schriftgestalt/glyphs-packages@dc7f567

This might be more convenient for the user than asking them to follow specific installation instructions.

@florianpircher
Copy link

florianpircher commented Jul 17, 2024

That sadly does not work with some of the dependencies of this plugin. HarfBuzz, as part of hyperglot, I believe, cannot be installed this way. We are currently looking into offering PIP for the Glyphs Python such that you could list your requirements directly and PIP installs them as per usual. One major question is what happens if different plugins require different versions of the same package. Since there is just on unified Python runtime inside Glyphs (for performance and memory efficiency and the chance of plugins/scripts to talk to each other, if needed), we cannot load different versions for different plugins.

See also: https://forum.glyphsapp.com/t/python-versions-not-finding-glyphs-python-version-glyphsapp-objc/20640/19

@justanotherfoundry
Copy link
Author

Thanks for the details. I kind of knew I was probably missing something.

@justinpenner
Copy link
Owner

justinpenner commented Jul 17, 2024

That sadly does not work with some of the dependencies of this plugin. HarfBuzz, as part of hyperglot, I believe, cannot be installed this way.

That's correct, a few packages including HarfBuzz, unicodedata2, and PyYAML install different sets of binaries depending on the user's OS, chipset, and Python version. So the Plugin Manager cannot install those, since it only downloads a repo and then makes an alias to a specified folder within it.

We are currently looking into offering PIP for the Glyphs Python such that you could list your requirements directly and PIP installs them as per usual.

I'm working on a module (mainly for TalkingLeaves, but it will be designed for other plugins to use) that wraps pip, and might be used like this:

from glyphspip import GlyphsPip
try:
    import hyperglot
except ImportError:
    hyperglot = None

class ____PluginClassName____(GeneralPlugin):

    @objc.python_method
    def settings(self):
        if hyperglot is None:
            pip = GlyphsPip(pluginName="PluginName")
            pip.require(
                requirements=["hyperglot"],
                successCallback=self.dependencies_installed,
            )

    @objc.python_method
    def start(self):
        pass

    @objc.python_method
    def dependencies_installed(self):
        global hyperglot
        import hyperglot

GlyphsPip.require() opens a modal to tell the user that the plugin wants to install dependencies, asking the user to confirm. Then it runs pip in a new thread, showing pip's progress/output in a new modal, then invokes a callback once pip is done.

But for this module to work, the user would still need to install Python on their system, until the GlyphsApp team can get pip working inside of GlyphsPython.

One major question is what happens if different plugins require different versions of the same package. Since there is just on unified Python runtime inside Glyphs (for performance and memory efficiency and the chance of plugins/scripts to talk to each other, if needed), we cannot load different versions for different plugins.

I have thought about this. The solutions that come to mind are limited: a) keep all pip packages updated, so plugins are forced to support the latest version of their dependencies, or b) allow plugins to specify versions using the standard pip syntax with ==, >=, >, <=, <, and resolve conflicts between plugins by choosing the later version and therefore breaking the outdated plugin. Or c) the same as (b) except notify the user and ask them to choose which plugin to break. With option (a) the developer could choose to bundle their own fixed version of a package, but they would need to edit the code inside that package to add a prefix to all local imports. And to enforce option (a) the GlyphsApp team would need to move Scripts/site-packages to the top of sys.path so it comes before all the plugin paths.

It would also be handy to have a small GUI where the user can see a list of installed packages, add/remove/clear all, as well as enter the name of any pypi package to install it. That is on my roadmap for my "GlyphsPip" project, but whether I implement it probably depends on what the GlyphsApp team are working on.

@florianpircher
Copy link

But for this module to work, the user would still need to install Python on their system, until the GlyphsApp team can get pip working inside of GlyphsPython.

PIP should work in the latest Glyphs Python, see:

https://forum.glyphsapp.com/t/python-versions-not-finding-glyphs-python-version-glyphsapp-objc/20640/15

@justinpenner
Copy link
Owner

But for this module to work, the user would still need to install Python on their system, until the GlyphsApp team can get pip working inside of GlyphsPython.

PIP should work in the latest Glyphs Python, see:

https://forum.glyphsapp.com/t/python-versions-not-finding-glyphs-python-version-glyphsapp-objc/20640/15

Fantastic! I wasn't aware it was fixed. It seems to work for me after removing all other Python frameworks from my system.

@florianpircher
Copy link

It seems to work for me after removing all other Python frameworks from my system.

Yeah, wrangling Python can be complicated. Removing all other versions should not be necessary, we’ll look into why that might be. Let us know of any other issues; this is still very much work in progress as there is not one true solution™ to managing Python dependencies.

@justinpenner
Copy link
Owner

justinpenner commented Jul 17, 2024

Removing all other versions should not be necessary, we’ll look into why that might be.

I should have clarified: removing all other Python versions is only necessary to test whether the fix for GlyphsPython's pip is working. Previously, GlyphsPython's pip was working for some people but not others, because it was broken but it was able to fall back to another Python version if it was available in certain locations such as /System/Library/Frameworks or /Library/Frameworks. See https://forum.glyphsapp.com/t/better-method-for-installing-python-dependencies/26972/35.

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

No branches or pull requests

4 participants