diff --git a/wa/framework/command.py b/wa/framework/command.py
index 7c481896..e2088028 100644
--- a/wa/framework/command.py
+++ b/wa/framework/command.py
@@ -40,6 +40,7 @@ class SubCommand(object):
     command line arguments.
 
     """
+    name = None
     help = None
     usage = None
     description = None
@@ -81,7 +82,7 @@ class SubCommand(object):
         raise NotImplementedError()
 
 
-class Command(Plugin, SubCommand):
+class Command(Plugin, SubCommand):  # pylint: disable=abstract-method
     """
     Defines a Workload Automation command. This will be executed from the
     command line as ``wa <command> [args ...]``. This defines the name to be
diff --git a/wa/framework/configuration/core.py b/wa/framework/configuration/core.py
index 7d7cf1fa..be409ecf 100644
--- a/wa/framework/configuration/core.py
+++ b/wa/framework/configuration/core.py
@@ -13,7 +13,6 @@
 # limitations under the License.
 
 import os
-import re
 from copy import copy, deepcopy
 from collections import OrderedDict, defaultdict
 
@@ -494,8 +493,10 @@ class MetaConfiguration(Configuration):
     def additional_packages_file(self):
         return os.path.join(self.user_directory, 'packages')
 
-    def __init__(self, environ=os.environ):
+    def __init__(self, environ=None):
         super(MetaConfiguration, self).__init__()
+        if environ is None:
+            environ = os.environ
         user_directory = environ.pop('WA_USER_DIRECTORY', '')
         if user_directory:
             self.set('user_directory', user_directory)
@@ -730,6 +731,7 @@ class RunConfiguration(Configuration):
 
 
 class JobSpec(Configuration):
+    # pylint: disable=access-member-before-definition,attribute-defined-outside-init
 
     name = "Job Spec"
 
@@ -826,7 +828,7 @@ class JobSpec(Configuration):
         pod['id'] = self.id
         return pod
 
-    def update_config(self, source, check_mandatory=True):
+    def update_config(self, source, check_mandatory=True):  # pylint: disable=arguments-differ
         self._sources.append(source)
         values = source.config
         for k, v in values.items():
diff --git a/wa/framework/configuration/execution.py b/wa/framework/configuration/execution.py
index b516e910..259c21c4 100644
--- a/wa/framework/configuration/execution.py
+++ b/wa/framework/configuration/execution.py
@@ -19,7 +19,7 @@ from itertools import groupby, chain
 from future.moves.itertools import zip_longest
 
 from wa.framework.configuration.core import (MetaConfiguration, RunConfiguration,
-                                             JobGenerator, Status, settings)
+                                             JobGenerator, settings)
 from wa.framework.configuration.parsers import ConfigParser
 from wa.framework.configuration.plugin_cache import PluginCache
 from wa.framework.exception import NotFoundError
@@ -36,7 +36,7 @@ class CombinedConfig(object):
         instance.run_config = RunConfiguration.from_pod(pod.get('run_config', {}))
         return instance
 
-    def __init__(self, settings=None, run_config=None):
+    def __init__(self, settings=None, run_config=None):  # pylint: disable=redefined-outer-name
         self.settings = settings
         self.run_config = run_config
 
@@ -78,7 +78,7 @@ class ConfigManager(object):
             raise RuntimeError(msg)
         return self._jobs
 
-    def __init__(self, settings=settings):
+    def __init__(self, settings=settings):  # pylint: disable=redefined-outer-name
         self.settings = settings
         self.run_config = RunConfiguration()
         self.plugin_cache = PluginCache()
@@ -93,7 +93,7 @@ class ConfigManager(object):
         self._config_parser.load_from_path(self, filepath)
         self.loaded_config_sources.append(filepath)
 
-    def load_config(self, values, source, wrap_exceptions=True):
+    def load_config(self, values, source):
         self._config_parser.load(self, values, source)
         self.loaded_config_sources.append(source)
 
