Announcements

The Autodesk Community Forums has a new look. Read more about what's changed on the Community Announcements board.

To install python modules.

Anonymous

To install python modules.

Anonymous
Not applicable

Good day!

 

Sorry, but I have one more question. 🙂

 

Is there something special to install python modules for Fusion? 

 

I used pip to install numpy 1.9.2 and pycollada 0.4.1 (module to work with COLLADA files). In addin's code I write "import collada" and then I get access to all functions and objects of pycollada using "pycollada.[object]". However, when I run code, import error rises:

>>> Traceback (most recent call last):
  File "D:/Projects/2-ExportModel/2/CAD to Earth Fusion 360. Python/CAD to Earth Fusion 360.py", line 13, in <module>
    import collada
  File "C:\Users\Anton\AppData\Local\Autodesk\webdeploy\production\d823d7c932fe4a7e4d638cb6af4b3845addcfe7d\Python\lib\collada\__init__.py", line 30, in <module>
    from collada import animation
ImportError: cannot import name animation

The file "__init__.py" does exist in directory C:\Users\Anton\AppData\Local\Autodesk\webdeploy\production\d823d7c932fe4a7e4d638cb6af4b3845addcfe7d\Python\lib\collada\ .
And when I check installed packages with command "pip list" in command prompt, it shows:

numpy (1.9.2)
pip (7.1.0)
pycollada (0.4.1)
python-dateutil (2.4.2)
setuptools (18.1)
six (1.9.0)
wheel (0.24.0)

The author of module pycollada doesn't know the reason of mistake and think that something is wrong with the PYTHONPATH in Fusion.

 

Best Regards,

Anton.

1 Like
Reply
Accepted solutions (1)
11,701 Views
11 Replies
Replies (11)

Anonymous
Not applicable

The issue was resolved in other way, without using pycollada.

But may be it will be useful for other developers.

0 Likes

KrisKaplan
Autodesk
Autodesk
Accepted solution

I'm not sure why that did not work.  The Python/lib folder is set to the system path on Fusion startup, so any packages located there should be found when imported from any script.

 

However, I definitely would not recomend installing packages into this Python/lib folder for your scripts.  One reason is that the specific webdepoly path will be abandoned every time the application is updated (every few weeks or so).  You would have to continuously apply your modifications to those locations.

 

