pythonflaskbpy

bpy works in global scope but not in flask app


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


Solution

  • 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