"Global name 'world' is not defined" in Client Tag Change script

Hi,

I have a piece of code that works fine in actionPerformed of components. The same exact code leads to “Global name ‘world’ is not defined” in my Client Tag Change script. Any idea why?

Code

from project.hello import world
try:
    def long_process():
        success = world()

        def send_back(success=success):
            if success:
                ...
            else:
                ...
        system.util.invokeLater(send_back)
    system.util.invokeAsynchronous(long_process)
except:
    ...

There is a scoping issue:

2 Likes

Thanks a lot!

Can I call success in send_back when I am not passing it as a parameter?

I’ve read this topic, but It’s not clear to me how I can solve this? Could you please elaborate?

The import doesn’t work because it doesn’t scope into your functions. You need to specifically reference it each time you use it:

try:
    def long_process():
        success = project.hello.world()

        def send_back(success=success):
            if success:
                ...
            else:
                ...
        system.util.invokeLater(send_back)
    system.util.invokeAsynchronous(long_process)
except:
    ...

You should still be able to use success as a parameter. Also, since you are using this in an event script, I don’t think you’ll need to use invokeLater, since it will run in a different thread.

This isn't strictly true. Inner functions have access to outer scope variables captured at the time of definition in their closures. In modern python. Legacy scoping is funky. That's one of the reasons later.py is a script module -- modern scoping applies no matter what calls into those functions.

1 Like

Thanks for the clarification, Phil. What about the use of invokeLater in a Client Tag Change event script?

I don’t remember which of those events use legacy scoping. If it isn’t a component event, I always place the actual event code in a project script module. Modern scoping is then applicable and closures work as expected.

1 Like

This doesn't work. Leads to global name 'project' is not defined

You aren't showing your code, but I'm going to guess that your project.hello.world() call is within another function you defined within the event. Legacy scoping basically prevents any function defined within the event from having system, shared, or project automatically present. They'll only be present at the top level.

Make your event a one-liner, passing the event to a project script:

project.someModule.someEventHandlerFunction(event)

If the event has other local variables, pass them to your function, too, if you need them. Do everything in that function.

Otherwise, import system, shared, and project in every nested function that needs them.