How to have variables communicating between two different python files

Hello Everyone !

I hope you are all going well !

I am currently trying to write an Auto-Rig tool for maya.
I want to have different Python files, for every major tasks that needs to be done by the script.
For example : one file for the UI, one for the Joints generation, one for the Arm construction, and so on…

The problem is how to define variables within one file, and use the same variables within another file to create a precise number of fingers, for example.

I want my Auto-Rig to be versatile, in order to do that I need the user to choose between values, and so on…

I will use a simple example,

the user can choose between creating 1 or 2 cubes.
I wrote this to have a better understanding of the issue.

UI_Script :

import maya.cmds as mc

class Window_UI:

    def Create_UI(self):

        UI = mc.window(title='Auto-Rig Tool')

        #Defining main layout
        main_Layout = mc.menuBarLayout()

        #Number of Cubes
        oneCube = mc.checkBox('1 Cube', label='1 Cube')
        twoCubes = mc.checkBox('2 Cubes', label='2 Cubes')

Create_Cube_Script :

import maya.cmds as mc

class Create_Cube:

    def CC(self):

        #Querying the value of the checkBox
        #Do not need to know the value of the second checkbox as we only 
        # have 2 options possible
        oneCube_Value = mc.checkBox(oneCube, query=True, value=True)
        
        
        if (oneCube_Value):
            number_of_cube = 1

        else:
            number_of_cube = 2

        for x in range(number_of_cube):
            mc.polyCube()

Launcher_Script :

import sys 

#load the path of the python files
sys.path.append('G:\\3D2\\Script\\Class_Exp')

import UI_Script
import Create_Cube_Script

reload UI_Script
reload Create_Cube_Script

Here I want to have the value of the checkBox (from de the UI_Script), tu be queried and used by the Create_Cube_Script.

I do know it is possible to do pretty much this kind of thing with Class, but even after days of research, I did not manage to find an answer or a possible way to solve my issue.

Thank you very much for your time.
Cordially.

So your idea of keeping tasks separated into classes is great!
However, you’ve got a bit of a misunderstanding how it works. There’s no magic mechanism for passing data between classes. If you want to pass data from one class to another, you have to pass it in a function.

To do that, I would make it so the Window_UI class was aware of Create_Cube. (When I say “aware” here, I just mean that your UI_Script should have import Create_Cube_Script at the top so you can call functions for creating cubes from inside the UI)

Any time you create an object in the UI layout, you need to store it on self. So when you create your checkboxes, do something like this:

        self.oneCube = mc.checkBox('1 Cube', label='1 Cube')
        self.twoCubes = mc.checkBox('2 Cubes', label='2 Cubes')

So right now, you’ve got two checkboxes in the ui, but you also need a button. That button is what will start the process of building the rig. When you create the button in the layout, you provide it a callback, which is just a function that gets called when you press the button. So, in the callback for that button, inside the Window_UI class, you read the value of the checkboxes, and pass that to your Create_Cube class.

So your Create_Cubes class should look more like this:

import maya.cmds as mc

class Create_Cube:
    def CC(self, number_of_cubes):
        for x in range(number_of_cube):
            mc.polyCube()

And somewhere in your button callback ( in the UI_Script not the Create_Cube_Script), should be code that looks like this:

        oneCube_Value = mc.checkBox(self.oneCube, query=True, value=True)
        cc_instance = CreateCube()
        if (oneCube_Value):
            number_of_cube = 1
        else:
            number_of_cube = 2
        cc_instance.CC(number_of_cube)

Notice the self.oneCube in there? That’s only available if you stored those checkboxes on self like I explained above.
Also when I said there’s no magic, and you have to pass the data in a function, I meant like in the line cc_instance.CC(number_of_cube). I’m passing the number of cubes to create to the function CC

Thank you so much !

I think I undersand what you mean. I juste have one more question, when creating the checkBox with “self”, should I create the UI within the def __init__(self) function ?

import maya.cmds as mc

class WindowUI:
    def __init__(self):
        self.oneCube = mc.checkBox('1 cube', label = '1 Cube')

Or can I just write it like this :

import maya.cmds as mc

class WindowUI:
    def createUI(self):
        self.oneCube = mc.checkBox('1 cube', label = '1 Cube')

