How do I make properties ignore the `set` function when they're initialized?

Godot Version

v4.7.2.stable.official [ed1daf0bf]

Question

My game has a few different fonts, and in order to quickly switch between them and change custom_minimum_size to adapt to them, I added a function that does exactly that.

@export var font_style: Styles:
	set(value):
		font_style = value
		update_font_style() # load the fonts
		
		match value:
			Styles.DIALOG:
				custom_minimum_size = MIN_SIZE_DIALOG
			Styles.DIALOG_SMALL:
				custom_minimum_size = MIN_SIZE_DIALOG
			Styles.MENU:
				custom_minimum_size = MIN_SIZE_MENU
			Styles.TITLE_CARD:
				custom_minimum_size = MIN_SIZE_TITLE_CARD
		
		if font_style == Styles.DIALOG or font_style == Styles.DIALOG_SMALL:
			text_color = ColorPresets.REGULAR
		elif font_style == Styles.TITLE_CARD:
			text_color = ColorPresets.GOLD

However, while this is really handy when I need to change the font style, it’s not so handy when my labels change their minimum size after a reload. So how can I say something like “I want you to change minimum size when you don’t have a custom font resource or if you have one but it’s not the same as the one you already have loaded”? I tried if not has_theme_font_override("font"): update_font_style(), but that doesn’t work since when the node is initialized, it doesn’t have a font loaded either way

Is this an editor script? Do you change font_style at run time? Maybe you can add if Engine.is_editor_hint() if you do only use this export for changing in-editor?

I know it’s common enough to use await ready to delay setters until the node is in the scene tree, maybe you could check if get_parent() returns null to determine if it isn’t in the scene.

I think it would still mess things up but only when the scene is reloaded in the editor, since it still has to load the font resource and all

But since I usually append my labels as children of other nodes, wouldn’t it never return null?

Then maybe await ready is what you want, maybe sharing update_font_style() would help clarify what data you are dependent on, and what exactly is going wrong vs what you expect

it should be non-null, to see it in the scene at all get_parent must be non-null. But nodes aren’t yet in the scene at the time of @export’s initialization, at least as I understand it get_parent() may return null at that time, could be wrong.

There’s a common idiom for setters that need to run some code only if some initialization condition is met. It’s typically done for ready state but can be used for any custom state.
In the setter, run the dependent code only if condition is met. When some other part of the code initializes the condition - call the setter explicitly immediately afterwards.

@export var foo:
	set(value):
		foo = value
		if is_node_ready():
			# do dependent stuff

func _ready():
	foo = foo

Didn’t it work this way until some update? Or did I get it wrong? Because I explicitly have font_size set an extra time in _ready() and I think I wouldn’t’ve had it if it always worked the way it does now

Edit: okay wait this works in the editor but not in the game for some reason

We don’t know what your actual condition is. It may still not be met when this node’s _ready() is called.