Fix lint issues for some early files.

BUG=chromium:758431
TEST=Ran bin/run_lint.

Change-Id: I8e9182d3cf38cedec6992b14cbd90706bbb9ffbc
diff --git a/build_lib.py b/build_lib.py
index 3676633..09f36d0 100644
--- a/build_lib.py
+++ b/build_lib.py
@@ -3,12 +3,15 @@
 # found in the LICENSE file.
 
 """Module for ChromeOS & Android build related logic in suite scheduler."""
+# pylint: disable=g-bad-import-order
 
-import apiclient
+from distutils import version
 import collections
 import logging
 import re
 
+import apiclient
+
 # Bare branches
 BARE_BRANCHES = ['factory', 'firmware']
 
@@ -19,190 +22,22 @@
 OS_TYPES = [OS_TYPE_CROS, OS_TYPE_BRILLO, OS_TYPE_ANDROID]
 OS_TYPES_LAUNCH_CONTROL = [OS_TYPE_BRILLO, OS_TYPE_ANDROID]
 
-
+# Launch control build's target's information
 LaunchControlBuildTargetInfo = collections.namedtuple(
     'LaunchControlBuildTargetInfo',
     [
-      'target',
-      'type',
+        'target',
+        'type',
     ])
 
+# ChromeOS build config's information
 CrOSBuildConfigInfo = collections.namedtuple(
     'CrOSBuildConfigInfo',
     [
-      'board',
-      'type',
+        'board',
+        'type',
     ])
 
-
-class NoBuildError(Exception):
-    """Raised when failing to get the required build from Google Storage."""
-
-
-class BuildType(object):
-    """Representing the type of test source build.
-
-    This is used to identify the test source build for testing.
-    """
-    FIRMWARE_RW = 'firmware_rw'
-    FIRMWARE_RO = 'firmware_ro'
-    CROS = 'cros'
-
-
-class BuildVersionKey(object):
-    """Keys referring to the builds to install in run_suites."""
-
-    CROS_VERSION = 'cros_version'
-    ANDROID_BUILD_VERSION = 'android_version'
-    TESTBED_BUILD_VERSION = 'testbed_version'
-    FW_RW_VERSION = 'fwrw_version'
-    FW_RO_VERSION = 'fwro_version'
-
-
-class AndroidBuild(collections.namedtuple(
-    '_AndroidBuildBase', ['branch', 'target', 'build_id']), object):
-
-    def __str__(self):
-        return _ANDROID_BUILD_PATTERN % {'branch': self.branch,
-                                         'target': self.target,
-                                         'build_id': self.build_id}
-
-
-class CrOSBuild(collections.namedtuple(
-    '_CrOSBuildBase',
-    ['board', 'build_type', 'milestone', 'manifest']), object):
-
-    def __str__(self):
-        return _CROS_BUILD_PATTERN % {'board': self.board,
-                                      'build_type': self.build_type,
-                                      'milestone': self.milestone,
-                                      'manifest': self.manifest}
-
-
-def get_latest_cros_build_from_gs(storage_client, board=None, suffix=None):
-    """Get latest build for given board from Google Storage.
-
-    Args:
-        storage_client: a rest_client.StorageRestClient object.
-        board: the board to fetch latest build. Default is 'master'.
-        suffix: suffix represents build channel, like '-release'.
-                Default is '-paladin'.
-
-    Returns:
-        a ChromeOS version string, e.g. '59.0.000.0'.
-
-    Raises:
-        HttpError if error happens in interacting with Google Storage.
-    """
-    board = board if board is not None else _DEFAULT_MASTER
-    suffix = suffix if suffix is not None else _DEFAULT_BUILD_SUFFIX
-    file_to_check = _GS_LATEST_MASTER_PATTERN % {
-        'board': board,
-        'suffix': suffix,
-        'name': _LATEST_MASTER}
-
-    try:
-        return storage_client.ReadObject(_GS_BUCKET, file_to_check)
-    except apiclient.errors.HttpError as e:
-        raise NoBuildError(
-            'Cannot find latest build for board %s, suffix %s: %s' %
-            (board, suffix, str(e)))
-
-
-def get_latest_launch_control_build(android_client, branch, target):
-    """Get the latest launch control build from Android Build API.
-
-    Args:
-        android_client: a rest_client.AndroidBuildRestClient object.
-        branch: the launch control branch.
-        target: the launch control target.
-
-    Returns:
-        a string latest launch control build id.
-
-    Raises:
-        NoBuildError if no latest launch control build is found.
-    """
-    try:
-        latest_build_id = android_client.get_latest_build_id(branch, target)
-        if latest_build_id is None:
-            raise NoBuildError('No latest builds is found.')
-
-        return latest_build_id
-    except apiclient.errors.HttpError as e:
-        raise NoBuildError('HttpError happened in getting the latest launch '
-                           'control build for '
-                           '%s,%s: %s' % (branch, target, str(e)))
-
-def parse_launch_control_target(target):
-    """Parse the build target and type from a Launch Control target.
-
-    The Launch Control target has the format of build_target-build_type, e.g.,
-    shamu-eng or dragonboard-userdebug. This method extracts the build target
-    and type from the target name.
-
-    Args:
-        target: Name of a Launch Control target, e.g., shamu-userdebug.
-
-    Returns:
-        a LaunchControlBuildTargetInfo object whose value is like
-            (target='shamu',
-             type='userdebug')
-
-    Raises:
-        Raise ValueError if target is not valid.
-    """
-    match = re.match(_LAUNCH_CONTROL_TARGET_PATTERN, target)
-    if not match:
-        raise ValueError('target format is not valid')
-
-    return LaunchControlBuildTargetInfo(match.group('build_target'),
-                                        match.group('build_type'))
-
-
-def parse_cros_build_config(board, build_config):
-    """Parse build_type from a given builder for a given board.
-
-    Args:
-        board: the prefix of a ChromeOS build_config, representing board.
-        build_config: a ChromeOS build_config name, like 'kevin-release'.
-
-    Returns:
-        a CrOSBuildConfigInfo object whose value is like
-            (board='kevin',
-             type='release')
-
-    Raises:
-        Raise ValueError if target is not valid.
-    """
-    if build_config[0:len(board)] != board:
-        raise ValueError('build_config cannot be parsed: %s' % build_config)
-
-    match = re.match(_CROS_BUILD_CONFIG_PATTERN, build_config[len(board):])
-    if not match:
-        raise ValueError('build_config %s is not matched %s' % (
-            build_config, _CROS_BUILD_CONFIG_PATTERN))
-
-    return CrOSBuildConfigInfo(board, match.groups()[0])
-
-
-def get_board_by_android_target(target):
-    """Map a android target to a android board.
-
-    # Mapping between an android board name and a build target. This is for
-    # special case handling for certain Android board that the board name and
-    # build target name does not match.
-    # This comes from server/site_utils.py in autotest module.
-
-    Args:
-        board: an android board.
-
-    Returns:
-        a string android board mapped by ANDROID_TARGET_TO_BOARD_MAP.
-    """
-    return _ANDROID_TARGET_TO_BOARD_MAP.get(target, target)
-
-
 # The default build type for fetching latest build.
 _DEFAULT_BUILD_SUFFIX = '-paladin'
 