@@ -169,7 +169,7 @@ def permute_by_iteration(specs):
     X.A1, Y.A1, X.B1, Y.B1, X.A2, Y.A2, X.B2, Y.B2
 
     """
-    groups = [list(g) for k, g in groupby(specs, lambda s: s.workload_id)]
+    groups = [list(g) for _, g in groupby(specs, lambda s: s.workload_id)]
 
     all_tuples = []
     for spec in chain(*groups):
@@ -195,7 +195,7 @@ def permute_by_section(specs):
     X.A1, X.B1, Y.A1, Y.B1, X.A2, X.B2, Y.A2, Y.B2
 
     """
-    groups = [list(g) for k, g in groupby(specs, lambda s: s.section_id)]
+    groups = [list(g) for _, g in groupby(specs, lambda s: s.section_id)]
 
     all_tuples = []
     for spec in chain(*groups):
diff --git a/wa/framework/configuration/parsers.py b/wa/framework/configuration/parsers.py
index 4909169c..0f17d728 100644
--- a/wa/framework/configuration/parsers.py
+++ b/wa/framework/configuration/parsers.py
@@ -12,16 +12,17 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
+# pylint: disable=no-self-use
 
 import os
 import logging
+from functools import reduce  # pylint: disable=redefined-builtin
 
 from wa.framework.configuration.core import JobSpec
 from wa.framework.exception import ConfigError
 from wa.utils import log
 from wa.utils.serializer import json, read_pod, SerializerSyntaxError
 from wa.utils.types import toggle_set, counter
-from functools import reduce
 
 
 logger = logging.getLogger('config')
@@ -135,7 +136,7 @@ class AgendaParser(object):
                 logger.debug('Setting run name to "{}"'.format(value))
                 state.run_config.set('run_name', value)
 
-            state.load_config(entry, '{}/{}'.format(source, name), wrap_exceptions=False)
+            state.load_config(entry, '{}/{}'.format(source, name))
 
     def _pop_sections(self, raw):
         sections = raw.pop("sections", [])
@@ -264,8 +265,8 @@ def merge_augmentations(raw):
             conflicts = check_entry.conflicts_with(e)
             if conflicts:
                 msg = '"{}" and "{}" have conflicting entries: {}'
-                conflict_string  = ', '.join('"{}"'.format(c.strip("~"))
-                                             for c in conflicts)
+                conflict_string = ', '.join('"{}"'.format(c.strip("~"))
+                                            for c in conflicts)
                 raise ConfigError(msg.format(check_entry, e, conflict_string))
 
     if entries:
@@ -354,4 +355,3 @@ def _process_workload_entry(workload, seen_workload_ids, jobs_config):
     if "workload_name" not in workload:
         raise ConfigError('No workload name specified in entry {}'.format(workload['id']))
     return workload
-
diff --git a/wa/framework/configuration/plugin_cache.py b/wa/framework/configuration/plugin_cache.py
index f18748df..d4f6734e 100644
--- a/wa/framework/configuration/plugin_cache.py
+++ b/wa/framework/configuration/plugin_cache.py
@@ -292,9 +292,9 @@ def update_config_from_source(final_config, source, state):
                             'already been specified more specifically for '
                             '{specific_name} in:\n\t\t{sources}')
                     seen_sources = state.seen_specific_config[name]
