diff --git a/bin/blendnavipy.py b/bin/blendnavipy.py new file mode 100644 index 0000000000000000000000000000000000000000..c19bf8eac77f78a1f0583ffcf9b41fda21173a9a --- /dev/null +++ b/bin/blendnavipy.py @@ -0,0 +1,132 @@ +""" +Run a script within blender +""" +import os +import sys +import shutil +import inspect +import tempfile +import argparse + + +def activate_virtualenv(venv_path): + """ activate venv + + Blender comes with its own python installation. Thus, we need to \ + tell blender to use our virtualenv where the navigation toolbox \ + is installed. + """ + if venv_path is None: + raise NameError('Python is not running within a virtualenv') + filepath = os.path.join(venv_path, 'bin', 'activate_this.py') + with open(filepath, 'r') as f: + exec(f.read(), dict(__file__=filepath)) + + +def blender_version(pyversion): + """ check version + + Blender comes with its own version of python, and should be + match the one used by navipy + """ + blendpyversion = sys.version_info[:3] + if blendpyversion != pyversion: + errormsg = 'Blender comes with its own version of python' + errormsg += ' (here: {}). To run without hard to debug issues, ' + errormsg += ' the python version used by navipy (here {}) and ' + errormsg += 'the python version used by blender should match' + errormsg = errormsg.format(blendpyversion, pyversion) + raise NameError(errormsg) + + +def parser_blendnavipy(): + # Create command line options + parser = argparse.ArgumentParser() + arghelp = 'Path to the environment (.blend) in which your agent lives' + parser.add_argument('--blender-world', + type=str, + default=None, + help=arghelp) + arghelp = 'Path to your python script to be run in blender' + parser.add_argument('--python-script', + type=str, + default=None, + help=arghelp) + arghelp = 'Command to run blender\n' + arghelp += 'If not provided, the script will try to find the command' + arghelp += " by using: shutil.which('blender')" + parser.add_argument('--blender-command', + type=str, + default=None, + help=arghelp) + + arghelp = 'To display some stuff \n' + arghelp += ' * -v print command \n' + arghelp += ' * -vv print also script' + parser.add_argument('-v', '--verbose', + action='count', + default=0, + help=arghelp) + return parser + + +def main(): + # Find the name of the virtualenv, so that we can activate + # it in blender + venv_path = sys.base_prefix + + # Find python version to be checked agains blender python version + pyver = sys.version_info[:3] + + # encoding for temporary file + encoding = 'utf-8' + + args = parser_blendnavipy().parse_args() + if args.blender_command is None: + # Find blender command to do a system call + args.blender_command = shutil.which('blender') + + python_script = args.python_script + + header = '""" Script generated by {}"""\n'.format(sys.argv[0]) + with tempfile.NamedTemporaryFile() as tfile: + # Start of file + tfile.write(header.encode(encoding)) + tfile.write('# check blender version\n'.encode(encoding)) + tfile.write('import sys \n'.encode(encoding)) + for line in inspect.getsourcelines(blender_version)[0]: + tfile.write(line.encode(encoding)) + line = 'blender_version({})\n'.format(pyver) + tfile.write(line.encode(encoding)) + tfile.write('# activate virtualenv within blender\n'.encode(encoding)) + tfile.write('import os \n'.encode(encoding)) + for line in inspect.getsourcelines(activate_virtualenv)[0]: + tfile.write(line.encode(encoding)) + line = 'activate_virtualenv(\"{}\")\n'.format(venv_path) + tfile.write(line.encode(encoding)) + tfile.write('# run simulation\n'.encode(encoding)) + with open(python_script) as infile: + for line in infile: + tfile.write(line.encode(encoding)) + tfile.write('print("I am done")\n'.encode(encoding)) + tfile.seek(0) + # End of file + if args.verbose > 1: + print('Script to be run:') + print('=================') + print(tfile.read().decode(encoding)) + tfile.seek(0) + command = '{} {} --background --python {}'.format( + args.blender_command, + args.blender_world, + tfile.name) + if args.verbose > 0: + print('Run blender with the following command') + print('======================================') + print('>>> ' + command) + os.system(command) + + +if __name__ == "__main__": + # execute only if run as a script + main()