Community
Fusion API and Scripts
Got a new add-in to share? Need something specialized to be scripted? Ask questions or share what you’ve discovered with the community.
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Importing Python Modules (those I create) into Scripts

4 REPLIES 4
SOLVED
Reply
Message 1 of 5
Anonymous
3795 Views, 4 Replies

Importing Python Modules (those I create) into Scripts

Anonymous
Not applicable

I have two python files, one with Utility functions and some with a script for running in Fusion 360. Both scripts are in the same directory. Normally using import Utility or Utility.py or from Utility import ReportMessageBox would work in a python enviroment. But when I do this and run my script, nothing happens in fusion 360. If I copy the code into my script it runs fine, so its definetly an import issue. How do I fix this?

import adsk.core, adsk.fusion, adsk.cam, traceback
import Utility.py

def run(context):
    ui = None
    try:
        app = adsk.core.Application.get()
        ui  = app.userInterface
        ui.messageBox('Hello script')
        Utility.reportMessageBox(ui, "Report is through", ("random"))

    except:
        if ui:
            ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

#Next File
#import adsk.core, adsk.fusion, adsk.cam
#
#def createNewComponent(rootComp):
#    allOccs = rootComp.occurrences
#    newOcc = allOccs.addNewComponent(adsk.core.Matrix3D.create())
#    return newOcc.component
#
#def nameObject(objectA, name):
#    objectA.name = name;
    
def reportMessageBox(ui, message, parameters):
    ui.messageBox("In here")
    for parameter in parameters:
        newMessage = message.replace("{}", str(parameter),1)
        if message == newMessage:#{} was not found and replaced
            message+=", "+str(parameter)
        else:
            message = newMessage
    ui.messageBox(message)
0 Likes

Importing Python Modules (those I create) into Scripts

I have two python files, one with Utility functions and some with a script for running in Fusion 360. Both scripts are in the same directory. Normally using import Utility or Utility.py or from Utility import ReportMessageBox would work in a python enviroment. But when I do this and run my script, nothing happens in fusion 360. If I copy the code into my script it runs fine, so its definetly an import issue. How do I fix this?

import adsk.core, adsk.fusion, adsk.cam, traceback
import Utility.py

def run(context):
    ui = None
    try:
        app = adsk.core.Application.get()
        ui  = app.userInterface
        ui.messageBox('Hello script')
        Utility.reportMessageBox(ui, "Report is through", ("random"))

    except:
        if ui:
            ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

#Next File
#import adsk.core, adsk.fusion, adsk.cam
#
#def createNewComponent(rootComp):
#    allOccs = rootComp.occurrences
#    newOcc = allOccs.addNewComponent(adsk.core.Matrix3D.create())
#    return newOcc.component
#
#def nameObject(objectA, name):
#    objectA.name = name;
    
def reportMessageBox(ui, message, parameters):
    ui.messageBox("In here")
    for parameter in parameters:
        newMessage = message.replace("{}", str(parameter),1)
        if message == newMessage:#{} was not found and replaced
            message+=", "+str(parameter)
        else:
            message = newMessage
    ui.messageBox(message)
Tags (3)
4 REPLIES 4
Message 2 of 5
KrisKaplan
in reply to: Anonymous

KrisKaplan
Autodesk
Autodesk
Accepted solution

This has to do with the way script modules are loaded into the shared Python environment in Fusion.  Your script is not being run as the __main__ module, but loaded and run in an existing environment.  So any imports would be relative to the existing sys.path.  But it would not be recomended to modify sys.path (because it would affect other scripts).  Instead, you should use relative imports.  So you should be able to just replace your "import Utility" with "from . import Utility".  This has the added benefit to also ensure that you will import your Utility module, and not any other Utility module that may have already been loaded or resolved somewhere previously along sys.path.

 

Kris



Kris Kaplan
3 Likes

This has to do with the way script modules are loaded into the shared Python environment in Fusion.  Your script is not being run as the __main__ module, but loaded and run in an existing environment.  So any imports would be relative to the existing sys.path.  But it would not be recomended to modify sys.path (because it would affect other scripts).  Instead, you should use relative imports.  So you should be able to just replace your "import Utility" with "from . import Utility".  This has the added benefit to also ensure that you will import your Utility module, and not any other Utility module that may have already been loaded or resolved somewhere previously along sys.path.

 

Kris



Kris Kaplan
Message 3 of 5
jesse
in reply to: KrisKaplan

jesse
Enthusiast
Enthusiast

Kris,

 

This solved my problem as well, but I have a question.  (Continuing the example) "from . import Utility" or "from .Utility import utility_func" works in my addin code, but I can't get either to work in the Fusion360 console.  Here's the error I get:

 

