def process(self, session, **kwargs): """Implement the behavior for when the action is triggered Args: session (dict): environment dictionary Returns: Popen instance of newly spawned process """ with pype.modified_environ(**session): # Get executable by name app = lib.get_application(self.name) executable = lib.which(app["executable"]) # Run as server arguments = [] tools_env = acre.get_tools([self.name]) env = acre.compute(tools_env) env = acre.merge(env, current_env=dict(os.environ)) if not env.get('AVALON_WORKDIR', None): project_name = env.get("AVALON_PROJECT") anatomy = Anatomy(project_name) os.environ['AVALON_PROJECT'] = project_name io.Session['AVALON_PROJECT'] = project_name task_name = os.environ.get("AVALON_TASK", io.Session["AVALON_TASK"]) asset_name = os.environ.get("AVALON_ASSET", io.Session["AVALON_ASSET"]) application = lib.get_application( os.environ["AVALON_APP_NAME"]) project_doc = io.find_one({"type": "project"}) data = { "task": task_name, "asset": asset_name, "project": { "name": project_doc["name"], "code": project_doc["data"].get("code", '') }, "hierarchy": pype.get_hierarchy(), "app": application["application_dir"] } anatomy_filled = anatomy.format(data) workdir = anatomy_filled["work"]["folder"] os.environ["AVALON_WORKDIR"] = workdir env.update(dict(os.environ)) lib.launch(executable=executable, args=arguments, environment=env) return
def process(self, session, **kwargs): """Implement the behavior for when the action is triggered Args: session (dict): environment dictionary Returns: Popen instance of newly spawned process """ with pype.modified_environ(**session): # Get executable by name app = lib.get_application(self.name) executable = lib.which(app["executable"]) # Run as server arguments = [] tools_env = acre.get_tools([self.name]) env = acre.compute(tools_env) env = acre.merge(env, current_env=dict(os.environ)) if not env.get('AVALON_WORKDIR', None): pype.load_data_from_templates() os.environ["AVALON_WORKDIR"] = pype.get_workdir_template( pype.Anatomy) pype.reset_data_from_templates() env.update(dict(os.environ)) lib.launch(executable=executable, args=arguments, environment=env) return
def process(self, session, **kwargs): """Implement the behavior for when the action is triggered Args: session (dict): environment dictionary Returns: Popen instance of newly spawned process """ # Update environment with session env = os.environ.copy() env.update(session) # Get executable by name app = lib.get_application(self.name) env.update(app["environment"]) executable = lib.which(app["executable"]) # Run as server arguments = ["-server", "-portNumber=20207"] return lib.launch(executable=executable, args=arguments, environment=env)
def get_anatomy_filled(self): root_path = api.registered_root() project_name = self._S["AVALON_PROJECT"] asset_name = self._S["AVALON_ASSET"] io.install() project_entity = io.find_one({ "type": "project", "name": project_name }) assert project_entity, ( "Project '{0}' was not found." ).format(project_name) log.debug("Collected Project \"{}\"".format(project_entity)) asset_entity = io.find_one({ "type": "asset", "name": asset_name, "parent": project_entity["_id"] }) assert asset_entity, ( "No asset found by the name '{0}' in project '{1}'" ).format(asset_name, project_name) project_name = project_entity["name"] log.info( "Anatomy object collected for project \"{}\".".format(project_name) ) hierarchy_items = asset_entity["data"]["parents"] hierarchy = "" if hierarchy_items: hierarchy = os.path.join(*hierarchy_items) template_data = { "root": root_path, "project": { "name": project_name, "code": project_entity["data"].get("code") }, "asset": asset_entity["name"], "hierarchy": hierarchy.replace("\\", "/"), "task": self._S["AVALON_TASK"], "ext": self.workfile_ext, "version": 1, "username": os.getenv("PYPE_USERNAME", "").strip() } avalon_app_name = os.environ.get("AVALON_APP_NAME") if avalon_app_name: application_def = lib.get_application(avalon_app_name) app_dir = application_def.get("application_dir") if app_dir: template_data["app"] = app_dir anatomy = Anatomy(project_name) anatomy_filled = anatomy.format_all(template_data).get_solved() return anatomy_filled
def process(self, session, **kwargs): """Implement the behavior for when the action is triggered Args: session (dict): environment dictionary Returns: Popen instance of newly spawned process """ APP = "shell" app_definition = lib.get_application(APP) self.config = app_definition session = session.copy() session["AVALON_APP"] = APP session["AVALON_APP_NAME"] = self.name env = self.environ(session) # Get executable by name executable = lib.which(self.config["executable"]) # # (NOTE): The result CWD path may not be accurate since the # Launcher did not clean up the entry while changing # frames. # For example: # if you were in 'ProjA > Char > Boy > modeling' # and jump to 'ProjB > Prop' then launch action, # you will find the CWD path is: # 'ProjB > Prop > Boy > modeling' # not just: # 'ProjB > Prop' # cwd = env.get("AVALON_SHELL_CWD", session.get("AVALON_PROJECTS", "")) if cwd and not os.path.isdir(cwd): self.log.error("The path of `cwd` is not a directory: " "{!r}".format(cwd)) cwd = None return lib.launch(executable=executable, args=[], environment=env, cwd=cwd)
def process(self, context): root_path = api.registered_root() task_name = api.Session["AVALON_TASK"] project_entity = context.data["projectEntity"] asset_entity = context.data["assetEntity"] project_name = project_entity["name"] context.data["anatomy"] = Anatomy(project_name) self.log.info("Anatomy object collected for project \"{}\".".format( project_name)) hierarchy_items = asset_entity["data"]["parents"] hierarchy = "" if hierarchy_items: hierarchy = os.path.join(*hierarchy_items) context_data = { "root": root_path, "project": { "name": project_name, "code": project_entity["data"].get("code") }, "asset": asset_entity["name"], "hierarchy": hierarchy.replace("\\", "/"), "task": task_name, "username": context.data["user"] } avalon_app_name = os.environ.get("AVALON_APP_NAME") if avalon_app_name: application_def = lib.get_application(avalon_app_name) app_dir = application_def.get("application_dir") if app_dir: context_data["app"] = app_dir datetime_data = context.data.get("datetimeData") or {} context_data.update(datetime_data) context.data["anatomyData"] = context_data self.log.info("Global anatomy Data collected") self.log.debug(json.dumps(context_data, indent=4))
def get_application_actions(project): """Define dynamic Application classes for project using `.toml` files Args: project (dict): project document from the database Returns: list: list of dictionaries """ apps = [] for app in project["config"]["apps"]: try: app_name = app["name"] app_definition = lib.get_application(app_name) except Exception as exc: print("Unable to load application: %s - %s" % (app['name'], exc)) continue # Get from app definition, if not there from app in project icon = app_definition.get("icon", app.get("icon", "folder-o")) color = app_definition.get("color", app.get("color", None)) order = app_definition.get("order", app.get("order", 0)) label = app_definition.get("label") or app.get("label") or app_name label_variant = app_definition.get("label_variant") group = app_definition.get("group") or app.get("group") action = type( "app_{}".format(app_name), (ApplicationAction,), { "name": app_name, "label": label, "label_variant": label_variant, "group": group, "icon": icon, "color": color, "order": order, "config": app_definition.copy() } ) apps.append(action) return apps
def get_render_path(node): ''' Generate Render path from presets regarding avalon knob data ''' data = dict() data['avalon'] = avalon.nuke.get_avalon_knob_data(node, ['avalon:', 'ak:']) data_preset = { "class": data['avalon']['family'], "preset": data['avalon']['families'] } nuke_dataflow_writes = get_node_dataflow_preset(**data_preset) nuke_colorspace_writes = get_node_colorspace_preset(**data_preset) application = lib.get_application(os.environ["AVALON_APP_NAME"]) data.update({ "application": application, "nuke_dataflow_writes": nuke_dataflow_writes, "nuke_colorspace_writes": nuke_colorspace_writes }) anatomy_filled = format_anatomy(data) return anatomy_filled["render"]["path"].replace("\\", "/")
def launch(self, session, entities, event): '''Callback method for the custom action. return either a bool ( True if successful or False if the action failed ) or a dictionary with they keys `message` and `success`, the message should be a string and will be displayed as feedback to the user, success should be a bool, True if successful or False if the action failed. *session* is a `ftrack_api.Session` instance *entities* is a list of tuples each containing the entity type and the entity id. If the entity is a hierarchical you will always get the entity type TypedContext, once retrieved through a get operation you will have the "real" entity type ie. example Shot, Sequence or Asset Build. *event* the unmodified original event ''' entity = entities[0] project_name = entity['project']['full_name'] database = pypelib.get_avalon_database() # Get current environments env_list = [ 'AVALON_PROJECT', 'AVALON_SILO', 'AVALON_ASSET', 'AVALON_TASK', 'AVALON_APP', 'AVALON_APP_NAME' ] env_origin = {} for env in env_list: env_origin[env] = os.environ.get(env, None) # set environments for Avalon os.environ["AVALON_PROJECT"] = project_name os.environ["AVALON_SILO"] = entity['ancestors'][0]['name'] os.environ["AVALON_ASSET"] = entity['parent']['name'] os.environ["AVALON_TASK"] = entity['name'] os.environ["AVALON_APP"] = self.identifier.split("_")[0] os.environ["AVALON_APP_NAME"] = self.identifier anatomy = Anatomy() hierarchy = "" parents = database[project_name].find_one({ "type": 'asset', "name": entity['parent']['name'] })['data']['parents'] if parents: hierarchy = os.path.join(*parents) application = avalonlib.get_application(os.environ["AVALON_APP_NAME"]) data = { "root": os.environ.get("PYPE_STUDIO_PROJECTS_MOUNT"), "project": { "name": entity['project']['full_name'], "code": entity['project']['name'] }, "task": entity['name'], "asset": entity['parent']['name'], "app": application["application_dir"], "hierarchy": hierarchy, } av_project = database[project_name].find_one({"type": 'project'}) templates = None if av_project: work_template = av_project.get('config', {}).get('template', {}).get('work', None) work_template = None try: work_template = work_template.format(**data) except Exception: try: anatomy = anatomy.format(data) work_template = anatomy["work"]["folder"] except Exception as exc: msg = "{} Error in anatomy.format: {}".format( __name__, str(exc)) self.log.error(msg, exc_info=True) return {'success': False, 'message': msg} workdir = os.path.normpath(work_template) os.environ["AVALON_WORKDIR"] = workdir try: os.makedirs(workdir) except FileExistsError: pass # collect all parents from the task parents = [] for item in entity['link']: parents.append(session.get(item['type'], item['id'])) # collect all the 'environment' attributes from parents tools_attr = [os.environ["AVALON_APP"], os.environ["AVALON_APP_NAME"]] for parent in reversed(parents): # check if the attribute is empty, if not use it if parent['custom_attributes']['tools_env']: tools_attr.extend(parent['custom_attributes']['tools_env']) break tools_env = acre.get_tools(tools_attr) env = acre.compute(tools_env) env = acre.merge(env, current_env=dict(os.environ)) env = acre.append(dict(os.environ), env) # # tools_env = acre.get_tools(tools) # env = acre.compute(dict(tools_env)) # env = acre.merge(env, dict(os.environ)) # os.environ = acre.append(dict(os.environ), env) # os.environ = acre.compute(os.environ) # Get path to execute st_temp_path = os.environ['PYPE_CONFIG'] os_plat = platform.system().lower() # Path to folder with launchers path = os.path.join(st_temp_path, 'launchers', os_plat) # Full path to executable launcher execfile = None if sys.platform == "win32": for ext in os.environ["PATHEXT"].split(os.pathsep): fpath = os.path.join(path.strip('"'), self.executable + ext) if os.path.isfile(fpath) and os.access(fpath, os.X_OK): execfile = fpath break pass # Run SW if was found executable if execfile is not None: avalonlib.launch(executable=execfile, args=[], environment=env) else: return { 'success': False, 'message': "We didn't found launcher for {0}".format(self.label) } pass if sys.platform.startswith('linux'): execfile = os.path.join(path.strip('"'), self.executable) if os.path.isfile(execfile): try: fp = open(execfile) except PermissionError as p: self.log.exception('Access denied on {0} - {1}'.format( execfile, p)) return { 'success': False, 'message': "Access denied on launcher - {}".format(execfile) } fp.close() # check executable permission if not os.access(execfile, os.X_OK): self.log.error( 'No executable permission on {}'.format(execfile)) return { 'success': False, 'message': "No executable permission - {}".format(execfile) } pass else: self.log.error('Launcher doesn\'t exist - {}'.format(execfile)) return { 'success': False, 'message': "Launcher doesn't exist - {}".format(execfile) } pass # Run SW if was found executable if execfile is not None: avalonlib.launch('/usr/bin/env', args=['bash', execfile], environment=env) else: return { 'success': False, 'message': "We didn't found launcher for {0}".format(self.label) } pass # Change status of task to In progress presets = config.get_presets()["ftrack"]["ftrack_config"] if 'status_update' in presets: statuses = presets['status_update'] actual_status = entity['status']['name'].lower() next_status_name = None for key, value in statuses.items(): if actual_status in value or '_any_' in value: if key != '_ignore_': next_status_name = key break if next_status_name is not None: try: query = 'Status where name is "{}"'.format( next_status_name) status = session.query(query).one() entity['status'] = status session.commit() except Exception: msg = ('Status "{}" in presets wasn\'t found on Ftrack' ).format(next_status_name) self.log.warning(msg) # Set origin avalon environments for key, value in env_origin.items(): if value == None: value = "" os.environ[key] = value return {'success': True, 'message': "Launching {0}".format(self.label)}
def create_write_node(name, data, input=None, prenodes=None): ''' Creating write node which is group node Arguments: name (str): name of node data (dict): data to be imprinted input (node): selected node to connect to prenodes (list, optional): list of lists, definitions for nodes to be created before write Example: prenodes = [( "NameNode", # string "NodeClass", # string ( # OrderDict: knob and values pairs ("knobName", "knobValue"), ("knobName", "knobValue") ), ( # list outputs "firstPostNodeName", "secondPostNodeName" ) ) ] Return: node (obj): group node with avalon data as Knobs ''' nuke_dataflow_writes = get_node_dataflow_preset(**data) nuke_colorspace_writes = get_node_colorspace_preset(**data) application = lib.get_application(os.environ["AVALON_APP_NAME"]) try: data.update({ "application": application, "nuke_dataflow_writes": nuke_dataflow_writes, "nuke_colorspace_writes": nuke_colorspace_writes }) anatomy_filled = format_anatomy(data) except Exception as e: log.error("problem with resolving anatomy tepmlate: {}".format(e)) # build file path to workfiles fpath = str(anatomy_filled["work"]["folder"]).replace("\\", "/") fpath = data["fpath_template"].format( work=fpath, version=data["version"], subset=data["subset"], frame=data["frame"], ext=data["nuke_dataflow_writes"]["file_type"]) # create directory if not os.path.isdir(os.path.dirname(fpath)): log.warning("Path does not exist! I am creating it.") os.makedirs(os.path.dirname(fpath), 0o766) _data = OrderedDict({"file": fpath}) # adding dataflow template log.debug("nuke_dataflow_writes: `{}`".format(nuke_dataflow_writes)) { _data.update({k: v}) for k, v in nuke_dataflow_writes.items() if k not in ["_id", "_previous"] } # adding colorspace template log.debug("nuke_colorspace_writes: `{}`".format(nuke_colorspace_writes)) {_data.update({k: v}) for k, v in nuke_colorspace_writes.items()} _data = avalon.nuke.lib.fix_data_for_node_create(_data) log.debug("_data: `{}`".format(_data)) if "frame_range" in data.keys(): _data["frame_range"] = data.get("frame_range", None) log.debug("_data[frame_range]: `{}`".format(_data["frame_range"])) GN = nuke.createNode("Group", "name {}".format(name)) prev_node = None with GN: connections = list() if input: # if connected input node was defined connections.append({"node": input, "inputName": input.name()}) prev_node = nuke.createNode("Input", "name {}".format(input.name())) else: # generic input node connected to nothing prev_node = nuke.createNode("Input", "name {}".format("rgba")) # creating pre-write nodes `prenodes` if prenodes: for name, klass, properties, set_output_to in prenodes: # create node now_node = nuke.createNode(klass, "name {}".format(name)) # add data to knob for k, v in properties: if k and v: now_node[k].serValue(str(v)) # connect to previous node if set_output_to: if isinstance(set_output_to, (tuple or list)): for i, node_name in enumerate(set_output_to): input_node = nuke.createNode( "Input", "name {}".format(node_name)) connections.append({ "node": nuke.toNode(node_name), "inputName": node_name }) now_node.setInput(1, input_node) elif isinstance(set_output_to, str): input_node = nuke.createNode( "Input", "name {}".format(node_name)) connections.append({ "node": nuke.toNode(set_output_to), "inputName": set_output_to }) now_node.setInput(0, input_node) else: now_node.setInput(0, prev_node) # swith actual node to previous prev_node = now_node # creating write node write_node = now_node = avalon.nuke.lib.add_write_node( "inside_{}".format(name), **_data) # connect to previous node now_node.setInput(0, prev_node) # swith actual node to previous prev_node = now_node now_node = nuke.createNode("Output", "name Output1") # connect to previous node now_node.setInput(0, prev_node) # imprinting group node GN = avalon.nuke.imprint(GN, data["avalon"]) divider = nuke.Text_Knob('') GN.addKnob(divider) add_rendering_knobs(GN) # adding write to read button add_button_write_to_read(GN) divider = nuke.Text_Knob('') GN.addKnob(divider) # set tile color tile_color = _data.get("tile_color", "0xff0000ff") GN["tile_color"].setValue(tile_color) # add render button lnk = nuke.Link_Knob("Render") lnk.makeLink(write_node.name(), "Render") lnk.setName("Render") GN.addKnob(lnk) # Deadline tab. add_deadline_tab(GN) return GN
def launch(self, session, entities, event): '''Callback method for custom action.''' with_childrens = True if self.without_interface is False: if 'values' not in event['data']: return with_childrens = event['data']['values']['children_included'] entity = entities[0] if entity.entity_type.lower() == 'project': proj = entity else: proj = entity['project'] project_name = proj['full_name'] project_code = proj['name'] if entity.entity_type.lower() == 'project' and with_childrens == False: return {'success': True, 'message': 'Nothing was created'} data = { "root": os.environ["AVALON_PROJECTS"], "project": { "name": project_name, "code": project_code } } all_entities = [] all_entities.append(entity) if with_childrens: all_entities = self.get_notask_children(entity) av_project = None try: self.db.install() self.db.Session['AVALON_PROJECT'] = project_name av_project = self.db.find_one({'type': 'project'}) template_work = av_project['config']['template']['work'] template_publish = av_project['config']['template']['publish'] self.db.uninstall() except Exception: templates = Anatomy().templates template_work = templates["avalon"]["work"] template_publish = templates["avalon"]["publish"] collected_paths = [] presets = config.get_presets()['tools']['sw_folders'] for entity in all_entities: if entity.entity_type.lower() == 'project': continue ent_data = data.copy() asset_name = entity['name'] ent_data['asset'] = asset_name parents = entity['link'] hierarchy_names = [p['name'] for p in parents[1:-1]] hierarchy = '' if hierarchy_names: hierarchy = os.path.sep.join(hierarchy_names) ent_data['hierarchy'] = hierarchy tasks_created = False if entity['children']: for child in entity['children']: if child['object_type']['name'].lower() != 'task': continue tasks_created = True task_type_name = child['type']['name'].lower() task_data = ent_data.copy() task_data['task'] = child['name'] possible_apps = presets.get(task_type_name, []) template_work_created = False template_publish_created = False apps = [] for app in possible_apps: try: app_data = avalonlib.get_application(app) app_dir = app_data['application_dir'] except ValueError: app_dir = app apps.append(app_dir) # Template wok if '{app}' in template_work: for app in apps: template_work_created = True app_data = task_data.copy() app_data['app'] = app collected_paths.append( self.compute_template(template_work, app_data)) if template_work_created is False: collected_paths.append( self.compute_template(template_work, task_data)) # Template publish if '{app}' in template_publish: for app in apps: template_publish_created = True app_data = task_data.copy() app_data['app'] = app collected_paths.append( self.compute_template(template_publish, app_data, True)) if template_publish_created is False: collected_paths.append( self.compute_template(template_publish, task_data, True)) if not tasks_created: # create path for entity collected_paths.append( self.compute_template(template_work, ent_data)) collected_paths.append( self.compute_template(template_publish, ent_data)) if len(collected_paths) > 0: self.log.info('Creating folders:') for path in set(collected_paths): self.log.info(path) if not os.path.exists(path): os.makedirs(path) return {'success': True, 'message': 'Created Folders Successfully!'}
def launch(self, session, entities, event): '''Callback method for custom action.''' with_childrens = True if self.without_interface is False: if "values" not in event["data"]: return with_childrens = event["data"]["values"]["children_included"] entity = entities[0] if entity.entity_type.lower() == "project": proj = entity else: proj = entity["project"] project_name = proj["full_name"] project_code = proj["name"] if entity.entity_type.lower() == 'project' and with_childrens is False: return {'success': True, 'message': 'Nothing was created'} all_entities = [] all_entities.append(entity) if with_childrens: all_entities = self.get_notask_children(entity) anatomy = Anatomy(project_name) work_keys = ["work", "folder"] work_template = anatomy.templates for key in work_keys: work_template = work_template[key] work_has_apps = "{app" in work_template publish_keys = ["publish", "folder"] publish_template = anatomy.templates for key in publish_keys: publish_template = publish_template[key] publish_has_apps = "{app" in publish_template presets = config.get_presets() app_presets = presets.get("tools", {}).get("sw_folders") cached_apps = {} collected_paths = [] for entity in all_entities: if entity.entity_type.lower() == "project": continue ent_data = { "project": { "name": project_name, "code": project_code } } ent_data["asset"] = entity["name"] parents = entity["link"][1:-1] hierarchy_names = [p["name"] for p in parents] hierarchy = "" if hierarchy_names: hierarchy = os.path.sep.join(hierarchy_names) ent_data["hierarchy"] = hierarchy tasks_created = False for child in entity["children"]: if child["object_type"]["name"].lower() != "task": continue tasks_created = True task_type_name = child["type"]["name"].lower() task_data = ent_data.copy() task_data["task"] = child["name"] apps = [] if app_presets and (work_has_apps or publish_has_apps): possible_apps = app_presets.get(task_type_name, []) for app in possible_apps: if app in cached_apps: app_dir = cached_apps[app] else: try: app_data = avalonlib.get_application(app) app_dir = app_data["application_dir"] except ValueError: app_dir = app cached_apps[app] = app_dir apps.append(app_dir) # Template wok if work_has_apps: app_data = task_data.copy() for app in apps: app_data["app"] = app collected_paths.append( self.compute_template(anatomy, app_data, work_keys)) else: collected_paths.append( self.compute_template(anatomy, task_data, work_keys)) # Template publish if publish_has_apps: app_data = task_data.copy() for app in apps: app_data["app"] = app collected_paths.append( self.compute_template(anatomy, app_data, publish_keys)) else: collected_paths.append( self.compute_template(anatomy, task_data, publish_keys)) if not tasks_created: # create path for entity collected_paths.append( self.compute_template(anatomy, ent_data, work_keys)) collected_paths.append( self.compute_template(anatomy, ent_data, publish_keys)) if len(collected_paths) == 0: return { "success": True, "message": "No project folders to create." } self.log.info("Creating folders:") for path in set(collected_paths): self.log.info(path) if not os.path.exists(path): os.makedirs(path) return { "success": True, "message": "Successfully created project folders." }
def __init__(self): self.config = lib.get_application(self.name)