Unittesting callbacks on a hda issues and questions

   1359   5   2
User Avatar
Member
13 posts
Joined: 2月 2016
Offline
Hi. I am making integration tests to verify that our production otl is always able to publish and load from the artists point of view. The issue that that I am having is that the callbacks happen after the script ends. For example a script that changes "parm1" which has a callback to set "parm2 with the same value as "parm1" won't trigger until my original script is over. In a case of a unittest I'd like to trigger those events.
Another example of this issue is that I can't capture raised Errors from a Parm.pressButton().
I used a subnet with button that had a `raise ValueError('test')` as a callback. Which allowed me to test with
try:
    hou.node('/obj/geo1/subnet').parm('button').pressButton()
except ValueError:
    print("error captured")
Nothing will get printed because the error happens later in event handling. Is there a pythonic way to force eval the events mid script execution?
User Avatar
Member
1906 posts
Joined: 11月 2006
Offline
I think you'll probably need to provide an example file of what you're trying to do since there should be no issue running callbacks via non-graphical Houdini and a quick test results in the expected behavior.

In terms of catching errors related to pressButton(), you'll never be able to. While calling it is done in Python, there's no guarantee that the callback is executing Python so there's no real expectation that any errors experienced during the callback would bubble up as something useful. It's mildly inconvenient that it doesn't throw some general exception like hou.OperationFailed when something seems to go wrong though.
Graham Thompson, Technical Artist @ Rockstar Games
User Avatar
Member
122 posts
Joined: 6月 2019
Offline
Yeah, this context is isolated and don't reraise which is unfortunate.

I think one solution is emulate this context and execute callback statement as string. It's just a bit tricky, depends on how artists use callbacks and do they use hda python modules. It's just you can trigger callback like hou.phm().on_parm()or kwargs["node"].hm().on_parm()
I guess something like this could work (py 3.9)

try:
    # emulate expression context
    expression_ctx = globals() | {
        "kwargs": {
            "node": hou.node("/obj/geo1/subnet"),
            "parm": hou.parm("/obj/geo1/subnet/button")
        }
    }

    callback = hou.parm("/obj/geo1/subnet/button").parmTemplate().scriptCallback()
    callback = f"hou.cd('/obj/geo1/subnet')\n" + callback # if you use hou.phm() for callback
    
    exec(callback, expression_ctx)
except Exception as err:
    print(f"Catched:\n {err}")

This is just a minimal example. To fully emulate this context you should pass everything in kwargs listed here: https://www.sidefx.com/docs/houdini/hom/locations.html#parameter_callback_scripts [www.sidefx.com]

It's also for python only callbacks, hscript in general doesn't throw as graham said. Though I'm not sure if it's useful as callback language.
Edited by elovikov - 2023年6月9日 05:35:57
User Avatar
Member
13 posts
Joined: 2月 2016
Offline
@elovikov thanks for the time to answer. As I was preparing a scene file for Graham today, I was thinking too of emulating the callback by running it through python exec. Luckily I am working on a package that doesn't use the global kwargs, so as long as I replace the hou.pwd() or hou.phm() calls by hou.node("/full_path_here") I should be good to run my tests.

@Graham I made this scene quickly to illustrate callback issues. Ideally I would have also given a hython script to go with it that opens the scene and does the small test, but instead I made a scene with two subnets and in one of them you have a payload that runs a test and the other holds a callback setup. subnet1 has a string parm called string1 that when changed should change string2 value. In the current example the callback is never executed for me. Again I knwo that ideally I should have given a hython test, but I need more time to look at how to run hython from windows. I usually work with linux and so this a quick setup to illustrate while I also build a hython example if this still get's attention.

I think elovikov has the right answer in terms that we might not have the possibility to test user interface using the conventionnal callback implementation. We might need to make a custom test function that sets a value on a parm and then emulate the callback through trickery :P

It would have been nice if there was a manual way to trigger a pass of callback evaluation through the hou module.

Attachments:
callback_example.hipnc (46.2 KB)

User Avatar
Member
1906 posts
Joined: 11月 2006
Offline
So the problem with your hip file, and tests assuming that they matching what this is doing, is that when you set a parameter via Python (or hscript) it doesn't actually cause the parameter callback to execute: you need to call hou.Parm.PressButton() to execute it. Annoyingly there is no kwarg on set() that allows you to trigger it in one go like the hscript opparm -C flag.

In terms of the issue with hou.Parm.pressButton() being lame and not helpful for discerning if anything happened I would probably forgo any attempts at using it. If it were me I would have things set up so that my callback was calling into the PythonModule (or I guess it could just be importing and calling all at once) such that to "test" it I would just call the function in the HDA module directly.

To ensure nobody messes with the callback code I'd probably access the parameter template and validate the code it's running is what I expect and that the language is set to Python. Not necessarily ideal but that's how I'd just do this call. Alternatively depending on what the callback is calling into, you could maybe just mock that, actually run the callback, and validate it was called with the expected args.
Graham Thompson, Technical Artist @ Rockstar Games
User Avatar
Member
13 posts
Joined: 2月 2016
Offline
I like this idea too. Thanks Graham. making sure the callback is the expected code sounds good too.
  • Quick Links