From 61fa63eb1d86bf1a09e61be58abc1836a927bb40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Thu, 22 Jun 2017 14:43:12 +0200 Subject: [PATCH] Compatibility fixes for Blender 2.78c Blender 2.78c is shipped with a version of the io_blend_utils module that doesn't have a `pythonpath()` function yet, and that's bundled with an older version of BAM. To work around this, we ship BAM as wheel, and detect whether this version is needed to run. As an added bonus, Blender 2.78c can now also use the file exclude filter for Flamenco. The `bam_supports_exclude_option()` function is thus no longer necessary. --- CHANGELOG.md | 5 +++ blender_cloud/blender.py | 11 +----- blender_cloud/flamenco/bam_interface.py | 47 +++++++++++++------------ blender_cloud/wheels/__init__.py | 10 ++++-- requirements.txt | 1 + setup.py | 5 +++ 6 files changed, 43 insertions(+), 36 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 48594a9..10cc186 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ # Blender Cloud changelog +## Version 1.7.2 (in development) + +- Fixed compatibility with Blender 2.78c. + + ## Version 1.7.1 (2017-06-13) - Fixed asyncio issues on Windows diff --git a/blender_cloud/blender.py b/blender_cloud/blender.py index 5b4fc46..f6a7b81 100644 --- a/blender_cloud/blender.py +++ b/blender_cloud/blender.py @@ -461,16 +461,7 @@ class BlenderCloudPreferences(AddonPreferences): path_box.prop(self, 'flamenco_job_output_path', text='') props = path_box.operator('flamenco.explore_file_path', text='', icon='DISK_DRIVE') props.path = self.flamenco_job_output_path - - show_warning = bool(self.flamenco_exclude_filter and - not bam_interface.bam_supports_exclude_option()) - job_output_box.alert = show_warning - job_output_box.prop(self, 'flamenco_exclude_filter', - icon='ERROR' if show_warning else 'NONE') - if show_warning: - job_output_box.label( - text='Warning, the exclusion filter requires a newer version of Blender!') - job_output_box.alert = False + job_output_box.prop(self, 'flamenco_exclude_filter') prop_split = job_output_box.split(0.32, align=True) prop_split.label('Strip Components:') diff --git a/blender_cloud/flamenco/bam_interface.py b/blender_cloud/flamenco/bam_interface.py index a75f50b..7d4737f 100644 --- a/blender_cloud/flamenco/bam_interface.py +++ b/blender_cloud/flamenco/bam_interface.py @@ -1,6 +1,5 @@ """BAM packing interface for Flamenco.""" -import functools import logging from pathlib import Path import typing @@ -15,26 +14,26 @@ class CommandExecutionError(Exception): pass -if 'bam_supports_exclude_option' in locals(): - locals()['bam_supports_exclude_option'].cache_clear() +def wheel_pythonpath_278() -> str: + """Returns the value of a PYTHONPATH environment variable needed to run BAM from its wheel file. - -@functools.lru_cache(maxsize=1) -def bam_supports_exclude_option() -> bool: - """Returns True if the version of BAM bundled with Blender supports --exclude. - - This feature was added to BAM 1.1.7, so we can do a simple version check. + Workaround for Blender 2.78c not having io_blend_utils.pythonpath() """ - try: - import io_blend_utils - except ImportError: - # If this happens, BAM won't work at all. However, this function can be called from - # the GUI; by being a bit careful while importing, we avoid breaking Blender's GUI. - log.exception('Error importing io_blend_utils module.') - return False + import os + from ..wheels import wheel_filename - return io_blend_utils.bl_info['version'] >= (1, 1, 7) + # Find the wheel to run. + wheelpath = wheel_filename('blender_bam') + + log.info('Using wheel %s to run BAM-Pack', wheelpath) + + # Update the PYTHONPATH to include that wheel. + existing_pypath = os.environ.get('PYTHONPATH', '') + if existing_pypath: + return os.pathsep.join((existing_pypath, wheelpath)) + + return wheelpath async def bam_copy(base_blendfile: Path, target_blendfile: Path, @@ -66,18 +65,20 @@ async def bam_copy(base_blendfile: Path, target_blendfile: Path, ] if exclusion_filter: - if bam_supports_exclude_option(): - args.extend(['--exclude', exclusion_filter]) - else: - log.warning('Your version of Blender does not support the exclusion filter, ' - 'copying all files.') + args.extend(['--exclude', exclusion_filter]) cmd_to_log = ' '.join(shlex.quote(s) for s in args) log.info('Executing %s', cmd_to_log) + # Workaround for Blender 2.78c not having io_blend_utils.pythonpath() + if hasattr(io_blend_utils, 'pythonpath'): + pythonpath = io_blend_utils.pythonpath() + else: + pythonpath = wheel_pythonpath_278() + proc = await asyncio.create_subprocess_exec( *args, - env={'PYTHONPATH': io_blend_utils.pythonpath()}, + env={'PYTHONPATH': pythonpath}, stdin=subprocess.DEVNULL, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, diff --git a/blender_cloud/wheels/__init__.py b/blender_cloud/wheels/__init__.py index 0edf4c9..24f01d3 100644 --- a/blender_cloud/wheels/__init__.py +++ b/blender_cloud/wheels/__init__.py @@ -44,6 +44,12 @@ def load_wheel(module_name, fname_prefix): module_name, module.__file__, fname_prefix) return + sys.path.append(wheel_filename(fname_prefix)) + module = __import__(module_name) + log.debug('Loaded %s from %s', module_name, module.__file__) + + +def wheel_filename(fname_prefix: str) -> str: path_pattern = os.path.join(my_dir, '%s*.whl' % fname_prefix) wheels = glob.glob(path_pattern) if not wheels: @@ -51,9 +57,7 @@ def load_wheel(module_name, fname_prefix): # If there are multiple wheels that match, load the latest one. wheels.sort() - sys.path.append(wheels[-1]) - module = __import__(module_name) - log.debug('Loaded %s from %s', module_name, module.__file__) + return wheels[-1] def load_wheels(): diff --git a/requirements.txt b/requirements.txt index b06f529..bd3d179 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,6 +3,7 @@ lockfile==0.12.2 pillarsdk==1.6.1 wheel==0.29.0 +blender-bam==1.1.7 # Secondary requirements: cffi==1.6.0 diff --git a/setup.py b/setup.py index 9a972e0..fc6c06f 100755 --- a/setup.py +++ b/setup.py @@ -101,6 +101,11 @@ class BuildWheels(Command): log.info('Downloading Pillar Python SDK wheel') self.download_wheel(requirements['pillarsdk']) + # Download BAM from pypi. This is required for compatibility with Blender 2.78. + if not list(self.wheels_path.glob('blender_bam*.whl')): + log.info('Downloading BAM wheel') + self.download_wheel(requirements['blender-bam']) + # Build CacheControl. if not list(self.wheels_path.glob('CacheControl*.whl')): log.info('Building CacheControl in %s', self.cachecontrol_path)