App initializations and hooks, difference in DCCs

There is a weird difference in behavior between two DCCs.
In the scene operation prepare_new I am calling an app (tk-multi-setframerange).

This works in Houdini, but not in Nuke.
I dug a bit in the tk-multi-workfiles2 code, and it is strange that there is a difference at all - the order of operations should be the same.

The NewFileAction does the following:

  1. reset scene
  2. prepare new scene
  3. change context

The app is configured in shot_step and not in the project environment, so when I am creating a new file in a task, I thought the app would be initialized after the context switch. But it does work in Houdini, so my assumption must be wrong.

Any ideas?

1 Like

Hi @mmoshev,

I’ve reached out to our Toolkit team about this post, they will answer when they have a moment.

To our community, feel free to comment as well! :+1:

Cheers,
Beth

Hey Mois!

It’s not too surprising that the behavior would be a little different here across engines when you get into the details, as scene operations like resetting the scene are native to the DCC. Additionally, there are actually different scene_operation hooks for the different DCCs, which makes different behavior even more plausible. Having said that, the NewFileAction class is not engine-specific; it’s part of the app, so the order in which the operations are executed should be the same across DCCs.

As for which environment’s hooks run at the time you hit the +New File button, my hunch would be the current environment – not the environment of the new file. Regardless of when in the process the context change happens, it doesn’t change configuration mid-hook-execution. This would mean that if you launch from Desktop and immediately browse to a task and hit +New File, you’d be using the hooks specified in the project environment.

