Virtual env modules aren't accessible from Maya (custom and standard Maya hook)
1 1

4 posts in this topic

I'm trying to update my custom application hooks to work with the latest connect and ftrack python api and I'm starting with Maya.  I'm running into an issue where Maya isn't picking up my custom virtual environment modules. At the moment I'm only aware of the inability to find Lucidity module because it's being used to generate my publish paths. My custom Maya tools fail to launch when the "Can't find import module: lucidity" error occrues. I didn't have this issue in previous versions.  

One thing to note though is that Connect is able to find them because I'm able to launch my custom Actions that use Lucidity from the web app.

Here's my Maya application launcher:

class ApplicationLauncher(ftrack_connect.application.ApplicationLauncher):
	"""Custom launcher to modify environment before launch."""

	def __init__(self, application_store):
		'''.'''
		super(ApplicationLauncher, self).__init__(application_store)

	def _getApplicationEnvironment(
		self, application, context=None
	):
		"""Override to modify environment before launch."""

		# Make sure to call super to retrieve original environment
		# which contains the selection and ftrack API.
		environment = super(
			ApplicationLauncher, self
		)._getApplicationEnvironment(application, context)

		environment['SOFTWARE'] = 'maya'
		environment['WORKING_DIR'] = 'scenes'

		environment['APP_VER'] = application['version']

		# Append or Prepend values to the environment.
		# Note that if you assign manually you will overwrite any
		# existing values on that variable.

		self.logger.info(u'context selection : %s' % context['selection'][0]) #

		entity = context['selection'][0]
		task = ftrack.Task(entity['entityId'])
		self.logger.info(u'Task : %s' % task)
		self.logger.info(u'Task keys : %s' % task.keys())

		taskParent = task.getParent()
		taskObjectType = taskParent.getObjectType()
		self.logger.info(u'Task parent : %s' % taskParent)
		self.logger.info(u'Task parent object type : %s' % taskObjectType)

		sequence = taskParent.getParent()
		episode = sequence.getParent()
		
		# Give different env variables depending on if sel is task or shot
		if task.getObjectType() == 'Task': 

			environment['CONTEXT_TYPE'] = 'task'

			try:
				environment['FS'] = str(int(taskParent.getFrameStart()))
			except Exception:
				environment['FS'] = '1'

			try:
				environment['FE'] = str(int(taskParent.getFrameEnd()))
			except Exception:
				environment['FE'] = '1'

			environment['FTRACK_TASKID'] = task.getId()

			# Check task parents until they're a Shot or Asset Build.
			# This allows us to ignore folders.
			while taskParent.getObjectType() not in ['Shot', 'Asset Build']:
				taskParent = taskParent.getParent()
			environment['FTRACK_SHOTID'] = taskParent.getId()

			# If the shot doesn't belong to an asset build,
			# get its sequence.
			if not taskParent.getObjectType() == 'Asset Build':
				while sequence.getObjectType() != 'Sequence':
					sequence = sequence.getParent()
				environment['FTRACK_SEQID'] = sequence.getId()

			# If the task doesn't belong to an asset build,
			# get its episode.
			while episode.getObjectType() != 'Episode':
				episode = episode.getParent()
			environment['FTRACK_EPID'] = episode.getId()

		elif task.getObjectType() == 'Shot': 

			environment['CONTEXT_TYPE'] = 'shot'

			try:
				environment['FS'] = str(int(task.getFrameStart()))
			except Exception:
				environment['FS'] = '1'

			try:
				environment['FE'] = str(int(task.getFrameEnd()))
			except Exception:
				environment['FE'] = '20'

			environment['FTRACK_SHOTID'] = task.getId()

			while taskParent.getObjectType() != 'Sequence':
				taskParent = taskParent.getParent()
			environment['FTRACK_SEQID'] = taskParent.getId()

			while episode.getObjectType() != 'Episode':
				episode = episode.getParent()
			environment['FTRACK_EPID'] = episode.getId()

		elif task.getObjectType() == 'Asset Build': 

			environment['CONTEXT_TYPE'] = 'asset_build'

			try:
				environment['FS'] = str(int(task.getFrameStart()))
			except Exception:
				environment['FS'] = '1'

			try:
				environment['FE'] = str(int(task.getFrameEnd()))
			except Exception:
				environment['FE'] = '20'

			environment['FTRACK_SHOTID'] = task.getId()

			while episode.getObjectType() != 'Episode':
				episode = episode.getParent()
			environment['FTRACK_EPID'] = episode.getId()
		
		# Set envs
		environment = ftrack_connect.application.appendPath(
			os.getenv('_MAYA_SCRIPTS_PATH'),
			'MAYA_SCRIPT_PATH',
			environment
		)
		environment = ftrack_connect.application.appendPath(
			os.getenv('_MAYA_PLUGINS_PATH').replace('MAYA_VER', str(application['version'])),
			'MAYA_PLUG_IN_PATH',
			environment
		)

		environment = ftrack_connect.application.appendPath(
			os.getenv('_MAYA_SCRIPTS_PATH'),
			'PYTHONPATH',
			environment
		)

		# Company
		environment = ftrack_connect.application.appendPath(
			os.getenv('_MAYA_MODULE_PATH').replace('MAYA_VER', str(application['version'])),
			'MAYA_MODULE_PATH',
			environment
		)
		environment = ftrack_connect.application.appendPath(
			os.getenv('_MAYA_RENDER_DESC_PATH').replace('MAYA_VER', str(application['version'])),
			'MAYA_RENDER_DESC_PATH',
			environment
		)
		environment = ftrack_connect.application.appendPath(
			os.getenv('_MAYA_SHELF_PATH'),
			'MAYA_SHELF_PATH',
			environment
		)
		environment = ftrack_connect.application.appendPath(
			os.getenv('_SOLIDANGLE_LICENSE'),
			'SOLIDANGLE_LICENSE',
			environment
		)
		environment = ftrack_connect.application.appendPath(
			os.getenv('_XBMLANGPATH'),
			'XBMLANGPATH',
			environment
		)

		environment['QT_PREFERRED_BINDING'] = 'PySide2'

		# Always return the environment at the end.
		return environment

 