-                    msg = msg.format(generic_name=generic_name,
+                    msg = msg.format(generic_name=state.generic_name,
                                         config_name=name,
-                                        specific_name=specific_name,
+                                        specific_name=state.specific_name,
                                         sources=", ".join(seen_sources))
                     raise ConfigError(msg)
                 value = state.generic_config[source].pop(name)
diff --git a/wa/framework/exception.py b/wa/framework/exception.py
index 97072c2b..4a6cff2e 100644
--- a/wa/framework/exception.py
+++ b/wa/framework/exception.py
@@ -12,6 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
+# pylint: disable=unused-import
 from devlib.exception import (DevlibError, HostError, TimeoutError,
                               TargetError, TargetNotRespondingError)
 
@@ -152,4 +153,3 @@ class WorkerThreadError(WAError):
         message = text.format(orig_name, thread, get_traceback(self.exc_info),
                               orig_name, orig)
         super(WorkerThreadError, self).__init__(message)
-
diff --git a/wa/framework/execution.py b/wa/framework/execution.py
index bb7da1ee..6cac8e5d 100644
--- a/wa/framework/execution.py
+++ b/wa/framework/execution.py
@@ -350,7 +350,6 @@ class Executor(object):
         signal.connect(self._error_signalled_callback, signal.ERROR_LOGGED)
         signal.connect(self._warning_signalled_callback, signal.WARNING_LOGGED)
 
-    def execute(self, config_manager, output):
         self.logger.info('Initializing run')
         self.logger.debug('Finalizing run configuration.')
         config = config_manager.finalize()
@@ -444,11 +443,11 @@ class Executor(object):
             self.logger.warn('There were warnings during execution.')
             self.logger.warn('Please see {}'.format(output.logfile))
 
-    def _error_signalled_callback(self, record):
+    def _error_signalled_callback(self, _):
         self.error_logged = True
         signal.disconnect(self._error_signalled_callback, signal.ERROR_LOGGED)
 
-    def _warning_signalled_callback(self, record):
+    def _warning_signalled_callback(self, _):
         self.warning_logged = True
         signal.disconnect(self._warning_signalled_callback, signal.WARNING_LOGGED)
 
@@ -492,7 +491,7 @@ class Runner(object):
         except Exception as e:
             message = e.args[0] if e.args else str(e)
             log.log_error(e, self.logger)
-            self.logger.error('Skipping remaining jobs due to "{}".'.format(e))
+            self.logger.error('Skipping remaining jobs due to "{}".'.format(message))
             self.context.skip_remaining_jobs()
             raise e
         finally:
@@ -563,6 +562,7 @@ class Runner(object):
             self.check_job(job)
 
     def do_run_job(self, job, context):
+        # pylint: disable=too-many-branches,too-many-statements
         rc = self.context.cm.run_config
         if job.workload.phones_home and not rc.allow_phone_home:
             self.logger.warning('Skipping job {} ({}) due to allow_phone_home=False'
@@ -583,7 +583,7 @@ class Runner(object):
         except Exception as e:
             job.set_status(Status.FAILED)
             log.log_error(e, self.logger)
-            if isinstance(e, TargetError) or isinstance(e, TimeoutError):
+            if isinstance(e, (TargetError, TimeoutError)):
                 context.tm.verify_target_responsive(context)
             self.context.record_ui_state('setup-error')
             raise e
@@ -599,7 +599,7 @@ class Runner(object):
             except Exception as e:
                 job.set_status(Status.FAILED)
                 log.log_error(e, self.logger)
-                if isinstance(e, TargetError) or isinstance(e, TimeoutError):
+                if isinstance(e, (TargetError, TimeoutError)):
                     context.tm.verify_target_responsive(context)
                 self.context.record_ui_state('run-error')
                 raise e
@@ -611,7 +611,7 @@ class Runner(object):
                     self.pm.export_job_output(context)
                 except Exception as e:
                     job.set_status(Status.PARTIAL)
-                    if isinstance(e, TargetError) or isinstance(e, TimeoutError):
+                    if isinstance(e, (TargetError, TimeoutError)):
                         context.tm.verify_target_responsive(context)
                     self.context.record_ui_state('output-error')
                     raise
diff --git a/wa/framework/host.py b/wa/framework/host.py
index b3df6a6a..807217a8 100644
--- a/wa/framework/host.py
+++ b/wa/framework/host.py
@@ -18,12 +18,11 @@ import shutil
 
 from wa.framework import pluginloader
 from wa.framework.configuration.core import (settings, ConfigurationPoint,
-                                             MetaConfiguration, RunConfiguration,
-                                             JobSpec)
+                                             MetaConfiguration, RunConfiguration)
 from wa.framework.configuration.default import (generate_default_config,
-                                                write_param_yaml, _format_yaml_comment)
+                                                write_param_yaml)
 from wa.framework.configuration.plugin_cache import PluginCache