I have a few follow-up questions:

  • When you say it doesn’t work, are you just not seeing the framerange get set? Are you getting any errors in tk-nuke.log or in Nuke’s Python console?
  • If in Nuke, you start in a shot_step context, and then go to another shot_step context (ie, you’ve opened a file via Workfiles, then you switch to a different task and hit the +New File button, does it work?
  • It might be helpful to add some logging to confirm that your code is actually being run as you expect – like you said, we may be wrong as far as assuming which environment’s hook is run. There are three things to disambiguate here:
    • ensuring that your modifications have been made in the correct environment (shot_step vs. project)
    • ensuring that your changes have been made in the correct engine-specific hook, and that your config is correctly pointing to it
    • ensuring that there’s not a bug in the logic of the code.

If you can confirm the first two and we know your code is actually running, if it’s still not working, it would be helpful to see how you’re pointing to the hook in your config in both contexts, and perhaps see what the prepare_new code block in your two scene_operation hooks looks like. Hopefully, the first two will take care of it, though. :slight_smile:

Let us know what you find!

Thank you for the detailed response.
The error is key error: tk-setframerange due to me doing

if operation == "prepare_new":
  engine.apps["tk-setframerange"].run()
  • as I laid out, the context change happens last in the process, so I’d have to try switching to shot_step first and then executing the hook by opening another scene.
  • tk-setframerange requires there to be a shot, so it cannot be configured in the project environment, unfortunately.

Let me try your second point, and see if that works.
It is strange though that it works in Houdini. I think automatic context switching works differently there.
Conceptually, what would be the correct solution here? I want the frame range for the shot to be synchronized only when starting a new scene, and do not want to overwrite something that the artist set afterwards. So I don’t know if reacting to context_switch would do the correct thing.

1 Like

Hi Mois –

First just a sanity check: I’m guessing it’s a transcription error, and your actual code is correct, but you’ve got:

if operation == "prepare_new":
  engine.apps["tk-setframerange"].run()

Beyond that, we’re still trying to make sense of the exact order of things, and why things would behave differently from engine to engine, but I ran this by @Ehsan on the engineering team this morning, and he had a great idea for a workaround that might suit your needs.

The idea here is that you’d use the context_change core hook to run setframerange, but it would rely on the presence of a marker of saved state, which you’d set in the prepare_new block in the scene_operation hook.

That way, although the logic would be in the context_change hook, it would only run in cases where the context was changed at New File time.

Here’s the code, again, with big thanks to @Ehsan. Note the caveat below:

In scene_operation_tk-nuke.py :

elif operation == "prepare_new":
    context.sgtk.set_cache_item("FILE_CREATION_IN_PROGRESS", True)

In context_change.py :

from sgtk.platform import current_engine
engine = current_engine()
if engine.name == "tk-nuke":
    if current_context.sgtk.get_cache_item("FILE_CREATION_IN_PROGRESS"):
        engine.apps["tk-multi-setframerange"].run_app()
        current_context.sgtk.set_cache_item("FILE_CREATION_IN_PROGRESS", None)

So it IS possible, but the set_cache_item method has this warning in its docstring:

Internal Use Only - We provide no guarantees that this method
will be backwards compatible.

Hope that helps! Let us know how it goes.

2 Likes

This sounds like it could work, thanks!

As I mentioned in the post, NewFileAction changes the context as last step, after prepare_new. One solution would be to change that order, but of course that’s bound to break a lot of existing hooks.

Will try the cache item solution and let you know.

Could it be that the opening happens “asynchronously” in one DCC and not in the other?

It does work, thanks a bunch!

We can live with using an internal method for the time being.
I wonder if there would be a “correct” solution, but there is a lot going on in workfiles that I don’t fully understand yet.

3 Likes

Actually there is a complication - Nuke now works (it was the problematic one initially), but Houdini does not.
The context_change hook does not get called in Houdini at all, though it is configured for the shot step environment. I see this in the tk-houdini logs, which I did not expect:

2020-10-28 16:11:47,905 [9744 DEBUG sgtk.env.shot_step.tk-houdini] Engine <Sgtk Engine 0xeb423630: tk-houdini, env: shot_step> does not allow context changes.
2020-10-28 16:11:47,907 [9744 DEBUG sgtk.env.shot_step.tk-houdini] Context change not allowed by engine, restarting instead.

automatic_context_switch is true by default, and I do not have overrides.
The original code I had for prepare_new does not work in Houdini now…

Hi @mmoshev,

I looked at this again and have another solution for you that feels a bit cleaner. It does require changes to the tk-multi-setframerange app. I’ve created a branch with the changes here.

In the scene_operations hook, the context you have available is the shot context you’re after. So you can modify the app’s run_app method to accept an optional context parameter and, if supplied, use that context instead of the current context.

The validation in the init_app method needs to be moved to allow the app to be added to the project environment as well.

I would also set the menu_name setting for the app to be an empty string in the project environment so the sync frame range menu item isn’t available.

2 Likes

Thank you, we are already using a forked tk-multi-setframerange (which also sets fps).
This sounds somewhat cleaner, though the possibilities of preparing a scene remain limited due to the new context not being available in prepare_new.
I’ll try it and report back.
Related to that, does tk-houdini allow context change? I scoured through the code but could not get a definite answer.

Just to clarify, in the scene_operation_hook when you’re processing prepare_new, the context parameter that’s passed in is the new context. It just hasn’t been set as the current context on the engine yet.

Regarding the Houdini part, I’ll have to take a look and get back to you.

1 Like

Right, thanks for the clarification. Yes the root problem here is that the engine has not initialized apps for the new environment. Cheers.

It looks like tk-houdini doesn’t define a context_change_allowed method. That means it is inheriting the default implementation which returns False, therefore not allowing context changes.

I’m not familiar enough with Houdini or the engine to comment on why this is the case though.

@Ehsan the suggestion worked, so once again thanks! The tk-multi-setframerange app is defined in the project environment, and gets called from there, with context explicitly passed from scene_operation.

The Houdini engine is a bit puzzling, there is a timer that scans the file name and changes context when it detects a new one. Perhaps someone who worked on the implementation could shed some light? Not critical at this point, but would be interesting and potentially useful for further customizations.

1 Like

While working on something else, I guess I found the reason for the timer - opening a file in Houdini is asynchronous, and even the hou.hipFileEventType.AfterLoad does not guarantee that the loading has completed… or so it seems.