@@ -235,3 +70,282 @@
 
 # The pattern for CrOS build config
 _CROS_BUILD_CONFIG_PATTERN = r'-([^-]+)(?:-group)?'
+
+
+class NoBuildError(Exception):
+  """Raised when failing to get the required build from Google Storage."""
+
+
+class BuildType(object):
+  """Representing the type of test source build.
+
+  This is used to identify the test source build for testing.
+  """
+  FIRMWARE_RW = 'firmware_rw'
+  FIRMWARE_RO = 'firmware_ro'
+  CROS = 'cros'
+
+
+class BuildVersionKey(object):
+  """Keys referring to the builds to install in run_suites."""
+
+  CROS_VERSION = 'cros_version'
+  ANDROID_BUILD_VERSION = 'android_version'
+  TESTBED_BUILD_VERSION = 'testbed_version'
+  FW_RW_VERSION = 'fwrw_version'
+  FW_RO_VERSION = 'fwro_version'
+
+
+class AndroidBuild(collections.namedtuple(
+    '_AndroidBuildBase', ['branch', 'target', 'build_id']), object):
+  """Class for constructing android build string."""
+
+  def __str__(self):
+    return _ANDROID_BUILD_PATTERN % {'branch': self.branch,
+                                     'target': self.target,
+                                     'build_id': self.build_id}
+
+
+class CrOSBuild(collections.namedtuple(
+    '_CrOSBuildBase',
+    ['board', 'build_type', 'milestone', 'manifest']), object):
+  """Class for constructing ChromeOS build string."""
+
+  def __str__(self):
+    return _CROS_BUILD_PATTERN % {'board': self.board,
+                                  'build_type': self.build_type,
+                                  'milestone': self.milestone,
+                                  'manifest': self.manifest}
+
+
+def get_latest_cros_build_from_gs(storage_client, board=None, suffix=None):
+  """Get latest build for given board from Google Storage.
+
+  Args:
+    storage_client: a rest_client.StorageRestClient object.
+    board: the board to fetch latest build. Default is 'master'.
+    suffix: suffix represents build channel, like '-release'.
+      Default is '-paladin'.
+
+  Returns:
+    a ChromeOS version string, e.g. '59.0.000.0'.
+
+  Raises:
+    HttpError if error happens in interacting with Google Storage.
+  """
+  board = board if board is not None else _DEFAULT_MASTER
+  suffix = suffix if suffix is not None else _DEFAULT_BUILD_SUFFIX
+  file_to_check = _GS_LATEST_MASTER_PATTERN % {
+      'board': board,
+      'suffix': suffix,
+      'name': _LATEST_MASTER}
+
+  try:
+    return storage_client.read_object(_GS_BUCKET, file_to_check)
+  except apiclient.errors.HttpError as e:
+    raise NoBuildError(
+        'Cannot find latest build for board %s, suffix %s: %s' %
+        (board, suffix, str(e)))
+
+
+def get_cros_builds_since_date_from_db(db_client, since_date):
+  """Get branch builds for ChromeOS boards.
+
+  Args:
+    db_client: a cloud_sql_client.CIDBClient object, to read cidb
+      build infos.
+    since_date: a datetime.datetime object in UTC to indicate since when CrOS
+      builds will be fetched.
+
+  Returns:
+    a branch build dict:
+    key: a tuple of (board, build_type, milestone), like:
+      ('wolf', 'release', '58')
+    value: the latest manifest for the given tuple, like:
+      '9242.0.0'.
+  """
+  # CIDB use UTC timezone
+  all_branch_builds = db_client.get_passed_builds_since_date(since_date)
+
+  branch_build_dict = {}
+  for build in all_branch_builds:
+    try:
+      build_config_info = parse_cros_build_config(build.board,
+                                                  build.build_config)
+    except ValueError as e:
+      logging.warning('Failed to parse build config: %s: %s',
+                      build.build_config, e)
+      continue
+
+    if build.board != build_config_info.board:
+      logging.warning('Non-matched build_config and board: %s, %s',
+                      build.board, build.board)
+      continue
+
+    build_key = (build.board, build_config_info.type, build.milestone)
+    cur_manifest = branch_build_dict.get(build_key)
+    if cur_manifest is not None:
+      branch_build_dict[build_key] = max(
+          [cur_manifest, build.platform], key=version.LooseVersion)
+    else:
+      branch_build_dict[build_key] = build.platform
+
+  return branch_build_dict
+
+
+def get_latest_launch_control_build(android_client, branch, target):
+  """Get the latest launch control build from Android Build API.
+
+  Args:
+    android_client: a rest_client.AndroidBuildRestClient object.
+    branch: the launch control branch.
+    target: the launch control target.
+
+  Returns:
+    a string latest launch control build id.
+
+  Raises:
+    NoBuildError if no latest launch control build is found.
+  """
+  try:
+    latest_build_id = android_client.get_latest_build_id(branch, target)
+    if latest_build_id is None:
+      raise NoBuildError('No latest builds is found.')
+
+    return latest_build_id
+  except apiclient.errors.HttpError as e:
+    raise NoBuildError('HttpError happened in getting the latest launch '
+                       'control build for '
+                       '%s,%s: %s' % (branch, target, str(e)))
+
+
+def get_launch_control_builds_by_branch_targets(
+    android_client, android_board_list, launch_control_branch_targets):
+  """Get latest launch_control_builds for android boards.
+
+  For every tasks in this event, if it has settings of launch control
+  branch & target, get the latest launch control build for it.
+
+  Args:
+    android_client: a rest_client.AndroidBuildRestClient object to
+      interact with android build API.
+    android_board_list: a list of Android boards.
+    launch_control_branch_targets: a dict of branch:targets, see property
+      launch_control_branch_targets in base_event.py.
+
+  Returns:
+    a launch control build dict:
+      key: an android board, like 'shamu'.
+      value: a list involves the latest builds for each pair
+        (branch, target) of this board, like:
+            [u'git_nyc-mr2-release/shamu-userdebug/3844975',
+             u'git_nyc-mr1-release/shamu-userdebug/3783920']
+  """
+  launch_control_dict = {}
+  board_to_builds_dict = {}
+  for branch, targets in launch_control_branch_targets.iteritems():
+    for t in targets:
+      try:
+        board = parse_launch_control_target(t).target
+      except ValueError:
+        logging.warning(
+            'Failed to parse launch control target: %s', t)
+        continue
+
+      if board not in android_board_list:
+        continue
+
+      # Use dict here to reduce the times to call AndroidBuild API
+      if launch_control_dict.get((branch, t)) is None:
+        try:
+          build_id = get_latest_launch_control_build(
+              android_client, branch, t)
+        except NoBuildError as e:
+          logging.warning(e)
+          continue
+
+        build = str(AndroidBuild(branch, t, build_id))
+        launch_control_dict[(branch, t)] = build
+        board_to_builds_dict.setdefault(board, []).append(
+            build)
+
+  for board, in board_to_builds_dict.iteritems():
+    mapped_board = get_board_by_android_target(board)
+    if mapped_board != board:
+      logging.debug('Map board %s to %s', board, mapped_board)
+      if board_to_builds_dict.get(mapped_board) is None:
+        del board_to_builds_dict[board]
+      else:
+        board_to_builds_dict[board] = board_to_builds_dict[
+            mapped_board]
+
+  return board_to_builds_dict
+
+
+def parse_launch_control_target(target):
+  """Parse the build target and type from a Launch Control target.
+
+  The Launch Control target has the format of build_target-build_type, e.g.,
+  shamu-eng or dragonboard-userdebug. This method extracts the build target
+  and type from the target name.
+
+  Args:
+    target: Name of a Launch Control target, e.g., shamu-userdebug.
+
+  Returns:
+    a LaunchControlBuildTargetInfo object whose value is like
+        (target='shamu',
+         type='userdebug')
+
+  Raises:
+    ValueError: if target is not valid.
+  """
+  match = re.match(_LAUNCH_CONTROL_TARGET_PATTERN, target)
+  if not match:
+    raise ValueError('target format is not valid')
+
+  return LaunchControlBuildTargetInfo(match.group('build_target'),
+                                      match.group('build_type'))
+
+
+def parse_cros_build_config(board, build_config):
+  """Parse build_type from a given builder for a given board.
+
+  Args:
+    board: the prefix of a ChromeOS build_config, representing board.
+    build_config: a ChromeOS build_config name, like 'kevin-release'.
+
+  Returns:
+    a CrOSBuildConfigInfo object whose value is like
+        (board='kevin',
+         type='release')
+
+  Raises:
+    ValueError: if build_config is in invalid form.
+  """
+  if build_config[0:len(board)] != board:
+    raise ValueError('build_config cannot be parsed: %s' % build_config)
+
+  match = re.match(_CROS_BUILD_CONFIG_PATTERN, build_config[len(board):])
+  if not match:
+    raise ValueError('build_config %s is not matched %s' % (
+        build_config, _CROS_BUILD_CONFIG_PATTERN))
+
+  return CrOSBuildConfigInfo(board, match.groups()[0])
+
+
+def get_board_by_android_target(target):
+  """Map a android target to a android board.
+
+  # Mapping between an android board name and a build target. This is for
+  # special case handling for certain Android board that the board name and
+  # build target name does not match.
+  # This comes from server/site_utils.py in autotest module.
+
+  Args:
+    target: an android target.
+
+  Returns:
+    a string android board mapped by ANDROID_TARGET_TO_BOARD_MAP.
+  """
+  return _ANDROID_TARGET_TO_BOARD_MAP.get(target, target)
diff --git a/cloud_sql_client.py b/cloud_sql_client.py
index 37312b0..dce8897 100644
--- a/cloud_sql_client.py
+++ b/cloud_sql_client.py
@@ -3,6 +3,7 @@
 # found in the LICENSE file.
 
 """Module for interacting with MySQL database, like cidb."""