-from wa.utils.misc import get_random_string, load_struct_from_python
+from wa.utils.misc import load_struct_from_python
 from wa.utils.serializer import yaml
 from wa.utils.types import identifier
 
@@ -138,7 +137,6 @@ def convert_wa2_agenda(filepath, output_path):
 
 def format_parameter(param):
     if isinstance(param, dict):
-         return {identifier(k) : v for k, v in param.items()}
+        return {identifier(k) : v for k, v in param.items()}
     else:
         return param
-
diff --git a/wa/framework/instrument.py b/wa/framework/instrument.py
index 78b0c44e..f5e5e76a 100644
--- a/wa/framework/instrument.py
+++ b/wa/framework/instrument.py
@@ -104,7 +104,7 @@ from collections import OrderedDict
 
 from wa.framework import signal
 from wa.framework.plugin import Plugin
-from wa.framework.exception import (WAError, TargetNotRespondingError, TimeoutError,
+from wa.framework.exception import (TargetNotRespondingError, TimeoutError,
                                     WorkloadError, TargetError)
 from wa.utils.log import log_error
 from wa.utils.misc import isiterable
@@ -165,7 +165,7 @@ def get_priority(func):
                    'priority', signal.CallbackPriority.normal)
 
 
-def priority(priority):
+def priority(priority):  # pylint: disable=redefined-outer-name
     def decorate(func):
         def wrapper(*args, **kwargs):
             return func(*args, **kwargs)
@@ -225,7 +225,7 @@ def is_installed(instrument):
 
 
 def is_enabled(instrument):
-    if isinstance(instrument, Instrument) or isinstance(instrument, type):
+    if isinstance(instrument, (Instrument, type)):
         name = instrument.name
     else:  # assume string
         name = instrument
@@ -279,7 +279,7 @@ class ManagedCallback(object):
                 context.add_event(e.args[0] if e.args else str(e))
                 if isinstance(e, WorkloadError):
                     context.set_status('FAILED')
-                elif isinstance(e, TargetError) or isinstance(e, TimeoutError):
+                elif isinstance(e, (TargetError, TimeoutError)):
                     context.tm.verify_target_responsive(context)
                 else:
                     if context.current_job:
