I’m working on a build script to help manipulate a GlyphsApp source via the command line, and I’ve gotten fairly far in using the Glyphs Core API (https://docu.glyphsapp.com/Core/index.html).
However, I’m getting hung up at trying to access layers and their associatedMasterIds, in order to copy outlines into newly-added masters. The code I’m ultimately trying to get to is similar to what you helped me figure out in the thread " How might I trigger “Instance as master” from the API?. I have successfully accessed an interpolatedFont and added a master, but now I need to copy between layers, and I’m hitting a wall.
Here’s an example of code I’m using. I call it with a command like python scripts/SCRIPT.py sources/FONT.glyphs:
from Glyphs import *
import sys
import os
import objc
relPath = sys.argv[-1] # gets file path passed in with command
directory = os.getcwd()
document = Glyphs.open((str(directory + "/" + relPath)), False)
currentFont = document.font()
print(currentFont.glyphs()[4]) # 👍 GSGlyph <0x7ffcc505d960>: Abrevedotbelow
print(currentFont.glyphs()[4].layers) # 👍 <native-selector layers of GSGlyph <0x7ffcc505d960>: Abrevedotbelow>
# The following are ways I tried to access the layer object, and the errors I received.
# print(currentFont.glyphs()[4].layers[0]) # 🚫 TypeError: 'objc.native_selector' object is not subscriptable
# print(currentFont.glyphs()[4].layers_()) # 🚫 AttributeError: 'NSDistantObject' object has no attribute 'layers_'
# print(currentFont.glyphs()[4].layers_()[0]) # 🚫 AttributeError: 'NSDistantObject' object has no attribute 'layers_'
# print(currentFont.glyphs()[4].layers()) # 🚫 objc.error: NSInternalInconsistencyException - decodeObjectForKey: class "MGOrderedDictionary" not loaded
# print(currentFont.glyphs()[4].layers()[0]) # 🚫 objc.error: NSInternalInconsistencyException - decodeObjectForKey: class "MGOrderedDictionary" not loaded
Thanks so much for any insight on this. I feel so close to doing what I need to do!
When script outside of Glyphs, the python wrapper is not available. So pretty much everything is a method and not a property. So you need to add parents behind everything.
Traceback (most recent call last):
File "scripts/helpers/git-remote-tests.py", line 14, in <module>
print(currentFont.glyphs()[4].layers()[0])
objc.error: NSInternalInconsistencyException - decodeObjectForKey: class "MGOrderedDictionary" not loaded
Thanks, @GeorgSeifert! This really came in handy, today.
(If anyone comes across this and is curious, I used it to access and decompose a specific glyph during a FontMake build process, in order to get around what seems to be a rendering bug on macOS. Script: decompose-oslash.py)
@GeorgSeifert@thundernixon Can you explain how I make the Glyphs Core API module available outside Glyphs? Do I copy or system link something to Python packages folder?
Thanks, working great! However I’m having difficulty with methods that aren’t documented in the Core API Docs. And using help() and dir() doesn’t reveal any useful information.
For example, I’d like to export the Font as a variable font, and can see there is an “export” method on the Font object, but cannot see what input it requires.
Ok, I would like to export the font as a variable font using the Core API. Is there any way to achieve this? I use tools like fontmake as well but for a particular build I need the GX font from Glyphs and currently need to export it manually.
I’m confused … my remote script for decomposing a specific glyph has stopped working, even if I use the previous versions of GlyphsApp (e.g. Version 2.5.2 (1191)).
For instance, print(font.fontMasterAtIndex_(0)) yields this error:
Traceback (most recent call last):
File "sources/scripts/helpers/decompose-oslash.py", line 27, in <module>
print(font.fontMasterAtIndex_(0))
objc.error: NSInternalInconsistencyException - decodeObjectForKey: class "GSFontMaster" not loaded
As another example, the original code:
for index,master in enumerate(font.fontMasters()):
print(master)
print(index)
master = font.fontMasterAtIndex_(index)
print(glyph.layerForKey_(master.id()))
glyph.layerForKey_(master.id()).decomposeComponents()
…results in:
Traceback (most recent call last):
File "sources/scripts/helpers/decompose-oslash.py", line 30, in <module>
for index,master in enumerate(font.fontMasters()):
objc.error: NSInternalInconsistencyException - decodeObjectForKey: class "GSFontMaster" not loaded
I know that my remote script still works to a degree, because I still get the correct index when I search for /oslash in the font:
def oslashIndexer():
oslashIndex = 0
for index,glyph in enumerate(font.glyphs()):
if glyph.name() == "oslash":
oslashIndex = index
return oslashIndex
oslashIndex = oslashIndexer()
print(oslashIndex)
# result: 389
I’m (nearly) certain that this scripting worked on the 18th. I can’t think of anything I’ve changed in my environment or the source file that would have caused the difference.
Thanks for the information! So, I guess some version of the app would probably work?
For now, I’m just manually decomposing the offending glyph, and leaving the composed version as duplicated layers, if someone needs to edit that in the future.
I think I saw you mention this in another thread, but I’m having trouble finding it now: is it possible to run a script that is available to Glyphs (a script that is in the Scripts menu) using remote execution? because then I could just handle that part of the build script using an installed-in-Glyphs script, instead of needing fontMasterAtIndex_