+# pylint: disable=g-bad-import-order
 
 import MySQLdb
 import collections
@@ -25,133 +26,132 @@
 
 
 class DBConnection(object):
-    """The class for reading ChromeOS lab's db."""
+  """The class for reading ChromeOS lab's db."""
 
-    def __init__(self, db_tag, db_name):
-        """Initialize a MySQLdb reader.
+  def __init__(self, db_tag, db_name):
+    """Initialize a MySQLdb reader.
 
-        Args:
-            db_tag: a string section name in db config file like
-                    credentials/cloud_sql_credentials.txt, to get
-                    db connection info.
-            db_name: the database to use.
-        """
-        self._db_tag = db_tag
-        self._read_credentials()
-        self._db = self.connect_to_cloudsql()
-        self._cursor = self._db.cursor()
+    Args:
+      db_tag: a string section name in db config file, e.g.
+        credentials/cloud_sql_credentials.txt, to get db connection info.
+      db_name: the database to use.
+    """
+    self._db_tag = db_tag
+    self._read_credentials()
+    self._db = self.connect_to_cloudsql()
+    self._cursor = self._db.cursor()
 
-        self._db_name = db_name
-        if self._db_name:
-            self._select_db(self._db_name)
+    self._db_name = db_name
+    if self._db_name:
+      self._select_db(self._db_name)
 
-    @property
-    def cursor(self):
-        return self._cursor
+  @property
+  def cursor(self):
+    return self._cursor
 
-    @property
-    def db(self):
-        return self._db
+  @property
+  def db(self):
+    return self._db
 
-    def connect_to_cloudsql(self):
-        """Connect to cloudsql by socket or tcp."""
-        cur_env = constants.environment()
-        if (cur_env == constants.RunningEnv.ENV_DEVELOPMENT_SERVER or
-            cur_env == constants.RunningEnv.ENV_PROD):
-            # Running on local development server or app engine
-            # Connect using the unix socket located at
-            # /cloudsql/cloudsql-connection-name.
-            cloudsql_unix_socket = os.path.join(
-                '/cloudsql', self._connection_name)
+  def connect_to_cloudsql(self):
+    """Connect to cloudsql by socket or tcp."""
+    cur_env = constants.environment()
+    if (cur_env == constants.RunningEnv.ENV_DEVELOPMENT_SERVER or
+        cur_env == constants.RunningEnv.ENV_PROD):
+      # Running on local development server or app engine
+      # Connect using the unix socket located at
+      # /cloudsql/cloudsql-connection-name.
+      cloudsql_unix_socket = os.path.join(
+          '/cloudsql', self._connection_name)
 
-            db = MySQLdb.connect(
-                unix_socket=cloudsql_unix_socket,
-                user=self._user,
-                passwd=self._pw)
+      db = MySQLdb.connect(
+          unix_socket=cloudsql_unix_socket,
+          user=self._user,
+          passwd=self._pw)
 