Share this post


Link to post
Share on other sites

Hi @Mike, although totally doable, rather than modifying the original maya hook I'd suggest to provide a separate event in your central or local FTRACK_CONNECT_PLUGIN_PATH such as this one that modifies the env at startup time.

import os
import ftrack
import ftrack_connect.application

python_dependencies = 'path to your modules'
maya_script_path = 'path to maya python scripts'


def on_application_launch(event):
    '''Handle application launch and add environment to *event*.'''

    ftrack_connect.application.appendPath(
        python_dependencies,
        'PYTHONPATH',
        event['data']['options']['env']
    )

    ftrack_connect.application.appendPath(
        maya_script_path,
        'PYTHONPATH',
        event['data']['options']['env']
    )


def register(registry):
    '''Subscribe to application launch events on *registry*.'''
    if registry is not ftrack.EVENT_HANDLERS:
        return

    ftrack.EVENT_HUB.subscribe(
        'topic=ftrack.connect.application.launch and data.application.identifier=maya*',
        on_application_launch
    )

For what concerns Lucidity, this module has been removed from ftrack connect package from verion 1.0.0 on:
https://bitbucket.org/ftrack/ftrack-connect-package/raw/09a31db1cba8586fa129d3fb64d91fec38d32dca/doc/release.rst

I'd suggest to install separately and provide it through the above system if you need it.

Hope it helps.

L.

Share this post


Link to post
Share on other sites

@Lorenzo AngeliThank you! I'll give this a shot.

When you say "install separately" do you mean like clone the Lucidity repo and install it to a folder within a dependencies directory? I'm currently just installing Lucidity to my virtual environment from PyPi.

Just to clarify: I always thought that any package I installed into my Python project's virtual environment through `pip install "package"`would be accessible to launched software, but I guess that's not the case? 

Share this post


Link to post
Share on other sites

Hi @Mike, virtual environment are made so whatever you do install in there (python module wise) will remain sandboxed and won't affect the system.
If you want to use Lucidity I'd suggest to create a virtualenv , activate it, and install the modules you need in there.
Once done , you can use an event like the one I posted to extend the PYTHONPATH including the one in the virtualenv to make them pick up.
Hope it helps!
L.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
1 1