def get_rows(select): # type: (cgtwq.Selection) -> List[Dict] histories = select.history.get( cgtwq.Field('status').in_(['Retake', 'Approve'])) tasks = set([i.task_id for i in histories]) tasks = select.module.select(*tasks) tasks = tasks.get_fields("id", "shot.entity", "pipeline", "artist") tasks = {i[0]: dict(shot=i[1], pipeline=i[2], artist=i[3]) for i in tasks} ret = [] history_by_task = {} for i in histories: history_by_task.setdefault(i.task_id, []).append(i) history_by_task = { k: sorted(v, reverse=True, key=lambda x: x.time) for k, v in history_by_task.iteritems() } for i in histories: # type: cgtwq.model.HistoryInfo task = tasks[i.task_id] row = dict(task) row.update(html=i.text, created_by=i.create_by, time=i.time, status=tr("status." + i.status), step=i.step, order=history_by_task[i.task_id].index(i) + 1) ret.append(row) return sorted(ret, key=lambda x: (x['shot'], x['pipeline'], x['order']))
def test_module_field(module): field_sign = "python_test_{}".format( "".join( [ random.choice("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") for i in range(20) ] ) ) module.field.create(sign=field_sign, type_="int") field = module.database.field.filter_one( cgtwq.Field("sign") == (cgtwq.Field(field_sign).in_namespace(module.default_field_namespace)) ) assert "python_test_" in field.sign module.field.delete(field.id)
def get_filebox_meta(select): """Get filebox for final files. """ assert isinstance(select, cgtwq.Selection), type(select) pipelines = select.pipeline.all() assert pipelines fileboxes = select.module.database.filebox.filter( cgtwq.Field('title').has('最终'), cgtwq.Field('#pipeline_id').in_([i.id for i in pipelines])) if not fileboxes: raise RuntimeError('No matched fileboxes') elif len(fileboxes) != 1: raise RuntimeError('Multiple matched filebox', fileboxes) ret = fileboxes[0] assert isinstance(ret, cgtwq.model.FileBoxMeta) return ret
def _apply_on_selection(select, data): def _check_alias(value, alias, name, label): if value not in alias: LOGGER.error('不能识别表格中给出的任务%s: 行=%s, 值=%s, 支持的值有: %s', label, data.index, value, ', '.join(i for j in [alias.keys()] + alias.values() for i in j)) raise ValueError('Can not recognize {}.'.format(name), value) assert isinstance(data, RowData) assert isinstance(select, cgtwq.Selection) status = data.status field = _convert_from_alias(data.phase, FIELD_ALIAS) _check_alias(field, FIELD_ALIAS, 'phase', '阶段') if field not in FIELD_ALIAS: LOGGER.error('不能识别表格中给出的任务阶段: 行=%s, 值=%s, 支持的值有: %s', data.index, field, ', '.join(i for j in [FIELD_ALIAS.keys()] + FIELD_ALIAS.values() for i in j)) raise ValueError('Can not recognize field.', field) entries = select.to_entries() if len(entries) != 1: LOGGER.warning('发现%s个名为%s的%s任务, 都将被修改', len(entries), data.shot, data.pipeline) for entry in entries: assert isinstance(entry, cgtwq.Entry) message = cgtwq.Message(_convert_note(data.note)) if message: _message = message.dumps() if entry.history.get( (cgtwq.Field('status') == status) & (cgtwq.Field('text') == _message)): LOGGER.info('此条已导入, 跳过: 行=%s', data.index) continue else: if entry['status'] == status: LOGGER.info('此条已导入, 跳过: 行=%s', data.index) continue try: entry.flow.update(field, status, message=message) LOGGER.info('成功导入: 行=%s, 镜头=%s, 流程=%s, 阶段=%s, 状态=%s, 备注=%s', data.index, data.shot, data.pipeline, data.phase, data.status, message) except cgtwq.PermissionError: LOGGER.error('当前用户无权限: 行=%s, 阶段=%s', data.index, data.phase) except ValueError as ex: LOGGER.error('错误: 行=%s, %s', data.index, ex)
def test_database_fields(database): # Get assert isinstance(database, cgtwq.Database) result = database.field.filter() assert all(isinstance(i, cgtwq.model.FieldMeta) for i in result) result = database.field.filter_one( cgtwq.Field("sign") == cgtwq.compat.adapt_field_sign("shot.entity")) assert isinstance(result, cgtwq.model.FieldMeta) # Create field_sign = "task.python_test_{}".format("".join([ random.choice("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") for _ in range(20) ])) database.field.create(sign=field_sign, type_="int") # Delete field = database.field.filter_one(cgtwq.Field("sign") == field_sign) assert field.sign == field_sign database.field.delete(field.id)
def test_get_database(): project = cgtwq.PROJECT.filter( cgtwq.Field("entity") == "SDKTEST").to_entry() orig_status = project["status"] project["status"] = "Active" assert (cgtwq.helper.wlf.get_database_by_file("sdktest_example.jpg") == "proj_sdktest") with pytest.raises(cgtwq.helper.wlf.DatabaseError): cgtwq.helper.wlf.CGTWQHelper.get_database("example.jpg") project["status"] = orig_status
def import_data(data, database, module, module_type): """Import data to cgtw database. """ module = cgtwq.Database(database).module(module, module_type) errors = [] for i in data: assert isinstance(i, RowData) try: select = module.filter( (cgtwq.Field('shot.entity') == i.shot) & (cgtwq.Field('pipeline') == i.pipeline)) except ValueError: LOGGER.error('找不到对应条目: 行=%s, 数据库=%s, 镜头号=%s, 流程=%s', i.index, database, i.shot, i.pipeline, ) errors.append(NoEntry(i)) continue try: _apply_on_selection(select, i) except ValueError: continue if errors: raise ImportError(errors)
def _link(db, shot, assets): # type: (cgtwq.Database, Text, Tuple[Text, ...]) -> ... if not assets: return asset_module = db.module("asset", "info") shot_module = db.module("shot", "info") try: matched_assets = asset_module.filter( cgtwq.Field("asset.entity").in_(assets), namespace="asset" ) if len(matched_assets) != len(assets): LOGGER.warning( "some asssets not found: assets=%s match=%d", assets, len(matched_assets) ) except cgtwq.EmptySelection: LOGGER.warning("not found assets: %s", assets) return try: shots = shot_module.filter(cgtwq.Field("shot.entity") == shot, namespace="shot") except cgtwq.EmptySelection: LOGGER.warning("not found shot: %s", shot) return shots.link.link(*matched_assets) # type: ignore LOGGER.info("link: shot=%s, assets=%s", shot, assets)
def test_in_namespace(): obj1 = cgtwq.Field("key1") obj2 = obj1.in_namespace("namespace1") assert obj1 == "key1" assert obj2 == "namespace1.key1" obj3 = cgtwq.Filter("key2", "value2") obj4 = obj3.in_namespace("namespace2") assert obj3[0] == "key2" assert obj4[0] == "namespace2.key2" obj5 = cgtwq.FilterList(obj3) obj6 = obj5.in_namespace("namespace3") assert obj5[0][0] == "key2" assert obj6[0][0] == "namespace3.key2" obj7 = cgtwq.FilterList.from_arbitrary_args(obj3, obj4) obj8 = obj7.in_namespace("namespace4") assert obj7[0][0] == "key2" assert obj8[0][0] == "namespace4.key2"
def dialog_create_dirs(): """A dialog for create dirs from cgtwq. """ folder_input_name = b'输出文件夹' database_input_name = b'数据库' prefix_input_name = b'镜头名前缀限制' panel = nuke.Panel(b'为项目创建文件夹') panel.addSingleLineInput(database_input_name, 'proj_qqfc_2017') panel.addSingleLineInput(prefix_input_name, '') panel.addFilenameSearch(folder_input_name, 'E:/temp') confirm = panel.show() if not confirm: return try: database = panel.value(database_input_name) save_path = panel.value(folder_input_name) prefix = panel.value(prefix_input_name) for _ in progress(['连接CGTeamWork...', ], '创建文件夹'): try: select = cgtwq.Database(database)['shot_task'].filter( cgtwq.Field('pipeline') == '合成') except cgtwq.IDError as ex: nuke.message(utf8('找不到对应条目\n{}'.format(ex))) return for name in progress(select['shot.shot'], '创建文件夹'): if not name or not name.startswith(prefix): continue _path = os.path.join(save_path, name) if not os.path.exists(_path): os.makedirs(_path) webbrowser.open(save_path) except CancelledError: LOGGER.debug('用户取消创建文件夹')
def main(): print('{:-^50s}'.format('导出历史 v{}'.format(__version__))) wlf.mp_logging.basic_config() dummy_app = QApplication(sys.argv) filename, _ = QFileDialog.getSaveFileName( None, '保存位置', 'E:/任务历史-{}.xlsx'.format(datetime.now().strftime('%Y%m%d-%H%M')), '*.xlsx') if not filename: return client = cgtwq.DesktopClient() client.connect() pipeline = set( client.selection().get_fields("pipeline").column("pipeline")) select = client.selection().module.filter( cgtwq.Field("pipeline").in_(list(pipeline)), ) try: rows = get_rows(select) wb = create_workbook(rows) wb.save(filename) webbrowser.open(os.path.dirname(filename)) except IOError: LOGGER.error('不能写入文件: %s', filename) msgbox('不能写入文件: {}, 请检查文件占用'.format(filename))
def test_list_filebox_by_pipeline(): db = cgtwq.Database("proj_sdktest") (pipeline, ) = db.pipeline.filter(cgtwq.Field("entity") == "合成") pipeline.module filebox_list = db.filebox.list_by_pipeline(pipeline) assert filebox_list
def _entry(): return (cgtwq.Database("proj_sdktest").module("shot").filter( cgtwq.Field("shot.entity") == "SDKTEST_EP01_01_sc001", cgtwq.Field("task.pipeline") == "合成", ).to_entry())
def test_module_count(module): result = module.count(cgtwq.Field("shot.entity").has("_sc001")) assert isinstance(result, int)
def test_filter_plugin(): result = cgtwq.PluginMeta.filter() for i in result: assert isinstance(i, cgtwq.PluginMeta) result = cgtwq.PluginMeta.filter(cgtwq.Field("name") == "测试")[0] assert isinstance(result, cgtwq.PluginMeta)
def _plugin(): return cgtwq.PluginMeta.filter(cgtwq.Field("name") == "测试")[0]
def test_selection_count(select): result = select.count(cgtwq.Field("shot.entity").has("_sc001")) assert isinstance(result, int) assert result > 0
def test_selection_distinct(select): result = select.distinct(cgtwq.Field("shot.entity").has("_sc001")) assert isinstance(result, tuple)
def test_database_filebox(database): result = database.filebox.filter() assert all(isinstance(i, cgtwq.model.FileBoxMeta) for i in result) result = database.filebox.filter(cgtwq.Field("title") == "检查MOV") result = database.filebox.from_id("271")