-        # If the unix socket is unavailable, then try to connect using TCP.
-        # This will work if you're running a local MySQL server or using the
-        # Cloud SQL proxy, for example:
-        #
-        #   $ cloud_sql_proxy -instances=your-connection-name=tcp:3306
-        #
-        else:
-            db = MySQLdb.connect(
-                host='127.0.0.1', user=self._user, passwd=self._pw)
+    # If the unix socket is unavailable, then try to connect using TCP.
+    # This will work if you're running a local MySQL server or using the
+    # Cloud SQL proxy, for example:
+    #
+    #   $ cloud_sql_proxy -instances=your-connection-name=tcp:3306
+    #
+    else:
+      db = MySQLdb.connect(
+          host='127.0.0.1', user=self._user, passwd=self._pw)
 
-        return db
+    return db
 
-    def _read_credentials(self):
-        """Read credentials from credentials_path."""
-        db_config = config_reader.DBConfig(
-            config_reader.ConfigReader(file_getter.SQL_CREDENTIAL_FILE))
-        configs = db_config.get_credentials(self._db_tag)
-        self._connection_name = configs.connection_name
-        self._user = configs.user
-        self._pw = configs.password
+  def _read_credentials(self):
+    """Read credentials from credentials_path."""
+    db_config = config_reader.DBConfig(
+        config_reader.ConfigReader(file_getter.SQL_CREDENTIAL_FILE))
+    configs = db_config.get_credentials(self._db_tag)
+    self._connection_name = configs.connection_name
+    self._user = configs.user
+    self._pw = configs.password
 
-    def _select_db(self, db_name):
-        self._cursor.execute('USE %s' % db_name)
+  def _select_db(self, db_name):
+    self._cursor.execute('USE %s' % db_name)
 
 
 class CIDBClient(object):
-    """class for interacting with CIDB."""
+  """class for interacting with CIDB."""
 
-    def __init__(self, db_tag, db_name):
-        """Initialize a cidb reader."""
-        self._connection = DBConnection(db_tag, db_name)
+  def __init__(self, db_tag, db_name):
+    """Initialize a cidb reader."""
+    self._connection = DBConnection(db_tag, db_name)
 
-    def get_passed_builds_since_date(self, since_date):
-        """Get passed builds since a given date.
+  def get_passed_builds_since_date(self, since_date):
+    """Get passed builds since a given date.
 
-        Args:
-            since_date: a date string, like '2017-02-01 23:00:00'.
+    Args:
+      since_date: a date string, like '2017-02-01 23:00:00'.
 
-        Returns:
-            A list of BuildInfo objects.
+    Returns:
+      A list of BuildInfo objects.
 
-        Raises:
-            MySQLdb.OperationalError if connection operations are not valid.
-        """
+    Raises:
+      MySQLdb.OperationalError if connection operations are not valid.
+    """
 
-        sql = """\
-            select bo.board, bu.milestone_version,
-            bu.platform_version, bu.build_config
-            from buildTable as bu, boardPerBuildTable as bo
-            where bu.status='pass' and bu.suite_scheduling=1 and
-            bu.finish_time > %s and bu.id=bo.build_id
-        """
-        logging.info('Get passed builds since %r', since_date)
-        self._connection.cursor.execute(sql,
-                             [since_date.strftime(time_converter.TIME_FORMAT)])
-        builds = self._connection.cursor.fetchall()
-        return [BuildInfo(board, milestone, platform, build_config)
-                for board, milestone, platform, build_config in builds]
+    sql = """\
+        select bo.board, bu.milestone_version,
+        bu.platform_version, bu.build_config
+        from buildTable as bu, boardPerBuildTable as bo
+        where bu.status='pass' and bu.suite_scheduling=1 and
+        bu.finish_time > %s and bu.id=bo.build_id
+    """
+    logging.info('Get passed builds since %r', since_date)
+    self._connection.cursor.execute(
+        sql, [since_date.strftime(time_converter.TIME_FORMAT)])
+    builds = self._connection.cursor.fetchall()
+    return [BuildInfo(board, milestone, platform, build_config)
+            for board, milestone, platform, build_config in builds]
 
-    def get_latest_passed_builds(self, build_config):
-        """Get latest passed builds by build_config.
+  def get_latest_passed_builds(self, build_config):
+    """Get latest passed builds by build_config.
 
-        Args:
-            build_config: format like '{board}-{build_type}', eg. link-release
+    Args:
+      build_config: format like '{board}-{build_type}', eg. link-release
 
-        Returns:
-            A BuildInfo object, represents the latest passed build.
+    Returns:
+      A BuildInfo object, represents the latest passed build.
 
-        Raises:
-            MySQLdb.OperationalError if connection operations are not valid.
-        """
-        sql = """\
-            select bo.board, bu.milestone_version, bu.platform_version
-            from buildTable as bu, boardPerBuildTable as bo
-            where bu.build_config=%s and bu.status='pass' and
-            bu.id=bo.build_id order by finish_time desc limit 1
-        """
-        self._connection.cursor.execute(sql, [build_config])
-        version_info = self._connection.cursor.fetchall()
-        if not version_info:
-            return None
-        else:
-            return BuildInfo(board=version_info[0][0],
-                             milestone=version_info[0][1],
-                             platform=version_info[0][2],
-                             build_config=build_config)
+    Raises:
+      MySQLdb.OperationalError if connection operations are not valid.
+    """
+    sql = """\
+        select bo.board, bu.milestone_version, bu.platform_version
+        from buildTable as bu, boardPerBuildTable as bo
+        where bu.build_config=%s and bu.status='pass' and
+        bu.id=bo.build_id order by finish_time desc limit 1
+    """
+    self._connection.cursor.execute(sql, [build_config])
+    version_info = self._connection.cursor.fetchall()
+    if not version_info:
+      return None
+    else:
+      return BuildInfo(board=version_info[0][0],
+                       milestone=version_info[0][1],
+                       platform=version_info[0][2],
+                       build_config=build_config)
diff --git a/constants.py b/constants.py
index 281cfdf..bc6cfaa 100644
--- a/constants.py
+++ b/constants.py
@@ -4,98 +4,98 @@
 
 """Module containing the constants to be reused throughout suite_scheduler."""
 
-from google.appengine.api import app_identity
 from collections import namedtuple
 import logging
 import os
 
+from google.appengine.api import app_identity
+
 # Namedtuple for storing rest client info.
 RestClientInfo = namedtuple(
     'RestClientInfo', 'scopes, service_name, service_version')
 
