Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(354)

Side by Side Diff: tools/rebaseline.py

Issue 26666004: Add ability to rebaseline skimage to rebaseline.py (Closed) Base URL: https://skia.googlecode.com/svn/trunk
Patch Set: Respond to comments Created 7 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « gm/gm_json.py ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/python 1 #!/usr/bin/python
2 2
3 ''' 3 '''
4 Copyright 2012 Google Inc. 4 Copyright 2012 Google Inc.
5 5
6 Use of this source code is governed by a BSD-style license that can be 6 Use of this source code is governed by a BSD-style license that can be
7 found in the LICENSE file. 7 found in the LICENSE file.
8 ''' 8 '''
9 9
10 ''' 10 '''
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after
152 # which updated expectations should be 152 # which updated expectations should be
153 # written; typically the same as 153 # written; typically the same as
154 # expectations_input_filename, to overwrite 154 # expectations_input_filename, to overwrite
155 # the old content 155 # the old content
156 # actuals_base_url: base URL from which to read actual-result JSON files 156 # actuals_base_url: base URL from which to read actual-result JSON files
157 # actuals_filename: filename (under actuals_base_url) from which to read a 157 # actuals_filename: filename (under actuals_base_url) from which to read a
158 # summary of results; typically "actual-results.json" 158 # summary of results; typically "actual-results.json"
159 # exception_handler: reference to rebaseline.ExceptionHandler object 159 # exception_handler: reference to rebaseline.ExceptionHandler object
160 # tests: list of tests to rebaseline, or None if we should rebaseline 160 # tests: list of tests to rebaseline, or None if we should rebaseline
161 # whatever files the JSON results summary file tells us to 161 # whatever files the JSON results summary file tells us to
162 # Ignored if 'skip_pattern_matching' is set to True
162 # configs: which configs to run for each test, or None if we should 163 # configs: which configs to run for each test, or None if we should
163 # rebaseline whatever configs the JSON results summary file tells 164 # rebaseline whatever configs the JSON results summary file tells
164 # us to 165 # us to
166 # Ignored if 'skip_pattern_matching' is set to True
165 # add_new: if True, add expectations for tests which don't have any yet 167 # add_new: if True, add expectations for tests which don't have any yet
166 # bugs: optional list of bug numbers which pertain to these expectations 168 # bugs: optional list of bug numbers which pertain to these expectations
167 # notes: free-form text notes to add to all updated expectations 169 # notes: free-form text notes to add to all updated expectations
168 # mark_unreviewed: if True, mark these expectations as NOT having been 170 # mark_unreviewed: if True, mark these expectations as NOT having been
169 # reviewed by a human; otherwise, leave that field blank. 171 # reviewed by a human; otherwise, leave that field blank.
170 # Currently, there is no way to make this script mark 172 # Currently, there is no way to make this script mark
171 # expectations as reviewed-by-human=True. 173 # expectations as reviewed-by-human=True.
172 # TODO(epoger): Add that capability to a review tool. 174 # TODO(epoger): Add that capability to a review tool.
173 # mark_ignore_failure: if True, mark failures of a given test as being 175 # mark_ignore_failure: if True, mark failures of a given test as being
174 # ignored. 176 # ignored.
177 # skip_pattern_matching: if True, do not attempt to skip tests/configs
178 # matching input parameters 'tests'/'configs'.
175 def __init__(self, expectations_root, expectations_input_filename, 179 def __init__(self, expectations_root, expectations_input_filename,
176 expectations_output_filename, actuals_base_url, 180 expectations_output_filename, actuals_base_url,
177 actuals_filename, exception_handler, 181 actuals_filename, exception_handler,
178 tests=None, configs=None, add_new=False, bugs=None, notes=None, 182 tests=None, configs=None, add_new=False, bugs=None, notes=None,
179 mark_unreviewed=None, mark_ignore_failure=False, 183 mark_unreviewed=None, mark_ignore_failure=False,
180 from_trybot=False): 184 from_trybot=False, skip_pattern_matching=False):
epoger 2013/10/10 19:51:39 Please add from_trybot to the docstring (I know yo
scroggo 2013/10/10 20:18:58 Done.
181 self._expectations_root = expectations_root 185 self._expectations_root = expectations_root
182 self._expectations_input_filename = expectations_input_filename 186 self._expectations_input_filename = expectations_input_filename
183 self._expectations_output_filename = expectations_output_filename 187 self._expectations_output_filename = expectations_output_filename
184 self._tests = tests 188 self._tests = tests
185 self._configs = configs 189 self._configs = configs
186 self._actuals_base_url = actuals_base_url 190 self._actuals_base_url = actuals_base_url
187 self._actuals_filename = actuals_filename 191 self._actuals_filename = actuals_filename
188 self._exception_handler = exception_handler 192 self._exception_handler = exception_handler
189 self._add_new = add_new 193 self._add_new = add_new
190 self._bugs = bugs 194 self._bugs = bugs
191 self._notes = notes 195 self._notes = notes
192 self._mark_unreviewed = mark_unreviewed 196 self._mark_unreviewed = mark_unreviewed
193 self._mark_ignore_failure = mark_ignore_failure; 197 self._mark_ignore_failure = mark_ignore_failure;
194 self._image_filename_re = re.compile(gm_json.IMAGE_FILENAME_PATTERN) 198 # TODO(scroggo): This is a hack. Since the filenames will not match
199 # the pattern in skimage, we skip the pattern matching entirely.
200 if skip_pattern_matching:
epoger 2013/10/10 19:51:39 Maybe, instead of adding the new parameter that ca
scroggo 2013/10/10 20:18:58 Done. I like this much better!
201 self._image_filename_re = None
202 if tests or configs:
203 raise _InternalException('"skip_pattern_matching" is incompatible with '
204 '"tests" and "configs"')
205 else:
206 self._image_filename_re = re.compile(gm_json.IMAGE_FILENAME_PATTERN)
195 self._using_svn = os.path.isdir(os.path.join(expectations_root, '.svn')) 207 self._using_svn = os.path.isdir(os.path.join(expectations_root, '.svn'))
196 self._from_trybot = from_trybot 208 self._from_trybot = from_trybot
197 209
198 # Executes subprocess.call(cmd). 210 # Executes subprocess.call(cmd).
199 # Raises an Exception if the command fails. 211 # Raises an Exception if the command fails.
200 def _Call(self, cmd): 212 def _Call(self, cmd):
201 if subprocess.call(cmd) != 0: 213 if subprocess.call(cmd) != 0:
202 raise _InternalException('error running command: ' + ' '.join(cmd)) 214 raise _InternalException('error running command: ' + ' '.join(cmd))
203 215
204 # Returns the full contents of filepath, as a single string. 216 # Returns the full contents of filepath, as a single string.
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
286 expected_results = expectations_dict.get(gm_json.JSONKEY_EXPECTEDRESULTS) 298 expected_results = expectations_dict.get(gm_json.JSONKEY_EXPECTEDRESULTS)
287 if not expected_results: 299 if not expected_results:
288 expected_results = {} 300 expected_results = {}
289 expectations_dict[gm_json.JSONKEY_EXPECTEDRESULTS] = expected_results 301 expectations_dict[gm_json.JSONKEY_EXPECTEDRESULTS] = expected_results
290 302
291 # Update the expectations in memory, skipping any tests/configs that 303 # Update the expectations in memory, skipping any tests/configs that
292 # the caller asked to exclude. 304 # the caller asked to exclude.
293 skipped_images = [] 305 skipped_images = []
294 if results_to_update: 306 if results_to_update:
295 for (image_name, image_results) in results_to_update.iteritems(): 307 for (image_name, image_results) in results_to_update.iteritems():
296 (test, config) = self._image_filename_re.match(image_name).groups() 308 if self._image_filename_re:
297 if self._tests: 309 (test, config) = self._image_filename_re.match(image_name).groups()
298 if test not in self._tests: 310 if self._tests:
299 skipped_images.append(image_name) 311 if test not in self._tests:
300 continue 312 skipped_images.append(image_name)
301 if self._configs: 313 continue
302 if config not in self._configs: 314 if self._configs:
303 skipped_images.append(image_name) 315 if config not in self._configs:
304 continue 316 skipped_images.append(image_name)
317 continue
305 if not expected_results.get(image_name): 318 if not expected_results.get(image_name):
306 expected_results[image_name] = {} 319 expected_results[image_name] = {}
307 expected_results[image_name]\ 320 expected_results[image_name]\
308 [gm_json.JSONKEY_EXPECTEDRESULTS_ALLOWEDDIGESTS]\ 321 [gm_json.JSONKEY_EXPECTEDRESULTS_ALLOWEDDIGESTS]\
309 = [image_results] 322 = [image_results]
310 if self._mark_unreviewed: 323 if self._mark_unreviewed:
311 expected_results[image_name]\ 324 expected_results[image_name]\
312 [gm_json.JSONKEY_EXPECTEDRESULTS_REVIEWED]\ 325 [gm_json.JSONKEY_EXPECTEDRESULTS_REVIEWED]\
313 = False 326 = False
314 if self._mark_ignore_failure: 327 if self._mark_ignore_failure:
(...skipping 12 matching lines...) Expand all
327 # Write out updated expectations. 340 # Write out updated expectations.
328 expectations_output_filepath = os.path.join( 341 expectations_output_filepath = os.path.join(
329 self._expectations_root, builder, self._expectations_output_filename) 342 self._expectations_root, builder, self._expectations_output_filename)
330 gm_json.WriteToFile(expectations_dict, expectations_output_filepath) 343 gm_json.WriteToFile(expectations_dict, expectations_output_filepath)
331 344
332 # Mark the JSON file as plaintext, so text-style diffs can be applied. 345 # Mark the JSON file as plaintext, so text-style diffs can be applied.
333 # Fixes https://code.google.com/p/skia/issues/detail?id=1442 346 # Fixes https://code.google.com/p/skia/issues/detail?id=1442
334 if self._using_svn: 347 if self._using_svn:
335 self._Call(['svn', 'propset', '--quiet', 'svn:mime-type', 348 self._Call(['svn', 'propset', '--quiet', 'svn:mime-type',
336 'text/x-json', expectations_output_filepath]) 349 'text/x-json', expectations_output_filepath])
337
338 # main... 350 # main...
339 351
340 parser = argparse.ArgumentParser( 352 parser = argparse.ArgumentParser(
341 formatter_class=argparse.RawDescriptionHelpFormatter, 353 formatter_class=argparse.RawDescriptionHelpFormatter,
342 epilog='Here is the full set of builders we know about:' + 354 epilog='Here is the full set of builders we know about:' +
343 '\n '.join([''] + sorted(TEST_BUILDERS))) 355 '\n '.join([''] + sorted(TEST_BUILDERS)))
344 parser.add_argument('--actuals-base-url', 356 parser.add_argument('--actuals-base-url',
345 help=('base URL from which to read files containing JSON ' 357 help=('base URL from which to read files containing JSON '
346 'summaries of actual GM results; defaults to ' 358 'summaries of actual GM results; defaults to '
347 '%(default)s. To get a specific revision (useful for' 359 '%(default)s. To get a specific revision (useful for '
348 'trybots) replace "svn" with "svn-history/r123".'), 360 'trybots) replace "svn" with "svn-history/r123". '
361 'If SKIMAGE is True, defaults to ' +
362 gm_json.SKIMAGE_ACTUALS_BASE_URL),
349 default='http://skia-autogen.googlecode.com/svn/gm-actual') 363 default='http://skia-autogen.googlecode.com/svn/gm-actual')
350 parser.add_argument('--actuals-filename', 364 parser.add_argument('--actuals-filename',
351 help=('filename (within builder-specific subdirectories ' 365 help=('filename (within builder-specific subdirectories '
352 'of ACTUALS_BASE_URL) to read a summary of results ' 366 'of ACTUALS_BASE_URL) to read a summary of results '
353 'from; defaults to %(default)s'), 367 'from; defaults to %(default)s'),
354 default='actual-results.json') 368 default='actual-results.json')
355 parser.add_argument('--add-new', action='store_true', 369 parser.add_argument('--add-new', action='store_true',
356 help=('in addition to the standard behavior of ' 370 help=('in addition to the standard behavior of '
357 'updating expectations for failing tests, add ' 371 'updating expectations for failing tests, add '
358 'expectations for tests which don\'t have ' 372 'expectations for tests which don\'t have '
359 'expectations yet.')) 373 'expectations yet.'))
360 parser.add_argument('--bugs', metavar='BUG', type=int, nargs='+', 374 parser.add_argument('--bugs', metavar='BUG', type=int, nargs='+',
361 help=('Skia bug numbers (under ' 375 help=('Skia bug numbers (under '
362 'https://code.google.com/p/skia/issues/list ) which ' 376 'https://code.google.com/p/skia/issues/list ) which '
363 'pertain to this set of rebaselines.')) 377 'pertain to this set of rebaselines.'))
364 parser.add_argument('--builders', metavar='BUILDER', nargs='+', 378 parser.add_argument('--builders', metavar='BUILDER', nargs='+',
365 help=('which platforms to rebaseline; ' 379 help=('which platforms to rebaseline; '
366 'if unspecified, rebaseline all known platforms ' 380 'if unspecified, rebaseline all known platforms '
367 '(see below for a list)')) 381 '(see below for a list)'))
368 # TODO(epoger): Add test that exercises --configs argument. 382 # TODO(epoger): Add test that exercises --configs argument.
369 parser.add_argument('--configs', metavar='CONFIG', nargs='+', 383 parser.add_argument('--configs', metavar='CONFIG', nargs='+',
370 help=('which configurations to rebaseline, e.g. ' 384 help=('which configurations to rebaseline, e.g. '
371 '"--configs 565 8888", as a filter over the full set ' 385 '"--configs 565 8888", as a filter over the full set '
372 'of results in ACTUALS_FILENAME; if unspecified, ' 386 'of results in ACTUALS_FILENAME; if unspecified, '
373 'rebaseline *all* configs that are available.')) 387 'rebaseline *all* configs that are available. '
388 'Ignored if SKIMAGE is True.'))
374 parser.add_argument('--expectations-filename', 389 parser.add_argument('--expectations-filename',
375 help=('filename (under EXPECTATIONS_ROOT) to read ' 390 help=('filename (under EXPECTATIONS_ROOT) to read '
376 'current expectations from, and to write new ' 391 'current expectations from, and to write new '
377 'expectations into (unless a separate ' 392 'expectations into (unless a separate '
378 'EXPECTATIONS_FILENAME_OUTPUT has been specified); ' 393 'EXPECTATIONS_FILENAME_OUTPUT has been specified); '
379 'defaults to %(default)s'), 394 'defaults to %(default)s'),
380 default='expected-results.json') 395 default='expected-results.json')
381 parser.add_argument('--expectations-filename-output', 396 parser.add_argument('--expectations-filename-output',
382 help=('filename (under EXPECTATIONS_ROOT) to write ' 397 help=('filename (under EXPECTATIONS_ROOT) to write '
383 'updated expectations into; by default, overwrites ' 398 'updated expectations into; by default, overwrites '
384 'the input file (EXPECTATIONS_FILENAME)'), 399 'the input file (EXPECTATIONS_FILENAME)'),
385 default='') 400 default='')
386 parser.add_argument('--expectations-root', 401 parser.add_argument('--expectations-root',
387 help=('root of expectations directory to update-- should ' 402 help=('root of expectations directory to update-- should '
388 'contain one or more builder subdirectories. ' 403 'contain one or more builder subdirectories. '
389 'Defaults to %(default)s'), 404 'Defaults to %(default)s. If SKIMAGE is set, '
405 ' defaults to ' + gm_json.SKIMAGE_EXPECTATIONS_ROOT),
390 default=os.path.join('expectations', 'gm')) 406 default=os.path.join('expectations', 'gm'))
391 parser.add_argument('--keep-going-on-failure', action='store_true', 407 parser.add_argument('--keep-going-on-failure', action='store_true',
392 help=('instead of halting at the first error encountered, ' 408 help=('instead of halting at the first error encountered, '
393 'keep going and rebaseline as many tests as ' 409 'keep going and rebaseline as many tests as '
394 'possible, and then report the full set of errors ' 410 'possible, and then report the full set of errors '
395 'at the end')) 411 'at the end'))
396 parser.add_argument('--notes', 412 parser.add_argument('--notes',
397 help=('free-form text notes to add to all updated ' 413 help=('free-form text notes to add to all updated '
398 'expectations')) 414 'expectations'))
399 # TODO(epoger): Add test that exercises --tests argument. 415 # TODO(epoger): Add test that exercises --tests argument.
400 parser.add_argument('--tests', metavar='TEST', nargs='+', 416 parser.add_argument('--tests', metavar='TEST', nargs='+',
401 help=('which tests to rebaseline, e.g. ' 417 help=('which tests to rebaseline, e.g. '
402 '"--tests aaclip bigmatrix", as a filter over the ' 418 '"--tests aaclip bigmatrix", as a filter over the '
403 'full set of results in ACTUALS_FILENAME; if ' 419 'full set of results in ACTUALS_FILENAME; if '
404 'unspecified, rebaseline *all* tests that are ' 420 'unspecified, rebaseline *all* tests that are '
405 'available.')) 421 'available. Ignored if SKIMAGE is True.'))
406 parser.add_argument('--unreviewed', action='store_true', 422 parser.add_argument('--unreviewed', action='store_true',
407 help=('mark all expectations modified by this run as ' 423 help=('mark all expectations modified by this run as '
408 '"%s": False' % 424 '"%s": False' %
409 gm_json.JSONKEY_EXPECTEDRESULTS_REVIEWED)) 425 gm_json.JSONKEY_EXPECTEDRESULTS_REVIEWED))
410 parser.add_argument('--ignore-failure', action='store_true', 426 parser.add_argument('--ignore-failure', action='store_true',
411 help=('mark all expectations modified by this run as ' 427 help=('mark all expectations modified by this run as '
412 '"%s": True' % 428 '"%s": True' %
413 gm_json.JSONKEY_ACTUALRESULTS_FAILUREIGNORED)) 429 gm_json.JSONKEY_ACTUALRESULTS_FAILUREIGNORED))
414 parser.add_argument('--from-trybot', action='store_true', 430 parser.add_argument('--from-trybot', action='store_true',
415 help=('pull the actual-results.json file from the ' 431 help=('pull the actual-results.json file from the '
416 'corresponding trybot, rather than the main builder')) 432 'corresponding trybot, rather than the main builder'))
433 parser.add_argument('--skimage', action='store_true',
434 help=('Rebaseline skimage results instead of gm. Defaults '
435 'to False. If True, TESTS and CONFIGS are ignored, '
436 'and ACTUALS_BASE_URL and EXPECTATIONS_ROOT are set '
437 'to alternate defaults, specific to skimage.'))
417 args = parser.parse_args() 438 args = parser.parse_args()
418 exception_handler = ExceptionHandler( 439 exception_handler = ExceptionHandler(
419 keep_going_on_failure=args.keep_going_on_failure) 440 keep_going_on_failure=args.keep_going_on_failure)
420 if args.builders: 441 if args.builders:
421 builders = args.builders 442 builders = args.builders
422 missing_json_is_fatal = True 443 missing_json_is_fatal = True
423 else: 444 else:
424 builders = sorted(TEST_BUILDERS) 445 builders = sorted(TEST_BUILDERS)
425 missing_json_is_fatal = False 446 missing_json_is_fatal = False
447 if args.skimage:
448 # Use a different default if --skimage is specified.
449 if args.actuals_base_url == parser.get_default('actuals_base_url'):
450 args.actuals_base_url = gm_json.SKIMAGE_ACTUALS_BASE_URL
451 if args.expectations_root == parser.get_default('expectations_root'):
452 args.expectations_root = gm_json.SKIMAGE_EXPECTATIONS_ROOT
426 for builder in builders: 453 for builder in builders:
427 if not builder in TEST_BUILDERS: 454 if not builder in TEST_BUILDERS:
428 raise Exception(('unrecognized builder "%s"; ' + 455 raise Exception(('unrecognized builder "%s"; ' +
429 'should be one of %s') % ( 456 'should be one of %s') % (
430 builder, TEST_BUILDERS)) 457 builder, TEST_BUILDERS))
431 458
432 expectations_json_file = os.path.join(args.expectations_root, builder, 459 expectations_json_file = os.path.join(args.expectations_root, builder,
433 args.expectations_filename) 460 args.expectations_filename)
434 if os.path.isfile(expectations_json_file): 461 if os.path.isfile(expectations_json_file):
435 rebaseliner = JsonRebaseliner( 462 rebaseliner = JsonRebaseliner(
436 expectations_root=args.expectations_root, 463 expectations_root=args.expectations_root,
437 expectations_input_filename=args.expectations_filename, 464 expectations_input_filename=args.expectations_filename,
438 expectations_output_filename=(args.expectations_filename_output or 465 expectations_output_filename=(args.expectations_filename_output or
439 args.expectations_filename), 466 args.expectations_filename),
440 tests=args.tests, configs=args.configs, 467 tests=args.tests, configs=args.configs,
441 actuals_base_url=args.actuals_base_url, 468 actuals_base_url=args.actuals_base_url,
442 actuals_filename=args.actuals_filename, 469 actuals_filename=args.actuals_filename,
443 exception_handler=exception_handler, 470 exception_handler=exception_handler,
444 add_new=args.add_new, bugs=args.bugs, notes=args.notes, 471 add_new=args.add_new, bugs=args.bugs, notes=args.notes,
445 mark_unreviewed=args.unreviewed, 472 mark_unreviewed=args.unreviewed,
446 mark_ignore_failure=args.ignore_failure, 473 mark_ignore_failure=args.ignore_failure,
447 from_trybot=args.from_trybot) 474 from_trybot=args.from_trybot,
475 skip_pattern_matching=args.skimage)
448 try: 476 try:
449 rebaseliner.RebaselineSubdir(builder=builder) 477 rebaseliner.RebaselineSubdir(builder=builder)
450 except: 478 except:
451 exception_handler.RaiseExceptionOrContinue() 479 exception_handler.RaiseExceptionOrContinue()
452 else: 480 else:
453 try: 481 try:
454 raise _InternalException('expectations_json_file %s not found' % 482 raise _InternalException('expectations_json_file %s not found' %
455 expectations_json_file) 483 expectations_json_file)
456 except: 484 except:
457 exception_handler.RaiseExceptionOrContinue() 485 exception_handler.RaiseExceptionOrContinue()
458 486
459 exception_handler.ReportAllFailures() 487 exception_handler.ReportAllFailures()
OLDNEW
« no previous file with comments | « gm/gm_json.py ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698