0

I have been using javascript and recently started python to use blender-python library.(bpy) So this problem can be some misunderstanding of mine due to lack of the knowledge of the language behaviour.

This function uses bpy. I tested and it successfully converts .gltf files to .fbx.

import os
import bpy

path = os.getcwd()
UPLOAD_FOLDER = os.path.join(path, 'uploads')
DOWNLOAD_FOLDER = os.path.join(path, 'downloads')

def gltf_to_fbx(filename):
    path = os.path.join(UPLOAD_FOLDER, filename)
    bpy.ops.import_scene.gltf(filepath = path)
    portion = os.path.splitext(filename)
    newname = portion[0] + ".fbx"
    path_to_file = os.path.join(DOWNLOAD_FOLDER, newname)
    bpy.ops.export_scene.fbx(filepath = path_to_file)
    bpy.ops.object.delete()

gltf_to_fbx("1.gltf")

However, when I run it in flask app router like this, it throws an error

from flask import Flask, flash, request

app = Flask(__name__)

@app.route('/', methods=['POST'])
def upload_file():
    file = request.files['model']
    filename = secure_filename(file.filename)
    save_path = os.path.join(UPLOAD_FOLDER, filename)
    file.save(save_path)
    gltf_to_fbx(filename)
    flash('File successfully uploaded')
    return "Success"

if __name__ == "__main__":
    app.run(host="localhost", port = 5000)

This is the error message

...
  File "index.py", line 62, in upload_file
    gltf_to_fbx("1_1.gltf")
  File "index.py", line 32, in gltf_to_fbx
    bpy.ops.import_scene.gltf(filepath = path)
  File "C:\ProgramData\Blender Foundation\Blender\2.82\scripts\modules\bpy\ops.py", line 201, in __call__       
    ret = op_call(self.idname_py(), None, kw)
RuntimeError: Error: Traceback (most recent call last):
  File "C:\ProgramData\Blender Foundation\Blender\2.82\scripts\addons\io_scene_gltf2\__init__.py", line 850, in 
execute
    return self.import_gltf2(context)
  File "C:\ProgramData\Blender Foundation\Blender\2.82\scripts\addons\io_scene_gltf2\__init__.py", line 869, in 
import_gltf2
    return self.unit_import(self.filepath, import_settings)
  File "C:\ProgramData\Blender Foundation\Blender\2.82\scripts\addons\io_scene_gltf2\__init__.py", line 887, in 
unit_import
    BlenderGlTF.create(self.gltf_importer)
  File "C:\ProgramData\Blender Foundation\Blender\2.82\scripts\addons\io_scene_gltf2\blender\imp\gltf2_blender_gltf.py", line 41, in create
    BlenderScene.create(gltf, scene_idx)
  File "C:\ProgramData\Blender Foundation\Blender\2.82\scripts\addons\io_scene_gltf2\blender\imp\gltf2_blender_scene.py", line 53, in create
    bpy.context.window.scene = bpy.data.scenes[gltf.blender_scene]
AttributeError: 'NoneType' object has no attribute 'scene'

location: C:\ProgramData\Blender Foundation\Blender\2.82\scripts\modules\bpy\ops.py:201

The error message seems to be saying that it can't import the file because it's... wrong? But it doesn't makes sense because it didn't throw error when it was ran outside of flask app.

I thought maybe the file was not saved until bpy tries to load it but no. I also tried running the gltf_to_fbx function with an already saved file path and it still throws the same error. The only reason I can imagine is that bpy works in global scope but not in flask app.. which sounds weird to me.

Any kind of opinion is appreciated. Thanks!

EDIT I just commented out the erroring line in bpy module. Then it threw another error and I also commented it out. Now it works! I'm not proud of this way of solution though. My assumption is that bpy is only designed to be run on Blender console. So import_scene.gltf function is assuming that the system has running Blender context, which It doesn't in this case.(there still remains question; how did it run without error in global scope?) I found this documentation that explains how to build a module outside of Blender that looks hopeful. https://wiki.blender.org/wiki/Building_Blender/Windows

Hoie
  • 23
  • 5

2 Answers2

0

Possible issue of overriding global name path = os.getcwd() in gltf_to_fbx function line path = os.path.join(UPLOAD_FOLDER, filename) as UPLOAD_FOLDER is using path = os.getcwd() to generate the path, try to change to a file_path like this file_path = os.path.join(UPLOAD_FOLDER, filename) and then pass this file_path to bpy like so bpy.ops.import_scene.gltf(filepath=file_path)

This might help as the error indicates that NoneType doesn't have attribute scene which might be true do to incorrect path provided to bpy.

bpy.context.window.scene = bpy.data.scenes[gltf.blender_scene]
AttributeError: 'NoneType' object has no attribute 'scene'
simkusr
  • 770
  • 2
  • 11
  • 20
  • I tried your suggestion but it doesn't seem to solve the problem. I prefer avoiding overriding variables but it should still work in this case in my opinion. – Hoie Jan 13 '21 at 01:22
  • ok so I see that there was an [issue](https://github.com/KhronosGroup/glTF-Blender-IO/issues/1183) raised in library there is couple of tips to resolve it also I see that there is another stackoverflow question that might help you out also https://stackoverflow.com/questions/28075599/opening-blend-files-using-blenders-python-api/28083541#28083541. Does any of those links helped you? – simkusr Jan 13 '21 at 08:29
  • I think the problem is something about `bpy.context.window` because the error message says it's none. This post seems to have similar problem but it still doesn't work in my case https://blender.stackexchange.com/questions/164083/how-to-set-bpy-context-window-scene-in-the-right-context – Hoie Jan 13 '21 at 13:04
0

I realized that the bpy module I installed is not correct. I thought bpy should work as a complete module since I found it in pip(I installed using pip install bpy) but actually it assumes that the module is run on Blender's in-app console. So instead of running the app via python index.py, running Blender in background first and running python on top of it solved the problem. blender --background python index.py

Hoie
  • 23
  • 5