-
-class RestClient(object):
-    """Constants related to rest clients to google service."""
-
-    # client info for connecting to android build API.
-    ANDROID_BUILD_CLIENT = RestClientInfo._make(
-        ['https://www.googleapis.com/auth/androidbuild.internal',
-         'androidbuildinternal',
-         'v2beta1'])
-
-    # client info for connecting to google storage API.
-    STORAGE_CLIENT = RestClientInfo._make(
-        ['https://www.googleapis.com/auth/devstorage.full_control',
-         'storage',
-         'v1'])
-
-    # client info for connecting to google calendar API.
-    CALENDAR_CLIENT = RestClientInfo._make(
-        ['https://www.googleapis.com/auth/calendar',
-         'calendar',
-         'v3'])
-
-    SWARMING_CLIENT = RestClientInfo._make(
-        ['https://www.googleapis.com/auth/userinfo.email',
-         'swarming',
-         'v1'])
-
-
-class RunningEnv(object):
-    """Constants related to app engine running environment."""
-
-    # Running this GAE project locally with python.
-    ENV_STANDALONE = 0
-
-    # Running this GAE project with local development server.
-    ENV_DEVELOPMENT_SERVER = 1
-
-    # Running this GAE project in app-engine production.
-    ENV_PROD = 2
-
-
-class Priorities(object):
-    """Constants related to task priority."""
-
-    # weekly task's priority
-    WEEKLY = 10
-
-    # daily task's priority
-    DAILY = 20
-
-    # postbuild task's priority
-    POSTBUILD = 30
-
-    # the default task priority
-    DEFAULT = 40
-
-
-def environment():
-    """Return proper environment settings."""
-    if os.getenv(_RUNNING_ENV, '').startswith(_ENV_DEVELOPMENT_STR):
-        return RunningEnv.ENV_DEVELOPMENT_SERVER
-    elif os.getenv(_RUNNING_ENV, '').startswith(_ENV_APP_ENGINE_STR):
-        return RunningEnv.ENV_PROD
-    else:
-        return RunningEnv.ENV_STANDALONE
-
-
-def application_id():
-    """Get current running application id.
-
-    Returns:
-        If it's a Google internal GAE whose id format is 'google.com:<name>',
-        return <name>; Otherwise, return the full id.
-    """
-    app_id = app_identity.get_application_id()
-    logging.info('app_id: %s', app_id)
-    if app_id is not None and len(app_id.split(':')) > 1:
-        return app_id.split(':')[1]
-    else:
-        return app_id
-
-
 # Constants for detecting the running environment.
 _RUNNING_ENV = 'SERVER_SOFTWARE'
 _ENV_DEVELOPMENT_STR = 'Development'
 _ENV_APP_ENGINE_STR = 'Google App Engine/'
+
+
+class RestClient(object):
+  """Constants related to rest clients to google service."""
+
+  # client info for connecting to android build API.
+  ANDROID_BUILD_CLIENT = RestClientInfo._make(
+      ['https://www.googleapis.com/auth/androidbuild.internal',
+       'androidbuildinternal',
+       'v2beta1'])
+
+  # client info for connecting to google storage API.
+  STORAGE_CLIENT = RestClientInfo._make(
+      ['https://www.googleapis.com/auth/devstorage.full_control',
+       'storage',
+       'v1'])
+
+  # client info for connecting to google calendar API.
+  CALENDAR_CLIENT = RestClientInfo._make(
+      ['https://www.googleapis.com/auth/calendar',
+       'calendar',
+       'v3'])
+
+  SWARMING_CLIENT = RestClientInfo._make(
+      ['https://www.googleapis.com/auth/userinfo.email',
+       'swarming',
+       'v1'])
+
+
+class RunningEnv(object):
+  """Constants related to app engine running environment."""
+
+  # Running this GAE project locally with python.
+  ENV_STANDALONE = 0
+
+  # Running this GAE project with local development server.
+  ENV_DEVELOPMENT_SERVER = 1
+
+  # Running this GAE project in app-engine production.
+  ENV_PROD = 2
+
+
+class Priorities(object):
+  """Constants related to task priority."""
+
+  # weekly task's priority
+  WEEKLY = 10
+
+  # daily task's priority
+  DAILY = 20
+
+  # postbuild task's priority
+  POSTBUILD = 30
+
+  # the default task priority
+  DEFAULT = 40
+
+
+def environment():
+  """Return proper environment settings."""
+  if os.getenv(_RUNNING_ENV, '').startswith(_ENV_DEVELOPMENT_STR):
+    return RunningEnv.ENV_DEVELOPMENT_SERVER
+  elif os.getenv(_RUNNING_ENV, '').startswith(_ENV_APP_ENGINE_STR):
+    return RunningEnv.ENV_PROD
+  else:
+    return RunningEnv.ENV_STANDALONE
+
+
+def application_id():
+  """Get current running application id.
+
+  Returns:
+      If it's a Google internal GAE whose id format is 'google.com:<name>',
+      return <name>; Otherwise, return the full id.
+  """
+  app_id = app_identity.get_application_id()
+  logging.info('app_id: %s', app_id)
+  if app_id is not None and len(app_id.split(':')) > 1:
+    return app_id.split(':')[1]
+  else:
+    return app_id
diff --git a/datastore_client.py b/datastore_client.py
index 62ab8cc..5438d47 100644
--- a/datastore_client.py
+++ b/datastore_client.py
@@ -3,6 +3,7 @@
 # found in the LICENSE file.
 
 """Module for interacting with datastore."""
+# pylint: disable=g-tzinfo-replace
 
 import pytz
 
@@ -10,83 +11,83 @@
 
 
 class LastExecutionRecord(ndb.Model):
-    """Models a last_execute_record entry with keyword & exec_time."""
+  """Models a last_execute_record entry with keyword & exec_time."""
 
-    # The keyword represents different types of events, e.g.
-    # Key('LastExecutionRecord', 'nightly')
-    event_type = ndb.StringProperty()
+  # The keyword represents different types of events, e.g.
+  # Key('LastExecutionRecord', 'nightly')
+  event_type = ndb.StringProperty()
 
-    # The last execute time for a given keyword.
-    exec_time = ndb.DateTimeProperty()
+  # The last execute time for a given keyword.
+  exec_time = ndb.DateTimeProperty()
 
 
 class LastExecutionRecordStore(object):
-    """Base class for reading google datastore."""
+  """Base class for reading google datastore."""
 
-    def set_last_execute_time(self, event_type, exec_time):
-        """Set the last execute time for the given keyword.
+  def set_last_execute_time(self, event_type, exec_time):
+    """Set the last execute time for the given keyword.
 
-        Args:
-            event_type: the keyword for saving last execute time.
-            exec_time: The UTC timestamp for last execute time.
+    Args:
+      event_type: the keyword for saving last execute time.
+      exec_time: The UTC timestamp for last execute time.
 
-        Returns:
-            The Key('LastExecutionRecord', event_type) to save the exec_time.
-        """
-        if exec_time.tzinfo is not None:
-            exec_time = exec_time.replace(tzinfo=None)
+    Returns:
+      The Key('LastExecutionRecord', event_type) to save the exec_time.
+    """
+    if exec_time.tzinfo is not None:
+      exec_time = exec_time.replace(tzinfo=None)
 
