new_contents: from __future__ import absolute_import, division, print_function
  
  import os
  
  def find_new_python3_incompatible_code(module_under_test):
    '''
      Check source code to see if any files violate Python 3 syntax that
      previously did not. Example call:
  
      def test_find_python3_violations():
        import xia2
        import pytest
        import dials.test.python3_regression as py3test
        result = py3test.find_new_python3_incompatible_code(xia2)
        if result is None:
          pytest.skip('No python3 interpreter available')
        elif result:
          pytest.fail(result)
  
      Known violations are kept in file .known-python3-violations in the
      module directory.
    '''
  
    # File containing list of excluded files
    allowed_broken_files_list = '.known-python3-violations'
  
    # Mask all *PYTHON* variables from environment - Python3 will not like cctbx python settings
    environ_override = { k: '' for k in list(os.environ) if 'PYTHON' in k }
  
    from dials.util.procrunner import run_process
    module_path = module_under_test.__path__[0]
    try:
      result = run_process(['python3', '-m', 'compileall', '-x', '\.git', '-q', module_path], environ=environ_override, print_stdout=False)
    except OSError as e:
      if e.errno == 2:
        return None
      raise
  
    if result['stderr']:
      return 'Python3 compilation exited with unexpected STDERR output'
  
    if not result['exitcode']: # No compilation errors
      return False
  
    errors = map(lambda x: x.replace(module_path + os.path.sep, '').strip(), result['stdout'].split('***'))
    errors = filter(lambda x: "'" in x, errors)
    broken_files = { error.split("'")[1]: error for error in errors }
  
    exclusion_file = os.path.join(module_path, allowed_broken_files_list)
    with open(exclusion_file + '.log', 'w') as fh:
      fh.write("\n".join(sorted(broken_files)))
    if os.path.exists(exclusion_file):
      with open(exclusion_file, 'r') as fh:
        excluded_files = fh.read().splitlines()
      broken_files = { filename: broken_files[filename] for filename in broken_files if filename not in excluded_files }
  
    if not broken_files: # No syntax violations in new files
      return False
  
    for filename in sorted(broken_files):
      print(broken_files[filename], end="\n\n")
  
    return "{} file[s] contain newly introduced Python3 syntax errors".format(len(broken_files))
  
subject: Add Jenkins Python3 monster to dials, but don't enable it here yet.