def test_update_paths_will_preserve_extension(self): """testing if update_paths method will preserve the extension. """ # create a FilenameTemplate for Task instances ft = FilenameTemplate( name="Task Filename Template", target_entity_type="Task", path="{{project.code}}/{%- for parent_task in parent_tasks -%}" "{{parent_task.nice_name}}/{%- endfor -%}", filename="{{task.nice_name}}_{{version.take_name}}" '_v{{"%03d"|format(version.version_number)}}{{extension}}', ) self.test_project.structure.templates.append(ft) new_version1 = Version(**self.kwargs) DBSession.add(new_version1) DBSession.commit() new_version1.update_paths() self.assertEqual(new_version1.path, "tp/SH001/Task1") extension = ".ma" new_version1.extension = extension self.assertEqual(new_version1.filename, "Task1_TestTake_v001.ma") # rename the task and update the paths self.test_task1.name = "Task2" # now call update_paths and expect the extension to be preserved new_version1.update_paths() self.assertEqual(new_version1.filename, "Task2_TestTake_v001.ma") self.assertEqual(new_version1.extension, extension)
def upload_version(self, task, file_object, take_name=None, extension=''): """Uploads versions to the Task.path/ folder and creates a Version object to there. Again the Version object will have a Repository root relative path. The filename of the version will be automatically generated by Stalker. :param task: The task that a version is uploaded to. Should be an instance of :class:`.Task` class. :param file_object: A file like object holding the content of the version. :param str take_name: A string showing the the take name of the Version. If skipped defaults.version_take_name will be used. :param str extension: The file extension of the version. :returns: :class:`.Version` instance. """ from stalker import defaults, Version if take_name is None: take_name = defaults.version_take_name v = Version(task=task, take_name=take_name, created_with='Stalker Pyramid') v.update_paths() v.extension = extension # upload it self.upload_file(file_object, v.absolute_path, v.filename) return v
def test_absolute_full_path_works_properly(self): """testing if the absolute_full_path attribute works properly """ ft = FilenameTemplate( name="Task Filename Template", target_entity_type="Task", path="{{project.code}}/{%- for parent_task in parent_tasks -%}" "{{parent_task.nice_name}}/{%- endfor -%}", filename="{{task.nice_name}}_{{version.take_name}}" '_v{{"%03d"|format(version.version_number)}}{{extension}}', ) self.test_project.structure.templates.append(ft) new_version1 = Version(**self.kwargs) DBSession.add(new_version1) DBSession.commit() new_version1.update_paths() new_version1.extension = ".ma" self.assertEqual(new_version1.extension, ".ma") self.assertEqual(new_version1.absolute_full_path, "/mnt/T/tp/SH001/Task1/Task1_TestTake_v001.ma")
def export_camera(): """exports camera and the related shot node """ from stalker import Task, Version from anima.env import mayaEnv m = mayaEnv.Maya() v = m.get_current_version() shot = pm.ls(type='shot')[0] try: sequencer = pm.ls(shot.message.connections(), type='sequencer')[0] except IndexError: sequencer = None camera = None if shot: camera = shot.currentCamera.get() camera_task = \ Task.query\ .filter(Task.parent == v.task.parent)\ .filter(Task.name == 'Camera').first() if camera_task: from stalker import LocalSession local_session = LocalSession() logged_in_user = local_session.logged_in_user cam_v = Version(task=camera_task, description='Exported from %s task on Publish' % v.task.name) cam_v.update_paths() cam_v.extension = '.ma' cam_v.is_published = True cam_v.created_by = cam_v.updated_by = logged_in_user pm.select([shot, camera, sequencer]) m.export_as(cam_v)
def copy_versions(self): """copies versions from one task to another """ # get from task from_task = self.get_task_from_tree_view(self.from_task_tree_view) # get logged in user logged_in_user = self.get_logged_in_user() if not from_task: QtWidgets.QMessageBox.critical( self, 'Error', 'Please select a task from <b>From Task</b> list') return # get to task to_task = self.get_task_from_tree_view(self.to_task_tree_view) if not to_task: QtWidgets.QMessageBox.critical( self, 'Error', 'Please select a task from <b>To Task</b> list') return # check if tasks are the same if from_task == to_task: QtWidgets.QMessageBox.critical( self, 'Error', 'Please select two different tasks') return # get take names and related versions # get distinct take names from stalker.db.session import DBSession from_take_names = map( lambda x: x[0], DBSession.query(distinct(Version.take_name)).filter( Version.task == from_task).order_by(Version.take_name).all()) # create versions for each take answer = QtWidgets.QMessageBox.question( self, 'Info', "Will copy %s versions from take names:<br><br>" "%s" "<br><br>" "Is that Ok?" % (len(from_take_names), '<br>'.join(from_take_names)), QtWidgets.QMessageBox.Yes, QtWidgets.QMessageBox.No) if answer == QtWidgets.QMessageBox.Yes: for take_name in from_take_names: latest_version = Version.query\ .filter_by(task=from_task)\ .filter_by(take_name=take_name)\ .order_by(Version.version_number.desc())\ .first() # create a new version new_version = Version(task=to_task, take_name=take_name) new_version.created_by = logged_in_user new_version.extension = latest_version.extension new_version.description = \ 'Moved from another task (id=%s) with Version Mover' % \ latest_version.task.id new_version.created_with = latest_version.created_with DBSession.add(new_version) DBSession.commit() # update path new_version.update_paths() DBSession.add(new_version) DBSession.commit() # now copy the last_version file to the new_version path try: os.makedirs(new_version.absolute_path) except OSError: # path exists pass # move the file there shutil.copyfile(latest_version.absolute_full_path, new_version.absolute_full_path) # inform the user QtWidgets.QMessageBox.information( self, 'Success', 'Successfully copied %s versions' % len(from_take_names))
repository=repo, structure=flat_struct) # now lets create a Task t1 = Task(name='Building 1', project=p1) t2 = Task(name='Model', parent=t1) t3 = Task(name='Lighting', parent=t1, depends=[t2]) # store all the data in the database db.DBSession.add_all([t1, t2, t3]) # this is enough to store the rest # lets create a Maya file for the Model task t2_v1 = Version(task=t1) t2_v1.update_paths() # for now this is needed to render the template, but will # remove it later on t2_v1.extension = '.ma' # set the extension for maya # lets create a new version for Lighting t3_v1 = Version(task=t3) t3_v1.update_paths() t3_v1.extension = '.ma' # you should see that all are in the same folder print(t2_v1.absolute_full_path) print(t3_v1.absolute_full_path) # # Lets create a second Project that use some other folder structure # # create a new project structure
) # now lets create a Task t1 = Task(name='Building 1', project=p1) t2 = Task(name='Model', parent=t1) t3 = Task(name='Lighting', parent=t1, depends=[t2]) # store all the data in the database db.DBSession.add_all([t1, t2, t3]) # this is enough to store the rest # lets create a Maya file for the Model task t2_v1 = Version(task=t1) t2_v1.update_paths() # for now this is needed to render the template, but will # remove it later on t2_v1.extension = '.ma' # set the extension for maya # lets create a new version for Lighting t3_v1 = Version(task=t3) t3_v1.update_paths() t3_v1.extension = '.ma' # you should see that all are in the same folder print(t2_v1.absolute_full_path) print(t3_v1.absolute_full_path) # # Lets create a second Project that use some other folder structure # # create a new project structure
def copy_versions(self): """copies versions from one task to another """ # get from task from_task = self.get_task_from_tree_view(self.from_task_tree_view) # get logged in user logged_in_user = self.get_logged_in_user() if not from_task: QtWidgets.QMessageBox.critical( self, 'Error', 'Please select a task from <b>From Task</b> list' ) return # get to task to_task = self.get_task_from_tree_view(self.to_task_tree_view) if not to_task: QtWidgets.QMessageBox.critical( self, 'Error', 'Please select a task from <b>To Task</b> list' ) return # check if tasks are the same if from_task == to_task: QtWidgets.QMessageBox.critical( self, 'Error', 'Please select two different tasks' ) return # get take names and related versions # get distinct take names from_take_names = map( lambda x: x[0], db.DBSession.query(distinct(Version.take_name)) .filter(Version.task == from_task) .order_by(Version.take_name) .all() ) # create versions for each take answer = QtWidgets.QMessageBox.question( self, 'Info', "Will copy %s versions from take names:<br><br>" "%s" "<br><br>" "Is that Ok?" % ( len(from_take_names), '<br>'.join(from_take_names) ), QtWidgets.QMessageBox.Yes, QtWidgets.QMessageBox.No ) if answer == QtWidgets.QMessageBox.Yes: for take_name in from_take_names: latest_version = Version.query\ .filter_by(task=from_task)\ .filter_by(take_name=take_name)\ .order_by(Version.version_number.desc())\ .first() # create a new version new_version = Version( task=to_task, take_name=take_name ) new_version.created_by = logged_in_user new_version.extension = latest_version.extension new_version.description = \ 'Moved from another task (id=%s) with Version Mover' % \ latest_version.task.id new_version.created_with = latest_version.created_with db.DBSession.add(new_version) db.DBSession.commit() # update path new_version.update_paths() db.DBSession.add(new_version) db.DBSession.commit() # now copy the last_version file to the new_version path try: os.makedirs(new_version.absolute_path) except OSError: # path exists pass # move the file there shutil.copyfile( latest_version.absolute_full_path, new_version.absolute_full_path ) # inform the user QtWidgets.QMessageBox.information( self, 'Success', 'Successfully copied %s versions' % len(from_take_names) )
def test_readme_tutorial_code(setup_sqlite3): """Tests the tutorial code in README.rst """ from stalker import db db.setup() db.init() from stalker.db.session import DBSession assert str(DBSession.connection().engine.url) == 'sqlite://' from stalker import User me = User(name='Erkan Ozgur Yilmaz', login='******', email='*****@*****.**', password='******') # Save the user to database DBSession.save(me) from stalker import Repository repo = Repository(name='Commercial Projects Repository', code='CPR', windows_path='Z:/Projects', linux_path='/mnt/Z/Projects', osx_path='/Volumes/Z/Projects') from stalker import FilenameTemplate task_template = FilenameTemplate( name='Standard Task Filename Template', target_entity_type='Task', # This is for files saved for Tasks path='{{project.repository.path}}/{{project.code}}/' '{%- for parent_task in parent_tasks -%}' '{{parent_task.nice_name}}/' '{%- endfor -%}', # This is Jinja2 template code filename= '{{version.nice_name}}_v{{"%03d"|format(version.version_number)}}') from stalker import Structure standard_folder_structure = Structure( name='Standard Project Folder Structure', templates=[task_template], custom_template= '{{project.code}}/References' # If you need extra folders ) from stalker import Project new_project = Project( name='Test Project', code='TP', structure=standard_folder_structure, repositories=[repo ], # if you have more than one repository you can do it ) from stalker import ImageFormat hd1080 = ImageFormat(name='1080p', width=1920, height=1080) new_project.image_format = hd1080 # Save the project and all the other data it is connected to it DBSession.save(new_project) from stalker import Task, Asset, Shot, Type # define Character asset type char_type = Type(name='Character', code='CHAR', target_entity_type='Asset') character1 = Asset(name='Character 1', code='CHAR1', type=char_type, project=new_project) # Save the Asset DBSession.save(character1) model = Task(name='Model', parent=character1) rigging = Task( name='Rig', parent=character1, depends=[model ], # For project management, define that Rig can not start # before Model ends. ) # Save the new tasks DBSession.save([model, rigging]) # A shot and some tasks for it shot = Shot(name='SH001', code='SH001', project=new_project) # Save the Shot DBSession.save(shot) animation = Task( name='Animation', parent=shot, ) lighting = Task( name='Lighting', parent=shot, depends=[animation], # Lighting can not start before Animation ends, schedule_timing=1, schedule_unit='d', # The task expected to take 1 day to complete resources=[me]) DBSession.save([animation, lighting]) from stalker import Version new_version = Version(task=animation) new_version.update_paths() # to render the naming convention template new_version.extension = '.ma' # let's say that we have created under Maya assert new_version.absolute_full_path == \ "%sTP/SH001/Animation/SH001_Animation_Main_v001.ma" % \ repo.path assert new_version.version_number == 1 new_version2 = Version(task=animation) new_version2.update_paths() # to render the naming convention template new_version2.extension = '.ma' # let's say that we have created under Maya assert new_version2.version_number == 2
def assign_version(request): """assigns the version to the given entity """ logged_in_user = get_logged_in_user(request) # TODO: this should be renamed to create version # collect data link_ids = get_multi_integer(request, 'link_ids') task_id = request.params.get('task_id', -1) link = Link.query.filter(Link.id.in_(link_ids)).first() task = Task.query.filter_by(id=task_id).first() logger.debug('link_ids : %s' % link_ids) logger.debug('link : %s' % link) logger.debug('task_id : %s' % task_id) logger.debug('task : %s' % task) if task and link: # delete the link and create a version instead full_path = convert_file_link_to_full_path(link.full_path) take_name = request.params.get('take_name', defaults.version_take_name) publish = bool(request.params.get('publish')) logger.debug('publish : %s' % publish) path_and_filename, extension = os.path.splitext(full_path) version = Version(task=task, take_name=take_name, created_by=logged_in_user) version.is_published = publish # generate path values version.update_paths() version.extension = extension # specify that this version is created with Stalker Pyramid version.created_with = 'StalkerPyramid' # TODO: that should also be a # config value # now move the link file to the version.absolute_full_path try: os.makedirs( os.path.dirname(version.absolute_full_path) ) except OSError: # dir exists pass logger.debug('full_path : %s' % full_path) logger.debug('version.absolute_full_path : %s' % version.absolute_full_path) shutil.copyfile(full_path, version.absolute_full_path) os.remove(full_path) # it is now safe to delete the link DBSession.add(task) DBSession.delete(link) DBSession.add(version) return HTTPOk()
def test_update_paths_will_render_the_appropriate_template_from_the_related_project(self): """testing if update_paths method will update the Version.full_path by rendering the related Project FilenameTemplate. """ # create a FilenameTemplate for Task instances # A Template for Assets # ......../Assets/{{asset.type.name}}/{{asset.nice_name}}/{{task.type.name}}/ # # Project1/Assets/Character/Sero/Modeling/Sero_Modeling_Main_v001.ma # # + Project1 # | # +-+ Assets (Task) # | | # | +-+ Characters # | | # | +-+ Sero (Asset) # | | # | +-> Version 1 # | | # | +-+ Modeling (Task) # | | # | +-+ Body Modeling (Task) # | | # | +-+ Coarse Modeling (Task) # | | | # | | +-> Version 1 (Version) # | | # | +-+ Fine Modeling (Task) # | | # | +-> Version 1 (Version): Fine_Modeling_Main_v001.ma # | Assets/Sero/Modeling/Body_Modeling/Fine_Modeling/Fine_Modeling_Main_v001.ma # | # +-+ Shots (Task) # | # +-+ Shot 10 (Shot) # | | # | +-+ Layout (Task) # | | # | +-> Version 1 (Version): Layout_v001.ma # | Shots/Shot_1/Layout/Layout_Main_v001.ma # | # +-+ Shot 2 (Shot) # | # +-+ FX (Task) # | # +-> Version 1 (Version) ft = FilenameTemplate( name="Task Filename Template", target_entity_type="Task", path="{{project.code}}/{%- for parent_task in parent_tasks -%}" "{{parent_task.nice_name}}/{%- endfor -%}", filename="{{task.nice_name}}_{{version.take_name}}" '_v{{"%03d"|format(version.version_number)}}{{extension}}', ) self.test_project.structure.templates.append(ft) new_version1 = Version(**self.kwargs) DBSession.add(new_version1) DBSession.commit() new_version1.update_paths() self.assertEqual(new_version1.path, "tp/SH001/Task1") new_version1.extension = ".ma" self.assertEqual(new_version1.filename, "Task1_TestTake_v001.ma")
def test_naming_case(self): """Test the case where naming should contain both Sequence Shot and other stuff (this is based on https://github.com/eoyilmaz/anima/issues/23) """ from stalker.db.session import DBSession from stalker import Project, Task, Sequence, Shot, FilenameTemplate, \ Version, Structure ft = FilenameTemplate( name='Normal Naming Convention', target_entity_type='Task', path= '$REPO{{project.repository.id}}/{{project.code}}/{%- for parent_task in parent_tasks -%}{{parent_task.nice_name}}/{%- endfor -%}', filename="""{%- for p in parent_tasks -%} {%- if p.entity_type == 'Sequence' -%} {{p.name}} {%- elif p.entity_type == 'Shot' -%} _{{p.name}}{{p.children[0].name}} {%- endif -%} {%- endfor -%} {%- set fx = parent_tasks[-2] -%} _{{fx.name}}_{{version.take_name}}_v{{"%02d"|format(version.version_number)}}""", ) DBSession.add(ft) st = Structure(name='Normal Project Structure', templates=[ft]) DBSession.add(st) test_project = Project(name='test001', code='test001', structure=st) DBSession.add(test_project) DBSession.commit() seq_task = Task(name='seq', project=test_project) DBSession.add(seq_task) ep101 = Sequence(name='ep101', code='ep101', parent=seq_task) DBSession.add(ep101) shot_task = Task(name='shot', parent=ep101) DBSession.add(shot_task) s001 = Shot(name='s001', code='s001', parent=shot_task) DBSession.add(s001) c001 = Task(name='c001', parent=s001) DBSession.add(c001) effects_scene = Task(name='effectScenes', parent=c001) DBSession.add(effects_scene) fxA = Task(name='fxA', parent=effects_scene) DBSession.add(fxA) maya = Task(name='maya', parent=fxA) DBSession.add(maya) DBSession.commit() v = Version(task=maya) v.update_paths() v.extension = '.ma' DBSession.add(v) DBSession.commit() assert v.filename == 'ep101_s001c001_fxA_Main_v01.ma'