-        cur_record_key = ndb.Key(LastExecutionRecord, event_type)
-        cur_record = cur_record_key.get()
-        if cur_record is not None:
-            cur_record.exec_time = exec_time
-        else:
-            cur_record = LastExecutionRecord(event_type=event_type,
-                                             exec_time=exec_time)
-            cur_record.key = cur_record_key
+    cur_record_key = ndb.Key(LastExecutionRecord, event_type)
+    cur_record = cur_record_key.get()
+    if cur_record is not None:
+      cur_record.exec_time = exec_time
+    else:
+      cur_record = LastExecutionRecord(event_type=event_type,
+                                       exec_time=exec_time)
+      cur_record.key = cur_record_key
 
-        return cur_record.put()
+    return cur_record.put()
 
-    def get_last_execute_time(self, event_type):
-        """Get the last execute time for the given event_type.
+  def get_last_execute_time(self, event_type):
+    """Get the last execute time for the given event_type.
 
-        Args:
-            event_type: the keyword to get its last execute time.
+    Args:
+      event_type: the keyword to get its last execute time.
 
-        Returns:
-            last_exec_time: an offset-aware datetime object with timezone
-                pytz.utc.
-        """
-        cur_record = ndb.Key(LastExecutionRecord, event_type).get()
-        if cur_record is not None:
-            return cur_record.exec_time.replace(tzinfo=pytz.utc)
-        else:
-            return None
+    Returns:
+      last_exec_time: an offset-aware datetime object with timezone
+        pytz.utc.
+    """
+    cur_record = ndb.Key(LastExecutionRecord, event_type).get()
+    if cur_record is not None:
+      return cur_record.exec_time.replace(tzinfo=pytz.utc)
+    else:
+      return None
 
-    def del_last_execute_time(self, event_type):
-        """Delete the last execute time for the given event_type.
+  def del_last_execute_time(self, event_type):
+    """Delete the last execute time for the given event_type.
 
-        Args:
-            event_type: the keyword to delete its last execute time.
-        """
-        cur_record_key = ndb.Key(LastExecutionRecord, event_type)
-        if cur_record_key.get() is not None:
-            cur_record_key.delete()
+    Args:
+      event_type: the keyword to delete its last execute time.
+    """
+    cur_record_key = ndb.Key(LastExecutionRecord, event_type)
+    if cur_record_key.get() is not None:
+      cur_record_key.delete()
 
-    def get_all(self):
-        """Get the last execute time for all event_types in datastore.
+  def get_all(self):
+    """Get the last execute time for all event_types in datastore.
 
-        Returns:
-            A list of LastExecutionRecord objects, whose exec_time is a
-            offset-aware datetime object with timezone pytz.utc.
-        """
-        qry = LastExecutionRecord.query()
-        for q in qry.iter():
-            q.exec_time = q.exec_time.replace(tzinfo=pytz.utc)
+    Returns:
+      A list of LastExecutionRecord objects, whose exec_time is a
+      offset-aware datetime object with timezone pytz.utc.
+    """
+    qry = LastExecutionRecord.query()
+    for q in qry.iter():
+      q.exec_time = q.exec_time.replace(tzinfo=pytz.utc)
 
-        return [q for q in qry.iter()]
+    return [q for q in qry.iter()]
 
-    def delete_all(self):
-        """Delete the last execute time for all event_types in datastore."""
-        for q in LastExecutionRecord.query().iter():
-            q.key.delete()
+  def delete_all(self):
+    """Delete the last execute time for all event_types in datastore."""
+    for q in LastExecutionRecord.query().iter():
+      q.key.delete()
diff --git a/datastore_client_unittest.py b/datastore_client_unittest.py
index 815af4b..40a7f83 100644
--- a/datastore_client_unittest.py
+++ b/datastore_client_unittest.py
@@ -3,74 +3,73 @@
 # found in the LICENSE file.
 
 """Module for datastore unittests."""
+# pylint: disable=g-tzinfo-replace,g-bad-import-order
 
 import datetime
+import pytz
 import unittest
 
 import datastore_client
 
-from google.appengine.api import memcache
 from google.appengine.ext import ndb
 from google.appengine.ext import testbed
-import pytz
 
 
 class DatastoreTestCase(unittest.TestCase):
 
-    def setUp(self):
-        self.testbed = testbed.Testbed()
-        self.testbed.activate()
-        self.addCleanup(self.testbed.deactivate)
-        self.testbed.init_datastore_v3_stub()
-        self.testbed.init_memcache_stub()
-        ndb.get_context().clear_cache()
+  def setUp(self):
+    self.testbed = testbed.Testbed()
+    self.testbed.activate()
+    self.addCleanup(self.testbed.deactivate)
+    self.testbed.init_datastore_v3_stub()
+    self.testbed.init_memcache_stub()
+    ndb.get_context().clear_cache()
 
-    def testSetLastExec(self):
-        last_exec_store = datastore_client.LastExecutionRecordStore()
-        exec_time = datetime.datetime(2017, 8, 1, 0)
-        last_exec_store.set_last_execute_time('nightly', exec_time)
-        self.assertEqual(last_exec_store.get_last_execute_time('nightly'),
-                         exec_time.replace(tzinfo=pytz.utc))
+  def testSetLastExec(self):
+    last_exec_store = datastore_client.LastExecutionRecordStore()
+    exec_time = datetime.datetime(2017, 8, 1, 0)
+    last_exec_store.set_last_execute_time('nightly', exec_time)
+    self.assertEqual(last_exec_store.get_last_execute_time('nightly'),
+                     exec_time.replace(tzinfo=pytz.utc))
 
-    def testDeleteLastExec(self):
-        last_exec_store = datastore_client.LastExecutionRecordStore()
-        exec_time = datetime.datetime(2017, 8, 1, 0)
-        last_exec_store.set_last_execute_time('nightly', exec_time)
-        last_exec_store.del_last_execute_time('nightly')
-        self.assertEqual(last_exec_store.get_last_execute_time('nightly'),
-                         None)
+  def testDeleteLastExec(self):
+    last_exec_store = datastore_client.LastExecutionRecordStore()
+    exec_time = datetime.datetime(2017, 8, 1, 0)
+    last_exec_store.set_last_execute_time('nightly', exec_time)
+    last_exec_store.del_last_execute_time('nightly')
+    self.assertEqual(last_exec_store.get_last_execute_time('nightly'),
+                     None)
 
-    def testDeleteLastExecWithNonExistentKey(self):
-        last_exec_store = datastore_client.LastExecutionRecordStore()
-        exec_time = datetime.datetime(2017, 8, 1, 0)
-        last_exec_store.del_last_execute_time('nightly')
+  def testDeleteLastExecWithNonExistentKey(self):
+    last_exec_store = datastore_client.LastExecutionRecordStore()
+    last_exec_store.del_last_execute_time('nightly')
 
