(Python help) Saving preferences with Glyphs

Hi, as part of a script I am trying to utilise the Glyphs.defaults. Theoretically, everything works, but when I run the script with the imported defaults, when I tick different boxes than was saved beforehand, I get:

TypeError: '__NSDictionaryI' object does not support item assignment

I can only find very little on this error and from what I’ve read, I don’t understand the issue in my code. My basic method is that I have:

my_dict = Glyphs.defaults["com.blabla.prefs"]
if my_box_is_checked:
    my_dict["key1"] = True

Is this a viable method? If anybody wants to take a moment and look at the code on github:

All objects stored in defaults are immutable. So you need to make it mutable:

my_dict = dict(Glyphs.defaults["com.blabla.prefs"])

or

my_dict = Glyphs.defaults["com.blabla.prefs"].mutableCopy()

If your case it might be better to use individual keys.

Glyphs.defaults["com_blabla_prefs_keys1"] = my_box_is_checked

I prefer to not use periods as that doesn’t work well with bindings and KVO.

1 Like

Hi Georg, thank you very much. I’m pretty confident I tried exactly this, to no avail, but I might have missed something and will try again. Regarding periods vs. underscores: I followed the Glyphs documentation, which stipulates that the reverse domain name is to be used, with the example of com.MyName.foo.bar – is that not what I’m looking for?

Many thanks for getting back to me so quickly!

I’m afraid I am still getting the same error, even after assigning like this:

my_dict = dict(Glyphs.defaults["com.blabla.prefs"])

I really don’t know what isn’t working. I’ll find some different solution.

The docs need an update then.
Use the individual keys.

Using individual keys would be extremely annoying, as my font export script iterates through the dictionary for every entry where “Export” == True. It would really be best to have a dictionary which I can save. I tried my_dict = Glpyhs.default[…].copy(), but somehow, now all my callbacks in the checkboxes are broken :grin:
No idea whether that has to do with each other. Would that be a viable solution, though?

Make a list of all keys and iterate though them.

.copy() will not help. Need to be .mutableCopy().

Okay. So. mutableCopy() didn’t work, same error, so I tried to find a way to copy the dictionary value by value. After a ton of wrenched-out hairs and chocolate, this worked for copying a nested dictionary through the Py-ObjC bridge:

dict1 = Glyphs.defaults["my_nested_dict"]
dict2 = {}

for key1 in dict1:
	for key2 in dict1[key1]:
		dict2[key1] = dict(dict1[key1])
		dict2[key1][key2] = dict1[key1][key2]

Don’t ask me why, but for whatever reason, Python throws a KeyError when you omit the second-last line.

The mutable copy is shallow. Meaning nested dictionaries are not mutable (see last line).
That seems to be a bit too complicated.
And the second to last line has an opening parenthesis that is not closed anywhere.

Sorry, fixed the open parenthesis (that was just an error of the example here). Anyway, it works like this all works now and I’m very happy. Thank you for bearing with me!

After a ton more of troubleshooting, it now really works: