Is there a way to access a bpy.types.Operator value?

I have a popup that can allow the user the set a value. I can see that the value is getting set correctly as it reports it to the console. However after the function that calls the Operator completes how is it possible to access values that we set inside the Operator class?

class OpenBrowser(bpy.types.Operator):
    bl_idname = "open.browser"
    bl_label = "Select Path"
    bl_options = {"REGISTER", "UNDO"}

    directory = StringProperty(subtype="DIR_PATH") 
    cancel_search = BoolProperty(
        name="Cancel Search",
        description="If no further images are to be found",
        default=False,
    )

    def execute(self, context):
        display = "dirpath=" + self.directory  
        print(display)  
        return {'FINISHED'}

    def invoke(self, context, event): 
        wm = context.window_manager
        wm.fileselect_add(self)
        return {'RUNNING_MODAL'}  

bpy.ops.open.browser('INVOKE_DEFAULT')

How do I access the value that was set for directory following the the completion of the last function call?

if this is for 2.8 then your class variables names and your class name do not follow the conventions of 2.8 as can be found here https://wiki.blender.org/wiki/Reference/Release_Notes/2.80/Python_API/Addons

An operator is a python class as such its variables are accessed the same way as all other python class objects. A Class object can define either class variables or instance variables, instance variables usually are defined inside the initialisation method __init__(self) as

self.my_instance_variable = "hello world".

In this case you use class variables as such you can access them directly from outside the class like this

print(OpenBrowser.directory)

this is under the assumption that the name of the class has been imported in the current namespace you are using (eg. module) . You can also access the same way the class variables from inside the class or you can use the special variable __class__ which like self represents the instance of class , __class__ represents the class of the instance.

print(self.__class__.directory)

The above example assumes the command is executed from inside the definition of an instance method , in your case can be either execute or invoke. __class__ is used here for mere convenience just in case you decide to change its name, so you don’t have to rename/rewrite also every piece of code that refers to it.

This means that your line of code

display = "dirpath=" + self.directory

is wrong because your directory variable is a class variable and you access it as an instance variable the correct would be either

display = "dirpath=" + OpenBrowser.directory

or

display = "dirpath=" + self.__class__.directory

I don’t think I have explained myself correctly. In a perfect world it should be something like this

x = bpy.ops.open.browser('INVOKE_DEFAULT')
print(x.directory)

however what ever is returned from the function call it is not the object as the object that is returned does not have a directory attribute. If the object has been created and is in the design some where where is it and how do I access it?

At the moment I am trying to write code that will work on both 2.79 and 2.80,

if you define it as a class variable as i told you then you will be able to access it outside even from its module like this

import sys
d = sys.modules["name of your addon goes here"].OpenBrowser.directory
print(d)

the name of your addon if its a python package is the name of its folder.

The code above goes through the list of modules imported by python, locates a specific module by name and references an object from inside it. In order for the module to be imported it will have to be registered which means that the addon was enabled by the user.

Using import sys seems way to heavy handed. I’ll give it go though.

Maybe I’ll explain my use case. I am working on a importer. I have an operator that opens file browser and picks the file to import. That works fine. As part of the import it looks from the images that are in the file that is being imported. If a file cannot be found i want to raise an exception, that opens another Operator and allow the user to pick a new directory, so imagine a operator that calls an operator on exception.

Or should i, in the function be setting the value to something that more global

the above I mention is also the same as

import name_of_your_addon
print(name_of_your_addon.OpenBrowser.directory)

obviously if its the same module (even if it is a different class) , there is no need for import and you can access the variable directly as I have already described in my first reply

the reason I gave you the first method is because its more reliable as it has full access to all modules imported by python while this one depends on the scope.

You can also store your property as part of the current scene, this is a common way to save addon data with the blend file.

I can think of many other solutions but I do not see why you will want so many solutions for one simple problem.

using global variables is considered very bad practice because they are prone to name conflicts (make it an easy mistake to use same name for different variables) and that are very hard to debug.

you keep describing how to instantiate a class. I get that, but i don’t want any class instance, I want the one that get called and spawns a popup window, sets a value, and then use that value else where. I think the my answer is closer to storing the property as part of the scene, the value that gets set I might want to use later.

The solutions I provided work predominately with class variables.

The reason I mentioned also the approach of instance variables is because this line of code you use

display = "dirpath=" + self.directory

is accessing an instance variable. I assumed that this was a mistake and you intended to access the class variable directory you previously defined. But just in case I was wrong and you indeed had also an instance variable named directory, I gave you also an instance variable solution.

But most of my first reply and all other replies focus on class variables. Using a class variable to share state between instances is a valid way of doing this. That’s is the prime purpose of class variables anyway.

So the last 2 replies are 100% class variable access. I actually use class variables for my modal operator to make sure that there is only one instance of the modal operator running at a time. Although in my case I do not use properties but standard python variables which means basically booleans and strings.

I also have never described how to instantiate a class, only how to define class and instance variables and how to access them from inside and outside the class.

To access properties from a specific (executed) operator try something like:

wm = bpy.context.window_manager
operator = [op for op in wm.operators if op.name == 'My Operator']

if operator:
    print(operator[-1].my_property)

This only works for operators with register/undo and annotated properties.

Otherwise, you can store temporary values in the global dictionary bpy.app.driver_namespace.

1 Like