Thank you so much for your help !

Based on what you have, it’s probably easiest to build your UI in the __init__.

However, that’s not a hard rule. You could easily do something like this if it makes more sense to you:

import maya.cmds as mc

class WindowUI(object):
    def __init__(self):
        self.createUI()

    def createUI(self):
        self.oneCube = mc.checkBox('1 cube', label='1 Cube')

I like to do this when my UI building code gets big. Yours isn’t big (yet) so I’d just keep it in the __init__. But it’s your code. If you decide to move it later, then go right ahead!

Oh, and also notice what I did here: class WindowUI(object):. If you’re making a class that doesn’t need to inherit from anything special, then you should inherit from object like I’m doing here. It makes it a “new-style class” which fixes some bugs, and it’s a good habit to get into for now.

From now on I have this :

UI_Script :

import sys 
sys.path.append('G:\\3D2\\Script\\Class_Exp')
import Create_Cube_Script

#Instanciate Create_Cube_Script and Class
CCS = Create_Cube_Script.Create_Cube()

import maya.cmds as mc

class Window_UI(object):

    def __init__(self):
        self.Create_UI()

    def Create_UI(self):
        self.UI = mc.window(title='Auto-Rig Tool')

        #Defining main layout
        self.main_Layout = mc.menuBarLayout()

        #Number of Cubes
        self.oneCube = mc.checkBox('1 Cube', label='1 Cube')
        self.twoCubes = mc.checkBox('2 Cubes', label='2 Cubes')

        #Button
        self.actionButton = mc.button(label = 'Run Script !', c=self.checkBox_Value)
        
    def checkBox_Value(self):
        oneCube_Value = mc.checkBox(self.oneCube, q=True, value=True)

        if (oneCube_Value):
            number_of_cube = 1
        else:
            number_of_cube = 2
        CCS.CC(number_of_cube)


Window_UI()
mc.showWindow()

Create_Cube_Script :

import maya.cmds as mc
class Create_Cube:
    def CC(self, number_of_cube):
        for x in range(number_of_cube):
            mc.polyCube()

The UI works perfectly, but when I want to execute the script by pressing the actionButton,
I have this error message : # Error: checkBox_Value() takes exactly 1 argument (2 given) #

I know that self is considered as an argument, and that every function within a class have self as an argument.
However I do not know what is the second argument the error message refers to. I did not write any arguments when creating or calling the checkBox_Value Function.

I thank you one more time for your patience and your time !

Maya button callbacks apparently add an additional argument. Just add an optional arg to your function
def checkBox_Value(self, btn_arg=None): or something like that.

And a couple other general things
Don’t make global variables when you don’t have to. Your variable CCS should either be created inside the checkBox_Value function just in time to call it. Or you could make it i the __init__ and store it on self for later use. When you eventually get to making lots of parts of the rig, you’ll probably make a list that holds a class instance for each part when you push your “Run Script” button. Your character has four legs? Four instances of your “Leg” class in the list. Then you loop through the list and build each part.

Start being consistent with your naming. Classes should use UpperCamelCase (no underscores, first letter capital). Functions and variables should use snake_case (no capitals, underscores separate words). Module names should use alllowercase, or if it enhances readability, use snake_case. These aren’t hard rules, however, they are usually followed. Sometimes you’ll see people use lowerCamelCase for function names and variables. That’s just a style choice. But whatever you choose, stay consistent.

Finally, NEVER use short flags in your code. When you read the checkbox, q should be query. When you make the button c should be command. Get into this habit now.
Code sticks around longer than your memory. It doesn’t matter how much it’s in your head right now, you will forget what a flag means. Save yourself from having to constantly look up flags when you read your old code. Also, some day other people may read your code. Save them some hassle too.

It works with the btn_arg=None, thank you. It’s a bit strange and I don’t quite understand why adding an “empty” argument solve the issue. I am going to do some research about it, to have a clear idea of it works.

I will of course try to stick to all the advices you just gave me, I did know that I need to be conscientious when creating variables, functions, … but I did not know these “common rules” like : writting functions with snake_case and so on…

Thank you so much for your help, I hope one day I will be able to help someone like you did with me.

Cordially,
Luca.