@@ -308,6 +308,7 @@ def install(instrument, context):
     :param instrument: Instrument instance to install.
 
     """
+    # pylint: disable=redefined-outer-name
     logger.debug('Installing instrument %s.', instrument)
 
     if is_installed(instrument):
diff --git a/wa/framework/output.py b/wa/framework/output.py
index 8029aca4..6cdec2c0 100644
--- a/wa/framework/output.py
+++ b/wa/framework/output.py
@@ -29,7 +29,7 @@ from wa.framework.run import RunState, RunInfo
 from wa.framework.target.info import TargetInfo
 from wa.framework.version import get_wa_version_with_commit
 from wa.utils.misc import touch, ensure_directory_exists, isiterable
-from wa.utils.serializer import write_pod, read_pod, is_pod
+from wa.utils.serializer import write_pod, read_pod
 from wa.utils.types import enum, numeric
 
 
@@ -86,7 +86,7 @@ class Output(object):
     @classifiers.setter
     def classifiers(self, value):
         if self.result is None:
-            msg ='Attempting to set classifiers before output has been set'
+            msg = 'Attempting to set classifiers before output has been set'
             raise RuntimeError(msg)
         self.result.classifiers = value
 
@@ -114,7 +114,7 @@ class Output(object):
             else:
                 self.result = Result()
                 self.result.status = Status.PENDING
-        except Exception as e:
+        except Exception as e:  # pylint: disable=broad-except
             self.result = Result()
             self.result.status = Status.UNKNOWN
             self.add_event(str(e))
@@ -676,7 +676,7 @@ def init_job_output(run_output, job):
 
 
 def discover_wa_outputs(path):
-    for root, dirs, files in os.walk(path):
+    for root, dirs, _ in os.walk(path):
         if '__meta' in dirs:
             yield  RunOutput(root)
 
diff --git a/wa/framework/output_processor.py b/wa/framework/output_processor.py
index 9ba1627d..0877fc26 100644
--- a/wa/framework/output_processor.py
+++ b/wa/framework/output_processor.py
@@ -139,7 +139,7 @@ class ProcessorManager(object):
                     try:
                         self.logger.info(message.format(proc.name))
                         proc_func(*args)
-                    except Exception as e:
+                    except Exception as e:  #  pylint: disable=broad-except
                         if isinstance(e, KeyboardInterrupt):
                             raise
                         log_error(e, self.logger)
@@ -155,4 +155,3 @@ class ProcessorManager(object):
         self.logger.debug('Disabling output processor {}'.format(inst.name))
         if inst.is_enabled:
             inst.is_enabled = False
-
diff --git a/wa/framework/plugin.py b/wa/framework/plugin.py
index e6c5dcb7..27b283bc 100644
--- a/wa/framework/plugin.py
+++ b/wa/framework/plugin.py
@@ -180,7 +180,8 @@ class PluginMeta(type):
         return cls
 
     @classmethod
-    def _propagate_attributes(mcs, bases, attrs, clsname):
+    def _propagate_attributes(mcs, bases, attrs, clsname):  # pylint: disable=too-many-locals
+        # pylint: disable=protected-access
         """
         For attributes specified by to_propagate, their values will be a union of
         that specified for cls and its bases (cls values overriding those of bases
@@ -488,7 +489,7 @@ class PluginLoader(object):
             raise NotFoundError(msg.format(name, get_article(kind), kind))
         return store[name]
 
-    def get_plugin(self, name=None, kind=None, *args, **kwargs):
+    def get_plugin(self, name=None, kind=None, *args, **kwargs):  # pylint: disable=keyword-arg-before-vararg
         """
         Return plugin of the specified kind with the specified name. Any
         additional parameters will be passed to the plugin's __init__.
diff --git a/wa/framework/pluginloader.py b/wa/framework/pluginloader.py
index bb091715..36f486a1 100644
--- a/wa/framework/pluginloader.py
+++ b/wa/framework/pluginloader.py
@@ -65,7 +65,7 @@ class __LoaderWrapper(object):
             self.reset()
         return self._loader.get_plugin_class(name, kind)
 
-    def get_plugin(self, name=None, kind=None, *args, **kwargs):
+    def get_plugin(self, name=None, kind=None, *args, **kwargs):  # pylint: disable=keyword-arg-before-vararg
         if not self._loader:
             self.reset()
         return self._loader.get_plugin(name=name, kind=kind, *args, **kwargs)
diff --git a/wa/framework/signal.py b/wa/framework/signal.py
index 0b81aec8..ee8f5095 100644
--- a/wa/framework/signal.py
+++ b/wa/framework/signal.py
@@ -24,7 +24,7 @@ import logging
 from contextlib import contextmanager
 
 import wrapt
-from louie import dispatcher
+from louie import dispatcher  # pylint: disable=wrong-import-order
 
 from wa.utils.types import prioritylist, enum
 
@@ -73,7 +73,7 @@ class Signal(object):
 RUN_STARTED = Signal('run-started', 'sent at the beginning of the run')
 RUN_INITIALIZED = Signal('run-initialized', 'set after the run has been initialized')
 RUN_ABORTED = Signal('run-aborted', 'set when the run has been aborted due to a keyboard interrupt')
-RUN_FAILED = Signal('run-failed', 'set if the run has failed to complete all jobs.' )
+RUN_FAILED = Signal('run-failed', 'set if the run has failed to complete all jobs.')
 RUN_FINALIZED = Signal('run-finalized', 'set after the run has been finalized')
 RUN_COMPLETED = Signal('run-completed', 'set upon completion of the run (regardless of whether or not it has failed')
 
@@ -291,23 +291,25 @@ log_error_func = logger.error
 
 
 def safe_send(signal, sender=dispatcher.Anonymous,
-              propagate=[KeyboardInterrupt], *args, **kwargs):
+              propagate=None, *args, **kwargs):
     """
     Same as ``send``, except this will catch and log all exceptions raised
     by handlers, except those specified in ``propagate`` argument (defaults
     to just ``[KeyboardInterrupt]``).
     """
+    if propagate is None:
+        propagate = [KeyboardInterrupt]
     try:
         logger.debug('Safe-sending {} from {}'.format(signal, sender))
         send(signal, sender, *args, **kwargs)
-    except Exception as e:
+    except Exception as e:  # pylint: disable=broad-except
         if any(isinstance(e, p) for p in propagate):
             raise e
         log_error_func(e)
 
 
 @contextmanager
-def wrap(signal_name, sender=dispatcher.Anonymous,*args, **kwargs):
+def wrap(signal_name, sender=dispatcher.Anonymous, *args, **kwargs):  # pylint: disable=keyword-arg-before-vararg
     """Wraps the suite in before/after signals, ensuring
     that after signal is always sent."""
     safe = kwargs.pop('safe', False)
@@ -324,7 +326,7 @@ def wrap(signal_name, sender=dispatcher.Anonymous,*args, **kwargs):
         yield
         send_func(success_signal, sender, *args, **kwargs)
     finally:
-        exc_type, exc, tb = sys.exc_info()
+        _, exc, _ = sys.exc_info()
         if exc:
             log_error_func(exc)
         send_func(after_signal, sender, *args, **kwargs)
@@ -333,10 +335,10 @@ def wrap(signal_name, sender=dispatcher.Anonymous,*args, **kwargs):
 def wrapped(signal_name, sender=dispatcher.Anonymous, safe=False):
     """A decorator for wrapping function in signal dispatch."""
     @wrapt.decorator
-    def signal_wrapped(wrapped, instance, args, kwargs):
+    def signal_wrapped(wrapped_func, _, args, kwargs):
         def signal_wrapper(*args, **kwargs):
             with wrap(signal_name, sender, safe):
-                return wrapped(*args, **kwargs)
+                return wrapped_func(*args, **kwargs)
 
         return signal_wrapper(*args, **kwargs)
 
diff --git a/wa/framework/target/config.py b/wa/framework/target/config.py
index 7cde5ee6..d8ae4fae 100644
--- a/wa/framework/target/config.py
+++ b/wa/framework/target/config.py
@@ -23,6 +23,7 @@ class TargetConfig(dict):
 
     """
     def __init__(self, config=None):
+        dict.__init__(self)
         if isinstance(config, TargetConfig):
             self.__dict__ = copy(config.__dict__)
         elif hasattr(config, 'iteritems'):
diff --git a/wa/framework/target/descriptor.py b/wa/framework/target/descriptor.py
index 5345451a..45a7abcc 100644
--- a/wa/framework/target/descriptor.py
+++ b/wa/framework/target/descriptor.py
@@ -54,6 +54,7 @@ def get_target_description(name, loader=pluginloader):
 
 
 def instantiate_target(tdesc, params, connect=None, extra_platform_params=None):
+    # pylint: disable=too-many-locals,too-many-branches
     target_params = get_config_point_map(tdesc.target_params)
     platform_params = get_config_point_map(tdesc.platform_params)
     conn_params = get_config_point_map(tdesc.conn_params)
@@ -136,7 +137,7 @@ class TargetDescription(object):
             vals = []
         elif isiterable(vals):
             if hasattr(vals, 'values'):
-                vals = list(v.values())
+                vals = list(vals.values())
         else:
             msg = '{} must be iterable; got "{}"'
             raise ValueError(msg.format(attr, vals))
@@ -147,7 +148,7 @@ class TargetDescriptor(Plugin):
 
     kind = 'target_descriptor'
 
-    def get_descriptions(self):
+    def get_descriptions(self):  # pylint: disable=no-self-use
         return []
 
 
@@ -472,11 +473,12 @@ class DefaultTargetDescriptor(TargetDescriptor):
     """
 
     def get_descriptions(self):
+        # pylint: disable=attribute-defined-outside-init,too-many-locals
         result = []
         for target_name, target_tuple in TARGETS.items():
             (target, conn), target_params = self._get_item(target_tuple)
             assistant = ASSISTANTS[target_name]
-            conn_params =  CONNECTION_PARAMS[conn]
+            conn_params = CONNECTION_PARAMS[conn]
             for platform_name, platform_tuple in PLATFORMS.items():
                 platform_target_defaults = platform_tuple[-1]
                 platform_tuple = platform_tuple[0:-1]
@@ -495,7 +497,7 @@ class DefaultTargetDescriptor(TargetDescriptor):
 
                 if plat_conn:
                     td.conn = plat_conn
-                    td.conn_params =  CONNECTION_PARAMS[plat_conn]
+                    td.conn_params = CONNECTION_PARAMS[plat_conn]
                 else:
                     td.conn = conn
                     td.conn_params = conn_params
@@ -503,7 +505,7 @@ class DefaultTargetDescriptor(TargetDescriptor):
                 result.append(td)
         return result
 
-    def _apply_param_defaults(self, params, defaults):
+    def _apply_param_defaults(self, params, defaults):  # pylint: disable=no-self-use
         '''Adds parameters in the defaults dict to params list.
         Return updated params as a list (idempotent function).'''
         if not defaults:
@@ -540,7 +542,7 @@ def create_target_description(name, *args, **kwargs):
     #  (frame_object, module_path, line_no, function_name, source_lines, source_lines_index)
     #
     # Here we assign the path of the calling module as the "source" for this description.
-    # because this might be invoked via the add_scription_for_target wrapper, we need to 
+    # because this might be invoked via the add_scription_for_target wrapper, we need to
     # check for that, and make sure that we get the info for *its* caller in that case.
     if stack[1][3] == 'add_description_for_target':
         source = stack[2][1]
@@ -555,15 +557,15 @@ def _get_target_defaults(target):
     res = ('linux', TARGETS['linux'])  # fallback to a generic linux target
     for name, ttup in TARGETS.items():
         if issubclass(target, ttup[0][0]):
-            new_spec =  len(inspect.getmro(ttup[0][0]))
+            new_spec = len(inspect.getmro(ttup[0][0]))
             if new_spec > specificity:
                 res = (name, ttup)
-                specificity  = new_spec
+                specificity = new_spec
     return res
 
 
 def add_description_for_target(target, description=None, **kwargs):
-    (base_name, ((base_target, base_conn), base_params, base_defaults)) = _get_target_defaults(target)
+    (base_name, ((_, base_conn), base_params, _)) = _get_target_defaults(target)
 
     if 'target_params' not in kwargs:
         kwargs['target_params'] = base_params
@@ -593,7 +595,7 @@ class SimpleTargetDescriptor(TargetDescriptor):
 
     name = 'adhoc_targets'
 
-    description="""
+    description = """
     Returns target descriptions added with ``create_target_description``.
 
     """
diff --git a/wa/framework/target/info.py b/wa/framework/target/info.py
index e7e3cb2a..06aa9886 100644
--- a/wa/framework/target/info.py
+++ b/wa/framework/target/info.py
@@ -12,6 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
+# pylint: disable=protected-access
 
 from copy import copy
 
@@ -261,6 +262,9 @@ class TargetInfo(object):
         self.kernel_version = None
         self.kernel_config = None
         self.sched_features = None
+        self.screen_resolution = None
+        self.prop = None
+        self.android_id = None
 
     def to_pod(self):
         pod = {}
diff --git a/wa/framework/target/manager.py b/wa/framework/target/manager.py
index 166531ea..21d7edf2 100644
--- a/wa/framework/target/manager.py
+++ b/wa/framework/target/manager.py
@@ -122,7 +122,7 @@ class TargetManager(object):
     def _init_target(self):
         tdesc = get_target_description(self.target_name)
 
-        extra_plat_params={}
+        extra_plat_params = {}
         if tdesc.platform is Gem5SimulationPlatform:
             extra_plat_params['host_output_dir'] = self.outdir
 
diff --git a/wa/framework/target/runtime_config.py b/wa/framework/target/runtime_config.py
index cd980ba1..2abcefa8 100644
--- a/wa/framework/target/runtime_config.py
+++ b/wa/framework/target/runtime_config.py
@@ -204,8 +204,8 @@ class SysfileValuesRuntimeConfig(RuntimeConfig):
 
     #pylint: disable=unused-argument
     @staticmethod
-    def set_sysfile(obj, value, core):
-        for path, value in value.items():
+    def set_sysfile(obj, values, core):
+        for path, value in values.items():
             verify = True
             if path.endswith('!'):
                 verify = False
@@ -323,14 +323,15 @@ class CpufreqRuntimeConfig(RuntimeConfig):
         super(CpufreqRuntimeConfig, self).__init__(target)
 
     def initialize(self):
+        # pylint: disable=too-many-statements
         if not self.target.has('cpufreq'):
             return
 
         self._retrive_cpufreq_info()
-        all_freqs, common_freqs, common_gov = self._get_common_values()
+        _, common_freqs, common_gov = self._get_common_values()
 
         # Add common parameters if available.
-        freq_val = FreqValue(all_freqs)
+        freq_val = FreqValue(common_freqs)
         param_name = 'frequency'
         self._runtime_params[param_name] = \
             RuntimeParameter(param_name, kind=freq_val,
@@ -873,7 +874,7 @@ class AndroidRuntimeConfig(RuntimeConfig):
                               the device
                               """)
 
-        if self.target.os is 'android':
+        if self.target.os == 'android':
             param_name = 'airplane_mode'
             self._runtime_params[param_name] = \
                 RuntimeParameter(param_name, kind=bool,
diff --git a/wa/framework/workload.py b/wa/framework/workload.py
index e06e66bd..e1480af3 100644
--- a/wa/framework/workload.py
+++ b/wa/framework/workload.py
@@ -14,7 +14,6 @@
 #
 import logging
 import os
-import re
 import time
 
 from wa import Parameter
@@ -658,11 +657,12 @@ class PackageHandler(object):
         self.uninstall = uninstall
         self.exact_abi = exact_abi
         self.prefer_host_package = prefer_host_package
+        self.supported_abi = self.target.supported_abi
         self.apk_file = None
         self.apk_info = None
         self.apk_version = None
         self.logcat_log = None
-        self.supported_abi = self.target.supported_abi
+        self.error_msg = None
 
     def initialize(self, context):
         self.resolve_package(context)
@@ -683,9 +683,9 @@ class PackageHandler(object):
         if self.prefer_host_package:
             self.resolve_package_from_host(context)
             if not self.apk_file:
-                self.resolve_package_from_target(context)
+                self.resolve_package_from_target()
         else:
-            self.resolve_package_from_target(context)
+            self.resolve_package_from_target()
             if not self.apk_file:
                 self.resolve_package_from_host(context)
 
@@ -734,7 +734,7 @@ class PackageHandler(object):
                 msg = 'Multiple matching packages found for "{}" on host: {}'
                 self.error_msg = msg.format(self.owner, available_packages)
 
-    def resolve_package_from_target(self, context):
+    def resolve_package_from_target(self):  # pylint: disable=too-many-branches
         self.logger.debug('Resolving package on target')
         if self.package_name:
             if not self.target.package_is_installed(self.package_name):
@@ -754,13 +754,13 @@ class PackageHandler(object):
                 if len(matching_packages) == 1:
                     self.package_name = matching_packages[0]
                 elif len(matching_packages) > 1:
-                   msg = 'Multiple matches for version "{}" found on device.'
-                   self.error_msg = msg.format(self.version)
+                    msg = 'Multiple matches for version "{}" found on device.'
+                    self.error_msg = msg.format(self.version)
             else:
                 if len(installed_versions) == 1:
                     self.package_name = installed_versions[0]
                 elif len(installed_versions) > 1:
-                   self.error_msg = 'Package version not set and multiple versions found on device.'
+                    self.error_msg = 'Package version not set and multiple versions found on device.'
 
         if self.package_name:
             self.logger.debug('Found matching package on target; Pulling to host.')