Skip to content

Commit ca68882

Browse files
committed
Merge pull request #509 from cchampet/dev_upToV0.12.7
New patch v0.12.7
2 parents e32d15b + 4f4653b commit ca68882

File tree

9 files changed

+131
-82
lines changed

9 files changed

+131
-82
lines changed

applications/sam/common/samUtils.py

Lines changed: 12 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -69,23 +69,17 @@ def setLogLevel(self, tuttleVerboseLevel):
6969
"""
7070
for handler in self.logger.handlers:
7171
if tuttleVerboseLevel is 0:
72-
# CRITICAL
73-
handler.setLevel(50)
72+
handler.setLevel(logging.CRITICAL)
7473
elif tuttleVerboseLevel is 1:
75-
# ERROR
76-
handler.setLevel(40)
74+
handler.setLevel(logging.ERROR)
7775
elif tuttleVerboseLevel is 2:
78-
# WARNING
79-
handler.setLevel(30)
76+
handler.setLevel(logging.WARNING)
8077
elif tuttleVerboseLevel is 3:
81-
# INFO
82-
handler.setLevel(20)
78+
handler.setLevel(logging.INFO)
8379
elif tuttleVerboseLevel >= 4:
84-
# DEBUG (and trace)
85-
handler.setLevel(10)
80+
handler.setLevel(logging.DEBUG)
8681
else:
87-
# WARNING
88-
handler.setLevel(30)
82+
handler.setLevel(logging.WARNING)
8983

9084

9185
class SamFormatter(logging.Formatter):
@@ -213,19 +207,17 @@ def getSequenceNameWithFormatting(sequence, formatChosen):
213207
"""
214208
Return the sequence name with a specific formatting (from nuke, rv...).
215209
"""
216-
sequenceName = sequence.getPrefix()
217210
if formatChosen == 'rv':
211+
sequenceName = sequence.getPrefix()
218212
sequenceName += (str(sequence.getFirstTime()) + '-' + str(sequence.getLastTime()))
219-
sequenceName += '@' * sequence.getPadding()
220-
if not sequence.getPadding():
213+
sequenceName += '@' * sequence.getFixedPadding()
214+
if not sequence.getFixedPadding():
221215
sequenceName += '@' # no padding
216+
sequenceName += sequence.getSuffix()
222217
elif formatChosen == 'nuke':
223-
sequenceName += '%0' + str(sequence.getPadding()) + 'd'
218+
sequenceName = sequence.getFilenameWithPrintfPattern()
224219
else: # default formatting
225-
sequenceName += '#' * sequence.getPadding()
226-
if not sequence.getPadding():
227-
sequenceName += '@' # no padding
228-
sequenceName += sequence.getSuffix()
220+
sequenceName = sequence.getFilenameWithStandardPattern()
229221
return sequenceName
230222

231223

applications/sam/sam_cp.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ def __init__(self):
2020
self.command = 'cp'
2121
self.help = 'to copy sequences'
2222
self.description = str(colored.green('''
23-
Copy sequences in a directory.
23+
Copy one or more sequences to a directory.
2424
'''))
2525
self._operation = shutil.copy2
2626

applications/sam/sam_do.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -527,6 +527,7 @@ def run(self, parser):
527527
self.logger.error('No tuttle graph to compute.')
528528
exit(1)
529529

530+
error = 0
530531
# Compute the corresponding tuttle graphs
531532
for graph, nodes in graphsWithNodes:
532533
# Options of process
@@ -565,8 +566,10 @@ def run(self, parser):
565566
except Exception as e:
566567
self.logger.error('Tuttle graph computation has failed.')
567568
self.logger.debug(e)
569+
error = 1
568570
self.logger.info('Memory usage: ' + str(int(samUtils.memoryUsageResource())) + 'KB')
569571

572+
exit(error)
570573

571574
if __name__ == '__main__':
572575
# Create the tool

applications/sam/sam_ls.py

Lines changed: 28 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ def printItems(self, items, args, detectionMethod, filters, level=0):
230230

231231
try:
232232
newFolder = os.path.join(item.getFolder(), item.getFilename())
233-
self.logger.info('Launch a browse on "' + newFolder + '" with the following filters: ' + str(filters))
233+
self.logger.debug('Browse in "' + newFolder + '" with the following filters: ' + str(filters))
234234
newItems = sequenceParser.browse(newFolder, detectionMethod, filters)
235235
level += 1
236236
self.printItems(newItems, args, detectionMethod, filters, level)
@@ -249,15 +249,22 @@ def run(self, parser):
249249
# Set sam log level
250250
self.setLogLevel(args.verbose)
251251

252-
# inputs to scan
253252
inputs = []
254-
for input in args.inputs:
255-
# if exists add the path
256-
if os.path.exists(input):
257-
inputs.append(input)
258-
# else use it as a filter expression
259-
else:
260-
args.expression.append(input)
253+
# for each input to scan
254+
for inputPath in args.inputs:
255+
# if the input is a directory, add it and continue
256+
if os.path.isdir(inputPath):
257+
inputs.append(inputPath)
258+
continue
259+
# else split the input to a path and a filename
260+
subPath = os.path.dirname(inputPath)
261+
if not subPath:
262+
subPath = '.'
263+
filename = os.path.basename(inputPath)
264+
# add the path and the filename as an expression
265+
inputs.append(subPath)
266+
if filename:
267+
args.expression.append(filename)
261268
if not inputs:
262269
inputs.append(os.getcwd())
263270

@@ -280,18 +287,19 @@ def run(self, parser):
280287
filters.append(expression)
281288

282289
# get list of items for each inputs
283-
for input in inputs:
290+
for inputPath in inputs:
284291
items = []
285292
try:
286-
self.logger.info('Launch a browse on "' + input + '" with the following filters: ' + str(filters))
287-
items = sequenceParser.browse(input, detectionMethod, filters)
293+
self.logger.debug('Browse in "' + inputPath + '" with the following filters: ' + str(filters))
294+
items = sequenceParser.browse(inputPath, detectionMethod, filters)
288295
except IOError as e:
296+
self.logger.debug('IOError raised: "' + str(e) + '".')
289297
# if the given input does not correspond to anything
290298
if 'No such file or directory' in str(e):
291299
# try to create a sequence from the given input
292300
sequence = sequenceParser.Sequence()
293-
self.logger.info('Launch a browseSequence on "' + input + '".')
294-
isSequence = sequenceParser.browseSequence(sequence, input)
301+
self.logger.debug('BrowseSequence on "' + inputPath + '".')
302+
isSequence = sequenceParser.browseSequence(sequence, inputPath)
295303
if isSequence:
296304
item = sequenceParser.Item(sequence, os.getcwd())
297305
# check if the sequence contains at least one element
@@ -301,22 +309,23 @@ def run(self, parser):
301309
else:
302310
self.logger.warning(e)
303311
continue
304-
# else it's not a directory: try a new browse with the given input name as filter
312+
# else it's not a directory
305313
else:
314+
self.logger.debug('Try a new browse with the given input name as filter.')
306315
# new path to browse
307-
newBrowsePath = os.path.dirname(input)
316+
newBrowsePath = os.path.dirname(inputPath)
308317
if not newBrowsePath:
309318
newBrowsePath = '.'
310319
# new filter
311320
newFilter = []
312321
newFilter.extend(filters)
313-
newFilter.append(os.path.basename(input))
322+
newFilter.append(os.path.basename(inputPath))
314323
# new browse
315-
self.logger.info('Launch a browse on "' + newBrowsePath + '" with the following filters: ' + str(newFilter))
324+
self.logger.debug('Browse in "' + newBrowsePath + '" with the following filters: ' + str(newFilter))
316325
items += sequenceParser.browse(newBrowsePath, detectionMethod, newFilter)
317326

318327
if not len(items):
319-
self.logger.warning('No items found for input "' + input + '".')
328+
self.logger.warning('No items found for input "' + inputPath + '".')
320329
else:
321330
self.printItems(items, args, detectionMethod, filters)
322331

applications/sam/sam_mv.py

Lines changed: 49 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,14 @@ def __init__(self):
2525
self.command = 'mv'
2626
self.help = 'to move sequences'
2727
self.description = str(colored.green('''
28-
Move sequences in a directory.
29-
Rename sequences if the output directory is the same as the input.
28+
Move one or more sequences to a directory.
29+
Rename / retime a sequence.
3030
'''))
3131
self._operation = shutil.move
3232

3333
def fillParser(self, parser):
34-
parser.add_argument('inputs', metavar='INPUTS', nargs='+', action='store', help='list of inputs').completer = samUtils.sequenceParserCompleter
35-
parser.add_argument('output', metavar='OUTPUT', help='the output to write').completer = samUtils.sequenceParserCompleter
34+
parser.add_argument('inputs', metavar='INPUTS', nargs='+', action='store', help='list of inputs (only sequences)').completer = samUtils.sequenceParserCompleter
35+
parser.add_argument('output', metavar='OUTPUT', help='the output to write (sequence or directory)').completer = samUtils.sequenceParserCompleter
3636

3737
# Options
3838
parser.add_argument('-o', '--offset', dest='offset', type=int, help='retime the sequence with the given offset')
@@ -48,6 +48,7 @@ def fillParser(self, parser):
4848

4949
parser.add_argument('--detect-negative', dest='detectNegative', action='store_true', help='detect negative numbers instead of detecting "-" as a non-digit character')
5050
parser.add_argument('-v', '--verbose', dest='verbose', action=samUtils.SamSetVerboseAction, default=2, help='verbose level (0/fatal, 1/error, 2/warn(by default), 3/info, 4(or upper)/debug)')
51+
parser.add_argument('--dry-run', dest='dryRun', action='store_true', help='only print what it will do (will force verbosity to info)')
5152

5253
def _getSequenceManipulators(self, inputSequence, args):
5354
"""
@@ -86,10 +87,11 @@ def _getSequenceManipulators(self, inputSequence, args):
8687