>>> from . import Utility
Traceback (most recent call last):
File "<string>", line 1, in <module>
SystemError: Parent module '' not loaded, cannot perform relative import

Is there something I need to configure in order to be able to import my modules into the console?

 

Thanks

 

Jesse

0 Likes

Kris,

 

This solved my problem as well, but I have a question.  (Continuing the example) "from . import Utility" or "from .Utility import utility_func" works in my addin code, but I can't get either to work in the Fusion360 console.  Here's the error I get:

 

>>> from . import Utility
Traceback (most recent call last):
File "<string>", line 1, in <module>
SystemError: Parent module '' not loaded, cannot perform relative import

Is there something I need to configure in order to be able to import my modules into the console?

 

Thanks

 

Jesse

Message 4 of 5
KrisKaplan
in reply to: jesse

KrisKaplan
Autodesk
Autodesk

'import's are always relative to sys.path.  Relative imports are always relative to the current module's __name__ and __package__ (and the path of that module in sys.modules).  So when your module is running, the relative imports are relative to this 'current module and parent package'.  But when you issue commands in the command line window, there is no such 'current module' context to perform relative imports from.  The same would be true if you ran the interactive python interpreter in a console.

 

For an interactive use in the text commands window, I would probably just go ahead and modify sys.path, adding the parent path of your modules.  For example:

 

sys.path[0:0] = 'c:/Users/me/AppData/Roaming/Autodesk/Autodesk Fusion 360/API/Scripts'

 

This prefixes the path with that folder, and now an import of a module by name contained in that folder should work fine.  As mentioned previously, you would probably want to avoid doing this in any real addin (especially distributed addin), but not likely to be a problem for interactive use of the interpreter.

 

But if you do want to avoid altering the path, you could directly access the importer with code similar to:

 

mymodule = importlib.machinery.SourceFileLoader('mymodule', 'C:/Users/me/AppData/Roaming/Autodesk/Autodesk Fusion 360/API/Scripts/mymodule.py')

 

This will load the script, but as '__main__', so it may not behave the same as when it is run by Fusion (which sets up a module to run the addin script in).

 

Kris

 



Kris Kaplan
0 Likes

'import's are always relative to sys.path.  Relative imports are always relative to the current module's __name__ and __package__ (and the path of that module in sys.modules).  So when your module is running, the relative imports are relative to this 'current module and parent package'.  But when you issue commands in the command line window, there is no such 'current module' context to perform relative imports from.  The same would be true if you ran the interactive python interpreter in a console.

 

For an interactive use in the text commands window, I would probably just go ahead and modify sys.path, adding the parent path of your modules.  For example:

 

sys.path[0:0] = 'c:/Users/me/AppData/Roaming/Autodesk/Autodesk Fusion 360/API/Scripts'

 

This prefixes the path with that folder, and now an import of a module by name contained in that folder should work fine.  As mentioned previously, you would probably want to avoid doing this in any real addin (especially distributed addin), but not likely to be a problem for interactive use of the interpreter.

 

But if you do want to avoid altering the path, you could directly access the importer with code similar to:

 

mymodule = importlib.machinery.SourceFileLoader('mymodule', 'C:/Users/me/AppData/Roaming/Autodesk/Autodesk Fusion 360/API/Scripts/mymodule.py')

 

This will load the script, but as '__main__', so it may not behave the same as when it is run by Fusion (which sets up a module to run the addin script in).

 

Kris

 



Kris Kaplan
Message 5 of 5
rantenki
in reply to: Anonymous

rantenki
Community Visitor
Community Visitor

As hinted above, the right way to do this is with a relative import: https://www.python.org/dev/peps/pep-0328/

 

If you have a plugin called foo, and a module called bar which contains the class Baz, and you try this inside foo.py, it'll likely fail:

 

 

from bar import Baz
>>> You'll get an ImportError because bar isn't in the path

But... If you use a slightly different syntax, it'll import just fine relative to the folder containing current __file__ to load the module:

 

from .bar import Baz
>>> This works because it searches in the folder holding the foo.py module

This works for nested folders too.

 

Unfortunately, the code running in the console is in a different folder/root, so you can't use the same trick there.

0 Likes

As hinted above, the right way to do this is with a relative import: https://www.python.org/dev/peps/pep-0328/

 

If you have a plugin called foo, and a module called bar which contains the class Baz, and you try this inside foo.py, it'll likely fail:

 

 

from bar import Baz
>>> You'll get an ImportError because bar isn't in the path

But... If you use a slightly different syntax, it'll import just fine relative to the folder containing current __file__ to load the module:

 

from .bar import Baz
>>> This works because it searches in the folder holding the foo.py module

This works for nested folders too.

 

Unfortunately, the code running in the console is in a different folder/root, so you can't use the same trick there.

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk Design & Make Report