-    def testGetAllLastExec(self):
-        last_exec_store = datastore_client.LastExecutionRecordStore()
-        exec_time = datetime.datetime(2017, 8, 1, 0)
-        event_types = ['nightly', 'weekly']
-        exec_time_records = [datastore_client.LastExecutionRecord(
-            key=ndb.Key(datastore_client.LastExecutionRecord, e),
-            event_type=e,
-            exec_time=exec_time.replace(tzinfo=pytz.utc)) for e in event_types]
+  def testGetAllLastExec(self):
+    last_exec_store = datastore_client.LastExecutionRecordStore()
+    exec_time = datetime.datetime(2017, 8, 1, 0)
+    event_types = ['nightly', 'weekly']
+    exec_time_records = [datastore_client.LastExecutionRecord(
+        key=ndb.Key(datastore_client.LastExecutionRecord, e),
+        event_type=e,
+        exec_time=exec_time.replace(tzinfo=pytz.utc)) for e in event_types]
 
-        for e in event_types:
-            last_exec_store.set_last_execute_time(e, exec_time)
+    for e in event_types:
+      last_exec_store.set_last_execute_time(e, exec_time)
 
-        last_exec_times = last_exec_store.get_all()
-        self.assertEqual(last_exec_times, exec_time_records)
+    last_exec_times = last_exec_store.get_all()
+    self.assertEqual(last_exec_times, exec_time_records)
 
-    def testDeleteAllLastExec(self):
-        last_exec_store = datastore_client.LastExecutionRecordStore()
-        exec_time = datetime.datetime(2017, 8, 1, 0)
-        event_types = ['nightly', 'weekly']
+  def testDeleteAllLastExec(self):
+    last_exec_store = datastore_client.LastExecutionRecordStore()
+    exec_time = datetime.datetime(2017, 8, 1, 0)
+    event_types = ['nightly', 'weekly']
 
-        for e in event_types:
-            last_exec_store.set_last_execute_time(e, exec_time)
+    for e in event_types:
+      last_exec_store.set_last_execute_time(e, exec_time)
 
-        last_exec_store.delete_all()
-        for e in event_types:
-            self.assertEqual(last_exec_store.get_last_execute_time(e), None)
+    last_exec_store.delete_all()
+    for e in event_types:
+      self.assertEqual(last_exec_store.get_last_execute_time(e), None)
 
 if __name__ == '__main__':
-    unittest.main()
+  unittest.main()
diff --git a/file_getter.py b/file_getter.py
index 65b254d..199016e 100644
--- a/file_getter.py
+++ b/file_getter.py
@@ -6,8 +6,6 @@
 
 import os
 
-import constants
-
 # The path to save credentials.
 CREDENTIALS_PATH = os.path.join(os.path.dirname(__file__), 'credentials')
 
diff --git a/rest_client.py b/rest_client.py
index 2092807..345e85c 100644
--- a/rest_client.py
+++ b/rest_client.py
@@ -3,11 +3,11 @@
 # found in the LICENSE file.
 
 """Module for interacting with google APIs."""
+# pylint: disable=g-bad-import-order
+
+import httplib2
 
 import apiclient
-import httplib2
-import os
-
 import constants
 import file_getter
 
@@ -16,174 +16,176 @@
 
 
 class RestClientError(Exception):
-    """Raised when there is a general error."""
+  """Raised when there is a general error."""
 
 
 class NoServiceRestClientError(RestClientError):
-    """Raised when there is no ready service for a google API."""
+  """Raised when there is no ready service for a google API."""
 
 
 class BaseRestClient(object):
-    """Base class of REST client for google APIs."""
+  """Base class of REST client for google APIs."""
 
-    def __init__(self, scopes, service_name, service_version):
-        """Initialize a REST client to connect to a google API.
+  def __init__(self, scopes, service_name, service_version):
+    """Initialize a REST client to connect to a google API.
 
-        Args:
-            scopes: the scopes of the to-be-connected API.
-            service_name: the service name of the to-be-connected API.
-            service_version: the service version of the to-be-connected API.
-        """
-        self._running_env = constants.environment()
-        self._scopes = scopes
-        self._service_name = service_name
-        self._service_version = service_version
+    Args:
+      scopes: the scopes of the to-be-connected API.
+      service_name: the service name of the to-be-connected API.
+      service_version: the service version of the to-be-connected API.
+    """
+    self.running_env = constants.environment()
+    self.scopes = scopes
+    self.service_name = service_name
+    self.service_version = service_version
 
-    @property
-    def service(self):
-        if not self._service:
-            raise NoServiceRestClientError('No service created for calling API')
+  @property
+  def service(self):
+    if not self._service:
+      raise NoServiceRestClientError('No service created for calling API')
 
-        return self._service
+    return self._service
 
-    def create_service(self, discovery_url=None):
-        """Create the service for a google API."""
-        self._init_credentials()
-        # Explicitly specify timeout for http to avoid DeadlineExceededError.
-        # It's used for services like AndroidBuild API, which raise such error
-        # when being triggered too many calls in a short time frame.
-        # http://stackoverflow.com/questions/14698119/httpexception-deadline-exceeded-while-waiting-for-http-response-from-url-dead
-        http_auth = self._credentials.authorize(httplib2.Http(timeout=30))
-        if discovery_url is None:
-            self._service = apiclient.discovery.build(
-                self._service_name, self._service_version,
-                http=http_auth)
-        else:
-            self._service = apiclient.discovery.build(
-                self._service_name, self._service_version, http=http_auth,
-                discoveryServiceUrl=discovery_url)
+  def create_service(self, discovery_url=None):
+    """Create the service for a google API."""
+    self._init_credentials()
+    # Explicitly specify timeout for http to avoid DeadlineExceededError.
+    # It's used for services like AndroidBuild API, which raise such error
+    # when being triggered too many calls in a short time frame.
+    # http://stackoverflow.com/questions/14698119/httpexception-deadline-exceeded-while-waiting-for-http-response-from-url-dead
+    http_auth = self._credentials.authorize(httplib2.Http(timeout=30))
+    if discovery_url is None:
+      self._service = apiclient.discovery.build(
+          self.service_name, self.service_version,
+          http=http_auth)
+    else:
+      self._service = apiclient.discovery.build(
+          self.service_name, self.service_version, http=http_auth,
+          discoveryServiceUrl=discovery_url)
 
