How to create and use python modules (files) in Mechanical
This relates to how to architect and create a solution that is maturing past something that is a snippet, or a set of routines into a code base where you have multiple files with routines and variables that may need to interact with each other.
""" In this example lets say you have a module you want to use at: "C:\Users\MyName\MyData\Code\MyModule.py" There is a method in this file called "DoMyStuff()" """ #import the sys module and add the path to the code to sys.path so you can import from that path import sys CodePath = r"C:\Users\MyName\MyData\Code" if not CodePath in sys.path: sys.path.append(CodePath) import MyModule #Imports the module for use reload(MyModule) #Only required if you want to save and re-read the new code MyModule.DoMyStuff() #Run the method from your file
Comments
-
Mike:
When I follow your procedure with the function below in the imported module it throws errors; can't find Ansys, MessageSeverityType.Info, etc. Same function in script window or in Python Code Object DPF works fine. Help please?
Thanks,
Ray
def send_WB_msg(my_msg):
"""
function to send a message to the user through a WB message - use as we do things test, test, test, for each step or thing, the python way...
"""
try:
print my_msg
except:
msg = Ansys.Mechanical.Application.Message(my_msg, MessageSeverityType.Info)
ExtAPI.Application.Messages.Add(msg) #test #send_WB_msg('Hello from DPF!')0 -
Good question!
The imported modules do NOT have the same variables like "ExtAPI" and "Ansys" defined within them. Often this is required to do anything worth doing, so you can use the following convention of having an "Initialize" function you use whenever importing these modules:
Update to original post text:
#import the sys module and add the path to the code to sys.path so you can import from that path import sys CodePath = r"C:\Users\MyName\MyData\Code" if not CodePath in sys.path: sys.path.append(CodePath) import MyModule #Imports the module for use reload(MyModule) #Only required if you want to save and re-read the new code MyModule.Initialize(ExtAPI, Ansys) #Call this function right after import or on reloading MyModule.DoMyStuff() #Run the method from your file
In MyModule.py lets say you also reference another module. You should have something like this at the top. After you have "Initialized" it after import, it will have the same global references and you should fix the error you mentioned.
ExtAPI = None; Ansys = None from module_base import * #This will import the Ansys.Mechanical.DataModel.Enums items import SomeOtherModule #another modules you are using in the project def Initialize(MyExtAPI, MyAnsys): global ExtAPI; global Ansys ExtAPI = MyExtAPI; Ansys = MyAnsys SomeOtherModule.Initialize(ExtAPI,Ansys) #Initializing the ExtAPI and Ansys variables on any used modules
5 -
Hi!
I initially thought the updated answer was a "catch-all" for the type of problem presented by Ray. However, I encountered some trouble and it took a while to realize it was just an example of how to write Initialize() to solve that specific problem. For others who might make the same mistake as me, I append a similar problem when referencing DataModel:
Let's say I want to get the current ForceUnit in Mechanical. From the Python scripting prompt, I can write:
forceUnit = DataModel.CurrentUnitFromQuantityName("Force")
If I use the solution proposed by Mike on July 28th, and I have my module saved in forceChecker.py, then forceChecker.py should look like this if I understand the answer correctly:
#forceChecker.py ExtAPI = None; Ansys = None from module_base import * def Initialize(MyExtAPI, MyAnsys): global ExtAPI; global Ansys; ExtAPI = MyExtAPI; Ansys = MyAnsys; def getForceUnit(): ForceUnit = DataModel.CurrentUnitFromQuantityName("Force") print(ForceUnit) return ForceUnit
and I would get my force unit by running the following code in the python scripting interface:
# main.py import sys CodePath = r"\\pathToModules\\" if not CodePath in sys.path: sys.path.append(CodePath) import forceChecker forceChecker.Initialize(ExtAPI, Ansys) currentUnit = forceChecker.getForceUnit()
However, doing so yields the following error message:
"global name 'DataModel' is not defined"
DataModel also needs to be passed to Initialize(). If we update our code and pass the DataModel to the Initialize function, everything works as expected:
#forceChecker_v2.py ExtAPI = None; Ansys = None; DataModel = None; from module_base import * def Initialize(MyExtAPI, MyAnsys, MyDataModel): global ExtAPI; global Ansys; global DataModel; ExtAPI = MyExtAPI; Ansys = MyAnsys; DataModel = MyDataModel; def getForceUnit(): ForceUnit = DataModel.CurrentUnitFromQuantityName("Force") print(ForceUnit) return ForceUnit
and
# main_v2.py import sys CodePath = r"\\pathToModules\\" if not CodePath in sys.path: sys.path.append(CodePath) import forceChecker forceChecker.Initialize(ExtAPI, Ansys, DataModel) currentUnit = forceChecker.getForceUnit()
0 -
@augustbrandberg ,
You are right. There is some loaded in shorthand in the mechanical scripting console. Things like: Model, Tree, DataModel and some others are ready in the global scope. All of these are derivative of ExtAPI like ExtAPI.DataModel, so if you have ExtAPI you can get to the variables you need.As pointed out, you can also set whatever global module variables you want and set them in the Initialize function so your module acts in the same way as the scripting console.
0 -
Most of the things I can access using the ExtAPI as you wrote. I still have a problem accessing things like 'Quantity', 'Field', 'DataModelObjectCategory', ... .
(For the DataModelObjectCategory I have found a workaround using the Ansys.ACT.Automation.Mechanical., but that's all I could find out how to do)
Is there a way to access Quantity or Field using ExtAPI or Ansys?
I just want to avoid to put all of them into the 'Initialize()' function of the .py file0 -
Put this in your file. This will take care of things like quantities and DataModelObjectCategory. This will generally have all the enumerations you get in the scripting console. Check the globals() after importing these. There will probably be hundreds of imported objects.
from module_base import *
0 -
Another trick to import all variables from your main file:
from __main__ import *
Sometimes module_base is discovered to have missing items after release. It can therefore be helpful to look at newer versions for hints. You can find it in your Ansys installation directory, for example (24R1 default):
C:\Program Files\ANSYS Inc\v241\aisol\DesignSpace\DSPages\PythonIt is based on another file that can also offer hints:
C:\Program Files\ANSYS Inc\v241\Addins\ACT\apis\Mechanical.py0