8788
return {'first': first, 'last': last, 'offset': offset, 'holes': holesToRemove}
8889

89-
def _processSequence(self, inputItem, outputSequence, outputSequencePath, moveManipulators):
90+
def _processSequence(self, inputItem, outputSequence, outputSequencePath, moveManipulators, dryRun):
9091
"""
9192
Apply operation to the sequence contained in inputItem (used by sam-mv and sam-cp).
9293
Depending on args, update the frame ranges of the output sequence.
94+
Return if the operation was a success or not.
9395
9496
:param inputItem: the item which contains the input sequence to process (move, copy...)
9597
:param outputSequence: the output sequence to write (destination of move, copy...)
@@ -101,17 +103,20 @@ def _processSequence(self, inputItem, outputSequence, outputSequencePath, moveMa
101103
offset used to retime the output sequence,
102104
list of holes to remove in the output sequence
103105
}
106+
:param dryRun: only print what it will do.
104107
"""
105108
# create output directory if not exists
106109
try:
107110
if not os.path.exists(outputSequencePath):
108-
os.makedirs(outputSequencePath)
111+
# sam-rm --dry-run
112+
if not dryRun:
113+
os.makedirs(outputSequencePath)
109114
except Exception as e:
110115
self.logger.error('Cannot create directory tree for "' + outputSequencePath + '": ' + str(e))
111-
exit(-1)
116+
return 1
112117