-    def _init_credentials(self):
-        """Initialize the credentials for a google API."""
-        if (self._running_env == constants.RunningEnv.ENV_STANDALONE or
-            self._running_env == constants.RunningEnv.ENV_DEVELOPMENT_SERVER):
-            # Running locally
-            service_credentials = service_account.ServiceAccountCredentials
-            self._credentials = service_credentials.from_json_keyfile_name(
-                file_getter.LOCAL_CLIENT_SECRETS_FILE, self._scopes)
-        else:
-            # Running in app-engine production
-            self._credentials = appengine.AppAssertionCredentials(self._scopes)
+  def _init_credentials(self):
+    """Initialize the credentials for a google API."""
+    if (self.running_env == constants.RunningEnv.ENV_STANDALONE or
+        self.running_env == constants.RunningEnv.ENV_DEVELOPMENT_SERVER):
+      # Running locally
+      service_credentials = service_account.ServiceAccountCredentials
+      self._credentials = service_credentials.from_json_keyfile_name(
+          file_getter.LOCAL_CLIENT_SECRETS_FILE, self.scopes)
+    else:
+      # Running in app-engine production
+      self._credentials = appengine.AppAssertionCredentials(self.scopes)
 
 
 class AndroidBuildRestClient(object):
-    """REST client for android build API."""
+  """REST client for android build API."""
 
-    def __init__(self, rest_client):
-        """Initialize a REST client for connecting to Android Build API."""
-        self._rest_client = rest_client
-        self._rest_client.create_service()
+  def __init__(self, rest_client):
+    """Initialize a REST client for connecting to Android Build API."""
+    self._rest_client = rest_client
+    self._rest_client.create_service()
 
-    def get_latest_build_id(self, branch, target):
-        """Get the latest build id for a given branch and target.
+  def get_latest_build_id(self, branch, target):
+    """Get the latest build id for a given branch and target.
 
-        Args:
-            branch: an android build's branch
-            target: an android build's target
+    Args:
+      branch: an android build's branch
+      target: an android build's target
 
-        Returns:
-            A string representing latest build id.
-        """
-        request = self._rest_client.service.build().list(
-            buildType='submitted',
-            branch=branch,
-            target=target,
-            successful=True,
-            maxResults=1)
-        builds = request.execute(num_retries=10)
-        if not builds or not builds['builds']:
-            return None
+    Returns:
+      A string representing latest build id.
+    """
+    request = self._rest_client.service.build().list(
+        buildType='submitted',
+        branch=branch,
+        target=target,
+        successful=True,
+        maxResults=1)
+    builds = request.execute(num_retries=10)
+    if not builds or not builds['builds']:
+      return None
 
-        return builds['builds'][0]['buildId']
+    return builds['builds'][0]['buildId']
 
 
 class StorageRestClient(object):
-    """REST client for google storage API."""
+  """REST client for google storage API."""
 
-    def __init__(self, rest_client):
-        """Initialize a REST client for connecting to Google storage API."""
-        self._rest_client = rest_client
-        self._rest_client.create_service()
+  def __init__(self, rest_client):
+    """Initialize a REST client for connecting to Google storage API."""
+    self._rest_client = rest_client
+    self._rest_client.create_service()
 
-    def ReadObject(self, input_bucket, input_object):
-        """Read the contents of input_object in input_bucket.
+  def read_object(self, input_bucket, input_object):
+    """Read the contents of input_object in input_bucket.
 
-        Args:
-            input_bucket: the bucket for fetching.
-            input_object: the object for checking the contents.
+    Args:
+      input_bucket: the bucket for fetching.
+      input_object: the object for checking the contents.
 
-        Returns:
-            the stripped string contents of the input object.
+    Returns:
+      the stripped string contents of the input object.
 
-        Raises:
-            apiclient.errors.HttpError
-        """
-        req = self._rest_client.service.objects().get_media(
-            bucket=input_bucket,
-            object=input_object)
-        return req.execute()
+    Raises:
+      apiclient.errors.HttpError
+    """
+    req = self._rest_client.service.objects().get_media(
+        bucket=input_bucket,
+        object=input_object)
+    return req.execute()
 
 
 class CalendarRestClient(object):
-    """Class of REST client for google calendar API."""
+  """Class of REST client for google calendar API."""
 
-    def __init__(self, rest_client):
-        """Initialize a REST client for connecting to Google calendar API."""
-        self._rest_client = rest_client
-        self._rest_client.create_service()
+  def __init__(self, rest_client):
+    """Initialize a REST client for connecting to Google calendar API."""
+    self._rest_client = rest_client
+    self._rest_client.create_service()
 
-    def AddEvent(self, calendar_id, input_event):
-        """Add events of a given calendar.
+  def add_event(self, calendar_id, input_event):
+    """Add events of a given calendar.
 
-        Args:
-            calendarId: the ID of the given calendar.
-            input_event: the event to be added.
-            kwargs: the parameters for adding events of the calendar.
-        """
-        self._rest_client.service.events().insert(
-            calendarId=calendar_id,
-            body=input_event).execute()
+    Args:
+      calendar_id: the ID of the given calendar.
+      input_event: the event to be added.
+    """
+    self._rest_client.service.events().insert(
+        calendarId=calendar_id,
+        body=input_event).execute()
 
 
 class SwarmingRestClient(object):
-    """REST client for swarming proxy API."""
+  """REST client for swarming proxy API."""
 
-    DISCOVERY_URL_PATTERN = '%s/discovery/v1/apis/%s/%s/rest'
+  DISCOVERY_URL_PATTERN = '%s/discovery/v1/apis/%s/%s/rest'
 
-    def __init__(self, rest_client, service_url):
-        self._rest_client = rest_client
-        discovery_url = self.DISCOVERY_URL_PATTERN % (
-            service_url, service_name, service_version)
-        self._rest_client.create_service(discovery_url=discovery_url)
+  def __init__(self, rest_client, service_url):
+    self._rest_client = rest_client
+    discovery_url = self.DISCOVERY_URL_PATTERN % (
+        service_url, rest_client.service_name, rest_client.service_version)
+    self._rest_client.create_service(discovery_url=discovery_url)
 
-    def create_task(self, request):
-        """Create new task.
+  def create_task(self, request):
+    """Create new task.
 
-        Args:
-            request: a json-compatible dict expected by swarming server.
-                See _to_raw_request's output in swarming_lib.py for details.
-        """
-        return self._rest_client.service.tasks().new(
-            fields='request,task_id', body=request).execute()
+    Args:
+      request: a json-compatible dict expected by swarming server.
+        See _to_raw_request's output in swarming_lib.py for details.
 
-    def request_task(self, task_id):
-        """Get task details by a given task_id.
+    Returns:
+      A json dict returned by API task.new.
+    """
+    return self._rest_client.service.tasks().new(
+        fields='request,task_id', body=request).execute()
 
-        Args:
-            task_id: A string, represents task id.
+  def get_task_result(self, task_id):
+    """Get task results by a given task_id.
 
-        Returns:
-            A json dict returned by API task.request.
-        """
-        return self._rest_client.service.task().request(
-            task_id=task_id).execute()
+    Args:
+        task_id: A string, represents task id.
+
+    Returns:
+        A json dict returned by API task.result.
+    """
+    return self._rest_client.service.task().result(
+        task_id=task_id).execute()