The other reason is that the Python environment in Fusion is a shared environment for all loaded scripts and addins.  Different scripts could be dependent on different versions of libraries.  Plus there is no (as of yet) setup/install phase for scripts.  A 'copy to deploy' model is desired.  For these reasons, the recomendation would be to include all of your dependent libraries in your script folder and use relative imports ('from .packages import collada' and copy (or virtual environment install) the libraries into 'YourScript/packages').  Most packages include their own dependencies and use relative imports, but some (such as collada) assume a shared install of numpy exists.  In that case, you would either need to change the collada code to do package (your script's package) relative imports of numpy (or any other external dependencies not in our distro), or use an absolute import.

 

Now using script relative libraries gives this isolation, but it can increase redundancy.  This normally wouldn't be a problem with publicly shared or published scripts.  But if you use a large library (say numpy) in a lot of your own local scripts, this would grow to be a problem.  In that case, you could create a shared library location and do an absolute import after modifying the sys.path list to include your shared library folder.  I would put this shared library folder out in the user API folder so it survives across updates (or any location convenient to you, but using a location relative to your scripts would make it more portable if you ever shared your scripts).

 

Kris



Kris Kaplan
4 Likes

Anonymous
Not applicable

Thank you for your detailed answer.

 

Best Regards,

Anton.

0 Likes

Anonymous
Not applicable

Could you explain this a little bit more? I use Fusion 360 on a Mac at home and on Windows at work and I'd like to be able to install python modules and use them within Fusion 360. It appears that Fusion 360 uses Python 3.3. Does this mean that if I install the Python 3.3 version of a module outside of Fusion that within Fusion that module will be available to me? Specifically I'm trying to import Scipy and NumPy into a script as I am used to them but I'm not sure how to go about doing it.

0 Likes

KrisKaplan
Autodesk
Autodesk

Fusion currently uses version 3.3.5 of Python located in the Fusion install (webdeploy) folder.  Just as you can install multiple separate versions of Python on your machine and packages installed in one are not visible to the other.  The same is true for the version of Python used by Fusion.  Even if it is the same version as another version of Python on your system, packages installed on one are not visible to the other.

 

This is all controlled by the standard package resolution rules in Python.  Packages are searched for relative to the current running module's __file__ path, then in some standard locations relative to the Python runtime location (e.g. site_packages), and then the paths enumerated by sys.path.  So in order to use a package in your Fusion script, it needs to be in one of these locations.  As mentioned above, you should avoid trying to add the packages directly to Fusion's Python folder, because this is in the webdepoloy folder that is recreated on every update and all scripts run in this shared environment, so there can be version problems between scripts.  Unfortunately, this would normally be the standard way to install packages.  So this leaves either relying on the module relative import mechanism (preferred), or modifying sys.path to point to the absolute path where these packages are located.

 

Unfortunately, the scientific packages (like numpy) make this harder with their extensive use of binary extensions.  And because numpy is so large, other packages like scipy normally assume numpy is available in the system path, and does not do a relative import (like other smaller packages tend to do).  This makes copying something like scipy into your script's folder and referencing it with a relative import a little more difficult (as it would require editing some of their files to perform relative imports).  So the easiest way forward would probably be to have your script append the path to these packages onto sys.path before importing these modules.  This has the downside of affecting the module search order for all scripts run in Fusion, so it would be best to revert the sys.path as soon as you are done (and ideally remove these absolute imported modules from sys.modules).  To do this, I might use virtualenv to create a virtual environment from a 64bit Python 3.3.5 (from Fusion's install directory or one you setup), and setup the desired packages (scipy, numpy), and add the path to this virtual environment's site-packages folder to sys.path in your script (if not already present).  Even better, you could copy the relevant module's from the virtual environment into a folder relative to your script (or common to all of your scripts if referenced by several) and add that folder to sys.path.  (Doing this prevents the other modules in the virtual environment's site-packages from being visible in the path.)

 

Another thing to be aware of is that because Python is running embedded in the Fusion process, and the Fusion process is a 64bit process, the Python version is also a 64bit version.  And because the scientific packages use binary extensions, you have to ensure that you get the 64bit versions of these packages (numpy, etc...) or they will not import in a script run in Fusion.

 

Kris



Kris Kaplan
7 Likes

Anonymous
Not applicable

Thank you for such a detailed reply. That is extremely helpful. I'll try a few things out and most likely will be back with more questions 🙂

0 Likes

Anonymous
Not applicable

I am sorry, but this is not a solution, this is a workaround.

Pip is available in the webdeploy version of Python included with Fusion and it is not working. If my module wants to install a pip module at runtime, say with something like 

pip.main(['install', 'MyModule'])
import MyModule

 

and I don't care about waiting for it to do so, this should be possible -since it is a much easier solution - however it runs into a "FileNotFoundError: [WinError 2] The system cannot find the file specified" error.
I believe that OP is correct and the setup of webdeploy for pip is incorrect and should be fixed.


0 Likes

J.M.MAY
Explorer
Explorer

I'm currently facing the same problem. I'd like to use numpy and some other modules that are already installed with anaconda on my PC. Shouldn't it work to just do the following at the beginning of my script, because it does not.

 

 

import os, sys
sys.path.append("C:\...\anaconda3\Lib\site-packages")
import numpy

 

 

 

Thanks in advance!

 
1 Like

jakedbirk
Enthusiast
Enthusiast

Have you solved this? If so, could you provide the code you used to import the packages? I’ve been at this for a while and nothing seems to work. Thanks in advanced!

0 Likes

lpurdy
Observer
Observer

Thank you for providing a solution, and keeping this form up, but I must complain a little about the nature of the solution. 

I am working on this add in: lpurdy01/Fusion-360-Camera-Control: A Fusion 360 script that allows for gamepad / controller input t... (Don't bother trying to run it if you don't have an os3m mouse, I haven't updated the gamepad input to work again yet.) 

To do hid input, have a debug/config view, and manipulate the camera I am using modules numpy, pygame, pywinusb, and scipy. These are all heavy packages that require complied binaries. 

I have found the following to work: 
- Creating a venv in the same directory as my Add-In
- Installing the packages using the pip in that venv

Then including this code in my run function:

# Get the path of the current script
        script_path = os.path.abspath(__file__)

        # Get the parent directory of the script
        parent_directory = os.path.dirname(script_path)

        # Construct the path to the 'site-packages' directory
        venv_site_packages = os.path.join(parent_directory, 'venv', 'Lib', 'site-packages')

        # Save the original sys.path
        original_sys_path = sys.path.copy()

        # Add the new path to sys.path
        sys.path.append(venv_site_packages)

        # Do my real import stuff...
        # ...

        # Reset sys.path to its original state
        sys.path = original_sys_path.copy()

        # Do my Add-In stuff


I fear forcing devs to include installed versions of packages will case software licensing issues. I would really appreciate it if Autodesk would consider investing the time to develop a more thought out solution. Possibly a wrapper for pip that could allow Script or Add-In developers to declare what packages they need and have fusion install them? 

2 Likes

nivekmai
Explorer
Explorer

Oddly enough, I'm trying to do the  (almost) exact same thing as @lpurdy, but I wanted it to work as an add-in that can be installed, instead of requiring that you package the binaries in your repo (since that'll probably break when you use a package that has binaries that do system checks and install different binaries based on the system).

I've combined @lpurdy and David Young's solution (after I found the right way to run the python executable) to make something that should be good to include in an add-in that can be deployed through the store.

 

My implementation is attempting to install pygame and falling back to using pyjoystick (which I had already update to be a relative module, but doesn't support a custom gamepad I made):

 

 

 

import os
import sys
import platform
import subprocess

from . import config
from .lib import fusionAddInUtils as futil
from adsk.core import LogLevels

def installPygameWindows():
    virtualenvDirName = f"{config.ADDIN_NAME}Venv"
    # Clean up path in case we crashed somewhere, sys should not contain our virtualenv yet
    sys.path = [dir for dir in sys.path if dir.find(virtualenvDirName) == -1]

    original_sys_path = sys.path.copy()

    virtualenv = os.path.join(sys.path[0], virtualenvDirName)
    python = os.path.join(sys.path[0], "Python", "python.exe")
    virtualenvSitePackages = os.path.join(virtualenv, "Lib", "site-packages")

    if not os.path.isdir(virtualenv):
        futil.log(f"{config.ADDIN_NAME}: missing virtualenv, creating...", LogLevels.WarningLogLevel)
        subprocess.check_call([python, '-m', 'venv', virtualenv]) 

    futil.log(f"{config.ADDIN_NAME}: virtualenv exists, attempting to import from virtualenv", LogLevels.InfoLogLevel)
    # in case of script failure, the virtualenv might already be in the path from a previous run
    if not virtualenv in sys.path:
        sys.path.insert(0, virtualenvSitePackages)
    try:
        import pygame
        return(True, original_sys_path.copy())
    except:
        try:
            futil.log(f"{config.ADDIN_NAME}: missing pygame, installing...", LogLevels.WarningLogLevel)
            subprocess.check_call([os.path.join(virtualenv, "Scripts", "pip.exe"), "install", "--upgrade", "pygame"])
            futil.log(f"{config.ADDIN_NAME}: pygame installed", LogLevels.InfoLogLevel)
            return (True, original_sys_path.copy())
        except:
            futil.handle_error("Failed to install and import pygame. See text console for more details", True)
            return (False, original_sys_path.copy())

installedPygame = False

if platform.system() is 'Windows':
    (installedPygame, original_sys_path) = installPygameWindows()
    if installedPygame:
        try:
            import pygame
            futil.log(f"{config.ADDIN_NAME}: pygame installed", LogLevels.InfoLogLevel)
        except:
            futil.handle_error(f"{config.ADDIN_NAME}: Failed to import pygame, falling back to use pyjoystick (less gamepad support). See text console for more details", True)
            installedPygame = False
    sys.path = original_sys_path
else:
    #TODO: figure out where the python executable is on mac
    futil.handle_error("Sorry, this OS is unsupported, falling back to use pyjoystick (less gamepad support)", True)

 

 

 

I then use installedPygame to determine whether to use pygame or pyjoystick.

Note that this only works on Windows (tested only on Windows 11 too), I've yet to find the executables necessary to replicate these commands on Mac (we'd need to locate which python is being run, and probably find the virtualenv's pip, but on mac it might just work to use a bit of bash instead of using a specific pip executable).

 

Also of note: for some reason, this doesn't work if you stop the add-in and restart it. I have no idea why that is, but I assume it's something specific to pygame and the dynamic linking of SDL2, other packages might work just fine.

My add-in repo where I'm actually using this code: https://github.com/nivekmai/Joystick-Control (note that this add-in totally works for an xbox 360 controller I'm using, and after I update with this new setup, it could probably work for any controller).

 

0 Likes