113-
# print brief of the operation
114-
self.logger.info(os.path.join(inputItem.getFolder(), str(inputItem.getSequence())) + ' -> ' + os.path.join(outputSequencePath, str(outputSequence)))
118+
# log brief of the operation
119+
self.logger.info(os.path.join(self.command + ' ' + inputItem.getFolder(), str(inputItem.getSequence())) + ' to ' + os.path.join(outputSequencePath, str(outputSequence)))
115120

116121
# get frame ranges
117122
inputFrameList = list(inputItem.getSequence().getFramesIterable(moveManipulators['first'], moveManipulators['last']))
@@ -128,14 +133,18 @@ def _processSequence(self, inputItem, outputSequence, outputSequencePath, moveMa
128133
# security: check if file already exist
129134
if os.path.exists(outputPath):
130135
self.logger.error('The output path "' + outputPath + '" already exist!')
131-
exit(-1)
136+
return 1
132137

133138
# process the image at time
134-
self._operation(inputPath, outputPath)
139+
self.logger.info(inputPath + ' -> ' + outputPath)
140+
# sam-rm --dry-run
141+
if not dryRun:
142+
self._operation(inputPath, outputPath)
135143

136144
def _getSequenceItemFromPath(self, inputPath, detectNegative):
137145
"""
138-
Get an Item (which corresponds to a sequence) from a path.
146+
Return an Item (which corresponds to a sequence) from a path.
147+
Return None if the operation failed.
139148
"""
140149
# get input path and name
141150
inputSequencePath = os.path.dirname(inputPath)
@@ -152,16 +161,16 @@ def _getSequenceItemFromPath(self, inputPath, detectNegative):
152161
inputItems = sequenceParser.browse(inputSequencePath, detectionMethod, [inputSequenceName])
153162
if not len(inputItems):
154163
self.logger.error('No existing file corresponds to the given input sequence: ' + inputPath)
155-
exit(-1)
164+
return None
156165
if len(inputItems) > 1:
157166
self.logger.error('Several items ' + str([item.getFilename() for item in inputItems]) + ' correspond to the given input sequence: ' + inputPath)
158-
exit(-1)
167+
return None
159168

160169
# check if the item is a sequence
161170
inputItem = inputItems[0]
162171
if inputItem.getType() != sequenceParser.eTypeSequence:
163172
self.logger.error('Input is not a sequence: ' + inputItem.getFilename())
164-
exit(-1)
173+
return None
165174

166175
return inputItem
167176

@@ -173,26 +182,39 @@ def run(self, parser):
173182
args = parser.parse_args()
174183

175184
# Set sam log level
176-
self.setLogLevel(args.verbose)
185+
# sam-rm --dry-run
186+
if args.dryRun:
187+
self.setLogLevel(3) # info
188+
else:
189+
self.setLogLevel(args.verbose)
177190

178191
# check command line
179192
if args.offset and (args.outputFirst is not None or args.outputLast is not None):
180193
self.logger.error('You cannot cumulate multiple options to modify the time.')
181194
exit(-1)
182195

183-
# Get output path
184-
outputSequencePath = os.path.dirname(args.output)
185-
if not outputSequencePath:
186-
outputSequencePath = '.'
187-
188196
# Get output sequence
189197
outputSequence = sequenceParser.Sequence()
190198
outputSequenceName = os.path.basename(args.output)
191199
outputIsSequence = outputSequence.initFromPattern(outputSequenceName, sequenceParser.ePatternDefault)
192200

201+
# Get output path
202+
if outputIsSequence:
203+
outputSequencePath = os.path.dirname(args.output)
204+
# if output path is the same as input
205+
if not len(outputSequencePath):
206+
outputSequencePath = '.'
207+
else:
208+
outputSequencePath = args.output
209+
self.logger.debug('Output sequence path is "' + outputSequencePath + '".')
210+
193211
# For each input
194-
for input in args.inputs:
195-
inputItem = self._getSequenceItemFromPath(input, args.detectNegative)
212+
error = 0
213+
for inputPath in args.inputs:
214+
inputItem = self._getSequenceItemFromPath(inputPath, args.detectNegative)
215+
if inputItem is None:
216+
error = 1
217+
continue
196218

197219
if not outputIsSequence:
198220
outputSequence = sequenceParser.Sequence(inputItem.getSequence())
@@ -201,8 +223,11 @@ def run(self, parser):
201223
moveManipulators = self._getSequenceManipulators(inputItem.getSequence(), args)
202224

203225
# move sequence
204-
self._processSequence(inputItem, outputSequence, outputSequencePath, moveManipulators)
226+
err = self._processSequence(inputItem, outputSequence, outputSequencePath, moveManipulators, args.dryRun)
227+
if err:
228+
error = err
205229

230+
exit(error)
206231

207232
if __name__ == '__main__':
208233
# Create the tool

0 commit comments

Comments
 (0)