summary refs log tree commit diff stats
diff options
context:
space:
mode:
authornfnty <git@nfnty.se>2017-01-20 12:07:53 +0100
committernfnty <git@nfnty.se>2017-01-20 12:07:53 +0100
commit1c90e610de6591e8052a1056c775219b5e767002 (patch)
tree69b56f67dee1d6dfcea869de897846baaded3fa6
parente26d163debc9f55a89a27f94a43771526d2ff0b7 (diff)
parent03ee065e35c6a8f0e0dc1e66d8f4c3e83c51f315 (diff)
downloadranger-1c90e610de6591e8052a1056c775219b5e767002.tar.gz
Merge branch 'lint'
-rw-r--r--.travis.yml21
-rw-r--r--Makefile12
-rwxr-xr-xdoc/tools/convert_papermode_to_metadata.py12
-rwxr-xr-xdoc/tools/print_colors.py17
-rwxr-xr-xdoc/tools/print_keys.py23
-rw-r--r--examples/plugin_chmod_keybindings.py9
-rw-r--r--examples/plugin_file_filter.py19
-rw-r--r--examples/plugin_hello_world.py7
-rw-r--r--examples/plugin_ipc.py17
-rw-r--r--examples/plugin_linemode.py10
-rw-r--r--examples/plugin_new_macro.py16
-rw-r--r--examples/plugin_new_sorting_method.py6
-rw-r--r--examples/plugin_pmount.py27
-rw-r--r--pylintrc14
-rwxr-xr-xranger.py12
-rw-r--r--ranger/__init__.py7
-rw-r--r--ranger/api/__init__.py13
-rw-r--r--ranger/api/commands.py95
-rw-r--r--ranger/api/options.py14
-rw-r--r--ranger/colorschemes/default.py16
-rw-r--r--ranger/colorschemes/jungle.py4
-rw-r--r--ranger/colorschemes/snow.py5
-rw-r--r--ranger/colorschemes/solarized.py18
-rwxr-xr-xranger/config/commands.py313
-rw-r--r--ranger/config/commands_sample.py11
-rw-r--r--ranger/config/pylintrc8
-rw-r--r--ranger/container/bookmarks.py22
-rw-r--r--ranger/container/directory.py114
-rw-r--r--ranger/container/file.py26
-rw-r--r--ranger/container/fsobject.py133
-rw-r--r--ranger/container/history.py13
-rw-r--r--ranger/container/settings.py59
-rw-r--r--ranger/container/tags.py41
-rw-r--r--ranger/core/actions.py396
-rw-r--r--ranger/core/fm.py154
-rw-r--r--ranger/core/linemode.py60
-rw-r--r--ranger/core/loader.py139
-rw-r--r--ranger/core/main.py240
-rw-r--r--ranger/core/metadata.py42
-rw-r--r--ranger/core/runner.py48
-rw-r--r--ranger/core/shared.py8
-rw-r--r--ranger/core/tab.py22
-rw-r--r--ranger/ext/accumulator.py19
-rw-r--r--ranger/ext/cached_function.py4
-rw-r--r--ranger/ext/curses_interrupt_handler.py11
-rw-r--r--ranger/ext/direction.py16
-rw-r--r--ranger/ext/get_executables.py9
-rw-r--r--ranger/ext/human_readable.py7
-rw-r--r--ranger/ext/img_display.py138
-rw-r--r--ranger/ext/iter_tools.py3
-rw-r--r--ranger/ext/keybinding_parser.py66
-rw-r--r--ranger/ext/lazy_property.py5
-rw-r--r--ranger/ext/logutils.py6
-rw-r--r--ranger/ext/mount_path.py2
-rw-r--r--ranger/ext/next_available_filename.py2
-rw-r--r--ranger/ext/openstruct.py7
-rw-r--r--ranger/ext/popen_forked.py6
-rw-r--r--ranger/ext/relative_symlink.py2
-rwxr-xr-xranger/ext/rifle.py102
-rw-r--r--ranger/ext/shell_escape.py12
-rw-r--r--ranger/ext/shutil_generatorized.py58
-rw-r--r--ranger/ext/signals.py29
-rw-r--r--ranger/ext/spawn.py5
-rw-r--r--ranger/ext/vcs/__init__.py2
-rw-r--r--ranger/ext/vcs/bzr.py4
-rw-r--r--ranger/ext/vcs/git.py7
-rw-r--r--ranger/ext/vcs/hg.py2
-rw-r--r--ranger/ext/vcs/svn.py2
-rw-r--r--ranger/ext/vcs/vcs.py3
-rw-r--r--ranger/ext/widestring.py53
-rw-r--r--ranger/gui/ansi.py20
-rw-r--r--ranger/gui/bar.py23
-rw-r--r--ranger/gui/color.py23
-rw-r--r--ranger/gui/colorscheme.py26
-rw-r--r--ranger/gui/context.py67
-rw-r--r--ranger/gui/curses_shortcuts.py7
-rw-r--r--ranger/gui/displayable.py29
-rw-r--r--ranger/gui/mouse_event.py21
-rw-r--r--ranger/gui/ui.py67
-rw-r--r--ranger/gui/widgets/__init__.py47
-rw-r--r--ranger/gui/widgets/browsercolumn.py53
-rw-r--r--ranger/gui/widgets/console.py71
-rw-r--r--ranger/gui/widgets/pager.py60
-rw-r--r--ranger/gui/widgets/statusbar.py37
-rw-r--r--ranger/gui/widgets/taskview.py13
-rw-r--r--ranger/gui/widgets/titlebar.py17
-rw-r--r--ranger/gui/widgets/view_base.py65
-rw-r--r--ranger/gui/widgets/view_miller.py49
-rw-r--r--ranger/gui/widgets/view_multipane.py9
-rwxr-xr-xsetup.py32
-rw-r--r--tests/ranger/container/test_bookmarks.py3
-rw-r--r--tests/ranger/container/test_container.py98
-rw-r--r--tests/ranger/container/test_fsobject.py13
-rw-r--r--tox.ini3
94 files changed, 2061 insertions, 1617 deletions
diff --git a/.travis.yml b/.travis.yml
index 2bc017d3..f9e31256 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,18 +1,13 @@
-language: python
+dist: 'trusty'
+
+language: 'python'
 python:
-  - "2.6"
-  - "2.7"
-  - "3.2"
-  - "3.3"
-  - "3.4"
-  - "3.5"
-  - "3.5-dev" # 3.5 development branch
-  - "nightly" # currently points to 3.6-dev
+    - '2.7'
+    - '3.4'
+    - '3.5'
 
-# command to install dependencies
 install:
-  - pip install pytest
+    - 'pip install pytest pylint flake8'
 
-# command to run tests
 script:
-  - make test
+    - 'make test'
diff --git a/Makefile b/Makefile
index 870901da..cd871d2e 100644
--- a/Makefile
+++ b/Makefile
@@ -60,7 +60,19 @@ doc: cleandoc
 		pydoc.writedocs("$(CWD)")'
 	find . -name \*.html -exec sed -i 's|'"$(CWD)"'|../..|g' -- {} \;
 
+TEST_PATHS_MAIN = \
+	$(shell find ranger -mindepth 1 -maxdepth 1 -type d -and -not -name '__pycache__' -and -not -path 'ranger/config' -and -not -path 'ranger/data') \
+	ranger/__init__.py \
+	$(shell find . '(' -path './ranger' -or -path './tests' ')' -prune -or -type f -name '*.py' -print) \
+	tests
+TEST_PATH_CONFIG = ranger/config
+
 test:
+	@echo "Running pylint..."
+	pylint $(TEST_PATHS_MAIN)
+	pylint --rcfile=$(TEST_PATH_CONFIG)/pylintrc $(TEST_PATH_CONFIG)
+	@echo "Running flake8..."
+	flake8 $(TEST_PATHS_MAIN) $(TEST_PATH_CONFIG)
 	@echo "Running doctests..."
 	@for FILE in $(shell grep -IHm 1 doctest -r ranger | grep $(FILTER) | cut -d: -f1); do \
 		echo "Testing $$FILE..."; \
diff --git a/doc/tools/convert_papermode_to_metadata.py b/doc/tools/convert_papermode_to_metadata.py
index 61427c83..d4427a10 100755
--- a/doc/tools/convert_papermode_to_metadata.py
+++ b/doc/tools/convert_papermode_to_metadata.py
@@ -9,15 +9,16 @@ ranger used to store metadata in .paperinfo files, but that format was rather
 limited, so .metadata.json files were introduced.
 """
 
+from __future__ import (absolute_import, print_function)
+
 import csv
 import json
 import os
 import sys
 
-if sys.version < '3.':
-    getuserinput = raw_input
-else:
-    getuserinput = input
+if sys.version_info[0] < 3:
+    input = raw_input  # NOQA pylint: disable=undefined-variable,redefined-builtin,invalid-name
+
 
 FIELDS = ["name", "year", "title", "authors", "url"]
 
@@ -30,7 +31,7 @@ def replace(source, target):
     # Ask for user confirmation if the target file already exists
     if os.path.exists(target):
         sys.stdout.write("Warning: target file `%s' exists! Overwrite? [y/N]")
-        userinput = getuserinput()
+        userinput = input()
         if not (userinput.startswith("y") or userinput.startswith("Y")):
             print("Skipping file `%s'" % source)
             return
@@ -63,6 +64,7 @@ def replace(source, target):
     else:
         print("Skipping writing `%s' due to a lack of data" % target)
 
+
 if __name__ == "__main__":
     if set(['--help', '-h']) & set(sys.argv[1:]):
         print(__doc__.strip())
diff --git a/doc/tools/print_colors.py b/doc/tools/print_colors.py
index 8cc944ed..69436778 100755
--- a/doc/tools/print_colors.py
+++ b/doc/tools/print_colors.py
@@ -4,28 +4,29 @@ You can use this tool to display all supported colors and their color number.
 It will exit after a keypress.
 """
 
+from __future__ import (absolute_import, print_function)
+
 import curses
-from curses import *
 
 
-@wrapper
+@curses.wrapper
 def main(win):
     def print_all_colors(attr):
-        for c in range(-1, curses.COLORS):
+        for color in range(-1, curses.COLORS):
             try:
-                init_pair(c, c, 0)
+                curses.init_pair(color, color, 0)
             except Exception:
                 pass
             else:
-                win.addstr(str(c) + ' ', color_pair(c) | attr)
-    start_color()
+                win.addstr(str(color) + ' ', curses.color_pair(color) | attr)
+    curses.start_color()
     try:
-        use_default_colors()
+        curses.use_default_colors()
     except Exception:
         pass
     win.addstr("available colors: %d\n\n" % curses.COLORS)
     print_all_colors(0)
     win.addstr("\n\n")
-    print_all_colors(A_BOLD)
+    print_all_colors(curses.A_BOLD)
     win.refresh()
     win.getch()
diff --git a/doc/tools/print_keys.py b/doc/tools/print_keys.py
index 73091db4..936d9bf0 100755
--- a/doc/tools/print_keys.py
+++ b/doc/tools/print_keys.py
@@ -3,18 +3,21 @@
 You can use this tool to find out values of keypresses
 """
 
-from curses import *
+from __future__ import (absolute_import, print_function)
 
-sep = '; '
+import curses
 
 
-@wrapper
-def main(w):
-    mousemask(ALL_MOUSE_EVENTS)
-    mouseinterval(0)
+SEPARATOR = '; '
+
+
+@curses.wrapper
+def main(window):
+    curses.mousemask(curses.ALL_MOUSE_EVENTS)
+    curses.mouseinterval(0)
     while True:
-        ch = w.getch()
-        if ch == KEY_MOUSE:
-            w.addstr(repr(getmouse()) + sep)
+        char = window.getch()
+        if char == curses.KEY_MOUSE:
+            window.addstr(repr(curses.getmouse()) + SEPARATOR)
         else:
-            w.addstr(str(ch) + sep)
+            window.addstr(str(char) + SEPARATOR)
diff --git a/examples/plugin_chmod_keybindings.py b/examples/plugin_chmod_keybindings.py
index 63f42b0e..faab2345 100644
--- a/examples/plugin_chmod_keybindings.py
+++ b/examples/plugin_chmod_keybindings.py
@@ -4,12 +4,16 @@
 # It could replace the ten lines in the rc.conf that create the key bindings
 # for the "chmod" command.
 
+from __future__ import (absolute_import, print_function)
+
 import ranger.api
-old_hook_init = ranger.api.hook_init
+
+
+HOOK_INIT_OLD = ranger.api.hook_init
 
 
 def hook_init(fm):
-    old_hook_init(fm)
+    HOOK_INIT_OLD(fm)
 
     # Generate key bindings for the chmod command
     command = "map {0}{1}{2} shell -d chmod {1}{0}{2} %s"
@@ -18,4 +22,5 @@ def hook_init(fm):
             fm.execute_console(command.format('-', mode, perm))
             fm.execute_console(command.format('+', mode, perm))
 
+
 ranger.api.hook_init = hook_init
diff --git a/examples/plugin_file_filter.py b/examples/plugin_file_filter.py
index 5d5f1466..f5c474c5 100644
--- a/examples/plugin_file_filter.py
+++ b/examples/plugin_file_filter.py
@@ -4,20 +4,23 @@
 # the "show_hidden" option is activated.
 
 # Save the original filter function
+
+from __future__ import (absolute_import, print_function)
+
 import ranger.container.directory
-old_accept_file = ranger.container.directory.accept_file
 
-HIDE_FILES = ("/boot", "/sbin", "/proc", "/sys")
 
-# Define a new one
+ACCEPT_FILE_OLD = ranger.container.directory.accept_file
 
+HIDE_FILES = ("/boot", "/sbin", "/proc", "/sys")
 
-def custom_accept_file(file, filters):
-    if not file.fm.settings.show_hidden and file.path in HIDE_FILES:
+
+# Define a new one
+def custom_accept_file(fobj, filters):
+    if not fobj.fm.settings.show_hidden and fobj.path in HIDE_FILES:
         return False
-    else:
-        return old_accept_file(file, filters)
+    return ACCEPT_FILE_OLD(fobj, filters)
+
 
 # Overwrite the old function
-import ranger.container.directory
 ranger.container.directory.accept_file = custom_accept_file
diff --git a/examples/plugin_hello_world.py b/examples/plugin_hello_world.py
index 0158a653..b1451be1 100644
--- a/examples/plugin_hello_world.py
+++ b/examples/plugin_hello_world.py
@@ -3,13 +3,15 @@
 # This is a sample plugin that displays "Hello World" in ranger's console after
 # it started.
 
+from __future__ import (absolute_import, print_function)
+
 # We are going to extend the hook "ranger.api.hook_ready", so first we need
 # to import ranger.api:
 import ranger.api
 
 # Save the previously existing hook, because maybe another module already
 # extended that hook and we don't want to lose it:
-old_hook_ready = ranger.api.hook_ready
+HOOK_READY_OLD = ranger.api.hook_ready
 
 # Create a replacement for the hook that...
 
@@ -19,7 +21,8 @@ def hook_ready(fm):
     fm.notify("Hello World")
     # ...and calls the saved hook.  If you don't care about the return value,
     # simply return the return value of the previous hook to be safe.
-    return old_hook_ready(fm)
+    return HOOK_READY_OLD(fm)
+
 
 # Finally, "monkey patch" the existing hook_ready function with our replacement:
 ranger.api.hook_ready = hook_ready
diff --git a/examples/plugin_ipc.py b/examples/plugin_ipc.py
index 47fb1c84..99637272 100644
--- a/examples/plugin_ipc.py
+++ b/examples/plugin_ipc.py
@@ -7,17 +7,20 @@
 # Example:
 #   $ echo tab_new ~/images > /tmp/ranger-ipc.1234
 
+from __future__ import (absolute_import, print_function)
+
 import ranger.api
 
-old_hook_init = ranger.api.hook_init
+
+HOOK_INIT_OLD = ranger.api.hook_init
 
 
 def hook_init(fm):
     try:
         # Create a FIFO.
         import os
-        IPC_FIFO = "/tmp/ranger-ipc." + str(os.getpid())
-        os.mkfifo(IPC_FIFO)
+        ipc_fifo = "/tmp/ranger-ipc." + str(os.getpid())
+        os.mkfifo(ipc_fifo)
 
         # Start the reader thread.
         try:
@@ -30,7 +33,7 @@ def hook_init(fm):
                 with open(filepath, 'r') as fifo:
                     line = fifo.read()
                     fm.execute_console(line.strip())
-        thread.start_new_thread(ipc_reader, (IPC_FIFO,))
+        thread.start_new_thread(ipc_reader, (ipc_fifo,))
 
         # Remove the FIFO on ranger exit.
         def ipc_cleanup(filepath):
@@ -39,10 +42,12 @@ def hook_init(fm):
             except IOError:
                 pass
         import atexit
-        atexit.register(ipc_cleanup, IPC_FIFO)
+        atexit.register(ipc_cleanup, ipc_fifo)
     except IOError:
         # IPC support disabled
         pass
     finally:
-        old_hook_init(fm)
+        HOOK_INIT_OLD(fm)
+
+
 ranger.api.hook_init = hook_init
diff --git a/examples/plugin_linemode.py b/examples/plugin_linemode.py
index 851d6213..84cc57cc 100644
--- a/examples/plugin_linemode.py
+++ b/examples/plugin_linemode.py
@@ -5,7 +5,10 @@
 # the linemode by typing ":linemode rot13" in ranger.  Type Mf to restore
 # the default linemode.
 
+from __future__ import (absolute_import, print_function)
+
 import codecs
+
 import ranger.api
 from ranger.core.linemode import LinemodeBase
 
@@ -14,5 +17,8 @@ from ranger.core.linemode import LinemodeBase
 class MyLinemode(LinemodeBase):
     name = "rot13"
 
-    def filetitle(self, file, metadata):
-        return codecs.encode(file.relative_path, "rot_13")
+    def filetitle(self, fobj, metadata):
+        return codecs.encode(fobj.relative_path, "rot_13")
+
+    def infostring(self, fobj, metadata):
+        raise NotImplementedError
diff --git a/examples/plugin_new_macro.py b/examples/plugin_new_macro.py
index 8dbe435d..0e44cdd3 100644
--- a/examples/plugin_new_macro.py
+++ b/examples/plugin_new_macro.py
@@ -4,18 +4,22 @@
 # date in commands that allow macros.  You can test it with the command
 # ":shell echo %date; read"
 
-# Save the original macro function
-import ranger.core.actions
-old_get_macros = ranger.core.actions.Actions._get_macros
+from __future__ import (absolute_import, print_function)
 
-# Define a new macro function
 import time
 
+import ranger.core.actions
 
+# Save the original macro function
+GET_MACROS_OLD = ranger.core.actions.Actions._get_macros  # pylint: disable=protected-access
+
+
+# Define a new macro function
 def get_macros_with_date(self):
-    macros = old_get_macros(self)
+    macros = GET_MACROS_OLD(self)
     macros['date'] = time.strftime('%m/%d/%Y')
     return macros
 
+
 # Overwrite the old one
-ranger.core.actions.Actions._get_macros = get_macros_with_date
+ranger.core.actions.Actions._get_macros = get_macros_with_date  # pylint: disable=protected-access
diff --git a/examples/plugin_new_sorting_method.py b/examples/plugin_new_sorting_method.py
index 012bd7a2..fefeaad9 100644
--- a/examples/plugin_new_sorting_method.py
+++ b/examples/plugin_new_sorting_method.py
@@ -3,6 +3,10 @@
 # This plugin adds the sorting algorithm called 'random'.  To enable it, type
 # ":set sort=random" or create a key binding with ":map oz set sort=random"
 
-from ranger.container.directory import Directory
+from __future__ import (absolute_import, print_function)
+
 from random import random
+
+from ranger.container.directory import Directory
+
 Directory.sort_dict['random'] = lambda path: random()
diff --git a/examples/plugin_pmount.py b/examples/plugin_pmount.py
index ba61b0e5..5db85385 100644
--- a/examples/plugin_pmount.py
+++ b/examples/plugin_pmount.py
@@ -9,24 +9,37 @@
 # alt+shift+m <uppercase letter>         : unmount /dev/sd<letter>
 # alt+shift+n                            : list the devices
 
+from __future__ import (absolute_import, print_function)
+
 import ranger.api
 
 MOUNT_KEY = '<alt>m'
 UMOUNT_KEY = '<alt>M'
 LIST_MOUNTS_KEY = '<alt>N'
 
-old_hook_init = ranger.api.hook_init
+
+HOOK_INIT_OLD = ranger.api.hook_init
 
 
 def hook_init(fm):
     try:
         fm.execute_console("map {key} shell -p lsblk".format(key=LIST_MOUNTS_KEY))
         for disk in "abcdefgh":
-            fm.execute_console("map {key}{0} chain shell pmount sd{1}; cd /media/sd{1}".format(disk.upper(), disk, key=MOUNT_KEY))
-            fm.execute_console("map {key}{0} chain cd; chain shell pumount sd{1}".format(disk.upper(), disk, key=UMOUNT_KEY))
+            fm.execute_console("map {key}{0} chain shell pmount sd{1}; cd /media/sd{1}".format(
+                disk.upper(), disk, key=MOUNT_KEY))
+            fm.execute_console("map {key}{0} chain cd; chain shell pumount sd{1}".format(
+                disk.upper(), disk, key=UMOUNT_KEY))
             for part in "123456789":
-                fm.execute_console("map {key}{0}{1} chain shell pmount sd{0}{1}; cd /media/sd{0}{1}".format(disk, part, key=MOUNT_KEY))
-                fm.execute_console("map {key}{0}{1} chain cd; shell pumount sd{0}{1}".format(disk, part, key=UMOUNT_KEY))
-    finally:
-        return old_hook_init(fm)
+                fm.execute_console(
+                    "map {key}{0}{1} chain shell pmount sd{0}{1}; cd /media/sd{0}{1}".format(
+                        disk, part, key=MOUNT_KEY)
+                )
+                fm.execute_console("map {key}{0}{1} chain cd; shell pumount sd{0}{1}".format(
+                    disk, part, key=UMOUNT_KEY))
+    except Exception:
+        pass
+
+    return HOOK_INIT_OLD(fm)
+
+
 ranger.api.hook_init = hook_init
diff --git a/pylintrc b/pylintrc
new file mode 100644
index 00000000..d2729ce4
--- /dev/null
+++ b/pylintrc
@@ -0,0 +1,14 @@
+[BASIC]
+good-names=i,j,k,n,x,y,ex,Run,_,fm,ui,fg,bg
+bad-names=foo,baz,toto,tutu,tata
+
+[DESIGN]
+max-args=6
+max-branches=16
+
+[FORMAT]
+max-line-length = 99
+disable=locally-disabled,locally-enabled,missing-docstring,duplicate-code,fixme,broad-except,cyclic-import,redefined-variable-type
+
+[TYPECHECK]
+ignored-classes=ranger.core.actions.Actions
diff --git a/ranger.py b/ranger.py
index 864acf27..3aa62eec 100755
--- a/ranger.py
+++ b/ranger.py
@@ -20,20 +20,22 @@ if [ "$(cat -- "$tempfile")" != "$(echo -n `pwd`)" ]; then
 fi
 rm -f -- "$tempfile"
 return $returnvalue
-""" and None
+"""
+
+from __future__ import (absolute_import, print_function)
 
 import sys
 from os.path import exists, abspath
 
 # Need to find out whether or not the flag --clean was used ASAP,
 # because --clean is supposed to disable bytecode compilation
-argv = sys.argv[1:sys.argv.index('--')] if '--' in sys.argv else sys.argv[1:]
-sys.dont_write_bytecode = '-c' in argv or '--clean' in argv
+ARGV = sys.argv[1:sys.argv.index('--')] if '--' in sys.argv else sys.argv[1:]
+sys.dont_write_bytecode = '-c' in ARGV or '--clean' in ARGV
 
 # Don't import ./ranger when running an installed binary at /usr/.../ranger
 if __file__[:4] == '/usr' and exists('ranger') and abspath('.') in sys.path:
     sys.path.remove(abspath('.'))
 
 # Start ranger
-import ranger
-sys.exit(ranger.main())
+import ranger  # NOQA pylint: disable=import-self,wrong-import-position
+sys.exit(ranger.main())  # pylint: disable=no-member
diff --git a/ranger/__init__.py b/ranger/__init__.py
index c2aa804e..a84bf3e8 100644
--- a/ranger/__init__.py
+++ b/ranger/__init__.py
@@ -8,9 +8,10 @@ directory hierarchy.  The secondary task of ranger is to figure out which
 program you want to use to open your files with.
 """
 
+from __future__ import (absolute_import, print_function)
+
 import sys
 import os
-import tempfile
 
 # Information
 __license__ = 'GPL3'
@@ -34,4 +35,6 @@ VERSION = 'ranger-master %s\n\nPython %s' % (__version__, sys.version)
 # and the configuration directory will be $XDG_CONFIG_HOME/ranger instead.
 CONFDIR = '~/.config/ranger'
 
-from ranger.core.main import main
+args = None  # pylint: disable=invalid-name
+
+from ranger.core.main import main  # NOQA pylint: disable=wrong-import-position
diff --git a/ranger/api/__init__.py b/ranger/api/__init__.py
index 5981c31a..992dfc20 100644
--- a/ranger/api/__init__.py
+++ b/ranger/api/__init__.py
@@ -3,10 +3,15 @@
 
 """Files in this module contain helper functions used in configuration files."""
 
-# Hooks for use in plugins:
+from __future__ import (absolute_import, print_function)
+
+import ranger  # NOQA
+
+from ranger.core.linemode import LinemodeBase  # NOQA
 
 
-def hook_init(fm):
+# Hooks for use in plugins:
+def hook_init(fm):  # pylint: disable=unused-argument
     """A hook that is called when ranger starts up.
 
     Parameters:
@@ -20,7 +25,7 @@ def hook_init(fm):
     """
 
 
-def hook_ready(fm):
+def hook_ready(fm):  # pylint: disable=unused-argument
     """A hook that is called after the ranger UI is initialized.
 
     Parameters:
@@ -32,8 +37,6 @@ def hook_ready(fm):
     NOT print anything to stdout anymore from here on.  Use fm.notify instead.
     """
 
-from ranger.core.linemode import LinemodeBase
-
 
 def register_linemode(linemode_class):
     """Add a custom linemode class.  See ranger.core.linemode"""
diff --git a/ranger/api/commands.py b/ranger/api/commands.py
index 93c50adb..0a3ea470 100644
--- a/ranger/api/commands.py
+++ b/ranger/api/commands.py
@@ -3,12 +3,17 @@
 
 # TODO: Add an optional "!" to all commands and set a flag if it's there
 
+from __future__ import (absolute_import, print_function)
+
 import os
-import ranger
 import re
 import inspect
-from collections import deque
-from ranger.api import *
+# COMPAT pylint: disable=unused-import
+from collections import deque  # NOQA
+from ranger.api import LinemodeBase, hook_init, hook_ready, register_linemode  # NOQA
+# pylint: enable=unused-import
+
+import ranger
 from ranger.core.shared import FileManagerAware
 from ranger.ext.lazy_property import lazy_property
 
@@ -16,6 +21,7 @@ _SETTINGS_RE = re.compile(r'^\s*([^\s]+?)=(.*)$')
 
 
 class CommandContainer(object):
+
     def __init__(self):
         self.commands = {}
 
@@ -25,10 +31,12 @@ class CommandContainer(object):
     def alias(self, name, full_command):
         try:
             cmd = type(name, (AliasCommand, ), dict())
+            # pylint: disable=protected-access
             cmd._based_function = name
             cmd._function_name = name
             cmd._object_name = name
             cmd._line = full_command
+            # pylint: enable=protected-access
             self.commands[name] = cmd
 
         except Exception:
@@ -50,17 +58,18 @@ class CommandContainer(object):
             attribute = getattr(obj, attribute_name)
             if hasattr(attribute, '__call__'):
                 cmd = type(attribute_name, (FunctionCommand, ), dict(__doc__=attribute.__doc__))
+                # pylint: disable=protected-access
                 cmd._based_function = attribute
                 cmd._function_name = attribute.__name__
                 cmd._object_name = obj.__class__.__name__
+                # pylint: enable=protected-access
                 self.commands[attribute_name] = cmd
 
     def get_command(self, name, abbrev=True):
         if abbrev:
             lst = [cls for cmd, cls in self.commands.items()
-                    if cls.allow_abbrev and cmd.startswith(name)
-                    or cmd == name]
-            if len(lst) == 0:
+                   if cls.allow_abbrev and cmd.startswith(name) or cmd == name]
+            if not lst:
                 raise KeyError
             if len(lst) == 1:
                 return lst[0]
@@ -98,12 +107,11 @@ class Command(FileManagerAware):
             self.firstpart = ''
 
     @classmethod
-    def get_name(self):
-        classdict = self.__mro__[0].__dict__
+    def get_name(cls):
+        classdict = cls.__mro__[0].__dict__
         if 'name' in classdict and classdict['name']:
-            return self.name
-        else:
-            return self.__name__
+            return cls.name
+        return cls.__name__
 
     def execute(self):
         """Override this"""
@@ -149,9 +157,6 @@ class Command(FileManagerAware):
         self._setting_line = None
         self._shifted += 1
 
-    def tabinsert(self, word):
-        return ''.join([self._tabinsert_left, word, self._tabinsert_right])
-
     def parse_setting_line(self):
         """
         Parses the command line argument that is passed to the `:set` command.
@@ -223,7 +228,7 @@ class Command(FileManagerAware):
         flags = ""
         args = self.line.split()
         rest = ""
-        if len(args) > 0:
+        if args:
             rest = self.line[len(args[0]):].lstrip()
             for arg in args[1:]:
                 if arg == "--":
@@ -241,18 +246,6 @@ class Command(FileManagerAware):
         import logging
         return logging.getLogger('ranger.commands.' + self.__class__.__name__)
 
-    # XXX: Lazy properties? Not so smart? self.line can change after all!
-    @lazy_property
-    def _tabinsert_left(self):
-        try:
-            return self.line[:self.line[0:self.pos].rindex(' ') + 1]
-        except ValueError:
-            return ''
-
-    @lazy_property
-    def _tabinsert_right(self):
-        return self.line[self.pos:]
-
     # COMPAT: this is still used in old commands.py configs
     def _tab_only_directories(self):
         from os.path import dirname, basename, expanduser, join
@@ -280,7 +273,7 @@ class Command(FileManagerAware):
             else:
                 _, dirnames, _ = next(os.walk(abs_dirname))
                 dirnames = [dn for dn in dirnames
-                        if dn.startswith(rel_basename)]
+                            if dn.startswith(rel_basename)]
         except (OSError, StopIteration):
             # os.walk found nothing
             pass
@@ -288,7 +281,7 @@ class Command(FileManagerAware):
             dirnames.sort()
 
             # no results, return None
-            if len(dirnames) == 0:
+            if not dirnames:
                 return
 
             # one result. since it must be a directory, append a slash.
@@ -300,7 +293,7 @@ class Command(FileManagerAware):
             return (self.start(1) + join(rel_dirname, dirname)
                     for dirname in dirnames)
 
-    def _tab_directory_content(self):
+    def _tab_directory_content(self):  # pylint: disable=too-many-locals
         from os.path import dirname, basename, expanduser, join
 
         cwd = self.fm.thisdir.path
@@ -331,30 +324,28 @@ class Command(FileManagerAware):
                 else:
                     # Fall back to old method with "os.walk"
                     _, dirnames, filenames = next(os.walk(abs_dest))
-                    names = dirnames + filenames
-                    names.sort()
+                    names = sorted(dirnames + filenames)
 
             # are we in the middle of the filename?
             else:
                 if directory.content_loaded:
                     # Take the order from the directory object
                     names = [f.basename for f in directory.files
-                            if f.basename.startswith(rel_basename)]
+                             if f.basename.startswith(rel_basename)]
                     if self.fm.thisfile.basename in names:
                         i = names.index(self.fm.thisfile.basename)
                         names = names[i:] + names[:i]
                 else:
                     # Fall back to old method with "os.walk"
                     _, dirnames, filenames = next(os.walk(abs_dirname))
-                    names = [name for name in (dirnames + filenames)
-                            if name.startswith(rel_basename)]
-                    names.sort()
+                    names = sorted([name for name in (dirnames + filenames)
+                                    if name.startswith(rel_basename)])
         except (OSError, StopIteration):
             # os.walk found nothing
             pass
         else:
             # no results, return None
-            if len(names) == 0:
+            if not names:
                 return
 
             # one result. append a slash if it's a directory
@@ -370,7 +361,7 @@ class Command(FileManagerAware):
     def _tab_through_executables(self):
         from ranger.ext.get_executables import get_executables
         programs = [program for program in get_executables() if
-                program.startswith(self.rest(1))]
+                    program.startswith(self.rest(1))]
         if not programs:
             return
         if len(programs) == 1:
@@ -384,14 +375,16 @@ class FunctionCommand(Command):
     _object_name = ""
     _function_name = "unknown"
 
-    def execute(self):
+    def execute(self):  # pylint: disable=too-many-branches
         if not self._based_function:
             return
         if len(self.args) == 1:
             try:
+                # pylint: disable=not-callable
                 return self._based_function(**{'narg': self.quantifier})
+                # pylint: enable=not-callable
             except TypeError:
-                return self._based_function()
+                return self._based_function()  # pylint: disable=not-callable
 
         args, keywords = list(), dict()
         for arg in self.args[1:]:
@@ -418,20 +411,22 @@ class FunctionCommand(Command):
 
         try:
             if self.quantifier is None:
-                return self._based_function(*args, **keywords)
+                return self._based_function(*args, **keywords)  # pylint: disable=not-callable
             else:
                 try:
-                    return self._based_function(*args, **keywords)
+                    return self._based_function(*args, **keywords)  # pylint: disable=not-callable
                 except TypeError:
                     del keywords['narg']
-                    return self._based_function(*args, **keywords)
+                    return self._based_function(*args, **keywords)  # pylint: disable=not-callable
         except TypeError:
-            if ranger.arg.debug:
+            if ranger.args.debug:
                 raise
             else:
-                self.fm.notify("Bad arguments for %s.%s: %s, %s" %
-                        (self._object_name, self._function_name,
-                            repr(args), repr(keywords)), bad=True)
+                self.fm.notify(
+                    "Bad arguments for %s.%s: %s, %s" % (
+                        self._object_name, self._function_name, repr(args), repr(keywords)),
+                    bad=True,
+                )
 
 
 class AliasCommand(Command):
@@ -448,8 +443,10 @@ class AliasCommand(Command):
 
     def tab(self, tabnum):
         cmd = self._make_cmd()
-        args = inspect.signature(cmd.tab).parameters if self.fm.py3 else \
-            inspect.getargspec(cmd.tab).args
+        if self.fm.py3:
+            args = inspect.signature(cmd.tab).parameters  # pylint: disable=no-member
+        else:
+            args = inspect.getargspec(cmd.tab).args  # pylint: disable=deprecated-method
         return cmd.tab(tabnum) if 'tabnum' in args else cmd.tab()
 
     def cancel(self):
diff --git a/ranger/api/options.py b/ranger/api/options.py
index 0cce1364..a2bf4e8c 100644
--- a/ranger/api/options.py
+++ b/ranger/api/options.py
@@ -2,7 +2,13 @@
 # License: GNU GPL version 3, see the file "AUTHORS" for details.
 
 # THIS WHOLE FILE IS OBSOLETE AND EXISTS FOR BACKWARDS COMPATIBILITIY
-import re
-from re import compile as regexp
-from ranger.api import *
-from ranger.gui import color
+
+from __future__ import (absolute_import, print_function)
+
+# pylint: disable=unused-import
+import re  # NOQA
+from re import compile as regexp  # NOQA
+
+from ranger.api import LinemodeBase, hook_init, hook_ready, register_linemode  # NOQA
+from ranger.gui import color  # NOQA
+# pylint: enable=unused-import
diff --git a/ranger/colorschemes/default.py b/ranger/colorschemes/default.py
index d04e5f6a..7f4c48c5 100644
--- a/ranger/colorschemes/default.py
+++ b/ranger/colorschemes/default.py
@@ -1,14 +1,20 @@
 # This file is part of ranger, the console file manager.
 # License: GNU GPL version 3, see the file "AUTHORS" for details.
 
+from __future__ import (absolute_import, print_function)
+
 from ranger.gui.colorscheme import ColorScheme
-from ranger.gui.color import *
+from ranger.gui.color import (
+    black, blue, cyan, green, magenta, red, white, yellow, default,
+    normal, bold, reverse,
+    default_colors,
+)
 
 
 class Default(ColorScheme):
     progress_bar_color = blue
 
-    def use(self, context):
+    def use(self, context):  # pylint: disable=too-many-branches,too-many-statements
         fg, bg, attr = default_colors
 
         if context.reset:
@@ -35,7 +41,7 @@ class Default(ColorScheme):
                 fg = blue
             elif context.executable and not \
                     any((context.media, context.container,
-                        context.fifo, context.socket)):
+                         context.fifo, context.socket)):
                 attr |= bold
                 fg = green
             if context.socket:
@@ -46,7 +52,7 @@ class Default(ColorScheme):
                 if context.device:
                     attr |= bold
             if context.link:
-                fg = context.good and cyan or magenta
+                fg = cyan if context.good else magenta
             if context.tag_marker and not context.selected:
                 attr |= bold
                 if fg in (red, magenta):
@@ -74,7 +80,7 @@ class Default(ColorScheme):
         elif context.in_titlebar:
             attr |= bold
             if context.hostname:
-                fg = context.bad and red or green
+                fg = red if context.bad else green
             elif context.directory:
                 fg = blue
             elif context.tab:
diff --git a/ranger/colorschemes/jungle.py b/ranger/colorschemes/jungle.py
index fbcfab7d..00f51d5c 100644
--- a/ranger/colorschemes/jungle.py
+++ b/ranger/colorschemes/jungle.py
@@ -1,8 +1,10 @@
 # This file is part of ranger, the console file manager.
 # License: GNU GPL version 3, see the file "AUTHORS" for details.
 
-from ranger.gui.color import *
+from __future__ import (absolute_import, print_function)
+
 from ranger.colorschemes.default import Default
+from ranger.gui.color import green, red, blue
 
 
 class Scheme(Default):
diff --git a/ranger/colorschemes/snow.py b/ranger/colorschemes/snow.py
index 90090854..2e0a004f 100644
--- a/ranger/colorschemes/snow.py
+++ b/ranger/colorschemes/snow.py
@@ -1,11 +1,14 @@
 # This file is part of ranger, the console file manager.
 # License: GNU GPL version 3, see the file "AUTHORS" for details.
 
+from __future__ import (absolute_import, print_function)
+
 from ranger.gui.colorscheme import ColorScheme
-from ranger.gui.color import *
+from ranger.gui.color import default_colors, reverse, bold
 
 
 class Snow(ColorScheme):
+
     def use(self, context):
         fg, bg, attr = default_colors
 
diff --git a/ranger/colorschemes/solarized.py b/ranger/colorschemes/solarized.py
index 8cdfb5ce..ad57dd8a 100644
--- a/ranger/colorschemes/solarized.py
+++ b/ranger/colorschemes/solarized.py
@@ -5,14 +5,20 @@
 # from https://github.com/seebi/dircolors-solarized.
 # This is a modification of Roman Zimbelmann's default colorscheme.
 
+from __future__ import (absolute_import, print_function)
+
 from ranger.gui.colorscheme import ColorScheme
-from ranger.gui.color import *
+from ranger.gui.color import (
+    cyan, magenta, red, white, default,
+    normal, bold, reverse,
+    default_colors,
+)
 
 
 class Solarized(ColorScheme):
     progress_bar_color = 33
 
-    def use(self, context):
+    def use(self, context):  # pylint: disable=too-many-branches,too-many-statements
         fg, bg, attr = default_colors
 
         if context.reset:
@@ -40,7 +46,7 @@ class Solarized(ColorScheme):
                 fg = 33
             elif context.executable and not \
                     any((context.media, context.container,
-                        context.fifo, context.socket)):
+                         context.fifo, context.socket)):
                 fg = 64
                 attr |= bold
             if context.socket:
@@ -56,7 +62,7 @@ class Solarized(ColorScheme):
                 bg = 230
                 attr |= bold
             if context.link:
-                fg = context.good and 37 or 160
+                fg = 37 if context.good else 160
                 attr |= bold
                 if context.bad:
                     bg = 235
@@ -87,13 +93,13 @@ class Solarized(ColorScheme):
         elif context.in_titlebar:
             attr |= bold
             if context.hostname:
-                fg = context.bad and 16 or 255
+                fg = 16 if context.bad else 255
                 if context.bad:
                     bg = 166
             elif context.directory:
                 fg = 33
             elif context.tab:
-                fg = context.good and 47 or 33
+                fg = 47 if context.good else 33
                 bg = 239
             elif context.link:
                 fg = cyan
diff --git a/ranger/config/commands.py b/ranger/config/commands.py
index a384f427..962a6a98 100755
--- a/ranger/config/commands.py
+++ b/ranger/config/commands.py
@@ -73,17 +73,23 @@
 # File objects (for example self.fm.thisfile) have these useful attributes and
 # methods:
 #
-# cf.path: The path to the file.
-# cf.basename: The base name only.
-# cf.load_content(): Force a loading of the directories content (which
+# tfile.path: The path to the file.
+# tfile.basename: The base name only.
+# tfile.load_content(): Force a loading of the directories content (which
 #      obviously works with directories only)
-# cf.is_directory: True/False depending on whether it's a directory.
+# tfile.is_directory: True/False depending on whether it's a directory.
 #
 # For advanced commands it is unavoidable to dive a bit into the source code
 # of ranger.
 # ===================================================================
 
-from ranger.api.commands import *
+from __future__ import (absolute_import, print_function)
+
+from collections import deque
+import os
+import re
+
+from ranger.api.commands import Command
 
 
 class alias(Command):
@@ -107,6 +113,7 @@ class echo(Command):
 
     Display the text in the statusbar.
     """
+
     def execute(self):
         self.fm.notify(self.rest(1))
 
@@ -120,7 +127,6 @@ class cd(Command):
     """
 
     def execute(self):
-        import os.path
         if self.arg(1) == '-r':
             self.shift()
             destination = os.path.realpath(self.rest(1))
@@ -138,15 +144,14 @@ class cd(Command):
         else:
             self.fm.cd(destination)
 
-    def tab(self, tabnum):
-        import os
+    def tab(self, tabnum):  # pylint: disable=too-many-locals
         from os.path import dirname, basename, expanduser, join
 
         cwd = self.fm.thisdir.path
         rel_dest = self.rest(1)
 
         bookmarks = [v.path for v in self.fm.bookmarks.dct.values()
-                if rel_dest in v.path]
+                     if rel_dest in v.path]
 
         # expand the tilde into the user directory
         if rel_dest.startswith('~'):
@@ -167,7 +172,7 @@ class cd(Command):
             else:
                 _, dirnames, _ = next(os.walk(abs_dirname))
                 dirnames = [dn for dn in dirnames
-                        if dn.startswith(rel_basename)]
+                            if dn.startswith(rel_basename)]
         except (OSError, StopIteration):
             # os.walk found nothing
             pass
@@ -177,7 +182,7 @@ class cd(Command):
                 dirnames = bookmarks + dirnames
 
             # no results, return None
-            if len(dirnames) == 0:
+            if not dirnames:
                 return
 
             # one result. since it must be a directory, append a slash.
@@ -194,6 +199,7 @@ class chain(Command):
 
     Calls multiple commands at once, separated by semicolons.
     """
+
     def execute(self):
         for command in [s.strip() for s in self.rest(1).split(";")]:
             self.fm.execute_console(command)
@@ -230,28 +236,28 @@ class shell(Command):
             selection = self.fm.thistab.get_selection()
             if len(selection) == 1:
                 return self.line + selection[0].shell_escaped_basename + ' '
-            else:
-                return self.line + '%s '
-        else:
-            before_word, start_of_word = self.line.rsplit(' ', 1)
-            return (before_word + ' ' + file.shell_escaped_basename
-                    for file in self.fm.thisdir.files or []
-                    if file.shell_escaped_basename.startswith(start_of_word))
+            return self.line + '%s '
+
+        before_word, start_of_word = self.line.rsplit(' ', 1)
+        return (before_word + ' ' + file.shell_escaped_basename
+                for file in self.fm.thisdir.files or []
+                if file.shell_escaped_basename.startswith(start_of_word))
 
 
 class open_with(Command):
+
     def execute(self):
         app, flags, mode = self._get_app_flags_mode(self.rest(1))
         self.fm.execute_file(
-                files=[f for f in self.fm.thistab.get_selection()],
-                app=app,
-                flags=flags,
-                mode=mode)
+            files=[f for f in self.fm.thistab.get_selection()],
+            app=app,
+            flags=flags,
+            mode=mode)
 
     def tab(self, tabnum):
         return self._tab_through_executables()
 
-    def _get_app_flags_mode(self, string):
+    def _get_app_flags_mode(self, string):  # pylint: disable=too-many-branches,too-many-statements
         """Extracts the application, flags and mode from a string.
 
         examples:
@@ -266,10 +272,7 @@ class open_with(Command):
         mode = 0
         split = string.split()
 
-        if len(split) == 0:
-            pass
-
-        elif len(split) == 1:
+        if len(split) == 1:
             part = split[0]
             if self._is_app(part):
                 app = part
@@ -326,11 +329,13 @@ class open_with(Command):
     def _is_app(self, arg):
         return not self._is_flags(arg) and not arg.isdigit()
 
-    def _is_flags(self, arg):
+    @staticmethod
+    def _is_flags(arg):
         from ranger.core.runner import ALLOWED_FLAGS
         return all(x in ALLOWED_FLAGS for x in arg)
 
-    def _is_mode(self, arg):
+    @staticmethod
+    def _is_mode(arg):
         return all(x in '0123456789' for x in arg)
 
 
@@ -351,7 +356,7 @@ class set_(Command):
         else:
             self.fm.set_option_from_string(name, value)
 
-    def tab(self, tabnum):
+    def tab(self, tabnum):  # pylint: disable=too-many-return-statements
         from ranger.gui.colorscheme import get_all_colorschemes
         name, value, name_done = self.parse_setting_line()
         settings = self.fm.settings
@@ -359,12 +364,12 @@ class set_(Command):
             return sorted(self.firstpart + setting for setting in settings)
         if not value and not name_done:
             return sorted(self.firstpart + setting for setting in settings
-                    if setting.startswith(name))
+                          if setting.startswith(name))
         if not value:
             # Cycle through colorschemes when name, but no value is specified
             if name == "colorscheme":
                 return sorted(self.firstpart + colorscheme for colorscheme
-                        in get_all_colorschemes())
+                              in get_all_colorschemes())
             return self.firstpart + str(settings[name])
         if bool in settings.types_of(name):
             if 'true'.startswith(value.lower()):
@@ -374,7 +379,7 @@ class set_(Command):
         # Tab complete colorscheme values if incomplete value is present
         if name == "colorscheme":
             return sorted(self.firstpart + colorscheme for colorscheme
-                    in get_all_colorschemes() if colorscheme.startswith(value))
+                          in get_all_colorschemes() if colorscheme.startswith(value))
 
 
 class setlocal(set_):
@@ -385,7 +390,6 @@ class setlocal(set_):
     PATH_RE = re.compile(r'^\s*path="?(.*?)"?\s*$')
 
     def execute(self):
-        import os.path
         match = self.PATH_RE.match(self.arg(1))
         if match:
             path = os.path.normpath(os.path.expanduser(match.group(1)))
@@ -406,6 +410,7 @@ class setintag(setlocal):
 
     Sets an option for directories that are tagged with a specific tag.
     """
+
     def execute(self):
         tags = self.arg(1)
         self.shift()
@@ -414,12 +419,13 @@ class setintag(setlocal):
 
 
 class default_linemode(Command):
+
     def execute(self):
-        import re
         from ranger.container.fsobject import FileSystemObject
 
         if len(self.args) < 2:
-            self.fm.notify("Usage: default_linemode [path=<regexp> | tag=<tag(s)>] <linemode>", bad=True)
+            self.fm.notify(
+                "Usage: default_linemode [path=<regexp> | tag=<tag(s)>] <linemode>", bad=True)
 
         # Extract options like "path=..." or "tag=..." from the command line
         arg1 = self.arg(1)
@@ -435,13 +441,16 @@ class default_linemode(Command):
             self.shift()
 
         # Extract and validate the line mode from the command line
-        linemode = self.rest(1)
-        if linemode not in FileSystemObject.linemode_dict:
-            self.fm.notify("Invalid linemode: %s; should be %s" %
-                    (linemode, "/".join(FileSystemObject.linemode_dict)), bad=True)
+        lmode = self.rest(1)
+        if lmode not in FileSystemObject.linemode_dict:
+            self.fm.notify(
+                "Invalid linemode: %s; should be %s" % (
+                    lmode, "/".join(FileSystemObject.linemode_dict)),
+                bad=True,
+            )
 
         # Add the prepared entry to the fm.default_linemodes
-        entry = [method, argument, linemode]
+        entry = [method, argument, lmode]
         self.fm.default_linemodes.appendleft(entry)
 
         # Redraw the columns
@@ -450,13 +459,12 @@ class default_linemode(Command):
                 col.need_redraw = True
 
     def tab(self, tabnum):
-        mode = self.arg(1)
-        return (self.arg(0) + " " + linemode
-                for linemode in self.fm.thisfile.linemode_dict.keys()
-                if linemode.startswith(self.arg(1)))
+        return (self.arg(0) + " " + lmode
+                for lmode in self.fm.thisfile.linemode_dict.keys()
+                if lmode.startswith(self.arg(1)))
 
 
-class quit(Command):
+class quit(Command):  # pylint: disable=redefined-builtin
     """:quit
 
     Closes the current tab.  If there is only one tab, quit the program.
@@ -492,6 +500,7 @@ class terminal(Command):
 
     Spawns an "x-terminal-emulator" starting in the current directory.
     """
+
     def execute(self):
         from ranger.ext.get_executables import get_term
         self.fm.run(get_term(), flags='f')
@@ -515,36 +524,33 @@ class delete(Command):
     escape_macros_for_shell = True
 
     def execute(self):
-        import os
         import shlex
         from functools import partial
-        from ranger.container.file import File
 
-        def is_directory_with_files(f):
-            import os.path
-            return (os.path.isdir(f) and not os.path.islink(f)
-                and len(os.listdir(f)) > 0)
+        def is_directory_with_files(path):
+            return os.path.isdir(path) and not os.path.islink(path) and len(os.listdir(path)) > 0
 
         if self.rest(1):
             files = shlex.split(self.rest(1))
             many_files = (len(files) > 1 or is_directory_with_files(files[0]))
         else:
             cwd = self.fm.thisdir
-            cf = self.fm.thisfile
-            if not cwd or not cf:
+            tfile = self.fm.thisfile
+            if not cwd or not tfile:
                 self.fm.notify("Error: no file selected for deletion!", bad=True)
                 return
 
             # relative_path used for a user-friendly output in the confirmation.
             files = [f.relative_path for f in self.fm.thistab.get_selection()]
-            many_files = (cwd.marked_items or is_directory_with_files(cf.path))
+            many_files = (cwd.marked_items or is_directory_with_files(tfile.path))
 
         confirm = self.fm.settings.confirm_on_delete
         if confirm != 'never' and (confirm != 'multiple' or many_files):
-            filename_list = files
-            self.fm.ui.console.ask("Confirm deletion of: %s (y/N)" %
-                ', '.join(files),
-                partial(self._question_callback, files), ('n', 'N', 'y', 'Y'))
+            self.fm.ui.console.ask(
+                "Confirm deletion of: %s (y/N)" % ', '.join(files),
+                partial(self._question_callback, files),
+                ('n', 'N', 'y', 'Y'),
+            )
         else:
             # no need for a confirmation, just delete
             self.fm.delete(files)
@@ -586,6 +592,7 @@ class console(Command):
 
     Open the console with the given command.
     """
+
     def execute(self):
         position = None
         if self.arg(1)[0:2] == '-p':
@@ -609,13 +616,13 @@ class load_copy_buffer(Command):
         from os.path import exists
         try:
             fname = self.fm.confpath(self.copy_buffer_filename)
-            f = open(fname, 'r')
+            fobj = open(fname, 'r')
         except Exception:
-            return self.fm.notify("Cannot open %s" %
-                    (fname or self.copy_buffer_filename), bad=True)
+            return self.fm.notify(
+                "Cannot open %s" % (fname or self.copy_buffer_filename), bad=True)
         self.fm.copy_buffer = set(File(g)
-            for g in f.read().split("\n") if exists(g))
-        f.close()
+                                  for g in fobj.read().split("\n") if exists(g))
+        fobj.close()
         self.fm.ui.redraw_main_column()
 
 
@@ -630,12 +637,12 @@ class save_copy_buffer(Command):
         fname = None
         try:
             fname = self.fm.confpath(self.copy_buffer_filename)
-            f = open(fname, 'w')
+            fobj = open(fname, 'w')
         except Exception:
             return self.fm.notify("Cannot open %s" %
-                    (fname or self.copy_buffer_filename), bad=True)
-        f.write("\n".join(f.path for f in self.fm.copy_buffer))
-        f.close()
+                                  (fname or self.copy_buffer_filename), bad=True)
+        fobj.write("\n".join(fobj.path for fobj in self.fm.copy_buffer))
+        fobj.close()
 
 
 class unmark_tag(mark_tag):
@@ -724,17 +731,16 @@ class eval_(Command):
         else:
             code = self.rest(1)
             quiet = False
-        import ranger
-        global cmd, fm, p, quantifier
+        global cmd, fm, p, quantifier  # pylint: disable=invalid-name,global-variable-undefined
         fm = self.fm
         cmd = self.fm.execute_console
         p = fm.notify
         quantifier = self.quantifier
         try:
             try:
-                result = eval(code)
+                result = eval(code)  # pylint: disable=eval-used
             except SyntaxError:
-                exec(code)
+                exec(code)  # pylint: disable=exec-used
             else:
                 if result and not quiet:
                     p(result)
@@ -756,10 +762,10 @@ class rename(Command):
 
         tagged = {}
         old_name = self.fm.thisfile.relative_path
-        for f in self.fm.tags.tags:
-            if str(f).startswith(self.fm.thisfile.path):
-                tagged[f] = self.fm.tags.tags[f]
-                self.fm.tags.remove(f)
+        for fobj in self.fm.tags.tags:
+            if str(fobj).startswith(self.fm.thisfile.path):
+                tagged[fobj] = self.fm.tags.tags[fobj]
+                self.fm.tags.remove(fobj)
 
         if not new_name:
             return self.fm.notify('Syntax: rename <newname>', bad=True)
@@ -771,19 +777,20 @@ class rename(Command):
             return self.fm.notify("Can't rename: file already exists!", bad=True)
 
         if self.fm.rename(self.fm.thisfile, new_name):
-            f = File(new_name)
+            fobj = File(new_name)
             # Update bookmarks that were pointing on the previous name
             obsoletebookmarks = [b for b in self.fm.bookmarks
                                  if b[1].path == self.fm.thisfile]
             if obsoletebookmarks:
                 for key, _ in obsoletebookmarks:
-                    self.fm.bookmarks[key] = f
+                    self.fm.bookmarks[key] = fobj
                 self.fm.bookmarks.update_if_outdated()
 
-            self.fm.thisdir.pointed_obj = f
-            self.fm.thisfile = f
-            for t in tagged:
-                self.fm.tags.tags[t.replace(old_name, new_name)] = tagged[t]
+            self.fm.thisdir.pointed_obj = fobj
+            self.fm.thisfile = fobj
+
+            for fobj in tagged:
+                self.fm.tags.tags[fobj.replace(old_name, new_name)] = tagged[fobj]
                 self.fm.tags.dump()
 
     def tab(self, tabnum):
@@ -793,13 +800,14 @@ class rename(Command):
 class rename_append(Command):
     """:rename_append
 
-    Creates an open_console for the rename command, automatically placing the cursor before the file extension.
+    Creates an open_console for the rename command, automatically placing
+    the cursor before the file extension.
     """
 
     def execute(self):
-        cf = self.fm.thisfile
-        path = cf.relative_path.replace("%", "%%")
-        if path.find('.') != 0 and path.rfind('.') != -1 and not cf.is_directory:
+        tfile = self.fm.thisfile
+        path = tfile.relative_path.replace("%", "%%")
+        if path.find('.') != 0 and path.rfind('.') != -1 and not tfile.is_directory:
             self.fm.open_console('rename ' + path, position=(7 + path.rfind('.')))
         else:
             self.fm.open_console('rename ' + path)
@@ -818,21 +826,21 @@ class chmod(Command):
     """
 
     def execute(self):
-        mode = self.rest(1)
-        if not mode:
-            mode = str(self.quantifier)
+        mode_str = self.rest(1)
+        if not mode_str:
+            mode_str = str(self.quantifier)
 
         try:
-            mode = int(mode, 8)
+            mode = int(mode_str, 8)
             if mode < 0 or mode > 0o777:
                 raise ValueError
         except ValueError:
             self.fm.notify("Need an octal number between 0 and 777!", bad=True)
             return
 
-        for file in self.fm.thistab.get_selection():
+        for fobj in self.fm.thistab.get_selection():
             try:
-                os.chmod(file.path, mode)
+                os.chmod(fobj.path, mode)
             except Exception as ex:
                 self.fm.notify(ex)
 
@@ -854,7 +862,8 @@ class bulkrename(Command):
     This shell script is opened in an editor for you to review.
     After you close it, it will be executed.
     """
-    def execute(self):
+
+    def execute(self):  # pylint: disable=too-many-locals,too-many-statements
         import sys
         import tempfile
         from ranger.container.file import File
@@ -886,7 +895,7 @@ class bulkrename(Command):
         script_lines.append("# This file will be executed when you close the editor.\n")
         script_lines.append("# Please double-check everything, clear the file to abort.\n")
         script_lines.extend("mv -vi -- %s %s\n" % (esc(old), esc(new))
-                for old, new in zip(filenames, new_filenames) if old != new)
+                            for old, new in zip(filenames, new_filenames) if old != new)
         script_content = "".join(script_lines)
         if py3:
             cmdfile.write(script_content.encode("utf-8"))
@@ -930,35 +939,32 @@ class relink(Command):
     """
 
     def execute(self):
-        from ranger.container.file import File
-
         new_path = self.rest(1)
-        cf = self.fm.thisfile
+        tfile = self.fm.thisfile
 
         if not new_path:
             return self.fm.notify('Syntax: relink <newpath>', bad=True)
 
-        if not cf.is_link:
-            return self.fm.notify('%s is not a symlink!' % cf.relative_path, bad=True)
+        if not tfile.is_link:
+            return self.fm.notify('%s is not a symlink!' % tfile.relative_path, bad=True)
 
-        if new_path == os.readlink(cf.path):
+        if new_path == os.readlink(tfile.path):
             return
 
         try:
-            os.remove(cf.path)
-            os.symlink(new_path, cf.path)
+            os.remove(tfile.path)
+            os.symlink(new_path, tfile.path)
         except OSError as err:
             self.fm.notify(err)
 
         self.fm.reset()
-        self.fm.thisdir.pointed_obj = cf
-        self.fm.thisfile = cf
+        self.fm.thisdir.pointed_obj = tfile
+        self.fm.thisfile = tfile
 
     def tab(self, tabnum):
         if not self.rest(1):
             return self.line + os.readlink(self.fm.thisfile.path)
-        else:
-            return self._tab_directory_content()
+        return self._tab_directory_content()
 
 
 class help_(Command):
@@ -981,8 +987,11 @@ class help_(Command):
             elif answer == "s":
                 self.fm.dump_settings()
 
-        c = self.fm.ui.console.ask("View [m]an page, [k]ey bindings,"
-                " [c]ommands or [s]ettings? (press q to abort)", callback, list("mkcsq") + [chr(27)])
+        self.fm.ui.console.ask(
+            "View [m]an page, [k]ey bindings, [c]ommands or [s]ettings? (press q to abort)",
+            callback,
+            list("mkcsq") + [chr(27)]
+        )
 
 
 class copymap(Command):
@@ -1133,32 +1142,34 @@ class scout(Command):
     Multiple flags can be combined.  For example, ":scout -gpt" would create
     a :filter-like command using globbing.
     """
-    AUTO_OPEN       = 'a'
-    OPEN_ON_ENTER   = 'e'
-    FILTER          = 'f'
-    SM_GLOB         = 'g'
-    IGNORE_CASE     = 'i'
-    KEEP_OPEN       = 'k'
-    SM_LETTERSKIP   = 'l'
-    MARK            = 'm'
-    UNMARK          = 'M'
-    PERM_FILTER     = 'p'
-    SM_REGEX        = 'r'
-    SMART_CASE      = 's'
-    AS_YOU_TYPE     = 't'
-    INVERT          = 'v'
+    # pylint: disable=bad-whitespace
+    AUTO_OPEN     = 'a'
+    OPEN_ON_ENTER = 'e'
+    FILTER        = 'f'
+    SM_GLOB       = 'g'
+    IGNORE_CASE   = 'i'
+    KEEP_OPEN     = 'k'
+    SM_LETTERSKIP = 'l'
+    MARK          = 'm'
+    UNMARK        = 'M'
+    PERM_FILTER   = 'p'
+    SM_REGEX      = 'r'
+    SMART_CASE    = 's'
+    AS_YOU_TYPE   = 't'
+    INVERT        = 'v'
+    # pylint: enable=bad-whitespace
 
     def __init__(self, *args, **kws):
         Command.__init__(self, *args, **kws)
         self._regex = None
         self.flags, self.pattern = self.parse_flags()
 
-    def execute(self):
+    def execute(self):  # pylint: disable=too-many-branches
         thisdir = self.fm.thisdir
-        flags   = self.flags
+        flags = self.flags
         pattern = self.pattern
-        regex   = self._build_regex()
-        count   = self._count(move=True)
+        regex = self._build_regex()
+        count = self._count(move=True)
 
         self.fm.thistab.last_search = regex
         self.fm.set_search_method(order="search")
@@ -1166,12 +1177,12 @@ class scout(Command):
         if (self.MARK in flags or self.UNMARK in flags) and thisdir.files:
             value = flags.find(self.MARK) > flags.find(self.UNMARK)
             if self.FILTER in flags:
-                for f in thisdir.files:
-                    thisdir.mark_item(f, value)
+                for fobj in thisdir.files:
+                    thisdir.mark_item(fobj, value)
             else:
-                for f in thisdir.files:
-                    if regex.search(f.relative_path):
-                        thisdir.mark_item(f, value)
+                for fobj in thisdir.files:
+                    if regex.search(fobj.relative_path):
+                        thisdir.mark_item(fobj, value)
 
         if self.PERM_FILTER in flags:
             thisdir.filter = regex if pattern else None
@@ -1219,8 +1230,8 @@ class scout(Command):
         if self._regex is not None:
             return self._regex
 
-        frmat   = "%s"
-        flags   = self.flags
+        frmat = "%s"
+        flags = self.flags
         pattern = self.pattern
 
         if pattern == ".":
@@ -1251,10 +1262,12 @@ class scout(Command):
             regex = "^(?:(?!%s).)*$" % regex
 
         # Compile Regular Expression
+        # pylint: disable=no-member
         options = re.UNICODE
         if self.IGNORE_CASE in flags or self.SMART_CASE in flags and \
                 pattern.islower():
             options |= re.IGNORECASE
+        # pylint: enable=no-member
         try:
             self._regex = re.compile(regex, options)
         except Exception:
@@ -1262,8 +1275,8 @@ class scout(Command):
         return self._regex
 
     def _count(self, move=False, offset=0):
-        count   = 0
-        cwd     = self.fm.thisdir
+        count = 0
+        cwd = self.fm.thisdir
         pattern = self.pattern
 
         if not pattern or not cwd.files:
@@ -1301,19 +1314,22 @@ class filter_inode_type(Command):
         f display files
         l display links
     """
-
+    # pylint: disable=bad-whitespace
     FILTER_DIRS  = 'd'
     FILTER_FILES = 'f'
     FILTER_LINKS = 'l'
+    # pylint: enable=bad-whitespace
 
     def execute(self):
         if not self.arg(1):
             self.fm.thisdir.inode_type_filter = None
         else:
             self.fm.thisdir.inode_type_filter = lambda file: (
-                    True if ((self.FILTER_DIRS  in self.arg(1) and file.is_directory) or
-                             (self.FILTER_FILES in self.arg(1) and file.is_file and not file.is_link) or
-                             (self.FILTER_LINKS in self.arg(1) and file.is_link)) else False)
+                True if (
+                    (self.FILTER_DIRS in self.arg(1) and file.is_directory) or
+                    (self.FILTER_FILES in self.arg(1) and file.is_file and not file.is_link) or
+                    (self.FILTER_LINKS in self.arg(1) and file.is_link)
+                ) else False)
         self.fm.thisdir.refilter()
 
 
@@ -1343,8 +1359,8 @@ class flat(Command):
 
     def execute(self):
         try:
-            level = self.rest(1)
-            level = int(level)
+            level_str = self.rest(1)
+            level = int(level_str)
         except ValueError:
             level = self.quantifier
         if level < -1:
@@ -1363,6 +1379,7 @@ class stage(Command):
 
     Stage selected files for the corresponding version control system
     """
+
     def execute(self):
         from ranger.ext.vcs import VcsError
 
@@ -1383,6 +1400,7 @@ class unstage(Command):
 
     Unstage selected files for the corresponding version control system
     """
+
     def execute(self):
         from ranger.ext.vcs import VcsError
 
@@ -1441,12 +1459,11 @@ class meta(prompt_metadata):
 
     def execute(self):
         key = self.arg(1)
-        value = self.rest(1)
         update_dict = dict()
         update_dict[key] = self.rest(2)
         selection = self.fm.thistab.get_selection()
-        for f in selection:
-            self.fm.metadata.set_metadata(f.path, update_dict)
+        for fobj in selection:
+            self.fm.metadata.set_metadata(fobj.path, update_dict)
         self._process_command_stack()
 
     def tab(self, tabnum):
@@ -1454,9 +1471,8 @@ class meta(prompt_metadata):
         metadata = self.fm.metadata.get_metadata(self.fm.thisfile.path)
         if key in metadata and metadata[key]:
             return [" ".join([self.arg(0), self.arg(1), metadata[key]])]
-        else:
-            return [self.arg(0) + " " + key for key in sorted(metadata)
-                    if key.startswith(self.arg(1))]
+        return [self.arg(0) + " " + k for k in sorted(metadata)
+                if k.startswith(self.arg(1))]
 
 
 class linemode(default_linemode):
@@ -1473,13 +1489,14 @@ class linemode(default_linemode):
         mode = self.arg(1)
 
         if mode == "normal":
+            from ranger.core.linemode import DEFAULT_LINEMODE
             mode = DEFAULT_LINEMODE
 
         if mode not in self.fm.thisfile.linemode_dict:
             self.fm.notify("Unhandled linemode: `%s'" % mode, bad=True)
             return
 
-        self.fm.thisdir._set_linemode_of_children(mode)
+        self.fm.thisdir._set_linemode_of_children(mode)  # pylint: disable=protected-access
 
         # Ask the browsercolumns to redraw
         for col in self.fm.ui.browser.columns:
diff --git a/ranger/config/commands_sample.py b/ranger/config/commands_sample.py
index 1386e84e..8d0e6256 100644
--- a/ranger/config/commands_sample.py
+++ b/ranger/config/commands_sample.py
@@ -4,19 +4,20 @@
 # documentation.  Do NOT add them all here, or you may end up with defunct
 # commands when upgrading ranger.
 
-# You always need to import ranger.api.commands here to get the Command class:
-from ranger.api.commands import *
-
 # A simple command for demonstration purposes follows.
 # -----------------------------------------------------------------------------
 
+from __future__ import (absolute_import, print_function)
+
 # You can import any python module as needed.
 import os
 
-# Any class that is a subclass of "Command" will be integrated into ranger as a
-# command.  Try typing ":my_edit<ENTER>" in ranger!
+# You always need to import ranger.api.commands here to get the Command class:
+from ranger.api.commands import Command
 
 
+# Any class that is a subclass of "Command" will be integrated into ranger as a
+# command.  Try typing ":my_edit<ENTER>" in ranger!
 class my_edit(Command):
     # The so-called doc-string of the class will be visible in the built-in
     # help that is accessible by typing "?c" inside ranger.
diff --git a/ranger/config/pylintrc b/ranger/config/pylintrc
new file mode 100644
index 00000000..adec41f1
--- /dev/null
+++ b/ranger/config/pylintrc
@@ -0,0 +1,8 @@
+[BASIC]
+good-names=i,j,k,n,ex,Run,_,fm,ui,fg,bg
+class-rgx=[a-z][a-z0-9_]{1,30}$
+
+[FORMAT]
+max-line-length = 99
+max-module-lines=3000
+disable=locally-disabled,locally-enabled,missing-docstring,duplicate-code,fixme,broad-except
diff --git a/ranger/container/bookmarks.py b/ranger/container/bookmarks.py
index cb15efee..964efcae 100644
--- a/ranger/container/bookmarks.py
+++ b/ranger/container/bookmarks.py
@@ -1,6 +1,8 @@
 # This file is part of ranger, the console file manager.
 # License: GNU GPL version 3, see the file "AUTHORS" for details.
 
+from __future__ import (absolute_import, print_function)
+
 import string
 import re
 import os
@@ -115,7 +117,7 @@ class Bookmarks(object):
         except OSError:
             return
 
-        for key in set(self.dct.keys()) | set(real_dict.keys()):
+        for key in set(self.dct) | set(real_dict):
             # set some variables
             if key in self.dct:
                 current = self.dct[key]
@@ -151,16 +153,16 @@ class Bookmarks(object):
         if self.path is None:
             return
         if os.access(self.path, os.W_OK):
-            f = open(self.path + ".new", 'w')
+            fobj = open(self.path + ".new", 'w')
             for key, value in self.dct.items():
-                if type(key) == str\
+                if isinstance(key, str)\
                         and key in ALLOWED_KEYS:
                     try:
-                        f.write("{0}:{1}\n".format(str(key), str(value)))
+                        fobj.write("{0}:{1}\n".format(str(key), str(value)))
                     except Exception:
                         pass
 
-            f.close()
+            fobj.close()
             old_perms = os.stat(self.path)
             try:
                 os.chown(self.path + ".new", old_perms.st_uid, old_perms.st_gid)
@@ -178,19 +180,19 @@ class Bookmarks(object):
 
         if not os.path.exists(self.path):
             try:
-                f = open(self.path, 'w')
+                fobj = open(self.path, 'w')
             except Exception:
                 raise OSError('Cannot read the given path')
-            f.close()
+            fobj.close()
 
         if os.access(self.path, os.R_OK):
-            f = open(self.path, 'r')
-            for line in f:
+            fobj = open(self.path, 'r')
+            for line in fobj:
                 if self.load_pattern.match(line):
                     key, value = line[0], line[2:-1]
                     if key in ALLOWED_KEYS:
                         dct[key] = self.bookmarktype(value)
-            f.close()
+            fobj.close()
             return dct
         else:
             raise OSError('Cannot read the given path')
diff --git a/ranger/container/directory.py b/ranger/container/directory.py
index f46f9d55..6c34641e 100644
--- a/ranger/container/directory.py
+++ b/ranger/container/directory.py
@@ -1,12 +1,13 @@
 # This file is part of ranger, the console file manager.
 # License: GNU GPL version 3, see the file "AUTHORS" for details.
 
+from __future__ import (absolute_import, print_function)
+
 import locale
 import os.path
+from os import stat as os_stat, lstat as os_lstat
 import random
 import re
-
-from os import stat as os_stat, lstat as os_lstat
 from collections import deque
 from time import time
 
@@ -56,17 +57,17 @@ def sort_unicode_wrapper_list(old_sort_func):
     return sort_unicode
 
 
-def accept_file(file, filters):
+def accept_file(fobj, filters):
     """
     Returns True if file shall be shown, otherwise False.
     Parameters:
-        file - an instance of FileSystemObject
-        filters - an array of lambdas, each expects a file and
-                  returns True if file shall be shown,
+        fobj - an instance of FileSystemObject
+        filters - an array of lambdas, each expects a fobj and
+                  returns True if fobj shall be shown,
                   otherwise False.
     """
-    for filter in filters:
-        if filter and not filter(file):
+    for filt in filters:
+        if filt and not filt(fobj):
             return False
     return True
 
@@ -85,14 +86,15 @@ def walklevel(some_dir, level):
 
 def mtimelevel(path, level):
     mtime = os.stat(path).st_mtime
-    for dirpath, dirnames, filenames in walklevel(path, level):
+    for dirpath, dirnames, _ in walklevel(path, level):
         dirlist = [os.path.join("/", dirpath, d) for d in dirnames
-                if level == -1 or dirpath.count(os.path.sep) - path.count(os.path.sep) <= level]
+                   if level == -1 or dirpath.count(os.path.sep) - path.count(os.path.sep) <= level]
         mtime = max(mtime, max([-1] + [os.stat(d).st_mtime for d in dirlist]))
     return mtime
 
 
-class Directory(FileSystemObject, Accumulator, Loadable):
+class Directory(  # pylint: disable=too-many-instance-attributes,too-many-public-methods
+        FileSystemObject, Accumulator, Loadable):
     is_directory = True
     enterable = False
     load_generator = None
@@ -146,14 +148,13 @@ class Directory(FileSystemObject, Accumulator, Loadable):
 
         self.marked_items = list()
 
-        for opt in ('sort_directories_first', 'sort', 'sort_reverse',
-                'sort_case_insensitive'):
-            self.settings.signal_bind('setopt.' + opt,
-                    self.request_resort, weak=True, autosort=False)
+        for opt in ('sort_directories_first', 'sort', 'sort_reverse', 'sort_case_insensitive'):
+            self.settings.signal_bind('setopt.' + opt, self.request_resort,
+                                      weak=True, autosort=False)
 
         for opt in ('hidden_filter', 'show_hidden'):
-            self.settings.signal_bind('setopt.' + opt,
-                self.refilter, weak=True, autosort=False)
+            self.settings.signal_bind('setopt.' + opt, self.refilter,
+                                      weak=True, autosort=False)
 
         self.settings = LocalSettings(path, self.settings)
 
@@ -172,7 +173,7 @@ class Directory(FileSystemObject, Accumulator, Loadable):
         return self.files
 
     def mark_item(self, item, val):
-        item._mark(val)
+        item._mark(val)  # pylint: disable=protected-access
         if val:
             if item in self.files and item not in self.marked_items:
                 self.marked_items.append(item)
@@ -207,7 +208,7 @@ class Directory(FileSystemObject, Accumulator, Loadable):
 
     def _clear_marked_items(self):
         for item in self.marked_items:
-            item._mark(False)
+            item._mark(False)  # pylint: disable=protected-access
         del self.marked_items[:]
 
     def get_selection(self):
@@ -215,12 +216,13 @@ class Directory(FileSystemObject, Accumulator, Loadable):
         self._gc_marked_items()
         if not self.files:
             return []
+
         if self.marked_items:
             return [item for item in self.files if item.marked]
         elif self.pointed_obj:
             return [self.pointed_obj]
-        else:
-            return []
+
+        return []
 
     def refilter(self):
         if self.files_all is None:
@@ -233,15 +235,15 @@ class Directory(FileSystemObject, Accumulator, Loadable):
         if not self.settings.show_hidden and self.settings.hidden_filter:
             hidden_filter = re.compile(self.settings.hidden_filter)
             hidden_filter_search = hidden_filter.search
-            filters.append(lambda file: not hidden_filter_search(file.basename))
+            filters.append(lambda fobj: not hidden_filter_search(fobj.basename))
         if self.filter:
             filter_search = self.filter.search
-            filters.append(lambda file: filter_search(file.basename))
+            filters.append(lambda fobj: filter_search(fobj.basename))
         if self.inode_type_filter:
             filters.append(self.inode_type_filter)
         if self.temporary_filter:
             temporary_filter_search = self.temporary_filter.search
-            filters.append(lambda file: temporary_filter_search(file.basename))
+            filters.append(lambda fobj: temporary_filter_search(fobj.basename))
 
         self.files = [f for f in self.files_all if accept_file(f, filters)]
 
@@ -256,6 +258,7 @@ class Directory(FileSystemObject, Accumulator, Loadable):
         self.move_to_obj(self.pointed_obj)
 
     # XXX: Check for possible race conditions
+    # pylint: disable=too-many-locals,too-many-branches,too-many-statements
     def load_bit_by_bit(self):
         """An iterator that loads a part on every next() call
 
@@ -269,7 +272,7 @@ class Directory(FileSystemObject, Accumulator, Loadable):
 
         basename_is_rel_to = self.path if self.flat else None
 
-        try:
+        try:  # pylint: disable=too-many-nested-blocks
             if self.runnable:
                 yield
                 mypath = self.path
@@ -279,8 +282,12 @@ class Directory(FileSystemObject, Accumulator, Loadable):
                 if self.flat:
                     filelist = []
                     for dirpath, dirnames, filenames in walklevel(mypath, self.flat):
-                        dirlist = [os.path.join("/", dirpath, d) for d in dirnames
-                                if self.flat == -1 or dirpath.count(os.path.sep) - mypath.count(os.path.sep) <= self.flat]
+                        dirlist = [
+                            os.path.join("/", dirpath, d)
+                            for d in dirnames
+                            if self.flat == -1 or
+                            (dirpath.count(os.path.sep) - mypath.count(os.path.sep)) <= self.flat
+                        ]
                         filelist += dirlist
                         filelist += [os.path.join("/", dirpath, f) for f in filenames]
                     filenames = filelist
@@ -288,7 +295,7 @@ class Directory(FileSystemObject, Accumulator, Loadable):
                 else:
                     filelist = os.listdir(mypath)
                     filenames = [mypath + (mypath == '/' and fname or '/' + fname)
-                            for fname in filelist]
+                                 for fname in filelist]
                     self.load_content_mtime = os.stat(mypath).st_mtime
 
                 if self._cumulative_size_calculated:
@@ -347,16 +354,20 @@ class Directory(FileSystemObject, Accumulator, Loadable):
                             if item.vcs.is_root_pointer:
                                 has_vcschild = True
                             else:
-                                item.vcsstatus = item.vcs.rootvcs.status_subpath(
-                                    os.path.join(self.realpath, item.basename), is_directory=True)
+                                item.vcsstatus = \
+                                    item.vcs.rootvcs.status_subpath(  # pylint: disable=no-member
+                                        os.path.join(self.realpath, item.basename),
+                                        is_directory=True,
+                                    )
                     else:
                         item = File(name, preload=stats, path_is_abs=True,
                                     basename_is_rel_to=basename_is_rel_to)
                         item.load()
                         disk_usage += item.size
                         if self.vcs and self.vcs.track:
-                            item.vcsstatus = self.vcs.rootvcs.status_subpath(
-                                os.path.join(self.realpath, item.basename))
+                            item.vcsstatus = \
+                                self.vcs.rootvcs.status_subpath(  # pylint: disable=no-member
+                                    os.path.join(self.realpath, item.basename))
 
                     files.append(item)
                     self.percent = 100 * len(files) // len(filenames)
@@ -370,10 +381,10 @@ class Directory(FileSystemObject, Accumulator, Loadable):
                 self._clear_marked_items()
                 for item in self.files_all:
                     if item.path in marked_paths:
-                        item._mark(True)
+                        item._mark(True)  # pylint: disable=protected-access
                         self.marked_items.append(item)
                     else:
-                        item._mark(False)
+                        item._mark(False)  # pylint: disable=protected-access
 
                 self.sort()
 
@@ -397,6 +408,7 @@ class Directory(FileSystemObject, Accumulator, Loadable):
             self.fm.signal_emit("finished_loading_dir", directory=self)
             if self.vcs:
                 self.fm.ui.vcsthread.process(self)
+    # pylint: enable=too-many-locals,too-many-branches,too-many-statements
 
     def unload(self):
         self.loading = False
@@ -475,14 +487,13 @@ class Directory(FileSystemObject, Accumulator, Loadable):
             return 0
         cum = 0
         realpath = os.path.realpath
-        for dirpath, dirnames, filenames in os.walk(self.path,
-                onerror=lambda _: None):
-            for file in filenames:
+        for dirpath, _, filenames in os.walk(self.path, onerror=lambda _: None):
+            for fname in filenames:
                 try:
                     if dirpath == self.path:
-                        stat = os_stat(realpath(dirpath + "/" + file))
+                        stat = os_stat(realpath(dirpath + "/" + fname))
                     else:
-                        stat = os_stat(dirpath + "/" + file)
+                        stat = os_stat(dirpath + "/" + fname)
                     cum += stat.st_size
                 except Exception:
                     pass
@@ -491,11 +502,10 @@ class Directory(FileSystemObject, Accumulator, Loadable):
     def look_up_cumulative_size(self):
         self._cumulative_size_calculated = True
         self.size = self._get_cumulative_size()
-        self.infostring = ('-> ' if self.is_link else ' ') + \
-                human_readable(self.size)
+        self.infostring = ('-> ' if self.is_link else ' ') + human_readable(self.size)
 
     @lazy_property
-    def size(self):
+    def size(self):  # pylint: disable=method-hidden
         try:
             if self.fm.settings.automatically_count_files:
                 size = len(os.listdir(self.path))
@@ -516,15 +526,15 @@ class Directory(FileSystemObject, Accumulator, Loadable):
             return size
 
     @lazy_property
-    def infostring(self):
-        self.size  # trigger the lazy property initializer
+    def infostring(self):  # pylint: disable=method-hidden
+        self.size  # trigger the lazy property initializer pylint: disable=pointless-statement
         if self.is_link:
             return '->' + self.infostring
         return self.infostring
 
     @lazy_property
-    def runnable(self):
-        self.size  # trigger the lazy property initializer
+    def runnable(self):  # pylint: disable=method-hidden
+        self.size  # trigger the lazy property initializer pylint: disable=pointless-statement
         return self.runnable
 
     def sort_if_outdated(self):
@@ -535,7 +545,7 @@ class Directory(FileSystemObject, Accumulator, Loadable):
             return True
         return False
 
-    def move_to_obj(self, arg):
+    def move_to_obj(self, arg, attr=None):
         try:
             arg = arg.path
         except Exception:
@@ -554,10 +564,10 @@ class Directory(FileSystemObject, Accumulator, Loadable):
 
         if forward:
             generator = ((self.pointer + (x + offset)) % length
-                    for x in range(length - 1))
+                         for x in range(length - 1))
         else:
             generator = ((self.pointer - (x + offset)) % length
-                    for x in range(length - 1))
+                         for x in range(length - 1))
 
         for i in generator:
             _file = self.files[i]
@@ -638,7 +648,7 @@ class Directory(FileSystemObject, Accumulator, Loadable):
             return True
         return self.last_used + seconds < time()
 
-    def go(self, history=True):
+    def go(self, history=True):  # pylint: disable=invalid-name
         """enter the directory if the filemanager is running"""
         if self.fm:
             return self.fm.enter_dir(self.path, history=history)
@@ -649,8 +659,8 @@ class Directory(FileSystemObject, Accumulator, Loadable):
         return self.files is None or len(self.files) == 0
 
     def _set_linemode_of_children(self, mode):
-        for f in self.files:
-            f._set_linemode(mode)
+        for fobj in self.files:
+            fobj._set_linemode(mode)  # pylint: disable=protected-access
 
     def __nonzero__(self):
         """Always True"""
diff --git a/ranger/container/file.py b/ranger/container/file.py
index 3058b9db..f98be1d7 100644
--- a/ranger/container/file.py
+++ b/ranger/container/file.py
@@ -1,12 +1,15 @@
 # This file is part of ranger, the console file manager.
 # License: GNU GPL version 3, see the file "AUTHORS" for details.
 
+from __future__ import (absolute_import, print_function)
+
 import re
 from ranger.container.fsobject import FileSystemObject
 
 N_FIRST_BYTES = 256
-control_characters = set(chr(n) for n in
-        set(range(0, 9)) | set(range(14, 32)))
+# pylint: disable=invalid-name
+control_characters = set(chr(n) for n in set(range(0, 9)) | set(range(14, 32)))
+# pylint: enable=invalid-name
 
 # Don't even try to preview files which match this regular expression:
 PREVIEW_BLACKLIST = re.compile(r"""
@@ -25,7 +28,7 @@ PREVIEW_BLACKLIST = re.compile(r"""
         # ignore fully numerical file extensions:
             (\.\d+)*?
         $
-""", re.VERBOSE | re.IGNORECASE)
+""", re.VERBOSE | re.IGNORECASE)  # pylint: disable=no-member
 
 # Preview these files (almost) always:
 PREVIEW_WHITELIST = re.compile(r"""
@@ -35,7 +38,7 @@ PREVIEW_WHITELIST = re.compile(r"""
         # ignore filetype-independent suffixes:
             (\.part|\.bak|~)?
         $
-""", re.VERBOSE | re.IGNORECASE)
+""", re.VERBOSE | re.IGNORECASE)  # pylint: disable=no-member
 
 
 class File(FileSystemObject):
@@ -45,26 +48,27 @@ class File(FileSystemObject):
     preview_loading = False
 
     _linemode = "filename"
+    _firstbytes = None
 
     @property
     def firstbytes(self):
-        try:
-            return self._firstbytes
-        except Exception:
+        if self._firstbytes is None:
             try:
-                f = open(self.path, 'r')
-                self._firstbytes = f.read(N_FIRST_BYTES)
-                f.close()
+                fobj = open(self.path, 'r')
+                self._firstbytes = fobj.read(N_FIRST_BYTES)
+                fobj.close()
                 return self._firstbytes
             except Exception:
                 pass
+        else:
+            return self._firstbytes
 
     def is_binary(self):
         if self.firstbytes and control_characters & set(self.firstbytes):
             return True
         return False
 
-    def has_preview(self):
+    def has_preview(self):  # pylint: disable=too-many-return-statements
         if not self.fm.settings.preview_files:
             return False
         if self.is_socket or self.is_fifo or self.is_device:
diff --git a/ranger/container/fsobject.py b/ranger/container/fsobject.py
index 9b312e6d..36817ff4 100644
--- a/ranger/container/fsobject.py
+++ b/ranger/container/fsobject.py
@@ -1,23 +1,17 @@
 # This file is part of ranger, the console file manager.
 # License: GNU GPL version 3, see the file "AUTHORS" for details.
 
-CONTAINER_EXTENSIONS = ('7z', 'ace', 'ar', 'arc', 'bz', 'bz2', 'cab', 'cpio',
-    'cpt', 'deb', 'dgc', 'dmg', 'gz', 'iso', 'jar', 'msi', 'pkg', 'rar',
-    'shar', 'tar', 'tbz', 'tgz', 'xar', 'xpi', 'xz', 'zip')
-DOCUMENT_EXTENSIONS = ('cfg', 'css', 'cvs', 'djvu', 'doc', 'docx', 'gnm',
-    'gnumeric', 'htm', 'html', 'md', 'odf', 'odg', 'odp', 'ods', 'odt', 'pdf',
-    'pod', 'ps', 'rtf', 'sxc', 'txt', 'xls', 'xlw', 'xml', 'xslx')
-DOCUMENT_BASENAMES = ('bugs', 'bugs', 'changelog', 'copying', 'credits',
-    'hacking', 'help', 'install', 'license', 'readme', 'todo')
-
-BAD_INFO = '?'
+from __future__ import (absolute_import, print_function)
 
 import re
 from grp import getgrgid
-from os import lstat, stat, getcwd
+from os import lstat, stat
 from os.path import abspath, basename, dirname, realpath, splitext, extsep, relpath
 from pwd import getpwuid
-from ranger.core.linemode import *
+from ranger.core.linemode import (
+    DEFAULT_LINEMODE, DefaultLinemode, TitleLinemode,
+    PermissionsLinemode, FileInfoLinemode, MtimeLinemode, SizeMtimeLinemode,
+)
 from ranger.core.shared import FileManagerAware, SettingsAware
 from ranger.ext.shell_escape import shell_escape
 from ranger.ext import spawn
@@ -25,54 +19,71 @@ from ranger.ext.lazy_property import lazy_property
 from ranger.ext.human_readable import human_readable
 
 if hasattr(str, 'maketrans'):
-    maketrans = str.maketrans
+    maketrans = str.maketrans  # pylint: disable=invalid-name,no-member
 else:
-    from string import maketrans
+    from string import maketrans  # pylint: disable=no-name-in-module
+
+
+CONTAINER_EXTENSIONS = ('7z', 'ace', 'ar', 'arc', 'bz', 'bz2', 'cab', 'cpio',
+                        'cpt', 'deb', 'dgc', 'dmg', 'gz', 'iso', 'jar', 'msi', 'pkg', 'rar',
+                        'shar', 'tar', 'tbz', 'tgz', 'xar', 'xpi', 'xz', 'zip')
+DOCUMENT_EXTENSIONS = ('cfg', 'css', 'cvs', 'djvu', 'doc', 'docx', 'gnm',
+                       'gnumeric', 'htm', 'html', 'md', 'odf', 'odg', 'odp', 'ods', 'odt', 'pdf',
+                       'pod', 'ps', 'rtf', 'sxc', 'txt', 'xls', 'xlw', 'xml', 'xslx')
+DOCUMENT_BASENAMES = ('bugs', 'bugs', 'changelog', 'copying', 'credits',
+                      'hacking', 'help', 'install', 'license', 'readme', 'todo')
+
+BAD_INFO = '?'
+
+
+# pylint: disable=invalid-name
 _unsafe_chars = '\n' + ''.join(map(chr, range(32))) + ''.join(map(chr, range(128, 256)))
 _safe_string_table = maketrans(_unsafe_chars, '?' * len(_unsafe_chars))
 _extract_number_re = re.compile(r'(\d+|\D)')
 _integers = set("0123456789")
+# pylint: enable=invalid-name
 
 
 def safe_path(path):
     return path.translate(_safe_string_table)
 
 
-class FileSystemObject(FileManagerAware, SettingsAware):
+class FileSystemObject(  # pylint: disable=too-many-instance-attributes
+        FileManagerAware, SettingsAware):
     (basename,
-    relative_path,
-    relative_path_lower,
-    dirname,
-    extension,
-    infostring,
-    path,
-    permissions,
-    stat) = (None,) * 9
+     relative_path,
+     relative_path_lower,
+     dirname,
+     extension,
+     infostring,
+     path,
+     permissions,
+     stat) = (None,) * 9
 
     (content_loaded,
-    force_load,
-
-    is_device,
-    is_directory,
-    is_file,
-    is_fifo,
-    is_link,
-    is_socket,
-
-    accessible,
-    exists,       # "exists" currently means "link_target_exists"
-    loaded,
-    marked,
-    runnable,
-    stopped,
-    tagged,
-
-    audio,
-    container,
-    document,
-    image,
-    media,
-    video) = (False,) * 21
+     force_load,
+
+     is_device,
+     is_directory,
+     is_file,
+     is_fifo,
+     is_link,
+     is_socket,
+
+     accessible,
+     exists,       # "exists" currently means "link_target_exists"
+     loaded,
+     marked,
+     runnable,
+     stopped,
+     tagged,
+
+     audio,
+     container,
+     document,
+     image,
+     media,
+     video) = (False,) * 21
 
     size = 0
 
@@ -164,8 +175,8 @@ class FileSystemObject(FileManagerAware, SettingsAware):
             return str(self.stat.st_gid)
 
     for attr in ('video', 'audio', 'image', 'media', 'document', 'container'):
-        exec("%s = lazy_property("
-            "lambda self: self.set_mimetype() or self.%s)" % (attr, attr))
+        exec(  # pylint: disable=exec-used
+            "%s = lazy_property(lambda self: self.set_mimetype() or self.%s)" % (attr, attr))
 
     def __str__(self):
         """returns a string containing the absolute path"""
@@ -179,27 +190,31 @@ class FileSystemObject(FileManagerAware, SettingsAware):
 
     def set_mimetype(self):
         """assign attributes such as self.video according to the mimetype"""
-        basename = self.basename
+        bname = self.basename
         if self.extension == 'part':
-            basename = basename[0:-5]
-        self._mimetype = self.fm.mimetypes.guess_type(basename, False)[0]
+            bname = bname[0:-5]
+        # pylint: disable=attribute-defined-outside-init
+        self._mimetype = self.fm.mimetypes.guess_type(bname, False)[0]
         if self._mimetype is None:
             self._mimetype = ''
+        # pylint: enable=attribute-defined-outside-init
 
         self.video = self._mimetype.startswith('video')
         self.image = self._mimetype.startswith('image')
         self.audio = self._mimetype.startswith('audio')
         self.media = self.video or self.image or self.audio
         self.document = self._mimetype.startswith('text') \
-                or self.extension in DOCUMENT_EXTENSIONS \
-                or self.basename.lower() in DOCUMENT_BASENAMES
+            or self.extension in DOCUMENT_EXTENSIONS \
+            or self.basename.lower() in DOCUMENT_BASENAMES
         self.container = self.extension in CONTAINER_EXTENSIONS
 
+        # pylint: disable=attribute-defined-outside-init
         keys = ('video', 'audio', 'image', 'media', 'document', 'container')
         self._mimetype_tuple = tuple(key for key in keys if getattr(self, key))
 
         if self._mimetype == '':
             self._mimetype = None
+        # pylint: enable=attribute-defined-outside-init
 
     @property
     def mimetype(self):
@@ -217,7 +232,7 @@ class FileSystemObject(FileManagerAware, SettingsAware):
             self.set_mimetype()
             return self._mimetype_tuple
 
-    def mark(self, boolean):
+    def mark(self, _):
         directory = self.fm.get_directory(self.dirname)
         directory.mark_item(self)
 
@@ -249,7 +264,7 @@ class FileSystemObject(FileManagerAware, SettingsAware):
         self.permissions = None
         new_stat = None
         path = self.path
-        is_link = False
+        self.is_link = False
         if self.preload:
             new_stat = self.preload[1]
             self.is_link = new_stat.st_mode & 0o170000 == 0o120000
@@ -272,16 +287,16 @@ class FileSystemObject(FileManagerAware, SettingsAware):
         self.accessible = True if new_stat else False
         mode = new_stat.st_mode if new_stat else 0
 
-        format = mode & 0o170000
-        if format == 0o020000 or format == 0o060000:  # stat.S_IFCHR/BLK
+        fmt = mode & 0o170000
+        if fmt == 0o020000 or fmt == 0o060000:  # stat.S_IFCHR/BLK
             self.is_device = True
             self.size = 0
             self.infostring = 'dev'
-        elif format == 0o010000:  # stat.S_IFIFO
+        elif fmt == 0o010000:  # stat.S_IFIFO
             self.is_fifo = True
             self.size = 0
             self.infostring = 'fifo'
-        elif format == 0o140000:  # stat.S_IFSOCK
+        elif fmt == 0o140000:  # stat.S_IFSOCK
             self.is_socket = True
             self.size = 0
             self.infostring = 'sock'
diff --git a/ranger/container/history.py b/ranger/container/history.py
index 4e06d4b2..5a75854e 100644
--- a/ranger/container/history.py
+++ b/ranger/container/history.py
@@ -3,17 +3,22 @@
 
 # TODO: rewrite to use deque instead of list
 
+from __future__ import (absolute_import, print_function)
+
 
 class HistoryEmptyException(Exception):
     pass
 
 
 class History(object):
+
     def __init__(self, maxlen=None, unique=True):
         assert maxlen is not None, "maxlen cannot be None"
         if isinstance(maxlen, History):
+            # pylint: disable=protected-access
             self._history = list(maxlen._history)
             self._index = maxlen._index
+            # pylint: enable=protected-access
             self.maxlen = maxlen.maxlen
             self.unique = maxlen.unique
         else:
@@ -67,16 +72,18 @@ class History(object):
         """
         assert isinstance(other_history, History)
 
-        if len(self._history) == 0:
+        if not self._history:
             self._index = 0
             future_length = 0
         else:
             future_length = len(self._history) - self._index - 1
 
         self._history[:self._index] = list(
-                other_history._history[:other_history._index + 1])
+            other_history._history[:other_history._index + 1])  # pylint: disable=protected-access
         if len(self._history) > self.maxlen:
+            # pylint: disable=protected-access,invalid-unary-operand-type
             self._history = self._history[-self.maxlen:]
+            # pylint: enable=protected-access,invalid-unary-operand-type
 
         self._index = len(self._history) - future_length - 1
         assert self._index < len(self._history)
@@ -118,7 +125,7 @@ class History(object):
 
     def search(self, string, n):
         if n != 0 and string:
-            step = n > 0 and 1 or -1
+            step = 1 if n > 0 else -1
             i = self._index
             steps_left = steps_left_at_start = int(abs(n))
             while steps_left:
diff --git a/ranger/container/settings.py b/ranger/container/settings.py
index 1faf5860..a83192ca 100644
--- a/ranger/container/settings.py
+++ b/ranger/container/settings.py
@@ -1,20 +1,25 @@
 # This file is part of ranger, the console file manager.
 # License: GNU GPL version 3, see the file "AUTHORS" for details.
 
+from __future__ import (absolute_import, print_function)
+
+import re
+import os.path
 from inspect import isfunction
-from ranger.ext.signals import SignalDispatcher, Signal
+
+from ranger.ext.signals import SignalDispatcher
 from ranger.core.shared import FileManagerAware
 from ranger.gui.colorscheme import _colorscheme_name_to_class
-import re
-import os.path
 
 # Use these priority constants to trigger events at specific points in time
 # during processing of the signals "setopt" and "setopt.<some_setting_name>"
+# pylint: disable=bad-whitespace
 SIGNAL_PRIORITY_RAW        = 2.0  # signal.value will be raw
 SIGNAL_PRIORITY_SANITIZE   = 1.0  # (Internal) post-processing signal.value
 SIGNAL_PRIORITY_BETWEEN    = 0.6  # sanitized signal.value, old fm.settings.XYZ
 SIGNAL_PRIORITY_SYNC       = 0.2  # (Internal) updating fm.settings.XYZ
 SIGNAL_PRIORITY_AFTER_SYNC = 0.1  # after fm.settings.XYZ was updated
+# pylint: enable=bad-whitespace
 
 
 ALLOWED_SETTINGS = {
@@ -98,6 +103,7 @@ DEFAULT_VALUES = {
 
 
 class Settings(SignalDispatcher, FileManagerAware):
+
     def __init__(self):
         SignalDispatcher.__init__(self)
         self.__dict__['_localsettings'] = dict()
@@ -105,12 +111,10 @@ class Settings(SignalDispatcher, FileManagerAware):
         self.__dict__['_tagsettings'] = dict()
         self.__dict__['_settings'] = dict()
         for name in ALLOWED_SETTINGS:
-            self.signal_bind('setopt.' + name,
-                    self._sanitize,
-                    priority=SIGNAL_PRIORITY_SANITIZE)
-            self.signal_bind('setopt.' + name,
-                    self._raw_set_with_signal,
-                    priority=SIGNAL_PRIORITY_SYNC)
+            self.signal_bind('setopt.' + name, self._sanitize,
+                             priority=SIGNAL_PRIORITY_SANITIZE)
+            self.signal_bind('setopt.' + name, self._raw_set_with_signal,
+                             priority=SIGNAL_PRIORITY_SYNC)
 
     def _sanitize(self, signal):
         name, value = signal.setting, signal.value
@@ -122,7 +126,7 @@ class Settings(SignalDispatcher, FileManagerAware):
                 signal.value = [1, 1]
             else:
                 signal.value = [int(i) if str(i).isdigit() else 1
-                        for i in value]
+                                for i in value]
 
         elif name == 'colorscheme':
             _colorscheme_name_to_class(signal)
@@ -139,7 +143,7 @@ class Settings(SignalDispatcher, FileManagerAware):
             if self._settings['preview_script'] is None and value \
                     and self.fm.ui.is_on:
                 self.fm.notify("Preview script undefined or not found!",
-                        bad=True)
+                               bad=True)
 
     def set(self, name, value, path=None, tags=None):
         assert name in ALLOWED_SETTINGS, "No such setting: {0}!".format(name)
@@ -151,7 +155,7 @@ class Settings(SignalDispatcher, FileManagerAware):
         assert not (tags and path), "Can't set a setting for path and tag " \
             "at the same time!"
         kws = dict(setting=name, value=value, previous=previous,
-                path=path, tags=tags, fm=self.fm)
+                   path=path, tags=tags, fm=self.fm)
         self.signal_emit('setopt', **kws)
         self.signal_emit('setopt.' + name, **kws)
 
@@ -170,20 +174,20 @@ class Settings(SignalDispatcher, FileManagerAware):
                 if name in self._localsettings[pattern] and\
                         regex.search(localpath):
                     return self._localsettings[pattern][name]
+
         if self._tagsettings and path:
             realpath = os.path.realpath(path)
             if realpath in self.fm.tags:
                 tag = self.fm.tags.marker(realpath)
                 if tag in self._tagsettings and name in self._tagsettings[tag]:
                     return self._tagsettings[tag][name]
-        if name in self._settings:
-            return self._settings[name]
-        else:
+
+        if name not in self._settings:
             type_ = self.types_of(name)[0]
             value = DEFAULT_VALUES[type_]
             self._raw_set(name, value)
             self.__setattr__(name, value)
-            return self._settings[name]
+        return self._settings[name]
 
     def __setattr__(self, name, value):
         if name.startswith('_'):
@@ -194,14 +198,14 @@ class Settings(SignalDispatcher, FileManagerAware):
     def __getattr__(self, name):
         if name.startswith('_'):
             return self.__dict__[name]
-        else:
-            return self.get(name, None)
+        return self.get(name, None)
 
     def __iter__(self):
-        for x in self._settings:
-            yield x
+        for setting in self._settings:
+            yield setting
 
-    def types_of(self, name):
+    @staticmethod
+    def types_of(name):
         try:
             typ = ALLOWED_SETTINGS[name]
         except KeyError:
@@ -209,8 +213,7 @@ class Settings(SignalDispatcher, FileManagerAware):
         else:
             if isinstance(typ, tuple):
                 return typ
-            else:
-                return (typ, )
+            return (typ,)
 
     def _check_type(self, name, value):
         typ = ALLOWED_SETTINGS[name]
@@ -258,7 +261,8 @@ class Settings(SignalDispatcher, FileManagerAware):
         self._raw_set(signal.setting, signal.value, signal.path, signal.tags)
 
 
-class LocalSettings():
+class LocalSettings(object):  # pylint: disable=too-few-public-methods
+
     def __init__(self, path, parent):
         self.__dict__['_parent'] = parent
         self.__dict__['_path'] = path
@@ -272,12 +276,11 @@ class LocalSettings():
     def __getattr__(self, name):
         if name.startswith('_'):
             return self.__dict__[name]
-        else:
-            return self._parent.get(name, self._path)
+        return self._parent.get(name, self._path)
 
     def __iter__(self):
-        for x in self._parent._settings:
-            yield x
+        for setting in self._parent._settings:  # pylint: disable=protected-access
+            yield setting
 
     __getitem__ = __getattr__
     __setitem__ = __setattr__
diff --git a/ranger/container/tags.py b/ranger/container/tags.py
index cf2f359d..dd13c432 100644
--- a/ranger/container/tags.py
+++ b/ranger/container/tags.py
@@ -3,6 +3,8 @@
 
 # TODO: add a __getitem__ method to get the tag of a file
 
+from __future__ import (absolute_import, print_function)
+
 from os.path import isdir, exists, dirname, abspath, realpath, expanduser
 import string
 import sys
@@ -39,7 +41,7 @@ class Tags(object):
         self.sync()
         for item in items:
             try:
-                del(self.tags[item])
+                del self.tags[item]
             except KeyError:
                 pass
         self.dump()
@@ -56,7 +58,7 @@ class Tags(object):
         for item in items:
             try:
                 if item in self and tag in (self.tags[item], self.default_tag):
-                    del(self.tags[item])
+                    del self.tags[item]
                 else:
                     self.tags[item] = tag
             except KeyError:
@@ -66,41 +68,40 @@ class Tags(object):
     def marker(self, item):
         if item in self.tags:
             return self.tags[item]
-        else:
-            return self.default_tag
+        return self.default_tag
 
     def sync(self):
         try:
             if sys.version_info[0] >= 3:
-                f = open(self._filename, 'r', errors='replace')
+                fobj = open(self._filename, 'r', errors='replace')
             else:
-                f = open(self._filename, 'r')
+                fobj = open(self._filename, 'r')
         except OSError:
             pass
         else:
-            self.tags = self._parse(f)
-            f.close()
+            self.tags = self._parse(fobj)
+            fobj.close()
 
     def dump(self):
         try:
-            f = open(self._filename, 'w')
+            fobj = open(self._filename, 'w')
         except OSError:
             pass
         else:
-            self._compile(f)
-            f.close()
+            self._compile(fobj)
+            fobj.close()
 
-    def _compile(self, f):
+    def _compile(self, fobj):
         for path, tag in self.tags.items():
             if tag == self.default_tag:
                 # COMPAT: keep the old format if the default tag is used
-                f.write(path + '\n')
+                fobj.write(path + '\n')
             elif tag in ALLOWED_KEYS:
-                f.write('{0}:{1}\n'.format(tag, path))
+                fobj.write('{0}:{1}\n'.format(tag, path))
 
-    def _parse(self, f):
+    def _parse(self, fobj):
         result = dict()
-        for line in f:
+        for line in fobj:
             line = line.strip()
             if len(line) > 2 and line[1] == ':':
                 tag, path = line[0], line[2:]
@@ -122,7 +123,7 @@ class TagsDummy(Tags):
     It acts like there are no tags and avoids writing any changes.
     """
 
-    def __init__(self, filename):
+    def __init__(self, filename):  # pylint: disable=super-init-not-called
         self.tags = dict()
 
     def __contains__(self, item):
@@ -131,7 +132,7 @@ class TagsDummy(Tags):
     def add(self, *items, **others):
         pass
 
-    def remove(self, *items, **others):
+    def remove(self, *items):
         pass
 
     def toggle(self, *items, **others):
@@ -146,8 +147,8 @@ class TagsDummy(Tags):
     def dump(self):
         pass
 
-    def _compile(self, f):
+    def _compile(self, fobj):
         pass
 
-    def _parse(self, f):
+    def _parse(self, fobj):
         pass
diff --git a/ranger/core/actions.py b/ranger/core/actions.py
index 8bbf1b62..070bda8c 100644
--- a/ranger/core/actions.py
+++ b/ranger/core/actions.py
@@ -1,14 +1,18 @@
 # This file is part of ranger, the console file manager.
 # License: GNU GPL version 3, see the file "AUTHORS" for details.
 
+# pylint: disable=too-many-lines,attribute-defined-outside-init
+
+from __future__ import (absolute_import, print_function)
+
 import codecs
 import os
+from os import link, symlink, getcwd, listdir, stat
+from os.path import join, isdir, realpath, exists
 import re
 import shutil
 import string
 import tempfile
-from os.path import join, isdir, realpath, exists
-from os import link, symlink, getcwd, listdir, stat
 from inspect import cleandoc
 from stat import S_IEXEC
 from hashlib import sha1
@@ -28,11 +32,10 @@ from ranger.container.directory import Directory
 from ranger.container.file import File
 from ranger.core.loader import CommandLoader, CopyLoader
 from ranger.container.settings import ALLOWED_SETTINGS, ALLOWED_VALUES
-from ranger.core.linemode import DEFAULT_LINEMODE
 
 MACRO_FAIL = "<\x01\x01MACRO_HAS_NO_VALUE\x01\01>"
 
-log = getLogger(__name__)
+LOG = getLogger(__name__)
 
 
 class _MacroTemplate(string.Template):
@@ -41,12 +44,15 @@ class _MacroTemplate(string.Template):
     idpattern = r"[_a-z0-9]*"
 
 
-class Actions(FileManagerAware, SettingsAware):
+class Actions(  # pylint: disable=too-many-instance-attributes,too-many-public-methods
+        FileManagerAware, SettingsAware):
+
     # --------------------------
     # -- Basic Commands
     # --------------------------
 
-    def exit(self):
+    @staticmethod
+    def exit():
         """:exit
 
         Exit the program.
@@ -71,17 +77,17 @@ class Actions(FileManagerAware, SettingsAware):
 
         Change mode to "visual" (selection) or "normal" mode.
         """
-        if mode == self.mode:
+        if mode == self.mode:  # pylint: disable=access-member-before-definition
             return
         if mode == 'visual':
-            self._visual_start       = self.thisdir.pointed_obj
-            self._visual_start_pos   = self.thisdir.pointer
+            self._visual_start = self.thisdir.pointed_obj
+            self._visual_start_pos = self.thisdir.pointer
             self._previous_selection = set(self.thisdir.marked_items)
             self.mark_files(val=not self._visual_reverse, movedown=False)
         elif mode == 'normal':
-            if self.mode == 'visual':
-                self._visual_start       = None
-                self._visual_start_pos   = None
+            if self.mode == 'visual':  # pylint: disable=access-member-before-definition
+                self._visual_start = None
+                self._visual_start_pos = None
                 self._previous_selection = None
         else:
             return
@@ -90,12 +96,12 @@ class Actions(FileManagerAware, SettingsAware):
 
     def set_option_from_string(self, option_name, value, localpath=None, tags=None):
         if option_name not in ALLOWED_SETTINGS:
-            raise ValueError("The option named `%s' does not exist" %
-                    option_name)
+            raise ValueError("The option named `%s' does not exist" % option_name)
         if not isinstance(value, str):
             raise ValueError("The value for an option needs to be a string.")
 
-        self.settings.set(option_name, self._parse_option_value(option_name, value), localpath, tags)
+        self.settings.set(option_name, self._parse_option_value(option_name, value),
+                          localpath, tags)
 
     def _parse_option_value(self, name, value):
         types = self.fm.settings.types_of(name)
@@ -104,7 +110,7 @@ class Actions(FileManagerAware, SettingsAware):
                 return False
             elif value.lower() in ('true', 'on', '1'):
                 return True
-        if type(None) in types and value.lower() == 'none':
+        if isinstance(None, types) and value.lower() == 'none':
             return None
         if int in types:
             try:
@@ -149,16 +155,16 @@ class Actions(FileManagerAware, SettingsAware):
         Display the text in the statusbar.
         """
         if isinstance(text, Exception):
-            if ranger.arg.debug:
-                raise
+            if ranger.args.debug:
+                raise text
             bad = True
-        elif bad is True and ranger.arg.debug:
+        elif bad is True and ranger.args.debug:
             raise Exception(str(text))
         text = str(text)
-        log.debug("Command notify invoked: [Bad: {0}, Text: '{1}']".format(bad, text))
+        LOG.debug("Command notify invoked: [Bad: %s, Text: '%s']", bad, text)
         if self.ui and self.ui.is_on:
             self.ui.status.notify("  ".join(text.split("\n")),
-                    duration=duration, bad=bad)
+                                  duration=duration, bad=bad)
         else:
             print(text)
 
@@ -176,8 +182,8 @@ class Actions(FileManagerAware, SettingsAware):
             self.loader.remove(index=0)
 
     def get_cumulative_size(self):
-        for f in self.thistab.get_selection() or ():
-            f.look_up_cumulative_size()
+        for fobj in self.thistab.get_selection() or ():
+            fobj.look_up_cumulative_size()
         self.ui.status.request_redraw()
         self.ui.redraw_main_column()
 
@@ -188,7 +194,8 @@ class Actions(FileManagerAware, SettingsAware):
         """
         self.ui.redraw_window()
 
-    def open_console(self, string='', prompt=None, position=None):
+    def open_console(self, string='',  # pylint: disable=redefined-outer-name
+                     prompt=None, position=None):
         """:open_console [string]
 
         Open the console.
@@ -196,7 +203,8 @@ class Actions(FileManagerAware, SettingsAware):
         self.change_mode('normal')
         self.ui.open_console(string, prompt=prompt, position=position)
 
-    def execute_console(self, string='', wildcards=[], quantifier=None):
+    def execute_console(self, string='',  # pylint: disable=redefined-outer-name
+                        wildcards=None, quantifier=None):
         """:execute_console [string]
 
         Execute a command for the console
@@ -209,28 +217,30 @@ class Actions(FileManagerAware, SettingsAware):
         cmd = cmd_class(string)
         if cmd.resolve_macros and _MacroTemplate.delimiter in string:
             macros = dict(('any%d' % i, key_to_string(char))
-                    for i, char in enumerate(wildcards))
+                          for i, char in enumerate(wildcards if wildcards is not None else []))
             if 'any0' in macros:
                 macros['any'] = macros['any0']
             try:
                 string = self.substitute_macros(string, additional=macros,
-                        escape=cmd.escape_macros_for_shell)
-            except ValueError as e:
-                if ranger.arg.debug:
+                                                escape=cmd.escape_macros_for_shell)
+            except ValueError as ex:
+                if ranger.args.debug:
                     raise
                 else:
-                    return self.notify(e)
+                    return self.notify(ex)
         try:
             cmd_class(string, quantifier=quantifier).execute()
-        except Exception as e:
-            if ranger.arg.debug:
+        except Exception as ex:
+            if ranger.args.debug:
                 raise
             else:
-                self.notify(e)
+                self.notify(ex)
 
-    def substitute_macros(self, string, additional=dict(), escape=False):
+    def substitute_macros(self, string,  # pylint: disable=redefined-outer-name
+                          additional=None, escape=False):
         macros = self._get_macros()
-        macros.update(additional)
+        if additional:
+            macros.update(additional)
         if escape:
             for key, value in macros.items():
                 if isinstance(value, list):
@@ -246,7 +256,7 @@ class Actions(FileManagerAware, SettingsAware):
             raise ValueError("Could not apply macros to `%s'" % string)
         return result
 
-    def _get_macros(self):
+    def _get_macros(self):  # pylint: disable=too-many-branches,too-many-statements
         macros = {}
 
         macros['rangerdir'] = ranger.RANGERDIR
@@ -260,7 +270,7 @@ class Actions(FileManagerAware, SettingsAware):
 
         if self.fm.thistab.get_selection:
             macros['p'] = [os.path.join(self.fm.thisdir.path, fl.relative_path)
-                    for fl in self.fm.thistab.get_selection()]
+                           for fl in self.fm.thistab.get_selection()]
             macros['s'] = [fl.relative_path for fl in self.fm.thistab.get_selection()]
         else:
             macros['p'] = MACRO_FAIL
@@ -273,7 +283,7 @@ class Actions(FileManagerAware, SettingsAware):
 
         if self.fm.thisdir.files:
             macros['t'] = [fl.relative_path for fl in self.fm.thisdir.files
-                    if fl.realpath in (self.fm.tags or [])]
+                           if fl.realpath in self.fm.tags or []]
         else:
             macros['t'] = MACRO_FAIL
 
@@ -295,7 +305,7 @@ class Actions(FileManagerAware, SettingsAware):
             macros[i + 'd'] = tabdir.path
             if tabdir.get_selection():
                 macros[i + 'p'] = [os.path.join(tabdir.path, fl.relative_path)
-                        for fl in tabdir.get_selection()]
+                                   for fl in tabdir.get_selection()]
                 macros[i + 's'] = [fl.path for fl in tabdir.get_selection()]
             else:
                 macros[i + 'p'] = MACRO_FAIL
@@ -329,7 +339,7 @@ class Actions(FileManagerAware, SettingsAware):
                 macros['F'] = MACRO_FAIL
             if next_tab_dir.get_selection():
                 macros['P'] = [os.path.join(next_tab.path, fl.path)
-                        for fl in next_tab.get_selection()]
+                               for fl in next_tab.get_selection()]
                 macros['S'] = [fl.path for fl in next_tab.get_selection()]
             else:
                 macros['P'] = MACRO_FAIL
@@ -347,20 +357,19 @@ class Actions(FileManagerAware, SettingsAware):
         Load a config file.
         """
         filename = os.path.expanduser(filename)
-        log.debug("Sourcing config file '{0}'".format(filename))
-        with open(filename, 'r') as f:
-            for line in f:
+        LOG.debug("Sourcing config file '%s'", filename)
+        with open(filename, 'r') as fobj:
+            for line in fobj:
                 line = line.strip(" \r\n")
                 if line.startswith("#") or not line.strip():
                     continue
                 try:
                     self.execute_console(line)
-                except Exception as e:
-                    if ranger.arg.debug:
+                except Exception as ex:
+                    if ranger.args.debug:
                         raise
                     else:
-                        self.notify('Error in line `%s\':\n  %s' %
-                                (line, str(e)), bad=True)
+                        self.notify('Error in line `%s\':\n  %s' % (line, str(ex)), bad=True)
 
     def execute_file(self, files, **kw):
         """Uses the "rifle" module to open/execute a file
@@ -379,19 +388,19 @@ class Actions(FileManagerAware, SettingsAware):
 
         # ranger can act as a file chooser when running with --choosefile=...
         if mode == 0 and 'label' not in kw:
-            if ranger.arg.choosefile:
-                open(ranger.arg.choosefile, 'w').write(self.fm.thisfile.path)
+            if ranger.args.choosefile:
+                open(ranger.args.choosefile, 'w').write(self.fm.thisfile.path)
 
-            if ranger.arg.choosefiles:
-                open(ranger.arg.choosefiles, 'w').write("".join(
-                    f.path + "\n" for f in self.fm.thistab.get_selection()))
+            if ranger.args.choosefiles:
+                open(ranger.args.choosefiles, 'w').write("".join(
+                    fobj.path + "\n" for fobj in self.fm.thistab.get_selection()))
 
-            if ranger.arg.choosefile or ranger.arg.choosefiles:
+            if ranger.args.choosefile or ranger.args.choosefiles:
                 raise SystemExit()
 
         if isinstance(files, set):
             files = list(files)
-        elif type(files) not in (list, tuple):
+        elif not isinstance(files, (list, tuple)):
             files = [files]
 
         flags = kw.get('flags', '')
@@ -399,7 +408,7 @@ class Actions(FileManagerAware, SettingsAware):
             files = [self.fm.thisfile]
 
         self.signal_emit('execute.before', keywords=kw)
-        filenames = [f.path for f in files]
+        filenames = [fobj.path for fobj in files]
         label = kw.get('label', kw.get('app', None))
         try:
             return self.rifle.execute(filenames, mode, label, flags, None)
@@ -410,7 +419,7 @@ class Actions(FileManagerAware, SettingsAware):
     # -- Moving Around
     # --------------------------
 
-    def move(self, narg=None, **kw):
+    def move(self, narg=None, **kw):  # pylint: disable=too-many-locals,too-many-branches
         """A universal movement method.
 
         Accepts these parameters:
@@ -442,19 +451,19 @@ class Actions(FileManagerAware, SettingsAware):
                 mode = 0
                 if narg is not None:
                     mode = narg
-                cf = self.thisfile
+                tfile = self.thisfile
                 selection = self.thistab.get_selection()
-                if not self.thistab.enter_dir(cf) and selection:
+                if not self.thistab.enter_dir(tfile) and selection:
                     result = self.execute_file(selection, mode=mode)
                     if result in (False, ASK_COMMAND):
                         self.open_console('open_with ')
             elif direction.vertical() and cwd.files:
                 newpos = direction.move(
-                        direction=direction.down(),
-                        override=narg,
-                        maximum=len(cwd),
-                        current=cwd.pointer,
-                        pagesize=self.ui.browser.hei)
+                    direction=direction.down(),
+                    override=narg,
+                    maximum=len(cwd),
+                    current=cwd.pointer,
+                    pagesize=self.ui.browser.hei)
                 cwd.move(to=newpos)
                 if self.mode == 'visual':
                     try:
@@ -463,8 +472,7 @@ class Actions(FileManagerAware, SettingsAware):
                         self._visual_start = None
                         startpos = min(self._visual_start_pos, len(cwd))
                     # The files between here and _visual_start_pos
-                    targets = set(cwd.files[min(startpos, newpos):
-                            max(startpos, newpos) + 1])
+                    targets = set(cwd.files[min(startpos, newpos):(max(startpos, newpos) + 1)])
                     # The selection before activating visual mode
                     old = self._previous_selection
                     # The current selection
@@ -472,15 +480,15 @@ class Actions(FileManagerAware, SettingsAware):
 
                     # Set theory anyone?
                     if not self._visual_reverse:
-                        for f in targets - current:
-                            cwd.mark_item(f, True)
-                        for f in current - old - targets:
-                            cwd.mark_item(f, False)
+                        for fobj in targets - current:
+                            cwd.mark_item(fobj, True)
+                        for fobj in current - old - targets:
+                            cwd.mark_item(fobj, False)
                     else:
-                        for f in targets & current:
-                            cwd.mark_item(f, False)
-                        for f in old - current - targets:
-                            cwd.mark_item(f, True)
+                        for fobj in targets & current:
+                            cwd.mark_item(fobj, False)
+                        for fobj in old - current - targets:
+                            cwd.mark_item(fobj, True)
                 if self.ui.pager.visible:
                     self.display_file()
 
@@ -520,8 +528,8 @@ class Actions(FileManagerAware, SettingsAware):
         cdpath = os.environ.get('CDPATH', None) or os.environ.get('cdpath', None)
         result = self.thistab.enter_dir(path, history=history)
         if result is False and cdpath:
-            for p in cdpath.split(':'):
-                curpath = os.path.join(p, path)
+            for comp in cdpath.split(':'):
+                curpath = os.path.join(comp, path)
                 if os.path.isdir(curpath):
                     result = self.thistab.enter_dir(curpath, history=history)
                     break
@@ -531,16 +539,16 @@ class Actions(FileManagerAware, SettingsAware):
             self.change_mode('normal')
         return result
 
-    def cd(self, path, remember=True):
+    def cd(self, path, remember=True):  # pylint: disable=invalid-name
         """enter the directory at the given path, remember=True"""
         self.enter_dir(path, remember=remember)
 
     def traverse(self):
         self.change_mode('normal')
-        cf = self.thisfile
+        tfile = self.thisfile
         cwd = self.thisdir
-        if cf is not None and cf.is_directory:
-            self.enter_dir(cf.path)
+        if tfile is not None and tfile.is_directory:
+            self.enter_dir(tfile.path)
         elif cwd.pointer >= len(cwd) - 1:
             while True:
                 self.move(left=1)
@@ -583,7 +591,7 @@ class Actions(FileManagerAware, SettingsAware):
     def execute_command(self, cmd, **kw):
         return self.run(cmd, **kw)
 
-    def edit_file(self, file=None):
+    def edit_file(self, file=None):  # pylint: disable=redefined-builtin
         """Calls execute_file with the current file and label='editor'"""
         if file is None:
             file = self.thisfile
@@ -593,7 +601,7 @@ class Actions(FileManagerAware, SettingsAware):
             return
         self.execute_file(file, label='editor')
 
-    def toggle_option(self, string):
+    def toggle_option(self, string):  # pylint: disable=redefined-outer-name
         """:toggle_option <string>
 
         Toggle a boolean option named <string>.
@@ -603,7 +611,7 @@ class Actions(FileManagerAware, SettingsAware):
         elif string in ALLOWED_VALUES:
             current = self.settings[string]
             allowed = ALLOWED_VALUES[string]
-            if len(allowed) > 0:
+            if allowed:
                 if current not in allowed and current == "":
                     current = allowed[0]
                 if current in allowed:
@@ -626,7 +634,8 @@ class Actions(FileManagerAware, SettingsAware):
         if func is not None:
             self.settings['sort'] = str(func)
 
-    def mark_files(self, all=False, toggle=False, val=None, movedown=None, narg=None):
+    def mark_files(self, all=False,  # pylint: disable=redefined-builtin,too-many-arguments
+                   toggle=False, val=None, movedown=None, narg=None):
         """A wrapper for the directory.mark_xyz functions.
 
         Arguments:
@@ -680,7 +689,7 @@ class Actions(FileManagerAware, SettingsAware):
         cwd = self.thisdir
         direction = Direction(dirarg)
         pos, selected = direction.select(lst=cwd.files, current=cwd.pointer,
-                pagesize=self.ui.termsize[0])
+                                         pagesize=self.ui.termsize[0])
         cwd.pointer = pos
         cwd.correct_pointer()
         for item in selected:
@@ -693,7 +702,7 @@ class Actions(FileManagerAware, SettingsAware):
     def search_file(self, text, offset=1, regexp=True):
         if isinstance(text, str) and regexp:
             try:
-                text = re.compile(text, re.U | re.I)
+                text = re.compile(text, re.UNICODE | re.IGNORECASE)  # pylint: disable=no-member
             except Exception:
                 return False
         self.thistab.last_search = text
@@ -713,11 +722,14 @@ class Actions(FileManagerAware, SettingsAware):
                 if arg is None:
                     return False
                 if hasattr(arg, 'search'):
-                    fnc = lambda x: arg.search(x.basename)
+                    def fnc(obj):
+                        return arg.search(obj.basename)
                 else:
-                    fnc = lambda x: arg in x.basename
+                    def fnc(obj):
+                        return arg in obj.basename
             elif order == 'tag':
-                fnc = lambda x: x.realpath in self.tags
+                def fnc(obj):
+                    return obj.realpath in self.tags
 
             return self.thisdir.search_fnc(fnc=fnc, offset=offset, forward=forward)
 
@@ -726,24 +738,28 @@ class Actions(FileManagerAware, SettingsAware):
             if original_order is not None or not cwd.cycle_list:
                 lst = list(cwd.files)
                 if order == 'size':
-                    fnc = lambda item: -item.size
+                    def fnc(item):
+                        return -item.size
                 elif order == 'mimetype':
-                    fnc = lambda item: item.mimetype or ''
+                    def fnc(item):
+                        return item.mimetype or ''
                 elif order == 'ctime':
-                    fnc = lambda item: -int(item.stat and item.stat.st_ctime)
+                    def fnc(item):
+                        return -int(item.stat and item.stat.st_ctime)
                 elif order == 'atime':
-                    fnc = lambda item: -int(item.stat and item.stat.st_atime)
+                    def fnc(item):
+                        return -int(item.stat and item.stat.st_atime)
                 elif order == 'mtime':
-                    fnc = lambda item: -int(item.stat and item.stat.st_mtime)
+                    def fnc(item):
+                        return -int(item.stat and item.stat.st_mtime)
                 lst.sort(key=fnc)
                 cwd.set_cycle_list(lst)
                 return cwd.cycle(forward=None)
 
             return cwd.cycle(forward=forward)
 
-    def set_search_method(self, order, forward=True):
-        if order in ('search', 'tag', 'size', 'mimetype', 'ctime',
-                'mtime', 'atime'):
+    def set_search_method(self, order, forward=True):  # pylint: disable=unused-argument
+        if order in ('search', 'tag', 'size', 'mimetype', 'ctime', 'mtime', 'atime'):
             self.search_method = order
 
     # --------------------------
@@ -826,12 +842,11 @@ class Actions(FileManagerAware, SettingsAware):
         except Exception:
             self.ui.browser.draw_info = []
             return
-        programs = [program for program in self.rifle.list_commands([target.path],
-                None)]
+        programs = [program for program in self.rifle.list_commands([target.path], None)]
         if programs:
             num_digits = max((len(str(program[0])) for program in programs))
-            program_info = ['%s | %s' % (str(program[0]).rjust(num_digits),
-                    program[1]) for program in programs]
+            program_info = ['%s | %s' % (str(program[0]).rjust(num_digits), program[1])
+                            for program in programs]
             self.ui.browser.draw_info = program_info
 
     def hide_console_info(self):
@@ -844,7 +859,7 @@ class Actions(FileManagerAware, SettingsAware):
 
     def display_command_help(self, console_widget):
         try:
-            command = console_widget._get_cmd_class()
+            command = console_widget._get_cmd_class()  # pylint: disable=protected-access
         except Exception:
             self.notify("Feature not available!", bad=True)
             return
@@ -854,8 +869,7 @@ class Actions(FileManagerAware, SettingsAware):
             return
 
         if not command.__doc__:
-            self.notify("Command has no docstring. Try using python without -OO",
-                    bad=True)
+            self.notify("Command has no docstring. Try using python without -OO", bad=True)
             return
 
         pager = self.ui.open_pager()
@@ -886,11 +900,11 @@ class Actions(FileManagerAware, SettingsAware):
             return
 
         pager = self.ui.open_pager()
-        f = self.thisfile.get_preview_source(pager.wid, pager.hei)
+        fobj = self.thisfile.get_preview_source(pager.wid, pager.hei)
         if self.thisfile.is_image_preview():
-            pager.set_image(f)
+            pager.set_image(fobj)
         else:
-            pager.set_source(f)
+            pager.set_source(fobj)
 
     # --------------------------
     # -- Previews
@@ -902,19 +916,16 @@ class Actions(FileManagerAware, SettingsAware):
         except Exception:
             return False
 
-    if version_info[0] == 3:
-        def sha1_encode(self, path):
-            return os.path.join(ranger.arg.cachedir,
-                    sha1(path.encode('utf-8', 'backslashreplace'))
-                            .hexdigest()) + '.jpg'
-    else:
-        def sha1_encode(self, path):
-            return os.path.join(ranger.arg.cachedir,
-                    sha1(path).hexdigest()) + '.jpg'
-
-    def get_preview(self, file, width, height):
+    @staticmethod
+    def sha1_encode(path):
+        if version_info[0] < 3:
+            return os.path.join(ranger.args.cachedir, sha1(path).hexdigest()) + '.jpg'
+        return os.path.join(ranger.args.cachedir,
+                            sha1(path.encode('utf-8', 'backslashreplace')).hexdigest()) + '.jpg'
+
+    def get_preview(self, fobj, width, height):  # pylint: disable=too-many-return-statements
         pager = self.ui.get_pager()
-        path = file.realpath
+        path = fobj.realpath
 
         if not path or not os.path.exists(path):
             return None
@@ -936,19 +947,30 @@ class Actions(FileManagerAware, SettingsAware):
                 if data['loading']:
                     return None
 
-            found = data.get((-1, -1), data.get((width, -1),
-                data.get((-1, height), data.get((width, height), False))))
+            found = data.get(
+                (-1, -1), data.get(
+                    (width, -1), data.get(
+                        (-1, height), data.get(
+                            (width, height), False
+                        )
+                    )
+                )
+            )
             if found is False:
                 try:
                     stat_ = os.stat(self.settings.preview_script)
                 except Exception:
-                    self.fm.notify("Preview Script `%s' doesn't exist!" %
-                            self.settings.preview_script, bad=True)
+                    self.fm.notify(
+                        "Preview Script `%s' doesn't exist!" % self.settings.preview_script,
+                        bad=True,
+                    )
                     return None
 
                 if not stat_.st_mode & S_IEXEC:
-                    self.fm.notify("Preview Script `%s' is not executable!" %
-                            self.settings.preview_script, bad=True)
+                    self.fm.notify(
+                        "Preview Script `%s' is not executable!" % self.settings.preview_script,
+                        bad=True,
+                    )
                     return None
 
                 data['loading'] = True
@@ -960,48 +982,51 @@ class Actions(FileManagerAware, SettingsAware):
                     data['loading'] = False
                     return path
 
-                cacheimg = os.path.join(ranger.arg.cachedir, self.sha1_encode(path))
-                if (os.path.isfile(cacheimg) and os.path.getmtime(cacheimg) > os.path.getmtime(path)):
+                cacheimg = os.path.join(ranger.args.cachedir, self.sha1_encode(path))
+                if os.path.isfile(cacheimg) and \
+                        os.path.getmtime(cacheimg) > os.path.getmtime(path):
                     data['foundpreview'] = True
                     data['imagepreview'] = True
                     pager.set_image(cacheimg)
                     data['loading'] = False
                     return cacheimg
 
-                loadable = CommandLoader(args=[self.settings.preview_script,
-                    path, str(width), str(height), cacheimg,
-                    str(self.settings.preview_images)], read=True,
-                    silent=True, descr="Getting preview of %s" % path)
+                loadable = CommandLoader(
+                    args=[self.settings.preview_script, path, str(width), str(height),
+                          cacheimg, str(self.settings.preview_images)],
+                    read=True,
+                    silent=True,
+                    descr="Getting preview of %s" % path,
+                )
 
                 def on_after(signal):
-                    exit = signal.process.poll()
+                    rcode = signal.process.poll()
                     content = signal.loader.stdout_buffer
                     data['foundpreview'] = True
-                    if exit == 0:
+                    if rcode == 0:
                         data[(width, height)] = content
-                    elif exit == 3:
+                    elif rcode == 3:
                         data[(-1, height)] = content
-                    elif exit == 4:
+                    elif rcode == 4:
                         data[(width, -1)] = content
-                    elif exit == 5:
+                    elif rcode == 5:
                         data[(-1, -1)] = content
-                    elif exit == 6:
+                    elif rcode == 6:
                         data['imagepreview'] = True
-                    elif exit == 7:
+                    elif rcode == 7:
                         data['directimagepreview'] = True
-                    elif exit == 1:
+                    elif rcode == 1:
                         data[(-1, -1)] = None
                         data['foundpreview'] = False
-                    elif exit == 2:
-                        f = codecs.open(path, 'r', errors='ignore')
+                    elif rcode == 2:
+                        fobj = codecs.open(path, 'r', errors='ignore')
                         try:
-                            data[(-1, -1)] = f.read(1024 * 32)
+                            data[(-1, -1)] = fobj.read(1024 * 32)
                         except UnicodeDecodeError:
-                            f.close()
-                            f = codecs.open(path, 'r', encoding='latin-1',
-                                    errors='ignore')
-                            data[(-1, -1)] = f.read(1024 * 32)
-                        f.close()
+                            fobj.close()
+                            fobj = codecs.open(path, 'r', encoding='latin-1', errors='ignore')
+                            data[(-1, -1)] = fobj.read(1024 * 32)
+                        fobj.close()
                     else:
                         data[(-1, -1)] = None
                     if self.thisfile and self.thisfile.realpath == path:
@@ -1019,7 +1044,7 @@ class Actions(FileManagerAware, SettingsAware):
                             pager.set_source(self.thisfile.get_preview_source(
                                 pager.wid, pager.hei))
 
-                def on_destroy(signal):
+                def on_destroy(signal):  # pylint: disable=unused-argument
                     try:
                         del self.previews[path]
                     except Exception:
@@ -1094,8 +1119,7 @@ class Actions(FileManagerAware, SettingsAware):
                     tab.enter_dir(tab.path, history=False)
                     self.thistab = tab
                     self.change_mode('normal')
-                    self.signal_emit('tab.change', old=previous_tab,
-                            new=self.thistab)
+                    self.signal_emit('tab.change', old=previous_tab, new=self.thistab)
                     break
 
     def tab_move(self, offset, narg=None):
@@ -1125,7 +1149,8 @@ class Actions(FileManagerAware, SettingsAware):
             file_selection = None
             if create_directory:
                 try:
-                    os.makedirs(path, exist_ok=True)
+                    if not os.path.isdir(path):
+                        os.makedirs(path)
                 except OSError as err:
                     self.fm.notify(err, bad=True)
                     return
@@ -1159,7 +1184,7 @@ class Actions(FileManagerAware, SettingsAware):
             self.fm.select_file(file_selection)
 
     def _get_tab_list(self):
-        assert len(self.tabs) > 0, "There must be >=1 tabs at all times"
+        assert self.tabs, "There must be at least 1 tab at all times"
         return sorted(self.tabs)
 
     # --------------------------
@@ -1172,7 +1197,7 @@ class Actions(FileManagerAware, SettingsAware):
 
         temporary_file = tempfile.NamedTemporaryFile()
 
-        def write(string):
+        def write(string):  # pylint: disable=redefined-outer-name
             temporary_file.write(string.encode('utf-8'))
 
         def recurse(before, pointer):
@@ -1198,7 +1223,7 @@ class Actions(FileManagerAware, SettingsAware):
     def dump_commands(self):
         temporary_file = tempfile.NamedTemporaryFile()
 
-        def write(string):
+        def write(string):  # pylint: disable=redefined-outer-name
             temporary_file.write(string.encode('utf-8'))
 
         undocumented = []
@@ -1224,7 +1249,7 @@ class Actions(FileManagerAware, SettingsAware):
     def dump_settings(self):
         temporary_file = tempfile.NamedTemporaryFile()
 
-        def write(string):
+        def write(string):  # pylint: disable=redefined-outer-name
             temporary_file.write(string.encode('utf-8'))
 
         for setting in sorted(ALLOWED_SETTINGS):
@@ -1256,7 +1281,7 @@ class Actions(FileManagerAware, SettingsAware):
         assert mode in ('set', 'add', 'remove', 'toggle')
         cwd = self.thisdir
         if not narg and not dirarg:
-            selected = (f for f in self.thistab.get_selection() if f in cwd.files)
+            selected = (fobj for fobj in self.thistab.get_selection() if fobj in cwd.files)
         else:
             if not dirarg and narg:
                 direction = Direction(down=1)
@@ -1264,9 +1289,8 @@ class Actions(FileManagerAware, SettingsAware):
             else:
                 direction = Direction(dirarg)
                 offset = 1
-            pos, selected = direction.select(
-                    override=narg, lst=cwd.files, current=cwd.pointer,
-                    pagesize=self.ui.termsize[0], offset=offset)
+            pos, selected = direction.select(override=narg, lst=cwd.files, current=cwd.pointer,
+                                             pagesize=self.ui.termsize[0], offset=offset)
             cwd.pointer = pos
             cwd.correct_pointer()
         if mode == 'set':
@@ -1292,32 +1316,32 @@ class Actions(FileManagerAware, SettingsAware):
 
     def paste_symlink(self, relative=False):
         copied_files = self.copy_buffer
-        for f in copied_files:
-            self.notify(next_available_filename(f.basename))
+        for fobj in copied_files:
+            self.notify(next_available_filename(fobj.basename))
             try:
-                new_name = next_available_filename(f.basename)
+                new_name = next_available_filename(fobj.basename)
                 if relative:
-                    relative_symlink(f.path, join(getcwd(), new_name))
+                    relative_symlink(fobj.path, join(getcwd(), new_name))
                 else:
-                    symlink(f.path, join(getcwd(), new_name))
-            except Exception as x:
-                self.notify(x)
+                    symlink(fobj.path, join(getcwd(), new_name))
+            except Exception as ex:
+                self.notify(ex)
 
     def paste_hardlink(self):
-        for f in self.copy_buffer:
+        for fobj in self.copy_buffer:
             try:
-                new_name = next_available_filename(f.basename)
-                link(f.path, join(getcwd(), new_name))
-            except Exception as x:
-                self.notify(x)
+                new_name = next_available_filename(fobj.basename)
+                link(fobj.path, join(getcwd(), new_name))
+            except Exception as ex:
+                self.notify(ex)
 
     def paste_hardlinked_subtree(self):
-        for f in self.copy_buffer:
+        for fobj in self.copy_buffer:
             try:
-                target_path = join(getcwd(), f.basename)
-                self._recurse_hardlinked_tree(f.path, target_path)
-            except Exception as x:
-                self.notify(x)
+                target_path = join(getcwd(), fobj.basename)
+                self._recurse_hardlinked_tree(fobj.path, target_path)
+            except Exception as ex:
+                self.notify(ex)
 
     def _recurse_hardlinked_tree(self, source_path, target_path):
         if isdir(source_path):
@@ -1329,9 +1353,9 @@ class Actions(FileManagerAware, SettingsAware):
                     join(target_path, item))
         else:
             if not exists(target_path) \
-            or stat(source_path).st_ino != stat(target_path).st_ino:
+                    or stat(source_path).st_ino != stat(target_path).st_ino:
                 link(source_path,
-                    next_available_filename(target_path))
+                     next_available_filename(target_path))
 
     def paste(self, overwrite=False, append=False):
         """:paste
@@ -1347,23 +1371,23 @@ class Actions(FileManagerAware, SettingsAware):
         self.notify("Deleting!")
         # COMPAT: old command.py use fm.delete() without arguments
         if files is None:
-            files = (f.path for f in self.thistab.get_selection())
-        files = [os.path.abspath(f) for f in files]
-        for f in files:
+            files = (fobj.path for fobj in self.thistab.get_selection())
+        files = [os.path.abspath(path) for path in files]
+        for path in files:
             # Untag the deleted files.
             for tag in self.fm.tags.tags:
-                if str(tag).startswith(f):
+                if str(tag).startswith(path):
                     self.fm.tags.remove(tag)
-        self.copy_buffer = set(filter(lambda f: f.path not in files, self.copy_buffer))
-        for f in files:
-            if isdir(f) and not os.path.islink(f):
+        self.copy_buffer = set(fobj for fobj in self.copy_buffer if fobj.path not in files)
+        for path in files:
+            if isdir(path) and not os.path.islink(path):
                 try:
-                    shutil.rmtree(f)
+                    shutil.rmtree(path)
                 except OSError as err:
                     self.notify(err)
             else:
                 try:
-                    os.remove(f)
+                    os.remove(path)
                 except OSError as err:
                     self.notify(err)
         self.thistab.ensure_correct_pointer()
diff --git a/ranger/core/fm.py b/ranger/core/fm.py
index 5d630464..9b7c8fae 100644
--- a/ranger/core/fm.py
+++ b/ranger/core/fm.py
@@ -3,6 +3,8 @@
 
 """The File Manager, putting the pieces together"""
 
+from __future__ import (absolute_import, print_function)
+
 from time import time
 from collections import deque
 import logging
@@ -21,7 +23,8 @@ from ranger.container.tags import Tags, TagsDummy
 from ranger.gui.ui import UI
 from ranger.container.bookmarks import Bookmarks
 from ranger.core.runner import Runner
-from ranger.ext.img_display import *
+from ranger.ext.img_display import (W3MImageDisplayer, ITerm2ImageDisplayer,
+                                    URXVTImageDisplayer, URXVTImageFSDisplayer, ImageDisplayer)
 from ranger.core.metadata import MetadataManager
 from ranger.ext.rifle import Rifle
 from ranger.container.directory import Directory
@@ -29,10 +32,12 @@ from ranger.ext.signals import SignalDispatcher
 from ranger.core.loader import Loader
 from ranger.ext import logutils
 
-log = logging.getLogger(__name__)
+
+LOG = logging.getLogger(__name__)
 
 
-class FM(Actions, SignalDispatcher):
+class FM(Actions,  # pylint: disable=too-many-instance-attributes
+         SignalDispatcher):
     input_blocked = False
     input_blocked_until = 0
     mode = 'normal'  # either 'normal' or 'visual'.
@@ -43,15 +48,12 @@ class FM(Actions, SignalDispatcher):
     _visual_start = None
     _visual_start_pos = None
 
-    def __init__(self, ui=None, bookmarks=None, tags=None, paths=['.']):
+    def __init__(self, ui=None, bookmarks=None, tags=None, paths=None):
         """Initialize FM."""
         Actions.__init__(self)
         SignalDispatcher.__init__(self)
-        if ui is None:
-            self.ui = UI()
-        else:
-            self.ui = ui
-        self.start_paths = paths
+        self.ui = ui if ui is not None else UI()
+        self.start_paths = paths if paths is not None else ['.']
         self.directories = dict()
         self.bookmarks = bookmarks
         self.current_tab = 1
@@ -65,6 +67,10 @@ class FM(Actions, SignalDispatcher):
         self.copy_buffer = set()
         self.do_cut = False
         self.metadata = MetadataManager()
+        self.image_displayer = None
+        self.run = None
+        self.rifle = None
+        self.thistab = None
 
         try:
             self.username = pwd.getpwuid(os.geteuid()).pw_name
@@ -80,8 +86,7 @@ class FM(Actions, SignalDispatcher):
     def initialize(self):
         """If ui/bookmarks are None, they will be initialized here."""
 
-        self.tabs = dict((n + 1, Tab(path)) for n, path in
-                enumerate(self.start_paths))
+        self.tabs = dict((n + 1, Tab(path)) for n, path in enumerate(self.start_paths))
         tab_list = self._get_tab_list()
         if tab_list:
             self.current_tab = tab_list[0]
@@ -90,7 +95,7 @@ class FM(Actions, SignalDispatcher):
             self.current_tab = 1
             self.tabs[self.current_tab] = self.thistab = Tab('.')
 
-        if not ranger.arg.clean and os.path.isfile(self.confpath('rifle.conf')):
+        if not ranger.args.clean and os.path.isfile(self.confpath('rifle.conf')):
             rifleconf = self.confpath('rifle.conf')
         else:
             rifleconf = self.relpath('config/rifle.conf')
@@ -100,24 +105,23 @@ class FM(Actions, SignalDispatcher):
         def set_image_displayer():
             self.image_displayer = self._get_image_displayer()
         set_image_displayer()
-        self.settings.signal_bind('setopt.preview_images_method',
-                set_image_displayer,
-                priority=settings.SIGNAL_PRIORITY_AFTER_SYNC)
+        self.settings.signal_bind('setopt.preview_images_method', set_image_displayer,
+                                  priority=settings.SIGNAL_PRIORITY_AFTER_SYNC)
 
-        if not ranger.arg.clean and self.tags is None:
+        if not ranger.args.clean and self.tags is None:
             self.tags = Tags(self.confpath('tagged'))
-        elif ranger.arg.clean:
+        elif ranger.args.clean:
             self.tags = TagsDummy("")
 
         if self.bookmarks is None:
-            if ranger.arg.clean:
+            if ranger.args.clean:
                 bookmarkfile = None
             else:
                 bookmarkfile = self.confpath('bookmarks')
             self.bookmarks = Bookmarks(
-                    bookmarkfile=bookmarkfile,
-                    bookmarktype=Directory,
-                    autosave=self.settings.autosave_bookmarks)
+                bookmarkfile=bookmarkfile,
+                bookmarktype=Directory,
+                autosave=self.settings.autosave_bookmarks)
             self.bookmarks.load()
 
         self.ui.setup_curses()
@@ -141,12 +145,11 @@ class FM(Actions, SignalDispatcher):
             from ranger.ext.shell_escape import shell_quote
 
             if self.settings.open_all_images and \
-                    len(self.thisdir.marked_items) == 0 and \
+                    not self.thisdir.marked_items and \
                     re.match(r'^(feh|sxiv|imv|pqiv) ', command):
 
                 images = [f.relative_path for f in self.thisdir.files if f.image]
-                escaped_filenames = " ".join(shell_quote(f)
-                        for f in images if "\x00" not in f)
+                escaped_filenames = " ".join(shell_quote(f) for f in images if "\x00" not in f)
 
                 if images and self.thisfile.relative_path in images and \
                         "$@" in command:
@@ -154,28 +157,26 @@ class FM(Actions, SignalDispatcher):
 
                     if command[0:5] == 'sxiv ':
                         number = images.index(self.thisfile.relative_path) + 1
-                        new_command = command.replace("sxiv ",
-                                "sxiv -n %d " % number, 1)
+                        new_command = command.replace("sxiv ", "sxiv -n %d " % number, 1)
 
                     if command[0:4] == 'feh ':
-                        new_command = command.replace("feh ",
-                            "feh --start-at %s " %
-                            shell_quote(self.thisfile.relative_path), 1)
+                        new_command = command.replace(
+                            "feh ",
+                            "feh --start-at %s " % shell_quote(self.thisfile.relative_path),
+                            1,
+                        )
 
                     if command[0:4] == 'imv ':
                         number = images.index(self.thisfile.relative_path) + 1
-                        new_command = command.replace("imv ",
-                                "imv -n %d " % number, 1)
+                        new_command = command.replace("imv ", "imv -n %d " % number, 1)
 
                     if command[0:5] == 'pqiv ':
                         number = images.index(self.thisfile.relative_path)
-                        new_command = command.replace("pqiv ",
-                                "pqiv --action \"goto_file_byindex(%d)\" " %
-                                number, 1)
+                        new_command = command.replace(
+                            "pqiv ", "pqiv --action \"goto_file_byindex(%d)\" " % number, 1)
 
                     if new_command:
-                        command = "set -- %s; %s" % (escaped_filenames,
-                                new_command)
+                        command = "set -- %s; %s" % (escaped_filenames, new_command)
             return old_preprocessing_hook(command)
 
         self.rifle.hook_command_preprocessing = sxiv_workaround_hook
@@ -184,12 +185,13 @@ class FM(Actions, SignalDispatcher):
             self.notify(text, bad=True)
         self.run = Runner(ui=self.ui, logfunc=mylogfunc, fm=self)
 
-        self.settings.signal_bind('setopt.metadata_deep_search',
-                lambda signal: setattr(signal.fm.metadata, 'deep_search',
-                    signal.value))
+        self.settings.signal_bind(
+            'setopt.metadata_deep_search',
+            lambda signal: setattr(signal.fm.metadata, 'deep_search', signal.value)
+        )
 
     def destroy(self):
-        debug = ranger.arg.debug
+        debug = ranger.args.debug
         if self.ui:
             try:
                 self.ui.destroy()
@@ -203,7 +205,8 @@ class FM(Actions, SignalDispatcher):
                 if debug:
                     raise
 
-    def get_log(self):
+    @staticmethod
+    def get_log():
         """Return the current log
 
         The log is returned as a list of string
@@ -221,8 +224,7 @@ class FM(Actions, SignalDispatcher):
             return URXVTImageDisplayer()
         elif self.settings.preview_images_method == "urxvt-full":
             return URXVTImageFSDisplayer()
-        else:
-            return ImageDisplayer()
+        return ImageDisplayer()
 
     def _get_thisfile(self):
         return self.thistab.thisfile
@@ -237,7 +239,7 @@ class FM(Actions, SignalDispatcher):
         self.thistab.thisdir = obj
 
     thisfile = property(_get_thisfile, _set_thisfile)
-    thisdir  = property(_get_thisdir, _set_thisdir)
+    thisdir = property(_get_thisdir, _set_thisdir)
 
     def block_input(self, sec=0):
         self.input_blocked = sec != 0
@@ -249,30 +251,30 @@ class FM(Actions, SignalDispatcher):
         return self.input_blocked
 
     def copy_config_files(self, which):
-        if ranger.arg.clean:
+        if ranger.args.clean:
             sys.stderr.write("refusing to copy config files in clean mode\n")
             return
         import shutil
         from errno import EEXIST
 
-        def copy(_from, to):
-            if os.path.exists(self.confpath(to)):
-                sys.stderr.write("already exists: %s\n" % self.confpath(to))
+        def copy(src, dest):
+            if os.path.exists(self.confpath(dest)):
+                sys.stderr.write("already exists: %s\n" % self.confpath(dest))
             else:
-                sys.stderr.write("creating: %s\n" % self.confpath(to))
+                sys.stderr.write("creating: %s\n" % self.confpath(dest))
                 try:
-                    os.makedirs(ranger.arg.confdir)
+                    os.makedirs(ranger.args.confdir)
                 except OSError as err:
                     if err.errno != EEXIST:  # EEXIST means it already exists
                         print("This configuration directory could not be created:")
-                        print(ranger.arg.confdir)
+                        print(ranger.args.confdir)
                         print("To run ranger without the need for configuration")
                         print("files, use the --clean option.")
                         raise SystemExit()
                 try:
-                    shutil.copy(self.relpath(_from), self.confpath(to))
-                except Exception as e:
-                    sys.stderr.write("  ERROR: %s\n" % str(e))
+                    shutil.copy(self.relpath(src), self.confpath(dest))
+                except Exception as ex:
+                    sys.stderr.write("  ERROR: %s\n" % str(ex))
         if which == 'rifle' or which == 'all':
             copy('config/rifle.conf', 'rifle.conf')
         if which == 'commands' or which == 'all':
@@ -284,28 +286,30 @@ class FM(Actions, SignalDispatcher):
         if which == 'scope' or which == 'all':
             copy('data/scope.sh', 'scope.sh')
             os.chmod(self.confpath('scope.sh'),
-                os.stat(self.confpath('scope.sh')).st_mode | stat.S_IXUSR)
+                     os.stat(self.confpath('scope.sh')).st_mode | stat.S_IXUSR)
         if which in ('all', 'rifle', 'scope', 'commands', 'commands_full', 'rc'):
             sys.stderr.write("\n> Please note that configuration files may "
-                "change as ranger evolves.\n  It's completely up to you to "
-                "keep them up to date.\n")
+                             "change as ranger evolves.\n  It's completely up to you to "
+                             "keep them up to date.\n")
             if os.environ.get('RANGER_LOAD_DEFAULT_RC', 0) != 'FALSE':
                 sys.stderr.write("\n> To stop ranger from loading "
-                "\033[1mboth\033[0m the default and your custom rc.conf,\n"
-                "  please set the environment variable "
-                "\033[1mRANGER_LOAD_DEFAULT_RC\033[0m to "
-                "\033[1mFALSE\033[0m.\n")
+                                 "\033[1mboth\033[0m the default and your custom rc.conf,\n"
+                                 "  please set the environment variable "
+                                 "\033[1mRANGER_LOAD_DEFAULT_RC\033[0m to "
+                                 "\033[1mFALSE\033[0m.\n")
         else:
             sys.stderr.write("Unknown config file `%s'\n" % which)
 
-    def confpath(self, *paths):
+    @staticmethod
+    def confpath(*paths):
         """returns the path relative to rangers configuration directory"""
-        if ranger.arg.clean:
+        if ranger.args.clean:
             assert 0, "Should not access relpath_conf in clean mode!"
         else:
-            return os.path.join(ranger.arg.confdir, *paths)
+            return os.path.join(ranger.args.confdir, *paths)
 
-    def relpath(self, *paths):
+    @staticmethod
+    def relpath(*paths):
         """returns the path relative to rangers library directory"""
         return os.path.join(ranger.RANGERDIR, *paths)
 
@@ -319,7 +323,9 @@ class FM(Actions, SignalDispatcher):
             self.directories[path] = obj
             return obj
 
-    def garbage_collect(self, age, tabs=None):  # tabs=None is for COMPATibility
+    def garbage_collect(
+            self, age,
+            tabs=None):  # tabs=None is for COMPATibility pylint: disable=unused-argument
         """Delete unused directory objects"""
         for key in tuple(self.directories):
             value = self.directories[key]
@@ -346,8 +352,6 @@ class FM(Actions, SignalDispatcher):
 
         self.enter_dir(self.thistab.path)
 
-        gc_tick = 0
-
         # for faster lookup:
         ui = self.ui
         throbber = ui.throbber
@@ -357,7 +361,7 @@ class FM(Actions, SignalDispatcher):
 
         ranger.api.hook_ready(self)
 
-        try:
+        try:  # pylint: disable=too-many-nested-blocks
             while True:
                 loader.work()
                 if has_throbber:
@@ -379,10 +383,10 @@ class FM(Actions, SignalDispatcher):
                         if zombie.poll() is not None:
                             zombies.remove(zombie)
 
-                #gc_tick += 1
-                #if gc_tick > ranger.TICKS_BEFORE_COLLECTING_GARBAGE:
-                    #gc_tick = 0
-                    #self.garbage_collect(ranger.TIME_BEFORE_FILE_BECOMES_GARBAGE)
+                # gc_tick += 1
+                # if gc_tick > ranger.TICKS_BEFORE_COLLECTING_GARBAGE:
+                    # gc_tick = 0
+                    # self.garbage_collect(ranger.TIME_BEFORE_FILE_BECOMES_GARBAGE)
 
         except KeyboardInterrupt:
             # this only happens in --debug mode. By default, interrupts
@@ -391,9 +395,9 @@ class FM(Actions, SignalDispatcher):
 
         finally:
             self.image_displayer.quit()
-            if ranger.arg.choosedir and self.thisdir and self.thisdir.path:
+            if ranger.args.choosedir and self.thisdir and self.thisdir.path:
                 # XXX: UnicodeEncodeError: 'utf-8' codec can't encode character
                 # '\udcf6' in position 42: surrogates not allowed
-                open(ranger.arg.choosedir, 'w').write(self.thisdir.path)
+                open(ranger.args.choosedir, 'w').write(self.thisdir.path)
             self.bookmarks.remember(self.thisdir)
             self.bookmarks.save()
diff --git a/ranger/core/linemode.py b/ranger/core/linemode.py
index c7839723..8b225787 100644
--- a/ranger/core/linemode.py
+++ b/ranger/core/linemode.py
@@ -3,8 +3,11 @@
 # License: GNU GPL version 3, see the file "AUTHORS" for details.
 # Author: Wojciech Siewierski <wojciech.siewierski@onet.pl>, 2015
 
+from __future__ import (absolute_import, print_function)
+
 import sys
-from abc import *
+
+from abc import ABCMeta, abstractproperty, abstractmethod
 from datetime import datetime
 from ranger.ext.human_readable import human_readable
 from ranger.ext import spawn
@@ -32,11 +35,11 @@ class LinemodeBase(object):
     name = abstractproperty()
 
     @abstractmethod
-    def filetitle(self, file, metadata):
+    def filetitle(self, fobj, metadata):
         """The left-aligned part of the line."""
         raise NotImplementedError
 
-    def infostring(self, file, metadata):
+    def infostring(self, fobj, metadata):
         """The right-aligned part of the line.
 
         If `NotImplementedError' is raised (e.g. this method is just
@@ -51,11 +54,11 @@ class LinemodeBase(object):
         raise NotImplementedError
 
 
-class DefaultLinemode(LinemodeBase):
+class DefaultLinemode(LinemodeBase):  # pylint: disable=abstract-method
     name = "filename"
 
-    def filetitle(self, file, metadata):
-        return file.relative_path
+    def filetitle(self, fobj, metadata):
+        return fobj.relative_path
 
 
 class TitleLinemode(LinemodeBase):
@@ -63,14 +66,13 @@ class TitleLinemode(LinemodeBase):
     uses_metadata = True
     required_metadata = ["title"]
 
-    def filetitle(self, file, metadata):
+    def filetitle(self, fobj, metadata):
         name = metadata.title
         if metadata.year:
             return "%s - %s" % (metadata.year, name)
-        else:
-            return name
+        return name
 
-    def infostring(self, file, metadata):
+    def infostring(self, fobj, metadata):
         if metadata.authors:
             authorstring = metadata.authors
             if ',' in authorstring:
@@ -82,25 +84,25 @@ class TitleLinemode(LinemodeBase):
 class PermissionsLinemode(LinemodeBase):
     name = "permissions"
 
-    def filetitle(self, file, metadata):
-        return "%s %s %s %s" % (file.get_permission_string(),
-                file.user, file.group, file.relative_path)
+    def filetitle(self, fobj, metadata):
+        return "%s %s %s %s" % (
+            fobj.get_permission_string(), fobj.user, fobj.group, fobj.relative_path)
 
-    def infostring(self, file, metadata):
+    def infostring(self, fobj, metadata):
         return ""
 
 
 class FileInfoLinemode(LinemodeBase):
     name = "fileinfo"
 
-    def filetitle(self, file, metadata):
-        return file.relative_path
+    def filetitle(self, fobj, metadata):
+        return fobj.relative_path
 
-    def infostring(self, file, metadata):
-        if not file.is_directory:
-            from subprocess import Popen, PIPE, CalledProcessError
+    def infostring(self, fobj, metadata):
+        if not fobj.is_directory:
+            from subprocess import CalledProcessError
             try:
-                fileinfo = spawn.check_output(["file", "-bL", file.path]).strip()
+                fileinfo = spawn.check_output(["file", "-bL", fobj.path]).strip()
             except CalledProcessError:
                 return "unknown"
             if sys.version_info[0] >= 3:
@@ -113,19 +115,19 @@ class FileInfoLinemode(LinemodeBase):
 class MtimeLinemode(LinemodeBase):
     name = "mtime"
 
-    def filetitle(self, file, metadata):
-        return file.relative_path
+    def filetitle(self, fobj, metadata):
+        return fobj.relative_path
 
-    def infostring(self, file, metadata):
-        return datetime.fromtimestamp(file.stat.st_mtime).strftime("%Y-%m-%d %H:%M")
+    def infostring(self, fobj, metadata):
+        return datetime.fromtimestamp(fobj.stat.st_mtime).strftime("%Y-%m-%d %H:%M")
 
 
 class SizeMtimeLinemode(LinemodeBase):
     name = "sizemtime"
 
-    def filetitle(self, file, metadata):
-        return file.relative_path
+    def filetitle(self, fobj, metadata):
+        return fobj.relative_path
 
-    def infostring(self, file, metadata):
-        return "%s %s" % (human_readable(file.size),
-                          datetime.fromtimestamp(file.stat.st_mtime).strftime("%Y-%m-%d %H:%M"))
+    def infostring(self, fobj, metadata):
+        return "%s %s" % (human_readable(fobj.size),
+                          datetime.fromtimestamp(fobj.stat.st_mtime).strftime("%Y-%m-%d %H:%M"))
diff --git a/ranger/core/loader.py b/ranger/core/loader.py
index 0cdc5368..db1f0651 100644
--- a/ranger/core/loader.py
+++ b/ranger/core/loader.py
@@ -1,18 +1,22 @@
 # This file is part of ranger, the console file manager.
 # License: GNU GPL version 3, see the file "AUTHORS" for details.
 
+from __future__ import (absolute_import, print_function)
+
 from collections import deque
-from time import time, sleep
 from subprocess import Popen, PIPE
-from ranger.core.shared import FileManagerAware
-from ranger.ext.signals import SignalDispatcher
-from ranger.ext.human_readable import human_readable
+from time import time, sleep
 import math
 import os.path
-import sys
 import select
+import sys
+import errno
+
+from ranger.core.shared import FileManagerAware
+from ranger.ext.signals import SignalDispatcher
+from ranger.ext.human_readable import human_readable
 try:
-    import chardet
+    import chardet  # pylint: disable=import-error
     HAVE_CHARDET = True
 except Exception:
     HAVE_CHARDET = False
@@ -43,7 +47,7 @@ class Loadable(object):
         pass
 
 
-class CopyLoader(Loadable, FileManagerAware):
+class CopyLoader(Loadable, FileManagerAware):  # pylint: disable=too-many-instance-attributes
     progressbar_supported = True
 
     def __init__(self, copy_buffer, do_cut=False, overwrite=False):
@@ -60,7 +64,7 @@ class CopyLoader(Loadable, FileManagerAware):
     def _calculate_size(self, step):
         from os.path import join
         size = 0
-        stack = [f.path for f in self.copy_buffer]
+        stack = [fobj.path for fobj in self.copy_buffer]
         while stack:
             fname = stack.pop()
             if os.path.islink(fname):
@@ -89,49 +93,51 @@ class CopyLoader(Loadable, FileManagerAware):
                     self.description = "moving: " + self.one_file.path + size_str
                 else:
                     self.description = "moving files from: " + self.one_file.dirname + size_str
-                for f in self.copy_buffer:
-                    for tf in self.fm.tags.tags:
-                        if tf == f.path or str(tf).startswith(f.path):
-                            tag = self.fm.tags.tags[tf]
-                            self.fm.tags.remove(tf)
-                            self.fm.tags.tags[tf.replace(f.path, self.original_path
-                                    + '/' + f.basename)] = tag
+                for fobj in self.copy_buffer:
+                    for path in self.fm.tags.tags:
+                        if path == fobj.path or str(path).startswith(fobj.path):
+                            tag = self.fm.tags.tags[path]
+                            self.fm.tags.remove(path)
+                            self.fm.tags.tags[
+                                path.replace(fobj.path, self.original_path + '/' + fobj.basename)
+                            ] = tag
                             self.fm.tags.dump()
-                    d = 0
-                    for d in shutil_g.move(src=f.path,
-                            dst=self.original_path,
-                            overwrite=self.overwrite):
-                        self.percent = float(done + d) / size * 100.
+                    n = 0
+                    for n in shutil_g.move(src=fobj.path, dst=self.original_path,
+                                           overwrite=self.overwrite):
+                        self.percent = float(done + n) / size * 100.
                         yield
-                    done += d
+                    done += n
             else:
                 if len(self.copy_buffer) == 1:
                     self.description = "copying: " + self.one_file.path + size_str
                 else:
                     self.description = "copying files from: " + self.one_file.dirname + size_str
-                for f in self.copy_buffer:
-                    if os.path.isdir(f.path) and not os.path.islink(f.path):
-                        d = 0
-                        for d in shutil_g.copytree(src=f.path,
-                                dst=os.path.join(self.original_path, f.basename),
+                for fobj in self.copy_buffer:
+                    if os.path.isdir(fobj.path) and not os.path.islink(fobj.path):
+                        n = 0
+                        for n in shutil_g.copytree(
+                                src=fobj.path,
+                                dst=os.path.join(self.original_path, fobj.basename),
                                 symlinks=True,
-                                overwrite=self.overwrite):
-                            self.percent = float(done + d) / size * 100.
+                                overwrite=self.overwrite,
+                        ):
+                            self.percent = float(done + n) / size * 100.
                             yield
-                        done += d
+                        done += n
                     else:
-                        d = 0
-                        for d in shutil_g.copy2(f.path, self.original_path,
-                                symlinks=True,
-                                overwrite=self.overwrite):
-                            self.percent = float(done + d) / size * 100.
+                        n = 0
+                        for n in shutil_g.copy2(fobj.path, self.original_path,
+                                                symlinks=True, overwrite=self.overwrite):
+                            self.percent = float(done + n) / size * 100.
                             yield
-                        done += d
+                        done += n
             cwd = self.fm.get_directory(self.original_path)
             cwd.load_content()
 
 
-class CommandLoader(Loadable, SignalDispatcher, FileManagerAware):
+class CommandLoader(  # pylint: disable=too-many-instance-attributes
+        Loadable, SignalDispatcher, FileManagerAware):
     """Run an external command with the loader.
 
     Output from stderr will be reported.  Ensure that the process doesn't
@@ -141,8 +147,9 @@ class CommandLoader(Loadable, SignalDispatcher, FileManagerAware):
     finished = False
     process = None
 
-    def __init__(self, args, descr, silent=False, read=False, input=None,
-            kill_on_pause=False, popenArgs=None):
+    def __init__(self, args, descr,  # pylint: disable=too-many-arguments
+                 silent=False, read=False, input=None,  # pylint: disable=redefined-builtin
+                 kill_on_pause=False, popenArgs=None):
         SignalDispatcher.__init__(self)
         Loadable.__init__(self, self.generate(), descr)
         self.args = args
@@ -151,18 +158,14 @@ class CommandLoader(Loadable, SignalDispatcher, FileManagerAware):
         self.stdout_buffer = ""
         self.input = input
         self.kill_on_pause = kill_on_pause
-        self.popenArgs = popenArgs
+        self.popenArgs = popenArgs  # pylint: disable=invalid-name
 
-    def generate(self):
+    def generate(self):  # pylint: disable=too-many-branches,too-many-statements
         py3 = sys.version_info[0] >= 3
-        if self.input:
-            stdin = PIPE
-        else:
-            stdin = open(os.devnull, 'r')
-        popenArgs = {} if self.popenArgs is None else self.popenArgs
-        popenArgs['stdout'] = popenArgs['stderr'] = PIPE
-        popenArgs['stdin'] = stdin
-        self.process = process = Popen(self.args, **popenArgs)
+        popenargs = {} if self.popenArgs is None else self.popenArgs
+        popenargs['stdout'] = popenargs['stderr'] = PIPE
+        popenargs['stdin'] = PIPE if self.input else open(os.devnull, 'r')
+        self.process = process = Popen(self.args, **popenargs)
         self.signal_emit('before', process=process, loader=self)
         if self.input:
             if py3:
@@ -172,11 +175,11 @@ class CommandLoader(Loadable, SignalDispatcher, FileManagerAware):
                 stdin = process.stdin
             try:
                 stdin.write(self.input)
-            except IOError as e:
-                if e.errno != errno.EPIPE and e.errno != errno.EINVAL:
+            except IOError as ex:
+                if ex.errno != errno.EPIPE and ex.errno != errno.EINVAL:
                     raise
             stdin.close()
-        if self.silent and not self.read:
+        if self.silent and not self.read:  # pylint: disable=too-many-nested-blocks
             while process.poll() is None:
                 yield
                 if self.finished:
@@ -193,17 +196,17 @@ class CommandLoader(Loadable, SignalDispatcher, FileManagerAware):
                 if self.finished:
                     break
                 try:
-                    rd, _, __ = select.select(selectlist, [], [], 0.03)
-                    if rd:
-                        rd = rd[0]
-                        if rd == process.stderr:
-                            read = rd.readline()
+                    robjs, _, _ = select.select(selectlist, [], [], 0.03)
+                    if robjs:
+                        robjs = robjs[0]
+                        if robjs == process.stderr:
+                            read = robjs.readline()
                             if py3:
                                 read = safeDecode(read)
                             if read:
                                 self.fm.notify(read, bad=True)
-                        elif rd == process.stdout:
-                            read = rd.read(512)
+                        elif robjs == process.stdout:
+                            read = robjs.read(512)
                             if py3:
                                 read = safeDecode(read)
                             if read:
@@ -259,15 +262,14 @@ class CommandLoader(Loadable, SignalDispatcher, FileManagerAware):
                 pass
 
 
-def safeDecode(string):
+def safeDecode(string):  # pylint: disable=invalid-name
     try:
         return string.decode("utf-8")
-    except (UnicodeDecodeError):
+    except UnicodeDecodeError:
         if HAVE_CHARDET:
             codec = chardet.detect(string)["encoding"]
             return string.decode(codec, 'ignore')
-        else:
-            return ""
+        return ""
 
 
 class Loader(FileManagerAware):
@@ -286,6 +288,7 @@ class Loader(FileManagerAware):
         self.throbber_status = 0
         self.rotate()
         self.old_item = None
+        self.status = None
 
     def rotate(self):
         """Rotate the throbber"""
@@ -314,19 +317,19 @@ class Loader(FileManagerAware):
         else:
             obj.unpause()
 
-    def move(self, _from, to):
+    def move(self, pos_src, pos_dest):
         try:
-            item = self.queue[_from]
+            item = self.queue[pos_src]
         except IndexError:
             return
 
-        del self.queue[_from]
+        del self.queue[pos_src]
 
-        if to == 0:
+        if pos_dest == 0:
             self.queue.appendleft(item)
-            if _from != 0:
+            if pos_src != 0:
                 self.queue[1].pause()
-        elif to == -1:
+        elif pos_dest == -1:
             self.queue.append(item)
         else:
             raise NotImplementedError
diff --git a/ranger/core/main.py b/ranger/core/main.py
index b0e3b600..b3173da2 100644
--- a/ranger/core/main.py
+++ b/ranger/core/main.py
@@ -3,16 +3,23 @@
 
 """The main function responsible to initialize the FM object and stuff."""
 
+from __future__ import (absolute_import, print_function)
+
 import os.path
 import sys
 import tempfile
-from ranger import __version__
 from logging import getLogger
 
-log = getLogger(__name__)
+from ranger import __version__
+
+
+LOG = getLogger(__name__)
 
 
-def main():
+def main(
+        # pylint: disable=too-many-locals,too-many-return-statements
+        # pylint: disable=too-many-branches,too-many-statements
+):
     """initialize objects and run the filemanager"""
     import locale
     import ranger.api
@@ -20,13 +27,15 @@ def main():
     from ranger.core.shared import FileManagerAware, SettingsAware
     from ranger.core.fm import FM
     from ranger.ext.logutils import setup_logging
+    from ranger.ext.openstruct import OpenStruct
 
-    ranger.arg = arg = parse_arguments()
-    setup_logging(debug=arg.debug, logfile=arg.logfile)
+    ranger.args = args = parse_arguments()
+    ranger.arg = OpenStruct(args.__dict__)  # COMPAT
+    setup_logging(debug=args.debug, logfile=args.logfile)
 
-    log.info("Ranger version {0}".format(__version__))
-    log.info('Running on Python ' + sys.version.replace('\n', ''))
-    log.info("Process ID is {0}".format(os.getpid()))
+    LOG.info("Ranger version %s", __version__)
+    LOG.info('Running on Python ' + sys.version.replace('\n', ''))
+    LOG.info("Process ID is %s", os.getpid())
 
     try:
         locale.setlocale(locale.LC_ALL, '')
@@ -43,40 +52,40 @@ def main():
     if 'SHELL' not in os.environ:
         os.environ['SHELL'] = 'sh'
 
-    log.debug("config dir: '{0}'".format(arg.confdir))
-    log.debug("cache dir: '{0}'".format(arg.cachedir))
+    LOG.debug("config dir: '%s'", args.confdir)
+    LOG.debug("cache dir: '%s'", args.cachedir)
 
-    if arg.copy_config is not None:
+    if args.copy_config is not None:
         fm = FM()
-        fm.copy_config_files(arg.copy_config)
-        return 1 if arg.fail_unless_cd else 0  # COMPAT
-    if arg.list_tagged_files:
+        fm.copy_config_files(args.copy_config)
+        return 1 if args.fail_unless_cd else 0  # COMPAT
+    if args.list_tagged_files:
         fm = FM()
         try:
             if sys.version_info[0] >= 3:
-                f = open(fm.confpath('tagged'), 'r', errors='replace')
+                fobj = open(fm.confpath('tagged'), 'r', errors='replace')
             else:
-                f = open(fm.confpath('tagged'), 'r')
+                fobj = open(fm.confpath('tagged'), 'r')
         except Exception:
             pass
         else:
-            for line in f.readlines():
+            for line in fobj.readlines():
                 if len(line) > 2 and line[1] == ':':
-                    if line[0] in arg.list_tagged_files:
+                    if line[0] in args.list_tagged_files:
                         sys.stdout.write(line[2:])
-                elif len(line) > 0 and '*' in arg.list_tagged_files:
+                elif line and '*' in args.list_tagged_files:
                     sys.stdout.write(line)
-        return 1 if arg.fail_unless_cd else 0  # COMPAT
+        return 1 if args.fail_unless_cd else 0  # COMPAT
 
-    SettingsAware._setup(Settings())
+    SettingsAware._setup(Settings())  # pylint: disable=protected-access
 
-    if arg.selectfile:
-        arg.selectfile = os.path.abspath(arg.selectfile)
-        arg.targets.insert(0, os.path.dirname(arg.selectfile))
+    if args.selectfile:
+        args.selectfile = os.path.abspath(args.selectfile)
+        args.targets.insert(0, os.path.dirname(args.selectfile))
 
-    targets = arg.targets or ['.']
+    targets = args.targets or ['.']
     target = targets[0]
-    if arg.targets:  # COMPAT
+    if args.targets:  # COMPAT
         if target.startswith('file://'):
             target = target[7:]
         if not os.access(target, os.F_OK):
@@ -84,38 +93,38 @@ def main():
             return 1
         elif os.path.isfile(target):
             sys.stderr.write("Warning: Using ranger as a file launcher is "
-                   "deprecated.\nPlease use the standalone file launcher "
-                   "'rifle' instead.\n")
+                             "deprecated.\nPlease use the standalone file launcher "
+                             "'rifle' instead.\n")
 
             from ranger.ext.rifle import Rifle
             fm = FM()
-            if not arg.clean and os.path.isfile(fm.confpath('rifle.conf')):
+            if not args.clean and os.path.isfile(fm.confpath('rifle.conf')):
                 rifleconf = fm.confpath('rifle.conf')
             else:
                 rifleconf = fm.relpath('config/rifle.conf')
             rifle = Rifle(rifleconf)
             rifle.reload_config()
-            rifle.execute(targets, number=ranger.arg.mode, flags=ranger.arg.flags)
-            return 1 if arg.fail_unless_cd else 0  # COMPAT
+            rifle.execute(targets, number=ranger.args.mode, flags=ranger.args.flags)
+            return 1 if args.fail_unless_cd else 0  # COMPAT
 
     crash_traceback = None
     try:
         # Initialize objects
         fm = FM(paths=targets)
-        FileManagerAware._setup(fm)
-        load_settings(fm, arg.clean)
+        FileManagerAware._setup(fm)  # pylint: disable=protected-access
+        load_settings(fm, args.clean)
 
-        if arg.list_unused_keys:
+        if args.list_unused_keys:
             from ranger.ext.keybinding_parser import (special_keys,
-                    reversed_special_keys)
+                                                      reversed_special_keys)
             maps = fm.ui.keymaps['browser']
-            for key in sorted(special_keys.values(), key=lambda x: str(x)):
+            for key in sorted(special_keys.values(), key=str):
                 if key not in maps:
                     print("<%s>" % reversed_special_keys[key])
             for key in range(33, 127):
                 if key not in maps:
                     print(chr(key))
-            return 1 if arg.fail_unless_cd else 0  # COMPAT
+            return 1 if args.fail_unless_cd else 0  # COMPAT
 
         if not sys.stdin.isatty():
             sys.stderr.write("Error: Must run ranger from terminal\n")
@@ -124,33 +133,33 @@ def main():
         if fm.username == 'root':
             fm.settings.preview_files = False
             fm.settings.use_preview_script = False
-            log.info("Running as root, disabling the file previews.")
-        if not arg.debug:
+            LOG.info("Running as root, disabling the file previews.")
+        if not args.debug:
             from ranger.ext import curses_interrupt_handler
             curses_interrupt_handler.install_interrupt_handler()
 
         # Create cache directory
         if fm.settings.preview_images and fm.settings.use_preview_script:
-            if not os.path.exists(arg.cachedir):
-                os.makedirs(arg.cachedir)
+            if not os.path.exists(args.cachedir):
+                os.makedirs(args.cachedir)
 
         # Run the file manager
         fm.initialize()
         ranger.api.hook_init(fm)
         fm.ui.initialize()
 
-        if arg.selectfile:
-            fm.select_file(arg.selectfile)
+        if args.selectfile:
+            fm.select_file(args.selectfile)
 
-        if arg.cmd:
-            for command in arg.cmd:
+        if args.cmd:
+            for command in args.cmd:
                 fm.execute_console(command)
 
-        if ranger.arg.profile:
+        if ranger.args.profile:
             import cProfile
             import pstats
             profile = None
-            ranger.__fm = fm
+            ranger.__fm = fm  # pylint: disable=protected-access
             cProfile.run('ranger.__fm.loop()', tempfile.gettempdir() + '/ranger_profile')
             profile = pstats.Stats(tempfile.gettempdir() + '/ranger_profile', stream=sys.stderr)
         else:
@@ -170,11 +179,11 @@ def main():
             fm.ui.destroy()
         except (AttributeError, NameError):
             pass
-        if ranger.arg.profile and profile:
+        if ranger.args.profile and profile:
             profile.strip_dirs().sort_stats('cumulative').print_callees()
         if crash_traceback:
             print("ranger version: %s, executed with python %s" %
-                    (ranger.__version__, sys.version.split()[0]))
+                  (ranger.__version__, sys.version.split()[0]))
             print("Locale: %s" % '.'.join(str(s) for s in locale.getlocale()))
             try:
                 print("Current file: %s" % filepath)
@@ -182,18 +191,17 @@ def main():
                 pass
             print(crash_traceback)
             print("ranger crashed.  "
-                "Please report this traceback at:")
+                  "Please report this traceback at:")
             print("https://github.com/hut/ranger/issues")
-            return 1
-        return 0
+            return 1  # pylint: disable=lost-exception
+        return 0  # pylint: disable=lost-exception
 
 
 def parse_arguments():
     """Parse the program arguments"""
-    from optparse import OptionParser, SUPPRESS_HELP
+    from optparse import OptionParser, SUPPRESS_HELP  # pylint: disable=deprecated-module
     from os.path import expanduser
     from ranger import CONFDIR, CACHEDIR, USAGE, VERSION
-    from ranger.ext.openstruct import OpenStruct
 
     if 'XDG_CONFIG_HOME' in os.environ and os.environ['XDG_CONFIG_HOME']:
         default_confdir = os.environ['XDG_CONFIG_HOME'] + '/ranger'
@@ -208,75 +216,78 @@ def parse_arguments():
     parser = OptionParser(usage=USAGE, version=VERSION)
 
     parser.add_option('-d', '--debug', action='store_true',
-            help="activate debug mode")
+                      help="activate debug mode")
     parser.add_option('-c', '--clean', action='store_true',
-            help="don't touch/require any config files. ")
+                      help="don't touch/require any config files. ")
     parser.add_option('--logfile', type='string', metavar='file',
-            help="log file to use, '-' for stderr")
+                      help="log file to use, '-' for stderr")
     parser.add_option('-r', '--confdir', type='string',
-            metavar='dir', default=default_confdir,
-            help="change the configuration directory. (%default)")
+                      metavar='dir', default=default_confdir,
+                      help="change the configuration directory. (%default)")
     parser.add_option('--copy-config', type='string', metavar='which',
-            help="copy the default configs to the local config directory. "
-            "Possible values: all, rc, rifle, commands, commands_full, scope")
+                      help="copy the default configs to the local config directory. "
+                      "Possible values: all, rc, rifle, commands, commands_full, scope")
     parser.add_option('--fail-unless-cd', action='store_true',
-            help=SUPPRESS_HELP)  # COMPAT
+                      help=SUPPRESS_HELP)  # COMPAT
     parser.add_option('-m', '--mode', type='int', default=0, metavar='n',
-            help=SUPPRESS_HELP)  # COMPAT
+                      help=SUPPRESS_HELP)  # COMPAT
     parser.add_option('-f', '--flags', type='string', default='',
-            metavar='string', help=SUPPRESS_HELP)  # COMPAT
+                      metavar='string', help=SUPPRESS_HELP)  # COMPAT
     parser.add_option('--choosefile', type='string', metavar='TARGET',
-            help="Makes ranger act like a file chooser. When opening "
-            "a file, it will quit and write the name of the selected "
-            "file to TARGET.")
+                      help="Makes ranger act like a file chooser. When opening "
+                      "a file, it will quit and write the name of the selected "
+                      "file to TARGET.")
     parser.add_option('--choosefiles', type='string', metavar='TARGET',
-            help="Makes ranger act like a file chooser for multiple files "
-            "at once. When opening a file, it will quit and write the name "
-            "of all selected files to TARGET.")
+                      help="Makes ranger act like a file chooser for multiple files "
+                      "at once. When opening a file, it will quit and write the name "
+                      "of all selected files to TARGET.")
     parser.add_option('--choosedir', type='string', metavar='TARGET',
-            help="Makes ranger act like a directory chooser. When ranger quits"
-            ", it will write the name of the last visited directory to TARGET")
+                      help="Makes ranger act like a directory chooser. When ranger quits"
+                      ", it will write the name of the last visited directory to TARGET")
     parser.add_option('--selectfile', type='string', metavar='filepath',
-            help="Open ranger with supplied file selected.")
+                      help="Open ranger with supplied file selected.")
     parser.add_option('--list-unused-keys', action='store_true',
-            help="List common keys which are not bound to any action.")
+                      help="List common keys which are not bound to any action.")
     parser.add_option('--list-tagged-files', type='string', default=None,
-            metavar='tag',
-            help="List all files which are tagged with the given tag, default: *")
+                      metavar='tag',
+                      help="List all files which are tagged with the given tag, default: *")
     parser.add_option('--profile', action='store_true',
-            help="Print statistics of CPU usage on exit.")
+                      help="Print statistics of CPU usage on exit.")
     parser.add_option('--cmd', action='append', type='string', metavar='COMMAND',
-            help="Execute COMMAND after the configuration has been read. "
-            "Use this option multiple times to run multiple commands.")
+                      help="Execute COMMAND after the configuration has been read. "
+                      "Use this option multiple times to run multiple commands.")
 
-    options, positional = parser.parse_args()
-    arg = OpenStruct(options.__dict__, targets=positional)
-    arg.confdir = expanduser(arg.confdir)
-    arg.cachedir = expanduser(default_cachedir)
+    args, positional = parser.parse_args()
+    args.targets = positional
+    args.confdir = expanduser(args.confdir)
+    args.cachedir = expanduser(default_cachedir)
 
-    if arg.fail_unless_cd:  # COMPAT
+    if args.fail_unless_cd:  # COMPAT
         sys.stderr.write("Warning: The option --fail-unless-cd is deprecated.\n"
-            "It was used to facilitate using ranger as a file launcher.\n"
-            "Now, please use the standalone file launcher 'rifle' instead.\n")
+                         "It was used to facilitate using ranger as a file launcher.\n"
+                         "Now, please use the standalone file launcher 'rifle' instead.\n")
+
+    return args
+
 
-    return arg
+COMMANDS_EXCLUDE = ['settings', 'notify']
 
 
-def load_settings(fm, clean):
+def load_settings(  # pylint: disable=too-many-locals,too-many-branches,too-many-statements
+        fm, clean):
     from ranger.core.actions import Actions
     import ranger.core.shared
     import ranger.api.commands
-    from ranger.config import commands
+    from ranger.config import commands as commands_default
 
     # Load default commands
     fm.commands = ranger.api.commands.CommandContainer()
-    exclude = ['settings', 'notify']
-    include = [name for name in dir(Actions) if name not in exclude]
+    include = [name for name in dir(Actions) if name not in COMMANDS_EXCLUDE]
     fm.commands.load_commands_from_object(fm, include)
-    fm.commands.load_commands_from_module(commands)
+    fm.commands.load_commands_from_module(commands_default)
 
     if not clean:
-        allow_access_to_confdir(ranger.arg.confdir, True)
+        allow_access_to_confdir(ranger.args.confdir, True)
 
         # Load custom commands
         custom_comm_path = fm.confpath('commands.py')
@@ -284,16 +295,16 @@ def load_settings(fm, clean):
             old_bytecode_setting = sys.dont_write_bytecode
             sys.dont_write_bytecode = True
             try:
-                import commands
-                fm.commands.load_commands_from_module(commands)
-            except ImportError as e:
-                log.debug("Failed to import custom commands from '{0}'".format(custom_comm_path))
-                log.exception(e)
+                import commands as commands_custom
+                fm.commands.load_commands_from_module(commands_custom)
+            except ImportError as ex:
+                LOG.debug("Failed to import custom commands from '%s'", custom_comm_path)
+                LOG.exception(ex)
             else:
-                log.debug("Loaded custom commands from '{0}'".format(custom_comm_path))
+                LOG.debug("Loaded custom commands from '%s'", custom_comm_path)
             sys.dont_write_bytecode = old_bytecode_setting
 
-        allow_access_to_confdir(ranger.arg.confdir, False)
+        allow_access_to_confdir(ranger.args.confdir, False)
 
         # Load rc.conf
         custom_conf = fm.confpath('rc.conf')
@@ -304,20 +315,20 @@ def load_settings(fm, clean):
         if os.access(custom_conf, os.R_OK):
             fm.source(custom_conf)
 
-        allow_access_to_confdir(ranger.arg.confdir, True)
+        allow_access_to_confdir(ranger.args.confdir, True)
 
         # XXX Load plugins (experimental)
         try:
             plugindir = fm.confpath('plugins')
             plugins = [p[:-3] for p in os.listdir(plugindir)
-                    if p.endswith('.py') and not p.startswith('_')]
+                       if p.endswith('.py') and not p.startswith('_')]
         except Exception:
             pass
         else:
             if not os.path.exists(fm.confpath('plugins', '__init__.py')):
-                log.debug("Creating missing '__init__.py' file in plugin folder")
-                f = open(fm.confpath('plugins', '__init__.py'), 'w')
-                f.close()
+                LOG.debug("Creating missing '__init__.py' file in plugin folder")
+                fobj = open(fm.confpath('plugins', '__init__.py'), 'w')
+                fobj.close()
 
             ranger.fm = fm
             for plugin in sorted(plugins):
@@ -332,12 +343,12 @@ def load_settings(fm, clean):
                     else:
                         module = importlib.import_module('plugins.' + plugin)
                         fm.commands.load_commands_from_module(module)
-                    log.debug("Loaded plugin '{0}'".format(plugin))
-                except Exception as e:
-                    mex = "Error while loading plugin '{0}'".format(plugin)
-                    log.error(mex)
-                    log.exception(e)
-                    fm.notify(mex, bad=True)
+                    LOG.debug("Loaded plugin '%s'", plugin)
+                except Exception as ex:
+                    ex_msg = "Error while loading plugin '{0}'".format(plugin)
+                    LOG.error(ex_msg)
+                    LOG.exception(ex)
+                    fm.notify(ex_msg, bad=True)
             ranger.fm = None
 
         # COMPAT: Load the outdated options.py
@@ -350,7 +361,7 @@ def load_settings(fm, clean):
                     fm.settings[setting] = getattr(module, setting)
 
             sys.stderr.write(
-"""******************************
+                """******************************
 Warning: The configuration file 'options.py' is deprecated.
 Please move all settings to the file 'rc.conf', converting lines like
     "preview_files = False"
@@ -361,13 +372,12 @@ copy & paste it to a .py file in ~/.config/ranger/plugins/.
 Remove the options.py or discard stderr to get rid of this warning.
 ******************************\n""")
 
-        allow_access_to_confdir(ranger.arg.confdir, False)
+        allow_access_to_confdir(ranger.args.confdir, False)
     else:
         fm.source(fm.relpath('config', 'rc.conf'))
 
 
 def allow_access_to_confdir(confdir, allow):
-    import sys
     from errno import EEXIST
 
     if allow:
@@ -381,7 +391,7 @@ def allow_access_to_confdir(confdir, allow):
                 print("files, use the --clean option.")
                 raise SystemExit()
         else:
-            log.debug("Created config directory '{0}'".format(confdir))
+            LOG.debug("Created config directory '%s'", confdir)
         if confdir not in sys.path:
             sys.path[0:0] = [confdir]
     else:
diff --git a/ranger/core/metadata.py b/ranger/core/metadata.py
index 299d2b85..76ff2bb9 100644
--- a/ranger/core/metadata.py
+++ b/ranger/core/metadata.py
@@ -11,15 +11,19 @@ The database is contained in a local .metadata.json file.
 # TODO: Update metadata keys if a file gets renamed/moved
 # TODO: A global metadata file, maybe as a replacement for tags
 
-METADATA_FILE_NAME = ".metadata.json"
-DEEP_SEARCH_DEFAULT = False
+from __future__ import (absolute_import, print_function)
 
 import copy
 from os.path import join, dirname, exists, basename
 from ranger.ext.openstruct import DefaultOpenStruct as ostruct
 
 
+METADATA_FILE_NAME = ".metadata.json"
+DEEP_SEARCH_DEFAULT = False
+
+
 class MetadataManager(object):
+
     def __init__(self):
         # metadata_cache maps filenames to dicts containing their metadata
         self.metadata_cache = dict()
@@ -41,10 +45,6 @@ class MetadataManager(object):
                 return ostruct()
 
     def set_metadata(self, filename, update_dict):
-        import json
-        result = None
-        found = False
-
         if not self.deep_search:
             metafile = next(self._get_metafile_names(filename))
             return self._set_metadata_raw(filename, update_dict, metafile)
@@ -54,7 +54,6 @@ class MetadataManager(object):
 
     def _set_metadata_raw(self, filename, update_dict, metafile):
         import json
-        valid = (filename, basename(filename))
 
         entries = self._get_metafile_content(metafile)
         try:
@@ -85,14 +84,13 @@ class MetadataManager(object):
         self.metadata_cache[filename] = entry
         self.metafile_cache[metafile] = entries
 
-        with open(metafile, "w") as f:
-            json.dump(entries, f, check_circular=True, indent=2)
+        with open(metafile, "w") as fobj:
+            json.dump(entries, fobj, check_circular=True, indent=2)
 
     def _get_entry(self, filename):
         if filename in self.metadata_cache:
             return self.metadata_cache[filename]
         else:
-            valid = (filename, basename(filename))
 
             # Try to find an entry for this file in any of
             # the applicable .metadata.json files
@@ -115,20 +113,20 @@ class MetadataManager(object):
 
     def _get_metafile_content(self, metafile):
         import json
+
         if metafile in self.metafile_cache:
             return self.metafile_cache[metafile]
-        else:
-            if exists(metafile):
-                with open(metafile, "r") as f:
-                    try:
-                        entries = json.load(f)
-                    except ValueError:
-                        raise ValueError("Failed decoding JSON file %s" %
-                                metafile)
-                self.metafile_cache[metafile] = entries
-                return entries
-            else:
-                return {}
+
+        if exists(metafile):
+            with open(metafile, "r") as fobj:
+                try:
+                    entries = json.load(fobj)
+                except ValueError:
+                    raise ValueError("Failed decoding JSON file %s" % metafile)
+            self.metafile_cache[metafile] = entries
+            return entries
+
+        return {}
 
     def _get_metafile_names(self, path):
         # Iterates through the paths of all .metadata.json files that could
diff --git a/ranger/core/runner.py b/ranger/core/runner.py
index 78d52764..ee182c29 100644
--- a/ranger/core/runner.py
+++ b/ranger/core/runner.py
@@ -22,6 +22,8 @@ t: run application in a new terminal window
 (An uppercase key negates the respective lower case flag)
 """
 
+from __future__ import (absolute_import, print_function)
+
 import os
 import sys
 from subprocess import Popen, PIPE
@@ -30,7 +32,7 @@ from ranger.ext.popen_forked import Popen_forked
 
 
 # TODO: Remove unused parts of runner.py
-#ALLOWED_FLAGS = 'sdpwcrtSDPWCRT'
+# ALLOWED_FLAGS = 'sdpwcrtSDPWCRT'
 ALLOWED_FLAGS = 'cfrtCFRT'
 
 
@@ -45,7 +47,7 @@ def press_enter():
     waitfnc()
 
 
-class Context(object):
+class Context(object):  # pylint: disable=too-many-instance-attributes
     """A context object contains data on how to run a process.
 
     The attributes are:
@@ -62,8 +64,18 @@ class Context(object):
     popen_kws -- keyword arguments which are directly passed to Popen
     """
 
-    def __init__(self, **keywords):
-        self.__dict__ = keywords
+    def __init__(  # pylint: disable=redefined-builtin,too-many-arguments
+            self, action=None, app=None, mode=None, flags=None,
+            files=None, file=None, fm=None, wait=None, popen_kws=None):
+        self.action = action
+        self.app = app
+        self.mode = mode
+        self.flags = flags
+        self.files = files
+        self.file = file
+        self.fm = fm
+        self.wait = wait
+        self.popen_kws = popen_kws
 
     @property
     def filepaths(self):
@@ -85,7 +97,8 @@ class Context(object):
                 self.flags = ''.join(c for c in self.flags if c not in bad)
 
 
-class Runner(object):
+class Runner(object):  # pylint: disable=too-few-public-methods
+
     def __init__(self, ui=None, logfunc=None, fm=None):
         self.ui = ui
         self.fm = fm
@@ -112,7 +125,10 @@ class Runner(object):
                 except Exception:
                     self._log("Failed to suspend UI")
 
-    def __call__(self, action=None, try_app_first=False,
+    def __call__(
+            # pylint: disable=too-many-branches,too-many-statements
+            # pylint: disable=too-many-arguments,too-many-locals
+            self, action=None, try_app_first=False,
             app='default', files=None, mode=0,
             flags='', wait=True, **popen_kws):
         """Run the application in the way specified by the options.
@@ -128,8 +144,8 @@ class Runner(object):
         # an Application object.
 
         context = Context(app=app, files=files, mode=mode, fm=self.fm,
-                flags=flags, wait=wait, popen_kws=popen_kws,
-                file=files and files[0] or None)
+                          flags=flags, wait=wait, popen_kws=popen_kws,
+                          file=files and files[0] or None)
 
         if action is None:
             return self._log("No way of determining the action!")
@@ -211,7 +227,7 @@ class Runner(object):
             error = None
             process = None
             self.fm.signal_emit('runner.execute.before',
-                    popen_kws=popen_kws, context=context)
+                                popen_kws=popen_kws, context=context)
             try:
                 if 'f' in context.flags:
                     # This can fail and return False if os.fork() is not
@@ -219,9 +235,9 @@ class Runner(object):
                     Popen_forked(**popen_kws)
                 else:
                     process = Popen(**popen_kws)
-            except Exception as e:
-                error = e
-                self._log("Failed to run: %s\n%s" % (str(action), str(e)))
+            except Exception as ex:
+                error = ex
+                self._log("Failed to run: %s\n%s" % (str(action), str(ex)))
             else:
                 if context.wait:
                     process.wait()
@@ -231,12 +247,12 @@ class Runner(object):
                     press_enter()
         finally:
             self.fm.signal_emit('runner.execute.after',
-                    popen_kws=popen_kws, context=context, error=error)
+                                popen_kws=popen_kws, context=context, error=error)
             if devnull:
                 devnull.close()
             if toggle_ui:
                 self._activate_ui(True)
             if pipe_output and process:
-                return self(action='less', app='pager', try_app_first=True,
-                        stdin=process.stdout)
-            return process
+                return self(action='less', app='pager',  # pylint: disable=lost-exception
+                            try_app_first=True, stdin=process.stdout)
+            return process  # pylint: disable=lost-exception
diff --git a/ranger/core/shared.py b/ranger/core/shared.py
index 38b0d35a..3595aede 100644
--- a/ranger/core/shared.py
+++ b/ranger/core/shared.py
@@ -3,17 +3,19 @@
 
 """Shared objects contain singletons for shared use."""
 
-from ranger.ext.lazy_property import lazy_property
+from __future__ import (absolute_import, print_function)
 
+from ranger.ext.lazy_property import lazy_property  # NOQA pylint: disable=unused-import
 
-class FileManagerAware(object):
+
+class FileManagerAware(object):  # pylint: disable=too-few-public-methods
     """Subclass this to gain access to the global "FM" object."""
     @staticmethod
     def _setup(fm):
         FileManagerAware.fm = fm
 
 
-class SettingsAware(object):
+class SettingsAware(object):  # pylint: disable=too-few-public-methods
     """Subclass this to gain access to the global "SettingObject" object."""
     @staticmethod
     def _setup(settings):
diff --git a/ranger/core/tab.py b/ranger/core/tab.py
index fa40a12b..60097ced 100644
--- a/ranger/core/tab.py
+++ b/ranger/core/tab.py
@@ -1,17 +1,19 @@
 # This file is part of ranger, the console file manager.
 # License: GNU GPL version 3, see the file "AUTHORS" for details.
 
+from __future__ import (absolute_import, print_function)
+
 import os
-import sys
 from os.path import abspath, normpath, join, expanduser, isdir
+import sys
 
 from ranger.container import settings
 from ranger.container.history import History
 from ranger.core.shared import FileManagerAware, SettingsAware
-from ranger.ext.signals import SignalDispatcher
 
 
-class Tab(FileManagerAware, SettingsAware):
+class Tab(FileManagerAware, SettingsAware):  # pylint: disable=too-many-instance-attributes
+
     def __init__(self, path):
         self.thisdir = None  # Current Working Directory
         self._thisfile = None  # Current File
@@ -24,10 +26,10 @@ class Tab(FileManagerAware, SettingsAware):
         # weak references are not equal to the original object when tested with
         # "==", and this breaks _set_thisfile_from_signal and _on_tab_change.
         self.fm.signal_bind('move', self._set_thisfile_from_signal,
-                priority=settings.SIGNAL_PRIORITY_AFTER_SYNC,
-                weak=(sys.version_info[0] >= 3))
+                            priority=settings.SIGNAL_PRIORITY_AFTER_SYNC,
+                            weak=(sys.version_info[0] >= 3))
         self.fm.signal_bind('tab.change', self._on_tab_change,
-                weak=(sys.version_info[0] >= 3))
+                            weak=(sys.version_info[0] >= 3))
 
     def _set_thisfile_from_signal(self, signal):
         if self == signal.tab:
@@ -65,7 +67,7 @@ class Tab(FileManagerAware, SettingsAware):
                 return None
         else:
             directory = self.thisdir
-            for i in range(level):
+            for _ in range(level):
                 if directory is None:
                     return None
                 if directory.is_directory:
@@ -82,7 +84,7 @@ class Tab(FileManagerAware, SettingsAware):
                 return [self._thisfile]
         return []
 
-    def assign_cursor_positions_for_subdirs(self):
+    def assign_cursor_positions_for_subdirs(self):  # pylint: disable=invalid-name
         """Assign correct cursor positions for subdirectories"""
         last_path = None
         for path in reversed(self.pathway):
@@ -142,8 +144,8 @@ class Tab(FileManagerAware, SettingsAware):
         else:
             pathway = []
             currentpath = '/'
-            for dir in path.split('/'):
-                currentpath = join(currentpath, dir)
+            for comp in path.split('/'):
+                currentpath = join(currentpath, comp)
                 pathway.append(self.fm.get_directory(currentpath))
             self.pathway = tuple(pathway)
 
diff --git a/ranger/ext/accumulator.py b/ranger/ext/accumulator.py
index 863a59df..d75363ca 100644
--- a/ranger/ext/accumulator.py
+++ b/ranger/ext/accumulator.py
@@ -1,10 +1,13 @@
 # This file is part of ranger, the console file manager.
 # License: GNU GPL version 3, see the file "AUTHORS" for details.
 
+from __future__ import (absolute_import, print_function)
+
 from ranger.ext.direction import Direction
 
 
 class Accumulator(object):
+
     def __init__(self):
         self.pointer = 0
         self.pointed_obj = None
@@ -15,11 +18,11 @@ class Accumulator(object):
         if not lst:
             return self.pointer
         pointer = direction.move(
-                direction=direction.down(),
-                maximum=len(lst),
-                override=narg,
-                pagesize=self.get_height(),
-                current=self.pointer)
+            direction=direction.down(),
+            maximum=len(lst),
+            override=narg,
+            pagesize=self.get_height(),
+            current=self.pointer)
         self.pointer = pointer
         self.correct_pointer()
         return pointer
@@ -88,10 +91,12 @@ class Accumulator(object):
     def sync_index(self, **kw):
         self.move_to_obj(self.pointed_obj, **kw)
 
-    def get_list(self):
+    @staticmethod
+    def get_list():
         """OVERRIDE THIS"""
         return []
 
-    def get_height(self):
+    @staticmethod
+    def get_height():
         """OVERRIDE THIS"""
         return 25
diff --git a/ranger/ext/cached_function.py b/ranger/ext/cached_function.py
index 6c1c7769..c5a4cb47 100644
--- a/ranger/ext/cached_function.py
+++ b/ranger/ext/cached_function.py
@@ -1,6 +1,8 @@
 # This file is part of ranger, the console file manager.
 # License: GNU GPL version 3, see the file "AUTHORS" for details.
 
+from __future__ import (absolute_import, print_function)
+
 
 def cached_function(fnc):
     cache = {}
@@ -12,5 +14,5 @@ def cached_function(fnc):
             value = fnc(*args)
             cache[args] = value
             return value
-    inner_cached_function._cache = cache
+    inner_cached_function._cache = cache  # pylint: disable=protected-access
     return inner_cached_function
diff --git a/ranger/ext/curses_interrupt_handler.py b/ranger/ext/curses_interrupt_handler.py
index 606cbd62..e31503b8 100644
--- a/ranger/ext/curses_interrupt_handler.py
+++ b/ranger/ext/curses_interrupt_handler.py
@@ -8,15 +8,17 @@ rise a KeyboardInterrupt exception and handle it by pushing
 a Ctrl+C (ASCII value 3) to the curses getch stack.
 """
 
+from __future__ import (absolute_import, print_function)
+
 import curses
 import signal
 
-_do_catch_interrupt = True
+_do_catch_interrupt = True  # pylint: disable=invalid-name
 
 
 def catch_interrupt(boolean=True):
     """Should interrupts be caught and simulate a ^C press in curses?"""
-    global _do_catch_interrupt
+    global _do_catch_interrupt  # pylint: disable=global-statement,invalid-name
     old_value = _do_catch_interrupt
     _do_catch_interrupt = bool(boolean)
     return old_value
@@ -24,15 +26,14 @@ def catch_interrupt(boolean=True):
 # The handler which will be used in signal.signal()
 
 
-def _interrupt_handler(a1, a2):
-    global _do_catch_interrupt
+def _interrupt_handler(signum, frame):
     # if a keyboard-interrupt occurs...
     if _do_catch_interrupt:
         # push a Ctrl+C (ascii value 3) to the curses getch stack
         curses.ungetch(3)
     else:
         # use the default handler
-        signal.default_int_handler(a1, a2)
+        signal.default_int_handler(signum, frame)
 
 
 def install_interrupt_handler():
diff --git a/ranger/ext/direction.py b/ranger/ext/direction.py
index 787da1bf..5d2341c2 100644
--- a/ranger/ext/direction.py
+++ b/ranger/ext/direction.py
@@ -18,8 +18,11 @@ has been defined.
 False
 """
 
+from __future__ import (absolute_import, print_function)
+
 
 class Direction(dict):
+
     def __init__(self, dictionary=None, **keywords):
         if dictionary is not None:
             dict.__init__(self, dictionary)
@@ -50,8 +53,8 @@ class Direction(dict):
             except Exception:
                 return fallback
 
-    def up(self):
-        return -Direction.down(self)
+    def up(self):  # pylint: disable=invalid-name
+        return -Direction.down(self)  # pylint: disable=invalid-unary-operand-type
 
     def down(self):
         return Direction._get_direction(self, 'down', 'up')
@@ -63,7 +66,7 @@ class Direction(dict):
         return Direction._get_bool(self, 'absolute', 'relative')
 
     def left(self):
-        return -Direction.right(self)
+        return -Direction.right(self)  # pylint: disable=invalid-unary-operand-type
 
     def relative(self):
         return not Direction.absolute(self)
@@ -103,8 +106,8 @@ class Direction(dict):
             if key in self:
                 self[key] = n
 
-    def move(self, direction, override=None, minimum=0, maximum=9999,
-            current=0, pagesize=1, offset=0):
+    def move(self, direction, override=None, minimum=0,  # pylint: disable=too-many-arguments
+             maximum=9999, current=0, pagesize=1, offset=0):
         """Calculates the new position in a given boundary.
 
         Example:
@@ -142,10 +145,11 @@ class Direction(dict):
 
     def select(self, lst, current, pagesize, override=None, offset=1):
         dest = self.move(direction=self.down(), override=override,
-            current=current, pagesize=pagesize, minimum=0, maximum=len(lst) + 1)
+                         current=current, pagesize=pagesize, minimum=0, maximum=len(lst) + 1)
         selection = lst[min(current, dest):max(current, dest) + offset]
         return dest + offset - 1, selection
 
+
 if __name__ == '__main__':
     import doctest
     doctest.testmod()
diff --git a/ranger/ext/get_executables.py b/ranger/ext/get_executables.py
index f2a31345..e077d149 100644
--- a/ranger/ext/get_executables.py
+++ b/ranger/ext/get_executables.py
@@ -1,18 +1,21 @@
 # This file is part of ranger, the console file manager.
 # License: GNU GPL version 3, see the file "AUTHORS" for details.
 
+from __future__ import (absolute_import, print_function)
+
 from stat import S_IXOTH, S_IFREG
-from ranger.ext.iter_tools import unique
 from os import listdir, environ, stat
 import shlex
 
+from ranger.ext.iter_tools import unique
+
 
-_cached_executables = None
+_cached_executables = None  # pylint: disable=invalid-name
 
 
 def get_executables():
     """Return all executable files in $PATH. Cached version."""
-    global _cached_executables
+    global _cached_executables  # pylint: disable=global-statement,invalid-name
     if _cached_executables is None:
         _cached_executables = get_executables_uncached()
     return _cached_executables
diff --git a/ranger/ext/human_readable.py b/ranger/ext/human_readable.py
index 31d5d279..71bc29b8 100644
--- a/ranger/ext/human_readable.py
+++ b/ranger/ext/human_readable.py
@@ -1,8 +1,10 @@
 # This file is part of ranger, the console file manager.
 # License: GNU GPL version 3, see the file "AUTHORS" for details.
 
+from __future__ import (absolute_import, print_function)
 
-def human_readable(byte, separator=' '):
+
+def human_readable(byte, separator=' '):  # pylint: disable=too-many-return-statements
     """Convert a large number of bytes to an easily readable format.
 
     >>> human_readable(54)
@@ -19,7 +21,7 @@ def human_readable(byte, separator=' '):
     if byte <= 0:
         return '0'
     if byte < 2**10:
-        return '%d%sB'   % (byte, separator)
+        return '%d%sB' % (byte, separator)
     if byte < 2**10 * 999:
         return '%.3g%sK' % (byte / 2**10.0, separator)
     if byte < 2**20:
@@ -42,6 +44,7 @@ def human_readable(byte, separator=' '):
         return '%.4g%sP' % (byte / 2**50.0, separator)
     return '>9000'
 
+
 if __name__ == '__main__':
     import doctest
     doctest.testmod()
diff --git a/ranger/ext/img_display.py b/ranger/ext/img_display.py
index 0e6b08fe..7c75214e 100644
--- a/ranger/ext/img_display.py
+++ b/ranger/ext/img_display.py
@@ -9,18 +9,21 @@ This module provides functions to draw images in the terminal using supported
 implementations, which are currently w3m, iTerm2 and urxvt.
 """
 
+from __future__ import (absolute_import, print_function)
+
 import base64
 import curses
 import errno
 import fcntl
 import imghdr
 import os
-import select
 import struct
 import sys
+from subprocess import Popen, PIPE
+
 import termios
+
 from ranger.core.shared import FileManagerAware
-from subprocess import Popen, PIPE
 
 W3MIMGDISPLAY_ENV = "W3MIMGDISPLAY_PATH"
 W3MIMGDISPLAY_OPTIONS = []
@@ -38,6 +41,7 @@ class ImgDisplayUnsupportedException(Exception):
 
 class ImageDisplayer(object):
     """Image display provider functions for drawing images in the terminal"""
+
     def draw(self, path, start_x, start_y, width, height):
         """Draw an image at the given coordinates."""
         pass
@@ -61,35 +65,39 @@ class W3MImageDisplayer(ImageDisplayer):
     """
     is_initialized = False
 
+    def __init__(self):
+        self.binary_path = None
+        self.process = None
+
     def initialize(self):
         """start w3mimgdisplay"""
         self.binary_path = None
         self.binary_path = self._find_w3mimgdisplay_executable()  # may crash
         self.process = Popen([self.binary_path] + W3MIMGDISPLAY_OPTIONS,
-                stdin=PIPE, stdout=PIPE, universal_newlines=True)
+                             stdin=PIPE, stdout=PIPE, universal_newlines=True)
         self.is_initialized = True
 
-    def _find_w3mimgdisplay_executable(self):
+    @staticmethod
+    def _find_w3mimgdisplay_executable():
         paths = [os.environ.get(W3MIMGDISPLAY_ENV, None)] + W3MIMGDISPLAY_PATHS
         for path in paths:
             if path is not None and os.path.exists(path):
                 return path
         raise RuntimeError("No w3mimgdisplay executable found.  Please set "
-            "the path manually by setting the %s environment variable.  (see "
-            "man page)" % W3MIMGDISPLAY_ENV)
+                           "the path manually by setting the %s environment variable.  (see "
+                           "man page)" % W3MIMGDISPLAY_ENV)
 
     def _get_font_dimensions(self):
         # Get the height and width of a character displayed in the terminal in
         # pixels.
         if self.binary_path is None:
             self.binary_path = self._find_w3mimgdisplay_executable()
-        s = struct.pack("HHHH", 0, 0, 0, 0)
+        farg = struct.pack("HHHH", 0, 0, 0, 0)
         fd_stdout = sys.stdout.fileno()
-        x = fcntl.ioctl(fd_stdout, termios.TIOCGWINSZ, s)
-        rows, cols, xpixels, ypixels = struct.unpack("HHHH", x)
+        fretint = fcntl.ioctl(fd_stdout, termios.TIOCGWINSZ, farg)
+        rows, cols, xpixels, ypixels = struct.unpack("HHHH", fretint)
         if xpixels == 0 and ypixels == 0:
-            process = Popen([self.binary_path, "-test"],
-                stdout=PIPE, universal_newlines=True)
+            process = Popen([self.binary_path, "-test"], stdout=PIPE, universal_newlines=True)
             output, _ = process.communicate()
             output = output.split()
             xpixels, ypixels = int(output[0]), int(output[1])
@@ -102,8 +110,7 @@ class W3MImageDisplayer(ImageDisplayer):
     def draw(self, path, start_x, start_y, width, height):
         if not self.is_initialized or self.process.poll() is not None:
             self.initialize()
-        self.process.stdin.write(self._generate_w3m_input(path, start_x,
-            start_y, width, height))
+        self.process.stdin.write(self._generate_w3m_input(path, start_x, start_y, width, height))
         self.process.stdin.flush()
         self.process.stdout.readline()
 
@@ -114,20 +121,20 @@ class W3MImageDisplayer(ImageDisplayer):
         fontw, fonth = self._get_font_dimensions()
 
         cmd = "6;{x};{y};{w};{h}\n4;\n3;\n".format(
-                x=int((start_x - 0.2) * fontw),
-                y=start_y * fonth,
-                # y = int((start_y + 1) * fonth), # (for tmux top status bar)
-                w=int((width + 0.4) * fontw),
-                h=height * fonth + 1)
-                # h = (height - 1) * fonth + 1) # (for tmux top status bar)
+            x=int((start_x - 0.2) * fontw),
+            y=start_y * fonth,
+            # y = int((start_y + 1) * fonth), # (for tmux top status bar)
+            w=int((width + 0.4) * fontw),
+            h=height * fonth + 1,
+            # h = (height - 1) * fonth + 1, # (for tmux top status bar)
+        )
 
         try:
             self.process.stdin.write(cmd)
-        except IOError as e:
-            if e.errno == errno.EPIPE:
+        except IOError as ex:
+            if ex.errno == errno.EPIPE:
                 return
-            else:
-                raise e
+            raise
         self.process.stdin.flush()
         self.process.stdout.readline()
 
@@ -168,12 +175,13 @@ class W3MImageDisplayer(ImageDisplayer):
             height = max_height_pixels
 
         return "0;1;{x};{y};{w};{h};;;;;{filename}\n4;\n3;\n".format(
-                x=int((start_x - 0.2) * fontw),
-                y=start_y * fonth,
-                # y = (start_y + 1) * fonth, # (for tmux top status bar)
-                w=width,
-                h=height,
-                filename=path)
+            x=int((start_x - 0.2) * fontw),
+            y=start_y * fonth,
+            # y = (start_y + 1) * fonth, # (for tmux top status bar)
+            w=width,
+            h=height,
+            filename=path,
+        )
 
     def quit(self):
         if self.is_initialized and self.process and self.process.poll() is None:
@@ -235,33 +243,34 @@ class ITerm2ImageDisplayer(ImageDisplayer, FileManagerAware):
                 min_scale = min(width_scale, height_scale)
                 max_scale = max(width_scale, height_scale)
                 if width * max_scale <= max_width and height * max_scale <= max_height:
-                    return (width * max_scale)
-                else:
-                    return (width * min_scale)
-            else:
-                scale = max_height / float(height)
-                return (width * scale)
+                    return width * max_scale
+                return width * min_scale
+
+            scale = max_height / float(height)
+            return width * scale
         elif width > max_width:
             scale = max_width / float(width)
-            return (width * scale)
-        else:
-            return width
+            return width * scale
+
+        return width
 
-    def _encode_image_content(self, path):
+    @staticmethod
+    def _encode_image_content(path):
         """Read and encode the contents of path"""
-        file = open(path, 'rb')
+        fobj = open(path, 'rb')
         try:
-            return base64.b64encode(file.read())
+            return base64.b64encode(fobj.read())
         except Exception:
             return ""
         finally:
-            file.close()
+            fobj.close()
 
-    def _get_image_dimensions(self, path):
+    @staticmethod
+    def _get_image_dimensions(path):
         """Determine image size using imghdr"""
         file_handle = open(path, 'rb')
         file_header = file_handle.read(24)
-        image_type  = imghdr.what(path)
+        image_type = imghdr.what(path)
         if len(file_header) != 24:
             file_handle.close()
             return 0, 0
@@ -305,17 +314,19 @@ class URXVTImageDisplayer(ImageDisplayer, FileManagerAware):
 
     """
 
-    def _get_max_sizes(self):
+    @staticmethod
+    def _get_max_sizes():
         """Use the whole terminal."""
-        w = 100
-        h = 100
-        return w, h
+        pct_width = 100
+        pct_height = 100
+        return pct_width, pct_height
 
-    def _get_centered_offsets(self):
+    @staticmethod
+    def _get_centered_offsets():
         """Center the image."""
-        x = 50
-        y = 50
-        return x, y
+        pct_x = 50
+        pct_y = 50
+        return pct_x, pct_y
 
     def _get_sizes(self):
         """Return the width and height of the preview pane in relation to the
@@ -327,18 +338,18 @@ class URXVTImageDisplayer(ImageDisplayer, FileManagerAware):
 
         total_columns_ratio = sum(self.fm.settings.column_ratios)
         preview_column_ratio = self.fm.settings.column_ratios[-1]
-        w = int((100 * preview_column_ratio) / total_columns_ratio)
-        h = 100  # As much as possible while preserving the aspect ratio.
-        return w, h
+        pct_width = int((100 * preview_column_ratio) / total_columns_ratio)
+        pct_height = 100  # As much as possible while preserving the aspect ratio.
+        return pct_width, pct_height
 
     def _get_offsets(self):
         """Return the offsets of the image center."""
         if self.fm.ui.pager.visible:
             return self._get_centered_offsets()
 
-        x = 100  # Right-aligned.
-        y = 2    # TODO: Use the font size to calculate this offset.
-        return x, y
+        pct_x = 100  # Right-aligned.
+        pct_y = 2    # TODO: Use the font size to calculate this offset.
+        return pct_x, pct_y
 
     def draw(self, path, start_x, start_y, width, height):
         # The coordinates in the arguments are ignored as urxvt takes
@@ -346,10 +357,15 @@ class URXVTImageDisplayer(ImageDisplayer, FileManagerAware):
         # image center as a percentage of the terminal size. As a
         # result all values below are in percents.
 
-        x, y = self._get_offsets()
-        w, h = self._get_sizes()
+        pct_x, pct_y = self._get_offsets()
+        pct_width, pct_height = self._get_sizes()
 
-        sys.stdout.write("\033]20;{path};{w}x{h}+{x}+{y}:op=keep-aspect\a".format(**vars()))
+        sys.stdout.write(
+            "\033]20;{path};{pct_width}x{pct_height}+{pct_x}+{pct_y}:op=keep-aspect\a".format(
+                path=path, pct_width=pct_width, pct_height=pct_height,
+                pct_x=pct_x, pct_y=pct_y,
+            )
+        )
         sys.stdout.flush()
 
     def clear(self, start_x, start_y, width, height):
diff --git a/ranger/ext/iter_tools.py b/ranger/ext/iter_tools.py
index 838d8aff..70b74c39 100644
--- a/ranger/ext/iter_tools.py
+++ b/ranger/ext/iter_tools.py
@@ -1,6 +1,8 @@
 # This file is part of ranger, the console file manager.
 # License: GNU GPL version 3, see the file "AUTHORS" for details.
 
+from __future__ import (absolute_import, print_function)
+
 from collections import deque
 
 
@@ -42,6 +44,7 @@ def unique(iterable):
             already_seen.append(item)
     return type(iterable)(already_seen)
 
+
 if __name__ == '__main__':
     import doctest
     doctest.testmod()
diff --git a/ranger/ext/keybinding_parser.py b/ranger/ext/keybinding_parser.py
index 6a4cbde9..b7816cf3 100644
--- a/ranger/ext/keybinding_parser.py
+++ b/ranger/ext/keybinding_parser.py
@@ -1,17 +1,19 @@
 # This file is part of ranger, the console file manager.
 # License: GNU GPL version 3, see the file "AUTHORS" for details.
 
+from __future__ import (absolute_import, print_function)
+
 import sys
 import copy
 import curses.ascii
 
 PY3 = sys.version_info[0] >= 3
-digits = set(range(ord('0'), ord('9') + 1))
+digits = set(range(ord('0'), ord('9') + 1))  # pylint: disable=invalid-name
 
 # Arbitrary numbers which are not used with curses.KEY_XYZ
 ANYKEY, PASSIVE_ACTION, ALT_KEY, QUANT_KEY = range(9001, 9005)
 
-special_keys = {
+special_keys = {  # pylint: disable=invalid-name
     'bs': curses.KEY_BACKSPACE,
     'backspace': curses.KEY_BACKSPACE,
     'backspace2': curses.ascii.DEL,
@@ -38,33 +40,39 @@ special_keys = {
     'gt': ord('>'),
 }
 
-very_special_keys = {
+very_special_keys = {  # pylint: disable=invalid-name
     'any': ANYKEY,
     'alt': ALT_KEY,
     'bg': PASSIVE_ACTION,
     'allow_quantifiers': QUANT_KEY,
 }
 
-for key, val in tuple(special_keys.items()):
-    special_keys['a-' + key] = (ALT_KEY, val)
 
-for char in 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_!{}':
-    special_keys['a-' + char] = (ALT_KEY, ord(char))
+def special_keys_init():
+    for key, val in tuple(special_keys.items()):
+        special_keys['a-' + key] = (ALT_KEY, val)
+
+    for char in 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_!{}':
+        special_keys['a-' + char] = (ALT_KEY, ord(char))
+
+    for char in 'abcdefghijklmnopqrstuvwxyz_':
+        special_keys['c-' + char] = ord(char) - 96
 
-for char in 'abcdefghijklmnopqrstuvwxyz_':
-    special_keys['c-' + char] = ord(char) - 96
+    special_keys['c-space'] = 0
 
-special_keys['c-space'] = 0
+    for n in range(64):
+        special_keys['f' + str(n)] = curses.KEY_F0 + n
 
-for n in range(64):
-    special_keys['f' + str(n)] = curses.KEY_F0 + n
+
+special_keys_init()
 
 special_keys.update(very_special_keys)
 del very_special_keys
-reversed_special_keys = dict((v, k) for k, v in special_keys.items())
+reversed_special_keys = dict(  # pylint: disable=invalid-name
+    (v, k) for k, v in special_keys.items())
 
 
-def parse_keybinding(obj):
+def parse_keybinding(obj):  # pylint: disable=too-many-branches
     """Translate a keybinding to a sequence of integers
 
     >>> tuple(parse_keybinding("lol<CR>"))
@@ -86,9 +94,9 @@ def parse_keybinding(obj):
             yield char
     elif isinstance(obj, int):
         yield obj
-    elif isinstance(obj, str):
+    elif isinstance(obj, str):  # pylint: disable=too-many-nested-blocks
         in_brackets = False
-        bracket_content = None
+        bracket_content = []
         for char in obj:
             if in_brackets:
                 if char == '>':
@@ -103,8 +111,8 @@ def parse_keybinding(obj):
                             yield int(string)
                         else:
                             yield ord('<')
-                            for c in bracket_content:
-                                yield ord(c)
+                            for bracket_char in bracket_content:
+                                yield ord(bracket_char)
                             yield ord('>')
                     except TypeError:
                         yield keys  # it was no tuple, just an int
@@ -118,8 +126,8 @@ def parse_keybinding(obj):
                     yield ord(char)
         if in_brackets:
             yield ord('<')
-            for c in bracket_content:
-                yield ord(c)
+            for char in bracket_content:
+                yield ord(char)
 
 
 def construct_keybinding(iterable):
@@ -151,6 +159,7 @@ def _unbind_traverse(pointer, keys, pos=0):
 
 
 class KeyMaps(dict):
+
     def __init__(self, keybuffer=None):
         dict.__init__(self)
         self.keybuffer = keybuffer
@@ -195,7 +204,7 @@ class KeyMaps(dict):
                 pointer = pointer[key]
             except Exception:
                 raise KeyError("Tried to copy the keybinding `%s',"
-                        " but it was not found." % source)
+                               " but it was not found." % source)
         self.bind(context, target, copy.deepcopy(pointer))
 
     def unbind(self, context, keys):
@@ -205,17 +214,14 @@ class KeyMaps(dict):
         _unbind_traverse(pointer, keys)
 
 
-class KeyBuffer(object):
-    any_key             = ANYKEY
-    passive_key         = PASSIVE_ACTION
-    quantifier_key      = QUANT_KEY
+class KeyBuffer(object):  # pylint: disable=too-many-instance-attributes
+    any_key = ANYKEY
+    passive_key = PASSIVE_ACTION
+    quantifier_key = QUANT_KEY
     exclude_from_anykey = [27]
 
     def __init__(self, keymap=None):
         self.keymap = keymap
-        self.clear()
-
-    def clear(self):
         self.keys = []
         self.wildcards = []
         self.pointer = self.keymap
@@ -229,6 +235,9 @@ class KeyBuffer(object):
             if self.keymap[self.quantifier_key] == 'false':
                 self.finished_parsing_quantifier = True
 
+    def clear(self):
+        self.__init__(self.keymap)
+
     def add(self, key):
         self.keys.append(key)
         self.result = None
@@ -263,6 +272,7 @@ class KeyBuffer(object):
     def __str__(self):
         return "".join(key_to_string(c) for c in self.keys)
 
+
 if __name__ == '__main__':
     import doctest
     doctest.testmod()
diff --git a/ranger/ext/lazy_property.py b/ranger/ext/lazy_property.py
index 4bdcda1e..2fbe0cfd 100644
--- a/ranger/ext/lazy_property.py
+++ b/ranger/ext/lazy_property.py
@@ -1,7 +1,9 @@
 # From http://blog.pythonisito.com/2008/08/lazy-descriptors.html
 
+from __future__ import (absolute_import, print_function)
 
-class lazy_property(object):
+
+class lazy_property(object):  # pylint: disable=invalid-name,too-few-public-methods
     """A @property-like decorator with lazy evaluation
 
     >>> class Foo:
@@ -29,6 +31,7 @@ class lazy_property(object):
         obj.__dict__[self.__name__] = result
         return result
 
+
 if __name__ == '__main__':
     import doctest
     doctest.testmod()
diff --git a/ranger/ext/logutils.py b/ranger/ext/logutils.py
index 0de6c333..ff27b420 100644
--- a/ranger/ext/logutils.py
+++ b/ranger/ext/logutils.py
@@ -1,3 +1,5 @@
+from __future__ import (absolute_import, print_function)
+
 import logging
 from collections import deque
 
@@ -28,9 +30,11 @@ class QueueHandler(logging.Handler):
         self.enqueue(self.format(record))
 
 
+# pylint: disable=invalid-name
 log_queue = deque(maxlen=1000)
 concise_formatter = logging.Formatter(fmt=LOG_FORMAT, datefmt=LOG_DATA_FORMAT)
 extended_formatter = logging.Formatter(fmt=LOG_FORMAT_EXT, datefmt=LOG_DATA_FORMAT)
+# pylint: enable=invalid-name
 
 
 def setup_logging(debug=True, logfile=None):
@@ -65,7 +69,7 @@ def setup_logging(debug=True, logfile=None):
     handlers = []
     handlers.append(QueueHandler(log_queue))
     if logfile:
-        if logfile is '-':
+        if logfile == '-':
             handlers.append(logging.StreamHandler())
         else:
             handlers.append(logging.FileHandler(logfile))
diff --git a/ranger/ext/mount_path.py b/ranger/ext/mount_path.py
index 69a277af..6c59b107 100644
--- a/ranger/ext/mount_path.py
+++ b/ranger/ext/mount_path.py
@@ -1,6 +1,8 @@
 # This file is part of ranger, the console file manager.
 # License: GNU GPL version 3, see the file "AUTHORS" for details.
 
+from __future__ import (absolute_import, print_function)
+
 from os.path import realpath, abspath, dirname, ismount
 
 
diff --git a/ranger/ext/next_available_filename.py b/ranger/ext/next_available_filename.py
index c408b35d..4ff9be24 100644
--- a/ranger/ext/next_available_filename.py
+++ b/ranger/ext/next_available_filename.py
@@ -1,6 +1,8 @@
 # This file is part of ranger, the console file manager.
 # License: GNU GPL version 3, see the file "AUTHORS" for details.
 
+from __future__ import (absolute_import, print_function)
+
 import os.path
 
 
diff --git a/ranger/ext/openstruct.py b/ranger/ext/openstruct.py
index 6479d158..7528ee92 100644
--- a/ranger/ext/openstruct.py
+++ b/ranger/ext/openstruct.py
@@ -1,11 +1,14 @@
 # This file is part of ranger, the console file manager.
 # License: GNU GPL version 3, see the file "AUTHORS" for details.
 
+from __future__ import (absolute_import, print_function)
+
 import collections
 
 
 class OpenStruct(dict):
     """The fusion of dict and struct"""
+
     def __init__(self, *args, **keywords):
         dict.__init__(self, *args, **keywords)
         self.__dict__ = self
@@ -13,6 +16,7 @@ class OpenStruct(dict):
 
 class DefaultOpenStruct(collections.defaultdict):
     """The fusion of dict and struct, with default values"""
+
     def __init__(self, *args, **keywords):
         collections.defaultdict.__init__(self, None, *args, **keywords)
         self.__dict__ = self
@@ -20,5 +24,4 @@ class DefaultOpenStruct(collections.defaultdict):
     def __getattr__(self, name):
         if name not in self.__dict__:
             return None
-        else:
-            return self.__dict__[name]
+        return self.__dict__[name]
diff --git a/ranger/ext/popen_forked.py b/ranger/ext/popen_forked.py
index d4a75a48..119ce46a 100644
--- a/ranger/ext/popen_forked.py
+++ b/ranger/ext/popen_forked.py
@@ -1,11 +1,13 @@
 # This file is part of ranger, the console file manager.
 # License: GNU GPL version 3, see the file "AUTHORS" for details.
 
+from __future__ import (absolute_import, print_function)
+
 import os
 import subprocess
 
 
-def Popen_forked(*args, **kwargs):
+def Popen_forked(*args, **kwargs):  # pylint: disable=invalid-name
     """Forks process and runs Popen with the given args and kwargs.
 
     Returns True if forking succeeded, otherwise False.
@@ -19,7 +21,7 @@ def Popen_forked(*args, **kwargs):
         kwargs['stdin'] = open(os.devnull, 'r')
         kwargs['stdout'] = kwargs['stderr'] = open(os.devnull, 'w')
         subprocess.Popen(*args, **kwargs)
-        os._exit(0)
+        os._exit(0)  # pylint: disable=protected-access
     else:
         os.wait()
     return True
diff --git a/ranger/ext/relative_symlink.py b/ranger/ext/relative_symlink.py
index 247d1318..85eb746e 100644
--- a/ranger/ext/relative_symlink.py
+++ b/ranger/ext/relative_symlink.py
@@ -1,6 +1,8 @@
 # This file is part of ranger, the console file manager.
 # License: GNU GPL version 3, see the file "AUTHORS" for details.
 
+from __future__ import (absolute_import, print_function)
+
 from os import symlink, sep
 
 
diff --git a/ranger/ext/rifle.py b/ranger/ext/rifle.py
index 7d1bd59e..6c5d70be 100755
--- a/ranger/ext/rifle.py
+++ b/ranger/ext/rifle.py
@@ -14,6 +14,8 @@ Example usage:
     rifle.execute(["file1", "file2"])
 """
 
+from __future__ import (absolute_import, print_function)
+
 import os.path
 import re
 from subprocess import Popen, PIPE
@@ -32,11 +34,11 @@ ENCODING = 'utf-8'
 try:
     from ranger.ext.get_executables import get_executables
 except ImportError:
-    _cached_executables = None
+    _cached_executables = None  # pylint: disable=invalid-name
 
     def get_executables():
         """Return all executable files in $PATH + Cache them."""
-        global _cached_executables
+        global _cached_executables  # pylint: disable=global-statement,invalid-name
         if _cached_executables is not None:
             return _cached_executables
 
@@ -70,7 +72,7 @@ except ImportError:
 try:
     from ranger.ext.popen_forked import Popen_forked
 except ImportError:
-    def Popen_forked(*args, **kwargs):
+    def Popen_forked(*args, **kwargs):  # pylint: disable=invalid-name
         """Forks process and runs Popen with the given args and kwargs."""
         try:
             pid = os.fork()
@@ -81,7 +83,7 @@ except ImportError:
             kwargs['stdin'] = open(os.devnull, 'r')
             kwargs['stdout'] = kwargs['stderr'] = open(os.devnull, 'w')
             Popen(*args, **kwargs)
-            os._exit(0)
+            os._exit(0)  # pylint: disable=protected-access
         return True
 
 
@@ -111,7 +113,7 @@ def squash_flags(flags):
     return ''.join(f for f in flags if f not in exclude)
 
 
-class Rifle(object):
+class Rifle(object):  # pylint: disable=too-many-instance-attributes
     delimiter1 = '='
     delimiter2 = ','
 
@@ -122,16 +124,20 @@ class Rifle(object):
     def hook_after_executing(self, command, mimetype, flags):
         pass
 
-    def hook_command_preprocessing(self, command):
+    @staticmethod
+    def hook_command_preprocessing(command):
         return command
 
-    def hook_command_postprocessing(self, command):
+    @staticmethod
+    def hook_command_postprocessing(command):
         return command
 
-    def hook_environment(self, env):
+    @staticmethod
+    def hook_environment(env):
         return env
 
-    def hook_logger(self, string):
+    @staticmethod
+    def hook_logger(string):
         sys.stderr.write(string + "\n")
 
     def __init__(self, config_file):
@@ -139,23 +145,25 @@ class Rifle(object):
         self._app_flags = ''
         self._app_label = None
         self._initialized_mimetypes = False
+        self._mimetype = None
+        self._skip = None
+        self.rules = None
 
         # get paths for mimetype files
-        self._mimetype_known_files = [
-                os.path.expanduser("~/.mime.types")]
+        self._mimetype_known_files = [os.path.expanduser("~/.mime.types")]
         if __file__.endswith("ranger/ext/rifle.py"):
             # Add ranger's default mimetypes when run from ranger directory
             self._mimetype_known_files.append(
-                    __file__.replace("ext/rifle.py", "data/mime.types"))
+                __file__.replace("ext/rifle.py", "data/mime.types"))
 
     def reload_config(self, config_file=None):
         """Replace the current configuration with the one in config_file"""
         if config_file is None:
             config_file = self.config_file
-        f = open(config_file, 'r')
+        fobj = open(config_file, 'r')
         self.rules = []
         lineno = 0
-        for line in f:
+        for line in fobj:
             lineno += 1
             line = line.strip()
             if line.startswith('#') or line == '':
@@ -168,10 +176,10 @@ class Rifle(object):
                 tests = tuple(tuple(f.strip().split(None, 1)) for f in tests)
                 command = command.strip()
                 self.rules.append((command, tests))
-            except Exception as e:
-                self.hook_logger("Syntax error in %s line %d (%s)" %
-                    (config_file, lineno, str(e)))
-        f.close()
+            except Exception as ex:
+                self.hook_logger(
+                    "Syntax error in %s line %d (%s)" % (config_file, lineno, str(ex)))
+        fobj.close()
 
     def _eval_condition(self, condition, files, label):
         # Handle the negation of conditions starting with an exclamation mark,
@@ -184,7 +192,8 @@ class Rifle(object):
             return not self._eval_condition2(new_condition, files, label)
         return self._eval_condition2(condition, files, label)
 
-    def _eval_condition2(self, rule, files, label):
+    def _eval_condition2(  # pylint: disable=too-many-return-statements,too-many-branches
+            self, rule, files, label):
         # This function evaluates the condition, after _eval_condition() handled
         # negation of conditions starting with a "!".
 
@@ -249,11 +258,10 @@ class Rifle(object):
         for path in self._mimetype_known_files:
             if path not in mimetypes.knownfiles:
                 mimetypes.knownfiles.append(path)
-        self._mimetype, encoding = mimetypes.guess_type(fname)
+        self._mimetype, _ = mimetypes.guess_type(fname)
 
         if not self._mimetype:
-            process = Popen(["file", "--mime-type", "-Lb", fname],
-                    stdout=PIPE, stderr=PIPE)
+            process = Popen(["file", "--mime-type", "-Lb", fname], stdout=PIPE, stderr=PIPE)
             mimetype, _ = process.communicate()
             self._mimetype = mimetype.decode(ENCODING).strip()
         return self._mimetype
@@ -263,8 +271,7 @@ class Rifle(object):
         if isinstance(flags, str):
             self._app_flags += flags
         self._app_flags = squash_flags(self._app_flags)
-        filenames = "' '".join(f.replace("'", "'\\\''") for f in files
-                if "\x00" not in f)
+        filenames = "' '".join(f.replace("'", "'\\\''") for f in files if "\x00" not in f)
         return "set -- '%s'; %s" % (filenames, action)
 
     def list_commands(self, files, mimetype=None):
@@ -292,7 +299,8 @@ class Rifle(object):
                     count = self._skip
                 yield (count, cmd, self._app_label, self._app_flags)
 
-    def execute(self, files, number=0, label=None, flags="", mimetype=None):
+    def execute(self, files,  # pylint: disable=too-many-branches,too-many-statements
+                number=0, label=None, flags="", mimetype=None):
         """Executes the given list of files.
 
         By default, this executes the first command where all conditions apply,
@@ -327,7 +335,7 @@ class Rifle(object):
                 command = self._build_command(files, cmd, flags)
 
         # Execute command
-        if command is None:
+        if command is None:  # pylint: disable=too-many-nested-blocks
             if found_at_least_one:
                 if label:
                     self.hook_logger("Label '%s' is undefined" % label)
@@ -362,7 +370,7 @@ class Rifle(object):
                                 term = 'urxvt'
                         if term not in get_executables():
                             self.hook_logger("Can not determine terminal command.  "
-                                "Please set $TERMCMD manually.")
+                                             "Please set $TERMCMD manually.")
                             # A fallback terminal that is likely installed:
                             term = 'xterm'
                         os.environ['TERMCMD'] = term
@@ -370,15 +378,14 @@ class Rifle(object):
                 if 'f' in flags or 't' in flags:
                     Popen_forked(cmd, env=self.hook_environment(os.environ))
                 else:
-                    p = Popen(cmd, env=self.hook_environment(os.environ))
-                    p.wait()
+                    process = Popen(cmd, env=self.hook_environment(os.environ))
+                    process.wait()
             finally:
                 self.hook_after_executing(command, self._mimetype, self._app_flags)
 
 
-def main():
+def main():  # pylint: disable=too-many-locals
     """The main function which is run when you start this program direectly."""
-    import sys
 
     # Find configuration file path
     if 'XDG_CONFIG_HOME' in os.environ and os.environ['XDG_CONFIG_HOME']:
@@ -388,7 +395,7 @@ def main():
     default_conf_path = conf_path
     if not os.path.isfile(conf_path):
         conf_path = os.path.normpath(os.path.join(os.path.dirname(__file__),
-            '../config/rifle.conf'))
+                                                  '../config/rifle.conf'))
     if not os.path.isfile(conf_path):
         try:
             # if ranger is installed, get the configuration from ranger
@@ -399,19 +406,19 @@ def main():
             conf_path = os.path.join(ranger.__path__[0], "config", "rifle.conf")
 
     # Evaluate arguments
-    from optparse import OptionParser
+    from optparse import OptionParser  # pylint: disable=deprecated-module
     parser = OptionParser(usage="%prog [-fhlpw] [files]", version=__version__)
     parser.add_option('-f', type="string", default="", metavar="FLAGS",
-            help="use additional flags: f=fork, r=root, t=terminal. "
-            "Uppercase flag negates respective lowercase flags.")
+                      help="use additional flags: f=fork, r=root, t=terminal. "
+                      "Uppercase flag negates respective lowercase flags.")
     parser.add_option('-l', action="store_true",
-            help="list possible ways to open the files (id:label:flags:command)")
+                      help="list possible ways to open the files (id:label:flags:command)")
     parser.add_option('-p', type='string', default='0', metavar="KEYWORD",
-            help="pick a method to open the files.  KEYWORD is either the "
-            "number listed by 'rifle -l' or a string that matches a label in "
-            "the configuration file")
+                      help="pick a method to open the files.  KEYWORD is either the "
+                      "number listed by 'rifle -l' or a string that matches a label in "
+                      "the configuration file")
     parser.add_option('-w', type='string', default=None, metavar="PROGRAM",
-            help="open the files with PROGRAM")
+                      help="open the files with PROGRAM")
     options, positional = parser.parse_args()
     if not positional:
         parser.print_help()
@@ -419,7 +426,7 @@ def main():
 
     if not os.path.isfile(conf_path):
         sys.stderr.write("Could not find a configuration file.\n"
-                "Please create one at %s.\n" % default_conf_path)
+                         "Please create one at %s.\n" % default_conf_path)
         raise SystemExit(1)
 
     if options.p.isdigit():
@@ -430,22 +437,23 @@ def main():
         label = options.p
 
     if options.w is not None and not options.l:
-        p = Popen([options.w] + list(positional))
-        p.wait()
+        process = Popen([options.w] + list(positional))
+        process.wait()
     else:
         # Start up rifle
         rifle = Rifle(conf_path)
         rifle.reload_config()
-        #print(rifle.list_commands(sys.argv[1:]))
+        # print(rifle.list_commands(sys.argv[1:]))
         if options.l:
             for count, cmd, label, flags in rifle.list_commands(positional):
                 print("%d:%s:%s:%s" % (count, label or '', flags, cmd))
         else:
-            result = rifle.execute(positional, number=number, label=label,
-                    flags=options.f)
+            result = rifle.execute(positional, number=number, label=label, flags=options.f)
             if result == ASK_COMMAND:
                 # TODO: implement interactive asking for file type?
-                print("Unknown file type: %s" % rifle._get_mimetype(positional[0]))
+                print("Unknown file type: %s" %
+                      rifle._get_mimetype(positional[0]))  # pylint: disable=protected-access
+
 
 if __name__ == '__main__':
     if 'RANGER_DOCTEST' in os.environ:
diff --git a/ranger/ext/shell_escape.py b/ranger/ext/shell_escape.py
index d57ff339..64ddb086 100644
--- a/ranger/ext/shell_escape.py
+++ b/ranger/ext/shell_escape.py
@@ -3,10 +3,12 @@
 
 """Functions to escape metacharacters of arguments for shell commands."""
 
+from __future__ import (absolute_import, print_function)
+
+
 META_CHARS = (' ', "'", '"', '`', '&', '|', ';', '#',
-        '$', '!', '(', ')', '[', ']', '<', '>', '\t')
-UNESCAPABLE = set(map(chr, list(range(9)) + list(range(10, 32))
-        + list(range(127, 256))))
+              '$', '!', '(', ')', '[', ']', '<', '>', '\t')
+UNESCAPABLE = set(map(chr, list(range(9)) + list(range(10, 32)) + list(range(127, 256))))
 META_DICT = dict([(mc, '\\' + mc) for mc in META_CHARS])
 
 
@@ -21,6 +23,6 @@ def shell_escape(arg):
     if UNESCAPABLE & set(arg):
         return shell_quote(arg)
     arg = arg.replace('\\', '\\\\')  # make sure this comes at the start
-    for k, v in META_DICT.items():
-        arg = arg.replace(k, v)
+    for key, value in META_DICT.items():
+        arg = arg.replace(key, value)
     return arg
diff --git a/ranger/ext/shutil_generatorized.py b/ranger/ext/shutil_generatorized.py
index b990aded..85d1d698 100644
--- a/ranger/ext/shutil_generatorized.py
+++ b/ranger/ext/shutil_generatorized.py
@@ -5,10 +5,12 @@
 XXX The functions here don't copy the resource fork or other metadata on Mac.
 """
 
+from __future__ import (absolute_import, print_function)
+
 import os
+from os.path import abspath
 import sys
 import stat
-from os.path import abspath
 
 __all__ = ["copyfileobj", "copyfile", "copystat", "copy2", "BLOCK_SIZE",
            "copytree", "move", "rmtree", "Error", "SpecialFileError"]
@@ -25,16 +27,17 @@ class SpecialFileError(EnvironmentError):
     """Raised when trying to do a kind of operation (e.g. copying) which is
     not supported on a special file (e.g. a named pipe)"""
 
+
 try:
     WindowsError
 except NameError:
-    WindowsError = None
+    WindowsError = None  # pylint: disable=invalid-name
 
 
 def copyfileobj(fsrc, fdst, length=BLOCK_SIZE):
     """copy data from file-like object fsrc to file-like object fdst"""
     done = 0
-    while 1:
+    while True:
         buf = fsrc.read(length)
         if not buf:
             break
@@ -63,16 +66,16 @@ def copyfile(src, dst):
 
     fsrc = None
     fdst = None
-    for fn in [src, dst]:
+    for path in [src, dst]:
         try:
-            st = os.stat(fn)
+            fstat = os.stat(path)
         except OSError:
             # File most likely does not exist
             pass
         else:
             # XXX What about other special files? (sockets, devices...)
-            if stat.S_ISFIFO(st.st_mode):
-                raise SpecialFileError("`%s` is a named pipe" % fn)
+            if stat.S_ISFIFO(fstat.st_mode):
+                raise SpecialFileError("`%s` is a named pipe" % path)
     try:
         fsrc = open(src, 'rb')
         fdst = open(dst, 'wb')
@@ -87,11 +90,11 @@ def copyfile(src, dst):
 
 def copystat(src, dst):
     """Copy all stat info (mode bits, atime, mtime, flags) from src to dst"""
-    st = os.lstat(src)
-    mode = stat.S_IMODE(st.st_mode)
+    fstat = os.lstat(src)
+    mode = stat.S_IMODE(fstat.st_mode)
     if hasattr(os, 'utime'):
         try:
-            os.utime(dst, (st.st_atime, st.st_mtime))
+            os.utime(dst, (fstat.st_atime, fstat.st_mtime))
         except Exception:
             pass
     if hasattr(os, 'chmod'):
@@ -99,9 +102,9 @@ def copystat(src, dst):
             os.chmod(dst, mode)
         except Exception:
             pass
-    if hasattr(os, 'chflags') and hasattr(st, 'st_flags'):
+    if hasattr(os, 'chflags') and hasattr(fstat, 'st_flags'):
         try:
-            os.chflags(dst, st.st_flags)
+            os.chflags(dst, fstat.st_flags)  # pylint: disable=no-member
         except Exception:
             pass
 
@@ -143,7 +146,8 @@ def get_safe_path(dst):
     return test_dst
 
 
-def copytree(src, dst, symlinks=False, ignore=None, overwrite=False):
+def copytree(src, dst,  # pylint: disable=too-many-locals,too-many-branches
+             symlinks=False, ignore=None, overwrite=False):
     """Recursively copy a directory tree using copy2().
 
     The destination directory must not already exist.
@@ -196,18 +200,16 @@ def copytree(src, dst, symlinks=False, ignore=None, overwrite=False):
                 os.symlink(linkto, dstname)
                 copystat(srcname, dstname)
             elif os.path.isdir(srcname):
-                d = 0
-                for d in copytree(srcname, dstname, symlinks,
-                        ignore, overwrite):
-                    yield done + d
-                done += d
+                n = 0
+                for n in copytree(srcname, dstname, symlinks, ignore, overwrite):
+                    yield done + n
+                done += n
             else:
                 # Will raise a SpecialFileError for unsupported file types
-                d = 0
-                for d in copy2(srcname, dstname,
-                        overwrite=overwrite, symlinks=symlinks):
-                    yield done + d
-                done += d
+                n = 0
+                for n in copy2(srcname, dstname, overwrite=overwrite, symlinks=symlinks):
+                    yield done + n
+                done += n
         # catch the Error from the recursive copytree so that we can
         # continue with other files
         except Error as err:
@@ -238,11 +240,11 @@ def rmtree(path, ignore_errors=False, onerror=None):
 
     """
     if ignore_errors:
-        def onerror(*args):
+        def onerror(*_):  # pylint: disable=function-redefined
             pass
     elif onerror is None:
-        def onerror(*args):
-            raise
+        def onerror(*_):  # pylint: disable=function-redefined
+            raise  # pylint: disable=misplaced-bare-raise
     try:
         if os.path.islink(path):
             # symlinks to directories are forbidden, see bug #1669
@@ -254,7 +256,7 @@ def rmtree(path, ignore_errors=False, onerror=None):
     names = []
     try:
         names = os.listdir(path)
-    except os.error as err:
+    except os.error:
         onerror(os.listdir, path, sys.exc_info())
     for name in names:
         fullname = os.path.join(path, name)
@@ -267,7 +269,7 @@ def rmtree(path, ignore_errors=False, onerror=None):
         else:
             try:
                 os.remove(fullname)
-            except os.error as err:
+            except os.error:
                 onerror(os.remove, fullname, sys.exc_info())
     try:
         os.rmdir(path)
diff --git a/ranger/ext/signals.py b/ranger/ext/signals.py
index 4167277f..83adf367 100644
--- a/ranger/ext/signals.py
+++ b/ranger/ext/signals.py
@@ -57,6 +57,8 @@ True
 True
 """
 
+from __future__ import (absolute_import, print_function)
+
 import weakref
 from types import MethodType
 
@@ -82,7 +84,7 @@ class Signal(dict):
         self.stopped = True
 
 
-class SignalHandler:
+class SignalHandler(object):  # pylint: disable=too-few-public-methods
     """Signal Handlers contain information about a signal binding.
 
     They are returned by signal_bind() and have to be passed to signal_unbind()
@@ -102,6 +104,7 @@ class SignalHandler:
 
 class SignalDispatcher(object):
     """This abstract class handles the binding and emitting of signals."""
+
     def __init__(self):
         self._signals = dict()
 
@@ -109,7 +112,7 @@ class SignalDispatcher(object):
         """Remove all signals."""
         for handler_list in self._signals.values():
             for handler in handler_list:
-                handler._function = None
+                handler._function = None  # pylint: disable=protected-access
         self._signals = dict()
 
     def signal_bind(self, signal_name, function, priority=0.5, weak=False, autosort=True):
@@ -148,7 +151,8 @@ class SignalDispatcher(object):
         handler = SignalHandler(signal_name, function, priority, nargs > 0)
         handlers.append(handler)
         if autosort:
-            handlers.sort(key=lambda handler: -handler._priority)
+            handlers.sort(
+                key=lambda handler: -handler._priority)  # pylint: disable=protected-access
         return handler
 
     def signal_force_sort(self, signal_name=None):
@@ -159,9 +163,11 @@ class SignalDispatcher(object):
         """
         if signal_name is None:
             for handlers in self._signals.values():
-                handlers.sort(key=lambda handler: -handler._priority)
+                handlers.sort(
+                    key=lambda handler: -handler._priority)  # pylint: disable=protected-access
         elif signal_name in self._signals:
-            self._signals[signal_name].sort(key=lambda handler: -handler._priority)
+            self._signals[signal_name].sort(
+                key=lambda handler: -handler._priority)  # pylint: disable=protected-access
         else:
             return False
 
@@ -172,12 +178,13 @@ class SignalDispatcher(object):
         signal_bind().
         """
         try:
-            handlers = self._signals[signal_handler._signal_name]
+            handlers = self._signals[
+                signal_handler._signal_name]  # pylint: disable=protected-access
         except Exception:
             pass
         else:
             try:
-                signal_handler._function = None
+                signal_handler._function = None  # pylint: disable=protected-access
                 handlers.remove(signal_handler)
             except Exception:
                 pass
@@ -219,14 +226,16 @@ class SignalDispatcher(object):
             while i:
                 i -= 1
                 handler = handler_list[i]
+                # pylint: disable=protected-access
                 try:
                     if isinstance(handler._function, tuple):
-                        handler._function[1].__class__
+                        handler._function[1].__class__  # pylint: disable=pointless-statement
                     else:
-                        handler._function.__class__
+                        handler._function.__class__  # pylint: disable=pointless-statement
                 except ReferenceError:
                     handler._function = None
                     del handler_list[i]
+                # pylint: enable=protected-access
 
     def signal_emit(self, signal_name, **kw):
         """Emits a signal and call every function that was bound to that signal.
@@ -250,6 +259,7 @@ class SignalDispatcher(object):
         # propagate
         for handler in tuple(handlers):
             if handler.active:
+                # pylint: disable=protected-access
                 try:
                     if isinstance(handler._function, tuple):
                         fnc = MethodType(*handler._function)
@@ -262,6 +272,7 @@ class SignalDispatcher(object):
                 except ReferenceError:
                     handler._function = None
                     handlers.remove(handler)
+                # pylint: enable=protected-access
                 if signal.stopped:
                     return False
         return True
diff --git a/ranger/ext/spawn.py b/ranger/ext/spawn.py
index 04abfbd2..ffb4d94b 100644
--- a/ranger/ext/spawn.py
+++ b/ranger/ext/spawn.py
@@ -1,6 +1,8 @@
 # This file is part of ranger, the console file manager.
 # License: GNU GPL version 3, see the file "AUTHORS" for details.
 
+from __future__ import (absolute_import, print_function)
+
 from os import devnull
 from subprocess import Popen, PIPE, CalledProcessError
 ENCODING = 'utf-8'
@@ -66,5 +68,4 @@ def spawn(*popenargs, **kwargs):
     """
     if len(popenargs) == 1:
         return check_output(popenargs[0], **kwargs)
-    else:
-        return check_output(list(popenargs), **kwargs)
+    return check_output(list(popenargs), **kwargs)
diff --git a/ranger/ext/vcs/__init__.py b/ranger/ext/vcs/__init__.py
index 26a32800..90f9a713 100644
--- a/ranger/ext/vcs/__init__.py
+++ b/ranger/ext/vcs/__init__.py
@@ -3,6 +3,8 @@
 
 """VCS Extension"""
 
+from __future__ import (absolute_import, print_function)
+
 from .vcs import Vcs, VcsError, VcsThread
 
 __all__ = ['Vcs', 'VcsError', 'VcsThread']
diff --git a/ranger/ext/vcs/bzr.py b/ranger/ext/vcs/bzr.py
index d0db1faf..753b5d05 100644
--- a/ranger/ext/vcs/bzr.py
+++ b/ranger/ext/vcs/bzr.py
@@ -3,6 +3,8 @@
 
 """GNU Bazaar module"""
 
+from __future__ import (absolute_import, print_function)
+
 from datetime import datetime
 import os
 import re
@@ -41,7 +43,9 @@ class Bzr(Vcs):
             output = self._run(args)
         except VcsError:
             return None
+        # pylint: disable=no-member
         entries = re.findall(r'-+\n(.+?)\n(?:-|\Z)', output, re.MULTILINE | re.DOTALL)
+        # pylint: enable=no-member
 
         log = []
         for entry in entries:
diff --git a/ranger/ext/vcs/git.py b/ranger/ext/vcs/git.py
index 06e066d2..c6cb2bf3 100644
--- a/ranger/ext/vcs/git.py
+++ b/ranger/ext/vcs/git.py
@@ -3,6 +3,8 @@
 
 """Git module"""
 
+from __future__ import (absolute_import, print_function)
+
 from datetime import datetime
 import os
 import re
@@ -159,12 +161,13 @@ class Git(Vcs):
             return 'none'
 
         output = self._run(['rev-list', '--left-right', '{0:s}...{1:s}'.format(remote, head)])
+        # pylint: disable=no-member
         ahead = re.search(r'^>', output, flags=re.MULTILINE)
         behind = re.search(r'^<', output, flags=re.MULTILINE)
+        # pylint: enable=no-member
         if ahead:
             return 'diverged' if behind else 'ahead'
-        else:
-            return 'behind' if behind else 'sync'
+        return 'behind' if behind else 'sync'
 
     def data_branch(self):
         try:
diff --git a/ranger/ext/vcs/hg.py b/ranger/ext/vcs/hg.py
index 21460975..94d0f749 100644
--- a/ranger/ext/vcs/hg.py
+++ b/ranger/ext/vcs/hg.py
@@ -3,6 +3,8 @@
 
 """Mercurial module"""
 
+from __future__ import (absolute_import, print_function)
+
 from datetime import datetime
 import json
 import os
diff --git a/ranger/ext/vcs/svn.py b/ranger/ext/vcs/svn.py
index 1f09cd52..ceac84cf 100644
--- a/ranger/ext/vcs/svn.py
+++ b/ranger/ext/vcs/svn.py
@@ -3,6 +3,8 @@
 
 """Subversion module"""
 
+from __future__ import (absolute_import, print_function)
+
 from datetime import datetime
 import os
 from xml.etree import ElementTree as etree
diff --git a/ranger/ext/vcs/vcs.py b/ranger/ext/vcs/vcs.py
index fa00777a..dbc2eace 100644
--- a/ranger/ext/vcs/vcs.py
+++ b/ranger/ext/vcs/vcs.py
@@ -3,6 +3,8 @@
 
 """VCS module"""
 
+from __future__ import (absolute_import, print_function)
+
 import os
 import subprocess
 import threading
@@ -378,6 +380,7 @@ class VcsRoot(Vcs):  # pylint: disable=abstract-method
 
 class VcsThread(threading.Thread):  # pylint: disable=too-many-instance-attributes
     """VCS thread"""
+
     def __init__(self, ui):
         super(VcsThread, self).__init__()
         self.daemon = True
diff --git a/ranger/ext/widestring.py b/ranger/ext/widestring.py
index 4890c20b..caab1c80 100644
--- a/ranger/ext/widestring.py
+++ b/ranger/ext/widestring.py
@@ -2,6 +2,8 @@
 # This file is part of ranger, the console file manager.
 # License: GNU GPL version 3, see the file "AUTHORS" for details.
 
+from __future__ import (absolute_import, print_function)
+
 import sys
 from unicodedata import east_asian_width
 
@@ -32,9 +34,9 @@ def string_to_charlist(string):
         return list(string)
     result = []
     if PY3:
-        for c in string:
-            result.append(c)
-            if east_asian_width(c) in WIDE_SYMBOLS:
+        for char in string:
+            result.append(char)
+            if east_asian_width(char) in WIDE_SYMBOLS:
                 result.append('')
     else:
         try:
@@ -45,14 +47,15 @@ def string_to_charlist(string):
             string = string.decode('utf-8', 'ignore')
         except UnicodeEncodeError:
             return []
-        for c in string:
-            result.append(c.encode('utf-8'))
-            if east_asian_width(c) in WIDE_SYMBOLS:
+        for char in string:
+            result.append(char.encode('utf-8'))
+            if east_asian_width(char) in WIDE_SYMBOLS:
                 result.append('')
     return result
 
 
-class WideString(object):
+class WideString(object):  # pylint: disable=too-few-public-methods
+
     def __init__(self, string, chars=None):
         try:
             self.string = str(string)
@@ -80,8 +83,7 @@ class WideString(object):
         if isinstance(string, str):
             return WideString(self.string + string)
         elif isinstance(string, WideString):
-            return WideString(self.string + string.string,
-                    self.chars + string.chars)
+            return WideString(self.string + string.string, self.chars + string.chars)
 
     def __radd__(self, string):
         """
@@ -91,8 +93,7 @@ class WideString(object):
         if isinstance(string, str):
             return WideString(string + self.string)
         elif isinstance(string, WideString):
-            return WideString(string.string + self.string,
-                    string.chars + self.chars)
+            return WideString(string.string + self.string, string.chars + self.chars)
 
     def __str__(self):
         return self.string
@@ -100,7 +101,7 @@ class WideString(object):
     def __repr__(self):
         return '<' + self.__class__.__name__ + " '" + self.string + "'>"
 
-    def __getslice__(self, a, z):
+    def __getslice__(self, start, stop):
         """
         >>> WideString("asdf")[1:3]
         <WideString 'sd'>
@@ -123,21 +124,21 @@ class WideString(object):
         >>> WideString("aモ")[0:1]
         <WideString 'a'>
         """
-        if z is None or z > len(self.chars):
-            z = len(self.chars)
-        if z < 0:
-            z = len(self.chars) + z
-        if z < 0:
+        if stop is None or stop > len(self.chars):
+            stop = len(self.chars)
+        if stop < 0:
+            stop = len(self.chars) + stop
+        if stop < 0:
             return WideString("")
-        if a is None or a < 0:
-            a = 0
-        if z < len(self.chars) and self.chars[z] == '':
-            if self.chars[a] == '':
-                return WideString(' ' + ''.join(self.chars[a:z - 1]) + ' ')
-            return WideString(''.join(self.chars[a:z - 1]) + ' ')
-        if self.chars[a] == '':
-            return WideString(' ' + ''.join(self.chars[a:z - 1]))
-        return WideString(''.join(self.chars[a:z]))
+        if start is None or start < 0:
+            start = 0
+        if stop < len(self.chars) and self.chars[stop] == '':
+            if self.chars[start] == '':
+                return WideString(' ' + ''.join(self.chars[start:stop - 1]) + ' ')
+            return WideString(''.join(self.chars[start:stop - 1]) + ' ')
+        if self.chars[start] == '':
+            return WideString(' ' + ''.join(self.chars[start:stop - 1]))
+        return WideString(''.join(self.chars[start:stop]))
 
     def __getitem__(self, i):
         """
diff --git a/ranger/gui/ansi.py b/ranger/gui/ansi.py
index 091406e9..e68e780a 100644
--- a/ranger/gui/ansi.py
+++ b/ranger/gui/ansi.py
@@ -4,12 +4,18 @@
 
 """A library to help to convert ANSI codes to curses instructions."""
 
-from ranger.gui import color
+from __future__ import (absolute_import, print_function)
+
 import re
 
+from ranger.gui import color
+
+
+# pylint: disable=invalid-name
 ansi_re = re.compile('(\x1b' + r'\[\d*(?:;\d+)*?[a-zA-Z])')
 codesplit_re = re.compile(r'38;5;(\d+);|48;5;(\d+);|(\d*);')
 reset = '\x1b[0m'
+# pylint: enable=invalid-name
 
 
 def split_ansi_from_text(ansi_text):
@@ -19,7 +25,7 @@ def split_ansi_from_text(ansi_text):
 # githttp://en.wikipedia.org/wiki/ANSI_escape_code
 
 
-def text_with_fg_bg_attr(ansi_text):
+def text_with_fg_bg_attr(ansi_text):  # pylint: disable=too-many-branches,too-many-statements
     fg, bg, attr = -1, -1, 0
     for chunk in split_ansi_from_text(ansi_text):
         if chunk and chunk[0] == '\x1b':
@@ -35,13 +41,13 @@ def text_with_fg_bg_attr(ansi_text):
             for x256fg, x256bg, arg in codesplit_re.findall(attr_args + ';'):
                 # first handle xterm256 codes
                 try:
-                    if len(x256fg) > 0:           # xterm256 foreground
+                    if x256fg:                    # xterm256 foreground
                         fg = int(x256fg)
                         continue
-                    elif len(x256bg) > 0:         # xterm256 background
+                    elif x256bg:                  # xterm256 background
                         bg = int(x256bg)
                         continue
-                    elif len(arg) > 0:            # usual ansi code
+                    elif arg:                     # usual ansi code
                         n = int(arg)
                     else:                         # empty code means reset
                         n = 0
@@ -82,7 +88,8 @@ def text_with_fg_bg_attr(ansi_text):
                 elif n == 49:
                     bg = -1
 
-                elif n >= 90 and n <= 97:         # 8 aixterm high intensity colors (light but not bold)
+                # 8 aixterm high intensity colors (light but not bold)
+                elif n >= 90 and n <= 97:
                     fg = n - 90 + 8
                 elif n == 99:
                     fg = -1
@@ -163,6 +170,7 @@ def char_slice(ansi_text, start, length):
             break
     return ''.join(chunks)
 
+
 if __name__ == '__main__':
     import doctest
     doctest.testmod()
diff --git a/ranger/gui/bar.py b/ranger/gui/bar.py
index 12c44488..730b7e27 100644
--- a/ranger/gui/bar.py
+++ b/ranger/gui/bar.py
@@ -1,8 +1,13 @@
 # This file is part of ranger, the console file manager.
 # License: GNU GPL version 3, see the file "AUTHORS" for details.
 
-from ranger.ext.widestring import WideString, utf_char_width
+from __future__ import (absolute_import, print_function)
+
 import sys
+
+from ranger.ext.widestring import WideString, utf_char_width
+
+
 PY3 = sys.version_info[0] >= 3
 
 
@@ -35,7 +40,7 @@ class Bar(object):
 
         # remove elemets from the left until it fits
         if sumsize > wid:
-            while len(self.left) > 0:
+            while self.left:
                 leftsize -= len(self.left.pop(-1))
                 if leftsize + rightsize <= wid:
                     break
@@ -43,7 +48,7 @@ class Bar(object):
 
             # remove elemets from the right until it fits
             if sumsize > wid:
-                while len(self.right) > 0:
+                while self.right:
                     rightsize -= len(self.right.pop(0))
                     if leftsize + rightsize <= wid:
                         break
@@ -87,13 +92,14 @@ class Bar(object):
 
 
 class BarSide(list):
-    def __init__(self, base_color_tag):
+
+    def __init__(self, base_color_tag):  # pylint: disable=super-init-not-called
         self.base_color_tag = base_color_tag
 
     def add(self, string, *lst, **kw):
-        cs = ColoredString(string, self.base_color_tag, *lst)
-        cs.__dict__.update(kw)
-        self.append(cs)
+        colorstr = ColoredString(string, self.base_color_tag, *lst)
+        colorstr.__dict__.update(kw)
+        self.append(colorstr)
 
     def add_space(self, n=1):
         self.add(' ' * n, 'space')
@@ -112,11 +118,12 @@ class BarSide(list):
 
 
 class ColoredString(object):
+
     def __init__(self, string, *lst):
         self.string = WideString(string)
         self.lst = lst
         self.fixed = False
-        if not len(string) or not len(self.string.chars):
+        if not string or not self.string.chars:
             self.min_size = 0
         elif PY3:
             self.min_size = utf_char_width(string[0])
diff --git a/ranger/gui/color.py b/ranger/gui/color.py
index aa3b931c..06ed4d3a 100644
--- a/ranger/gui/color.py
+++ b/ranger/gui/color.py
@@ -13,6 +13,8 @@ attr ^= reverse
 bool(attr & reverse) # => False
 """
 
+from __future__ import (absolute_import, print_function)
+
 import curses
 
 DEFAULT_FOREGROUND = curses.COLOR_WHITE
@@ -46,15 +48,17 @@ def get_color(fg, bg):
 
     return COLOR_PAIRS[key]
 
-black   = curses.COLOR_BLACK
-blue    = curses.COLOR_BLUE
-cyan    = curses.COLOR_CYAN
-green   = curses.COLOR_GREEN
-magenta = curses.COLOR_MAGENTA
-red     = curses.COLOR_RED
-white   = curses.COLOR_WHITE
-yellow  = curses.COLOR_YELLOW
-default = -1
+
+# pylint: disable=invalid-name,bad-whitespace
+black      = curses.COLOR_BLACK
+blue       = curses.COLOR_BLUE
+cyan       = curses.COLOR_CYAN
+green      = curses.COLOR_GREEN
+magenta    = curses.COLOR_MAGENTA
+red        = curses.COLOR_RED
+white      = curses.COLOR_WHITE
+yellow     = curses.COLOR_YELLOW
+default    = -1
 
 normal     = curses.A_NORMAL
 bold       = curses.A_BOLD
@@ -64,3 +68,4 @@ underline  = curses.A_UNDERLINE
 invisible  = curses.A_INVIS
 
 default_colors = (default, default, normal)
+# pylint: enable=invalid-name,bad-whitespace
diff --git a/ranger/gui/colorscheme.py b/ranger/gui/colorscheme.py
index c861a8e8..9bd96b17 100644
--- a/ranger/gui/colorscheme.py
+++ b/ranger/gui/colorscheme.py
@@ -24,6 +24,8 @@ Define which colorscheme in your settings (e.g. ~/.config/ranger/rc.conf):
 set colorscheme yourschemename
 """
 
+from __future__ import (absolute_import, print_function)
+
 import os.path
 from curses import color_pair
 
@@ -51,10 +53,9 @@ class ColorScheme(object):
         """
         context = Context(keys)
         color = self.use(context)
-        if len(color) != 3 or not all(isinstance(value, int)
-                for value in color):
+        if len(color) != 3 or not all(isinstance(value, int) for value in color):
             raise ValueError("Bad Value from colorscheme.  Need "
-                "a tuple of (foreground_color, background_color, attribute).")
+                             "a tuple of (foreground_color, background_color, attribute).")
         return color
 
     @cached_function
@@ -66,7 +67,8 @@ class ColorScheme(object):
         fg, bg, attr = self.get(*flatten(keys))
         return attr | color_pair(get_color(fg, bg))
 
-    def use(self, context):
+    @staticmethod
+    def use(_):
         """Use the colorscheme to determine the (fg, bg, attr) tuple.
 
         Override this method in your own colorscheme.
@@ -74,7 +76,7 @@ class ColorScheme(object):
         return (-1, -1, 0)
 
 
-def _colorscheme_name_to_class(signal):
+def _colorscheme_name_to_class(signal):  # pylint: disable=too-many-branches
     # Find the colorscheme.  First look in ~/.config/ranger/colorschemes,
     # then at RANGERDIR/colorschemes.  If the file contains a class
     # named Scheme, it is used.  Otherwise, an arbitrary other class
@@ -86,14 +88,14 @@ def _colorscheme_name_to_class(signal):
         signal.value = 'default'
 
     scheme_name = signal.value
-    usecustom = not ranger.arg.clean
+    usecustom = not ranger.args.clean
 
     def exists(colorscheme):
         return os.path.exists(colorscheme + '.py') or os.path.exists(colorscheme + '.pyc')
 
-    def is_scheme(x):
+    def is_scheme(cls):
         try:
-            return issubclass(x, ColorScheme)
+            return issubclass(cls, ColorScheme)
         except Exception:
             return False
 
@@ -121,11 +123,11 @@ def _colorscheme_name_to_class(signal):
         raise Exception("Cannot locate colorscheme `%s'" % scheme_name)
     else:
         if usecustom:
-            allow_access_to_confdir(ranger.arg.confdir, True)
-        scheme_module = getattr(__import__(scheme_supermodule,
-                globals(), locals(), [scheme_name], 0), scheme_name)
+            allow_access_to_confdir(ranger.args.confdir, True)
+        scheme_module = getattr(
+            __import__(scheme_supermodule, globals(), locals(), [scheme_name], 0), scheme_name)
         if usecustom:
-            allow_access_to_confdir(ranger.arg.confdir, False)
+            allow_access_to_confdir(ranger.args.confdir, False)
         if hasattr(scheme_module, 'Scheme') \
                 and is_scheme(scheme_module.Scheme):
             signal.value = scheme_module.Scheme()
diff --git a/ranger/gui/context.py b/ranger/gui/context.py
index e577d2be..dec00892 100644
--- a/ranger/gui/context.py
+++ b/ranger/gui/context.py
@@ -1,35 +1,46 @@
 # This file is part of ranger, the console file manager.
 # License: GNU GPL version 3, see the file "AUTHORS" for details.
 
-CONTEXT_KEYS = ['reset', 'error', 'badinfo',
-        'in_browser', 'in_statusbar', 'in_titlebar', 'in_console',
-        'in_pager', 'in_taskview',
-        'active_pane', 'inactive_pane',
-        'directory', 'file', 'hostname',
-        'executable', 'media', 'link', 'fifo', 'socket', 'device',
-        'video', 'audio', 'image', 'media', 'document', 'container',
-        'selected', 'empty', 'main_column', 'message', 'background',
-        'good', 'bad',
-        'space', 'permissions', 'owner', 'group', 'mtime', 'nlink',
-        'scroll', 'all', 'bot', 'top', 'percentage', 'filter',
-        'flat', 'marked', 'tagged', 'tag_marker', 'cut', 'copied',
-        'help_markup',  # COMPAT
-        'seperator', 'key', 'special', 'border',  # COMPAT
-        'title', 'text', 'highlight', 'bars', 'quotes', 'tab', 'loaded',
-        'keybuffer',
-        'infostring',
-        'vcsfile', 'vcsremote', 'vcsinfo', 'vcscommit', 'vcsdate',
-        'vcsconflict', 'vcschanged', 'vcsunknown', 'vcsignored',
-        'vcsstaged', 'vcssync', 'vcsnone', 'vcsbehind', 'vcsahead', 'vcsdiverged']
-
-
-class Context(object):
+from __future__ import (absolute_import, print_function)
+
+
+CONTEXT_KEYS = [
+    'reset', 'error', 'badinfo',
+    'in_browser', 'in_statusbar', 'in_titlebar', 'in_console',
+    'in_pager', 'in_taskview',
+    'active_pane', 'inactive_pane',
+    'directory', 'file', 'hostname',
+    'executable', 'media', 'link', 'fifo', 'socket', 'device',
+    'video', 'audio', 'image', 'media', 'document', 'container',
+    'selected', 'empty', 'main_column', 'message', 'background',
+    'good', 'bad',
+    'space', 'permissions', 'owner', 'group', 'mtime', 'nlink',
+    'scroll', 'all', 'bot', 'top', 'percentage', 'filter',
+    'flat', 'marked', 'tagged', 'tag_marker', 'cut', 'copied',
+    'help_markup',  # COMPAT
+    'seperator', 'key', 'special', 'border',  # COMPAT
+    'title', 'text', 'highlight', 'bars', 'quotes', 'tab', 'loaded',
+    'keybuffer',
+    'infostring',
+    'vcsfile', 'vcsremote', 'vcsinfo', 'vcscommit', 'vcsdate',
+    'vcsconflict', 'vcschanged', 'vcsunknown', 'vcsignored',
+    'vcsstaged', 'vcssync', 'vcsnone', 'vcsbehind', 'vcsahead', 'vcsdiverged'
+]
+
+
+class Context(object):  # pylint: disable=too-few-public-methods
+
     def __init__(self, keys):
         # set all given keys to True
-        d = self.__dict__
+        dictionary = self.__dict__
         for key in keys:
-            d[key] = True
+            dictionary[key] = True
+
+
+def _context_init():
+    # set all keys to False
+    for key in CONTEXT_KEYS:
+        setattr(Context, key, False)
+
 
-# set all keys to False
-for key in CONTEXT_KEYS:
-    setattr(Context, key, False)
+_context_init()
diff --git a/ranger/gui/curses_shortcuts.py b/ranger/gui/curses_shortcuts.py
index ed762c9e..25a9d947 100644
--- a/ranger/gui/curses_shortcuts.py
+++ b/ranger/gui/curses_shortcuts.py
@@ -1,9 +1,11 @@
 # This file is part of ranger, the console file manager.
 # License: GNU GPL version 3, see the file "AUTHORS" for details.
 
+from __future__ import (absolute_import, print_function)
+
+import sys
 import curses
 import _curses
-import sys
 
 from ranger.gui.color import get_color
 from ranger.core.shared import SettingsAware
@@ -26,6 +28,9 @@ class CursesShortcuts(SettingsAware):
     addstr(*args) -- failsafe version of self.win.addstr(*args)
     """
 
+    def __init__(self):
+        self.win = None
+
     def addstr(self, *args):
         y, x = self.win.getyx()
 
diff --git a/ranger/gui/displayable.py b/ranger/gui/displayable.py
index 62eb5300..16c78a91 100644
--- a/ranger/gui/displayable.py
+++ b/ranger/gui/displayable.py
@@ -1,11 +1,14 @@
 # This file is part of ranger, the console file manager.
 # License: GNU GPL version 3, see the file "AUTHORS" for details.
 
+from __future__ import (absolute_import, print_function)
+
 from ranger.core.shared import FileManagerAware
 from ranger.gui.curses_shortcuts import CursesShortcuts
 
 
-class Displayable(FileManagerAware, CursesShortcuts):
+class Displayable(  # pylint: disable=too-many-instance-attributes
+        FileManagerAware, CursesShortcuts):
     """Displayables are objects which are displayed on the screen.
 
     This is just the abstract class, defining basic operations
@@ -40,8 +43,10 @@ class Displayable(FileManagerAware, CursesShortcuts):
         settings, fm -- inherited shared variables
     """
 
-    def __init__(self, win, env=None, fm=None, settings=None):
+    def __init__(self, win,  # pylint: disable=super-init-not-called
+                 env=None, fm=None, settings=None):
         from ranger.gui.ui import UI
+
         if env is not None:
             self.env = env
         if fm is not None:
@@ -105,7 +110,7 @@ class Displayable(FileManagerAware, CursesShortcuts):
         x and y should be absolute coordinates.
         """
         return (x >= self.x and x < self.x + self.wid) and \
-                (y >= self.y and y < self.y + self.hei)
+            (y >= self.y and y < self.y + self.hei)
 
     def click(self, event):
         """Called when a mouse key is pressed and self.focused is True.
@@ -153,17 +158,19 @@ class Displayable(FileManagerAware, CursesShortcuts):
 
             if x < 0 or y < 0:
                 self.fm.notify("Warning: Subwindow origin below zero for <%s> "
-                    "(x = %d, y = %d)" % (self, x, y), bad=True)
+                               "(x = %d, y = %d)" % (self, x, y), bad=True)
 
             if x + wid > maxx or y + hei > maxy:
-                self.fm.notify("Warning: Subwindow size out of bounds for <%s> "
-                    "(x = %d, y = %d, hei = %d, wid = %d)" % (self,
-                    x, y, hei, wid), bad=True)
+                self.fm.notify(
+                    "Warning: Subwindow size out of bounds for <%s> "
+                    "(x = %d, y = %d, hei = %d, wid = %d)" % (self, x, y, hei, wid),
+                    bad=True,
+                )
 
         window_is_cleared = False
 
         if hei != self.hei or wid != self.wid:
-            #log("resizing " + str(self))
+            # log("resizing " + str(self))
             self.win.erase()
             self.need_redraw = True
             window_is_cleared = True
@@ -177,7 +184,7 @@ class Displayable(FileManagerAware, CursesShortcuts):
                     self.win.resize(hei, wid)
                 except Exception:
                     pass
-                    #raise ValueError("Resizing Failed!")
+                    # raise ValueError("Resizing Failed!")
 
             self.hei, self.wid = self.win.getmaxyx()
 
@@ -185,7 +192,7 @@ class Displayable(FileManagerAware, CursesShortcuts):
             if not window_is_cleared:
                 self.win.erase()
                 self.need_redraw = True
-            #log("moving " + str(self))
+            # log("moving " + str(self))
             try:
                 self.win.mvderwin(y, x)
             except Exception:
@@ -311,7 +318,7 @@ class DisplayableContainer(Displayable):
             if displayable.focused:
                 return displayable
             try:
-                obj = displayable._get_focused_obj()
+                obj = displayable._get_focused_obj()  # pylint: disable=protected-access
             except AttributeError:
                 pass
             else:
diff --git a/ranger/gui/mouse_event.py b/ranger/gui/mouse_event.py
index 1d3ec970..5a5f687f 100644
--- a/ranger/gui/mouse_event.py
+++ b/ranger/gui/mouse_event.py
@@ -1,15 +1,19 @@
 # This file is part of ranger, the console file manager.
 # License: GNU GPL version 3, see the file "AUTHORS" for details.
 
+from __future__ import (absolute_import, print_function)
+
 import curses
 
 
 class MouseEvent(object):
-    PRESSED = [0,
-            curses.BUTTON1_PRESSED,
-            curses.BUTTON2_PRESSED,
-            curses.BUTTON3_PRESSED,
-            curses.BUTTON4_PRESSED]
+    PRESSED = [
+        0,
+        curses.BUTTON1_PRESSED,
+        curses.BUTTON2_PRESSED,
+        curses.BUTTON3_PRESSED,
+        curses.BUTTON4_PRESSED,
+    ]
     CTRL_SCROLLWHEEL_MULTIPLIER = 5
 
     def __init__(self, getmouse):
@@ -39,13 +43,12 @@ class MouseEvent(object):
         # Recently it seems to have been fixed, as 2**21 was introduced as
         # the code for the "scroll down" button.
         if self.bstate & curses.BUTTON4_PRESSED:
-            return self.ctrl() and -self.CTRL_SCROLLWHEEL_MULTIPLIER or -1
+            return -self.CTRL_SCROLLWHEEL_MULTIPLIER if self.ctrl() else -1
         elif self.bstate & curses.BUTTON2_PRESSED \
                 or self.bstate & 2**21 \
                 or self.bstate > curses.ALL_MOUSE_EVENTS:
-            return self.ctrl() and self.CTRL_SCROLLWHEEL_MULTIPLIER or 1
-        else:
-            return 0
+            return self.CTRL_SCROLLWHEEL_MULTIPLIER if self.ctrl() else 1
+        return 0
 
     def ctrl(self):
         return self.bstate & curses.BUTTON_CTRL
diff --git a/ranger/gui/ui.py b/ranger/gui/ui.py
index f10bc0f2..97938453 100644
--- a/ranger/gui/ui.py
+++ b/ranger/gui/ui.py
@@ -1,18 +1,22 @@
 # This file is part of ranger, the console file manager.
 # License: GNU GPL version 3, see the file "AUTHORS" for details.
 
+from __future__ import (absolute_import, print_function)
+
 import os
 import sys
+import threading
 import curses
 import _curses
-import threading
 
-from .displayable import DisplayableContainer
-from .mouse_event import MouseEvent
 from ranger.ext.keybinding_parser import KeyBuffer, KeyMaps, ALT_KEY
 from ranger.ext.lazy_property import lazy_property
 from ranger.ext.signals import Signal
 
+from .displayable import DisplayableContainer
+from .mouse_event import MouseEvent
+
+
 MOUSEMASK = curses.ALL_MOUSE_EVENTS | curses.REPORT_MOUSE_POSITION
 
 _ASCII = ''.join(chr(c) for c in range(32, 127))
@@ -38,7 +42,8 @@ def _setup_mouse(signal):
         curses.mousemask(0)
 
 
-class UI(DisplayableContainer):
+class UI(  # pylint: disable=too-many-instance-attributes,too-many-public-methods
+        DisplayableContainer):
     ALLOWED_VIEWMODES = 'miller', 'multipane'
 
     is_set_up = False
@@ -46,12 +51,21 @@ class UI(DisplayableContainer):
     is_on = False
     termsize = None
 
-    def __init__(self, env=None, fm=None):
+    def __init__(self, env=None, fm=None):  # pylint: disable=super-init-not-called
         self.keybuffer = KeyBuffer()
         self.keymaps = KeyMaps(self.keybuffer)
         self.redrawlock = threading.Event()
         self.redrawlock.set()
 
+        self.titlebar = None
+        self._viewmode = None
+        self.taskview = None
+        self.status = None
+        self.console = None
+        self.pager = None
+        self._draw_title = None
+        self.browser = None
+
         if fm is not None:
             self.fm = fm
 
@@ -59,8 +73,8 @@ class UI(DisplayableContainer):
         os.environ['ESCDELAY'] = '25'   # don't know a cleaner way
         try:
             self.win = curses.initscr()
-        except _curses.error as e:
-            if e.args[0] == "setupterm: could not find terminal":
+        except _curses.error as ex:
+            if ex.args[0] == "setupterm: could not find terminal":
                 os.environ['TERM'] = 'linux'
                 self.win = curses.initscr()
         self.keymaps.use_keymap('browser')
@@ -172,13 +186,15 @@ class UI(DisplayableContainer):
         keybuffer.add(key)
         self.fm.hide_bookmarks()
         self.browser.draw_hints = not keybuffer.finished_parsing \
-                and keybuffer.finished_parsing_quantifier
+            and keybuffer.finished_parsing_quantifier
 
         if keybuffer.result is not None:
             try:
-                self.fm.execute_console(keybuffer.result,
-                        wildcards=keybuffer.wildcards,
-                        quantifier=keybuffer.quantifier)
+                self.fm.execute_console(
+                    keybuffer.result,
+                    wildcards=keybuffer.wildcards,
+                    quantifier=keybuffer.quantifier,
+                )
             finally:
                 if keybuffer.finished_parsing:
                     keybuffer.clear()
@@ -193,12 +209,12 @@ class UI(DisplayableContainer):
 
     def handle_input(self):
         key = self.win.getch()
-        if key is 27 or key >= 128 and key < 256:
+        if key == 27 or (key >= 128 and key < 256):
             # Handle special keys like ALT+X or unicode here:
             keys = [key]
             previous_load_mode = self.load_mode
             self.set_load_mode(True)
-            for n in range(4):
+            for _ in range(4):
                 getkey = self.win.getch()
                 if getkey is not -1:
                     keys.append(getkey)
@@ -231,7 +247,6 @@ class UI(DisplayableContainer):
 
     def setup(self):
         """Build up the UI by initializing widgets."""
-        from ranger.gui.widgets.view_miller import ViewMiller
         from ranger.gui.widgets.titlebar import TitleBar
         from ranger.gui.widgets.console import Console
         from ranger.gui.widgets.statusbar import StatusBar
@@ -330,10 +345,12 @@ class UI(DisplayableContainer):
                     cwd = os.sep.join(split[1:])
             try:
                 fixed_cwd = cwd.encode('utf-8', 'surrogateescape'). \
-                        decode('utf-8', 'replace')
-                sys.stdout.write("%sranger:%s%s" %
-                        (curses.tigetstr('tsl').decode('latin-1'), fixed_cwd,
-                         curses.tigetstr('fsl').decode('latin-1')))
+                    decode('utf-8', 'replace')
+                sys.stdout.write("%sranger:%s%s" % (
+                    curses.tigetstr('tsl').decode('latin-1'),
+                    fixed_cwd,
+                    curses.tigetstr('fsl').decode('latin-1'),
+                ))
                 sys.stdout.flush()
             except Exception:
                 pass
@@ -423,8 +440,7 @@ class UI(DisplayableContainer):
     def get_pager(self):
         if hasattr(self.browser, 'pager') and self.browser.pager.visible:
             return self.browser.pager
-        else:
-            return self.pager
+        return self.pager
 
     def _get_viewmode(self):
         return self._viewmode
@@ -439,23 +455,24 @@ class UI(DisplayableContainer):
                 self._viewmode = value
                 new_browser = self._viewmode_to_class(value)(self.win)
 
-                if hasattr(self, 'browser'):
+                if self.browser is None:
+                    self.add_child(new_browser)
+                else:
                     old_size = self.browser.y, self.browser.x, self.browser.hei, self.browser.wid
                     self.replace_child(self.browser, new_browser)
                     self.browser.destroy()
                     new_browser.resize(*old_size)
-                else:
-                    self.add_child(new_browser)
 
                 self.browser = new_browser
                 self.redraw_window()
         else:
             raise ValueError("Attempting to set invalid viewmode `%s`, should "
-                    "be one of `%s`." % (value, "`, `".join(self.ALLOWED_VIEWMODES)))
+                             "be one of `%s`." % (value, "`, `".join(self.ALLOWED_VIEWMODES)))
 
     viewmode = property(_get_viewmode, _set_viewmode)
 
-    def _viewmode_to_class(self, viewmode):
+    @staticmethod
+    def _viewmode_to_class(viewmode):
         if viewmode == 'miller':
             from ranger.gui.widgets.view_miller import ViewMiller
             return ViewMiller
diff --git a/ranger/gui/widgets/__init__.py b/ranger/gui/widgets/__init__.py
index 9a95509c..7fa796f6 100644
--- a/ranger/gui/widgets/__init__.py
+++ b/ranger/gui/widgets/__init__.py
@@ -1,5 +1,7 @@
 # -*- coding: utf-8 -*-
 
+from __future__ import (absolute_import, print_function)
+
 from ranger.gui.displayable import Displayable
 
 
@@ -7,24 +9,39 @@ class Widget(Displayable):
     """A class for classification of widgets."""
 
     vcsstatus_symb = {
-        'conflict':  ('X', ['vcsconflict']),
-        'untracked': ('+', ['vcschanged']),
-        'deleted':   ('-', ['vcschanged']),
-        'changed':   ('*', ['vcschanged']),
-        'staged':    ('*', ['vcsstaged']),
-        'ignored':   ('·', ['vcsignored']),
-        'sync':      ('√', ['vcssync']),
-        'none':      (' ', []),
-        'unknown':   ('?', ['vcsunknown']),
+        'conflict': (
+            'X', ['vcsconflict']),
+        'untracked': (
+            '+', ['vcschanged']),
+        'deleted': (
+            '-', ['vcschanged']),
+        'changed': (
+            '*', ['vcschanged']),
+        'staged': (
+            '*', ['vcsstaged']),
+        'ignored': (
+            '·', ['vcsignored']),
+        'sync': (
+            '√', ['vcssync']),
+        'none': (
+            ' ', []),
+        'unknown': (
+            '?', ['vcsunknown']),
     }
 
     vcsremotestatus_symb = {
-        'diverged': ('Y', ['vcsdiverged']),
-        'ahead':    ('>', ['vcsahead']),
-        'behind':   ('<', ['vcsbehind']),
-        'sync':     ('=', ['vcssync']),
-        'none':     ('⌂', ['vcsnone']),
-        'unknown':  ('?', ['vcsunknown']),
+        'diverged': (
+            'Y', ['vcsdiverged']),
+        'ahead': (
+            '>', ['vcsahead']),
+        'behind': (
+            '<', ['vcsbehind']),
+        'sync': (
+            '=', ['vcssync']),
+        'none': (
+            '⌂', ['vcsnone']),
+        'unknown': (
+            '?', ['vcsunknown']),
     }
 
     ellipsis = {False: '~', True: '…'}
diff --git a/ranger/gui/widgets/browsercolumn.py b/ranger/gui/widgets/browsercolumn.py
index 829809c0..222457c2 100644
--- a/ranger/gui/widgets/browsercolumn.py
+++ b/ranger/gui/widgets/browsercolumn.py
@@ -3,24 +3,23 @@
 
 """The BrowserColumn widget displays the contents of a directory or file."""
 
-import curses
+from __future__ import (absolute_import, print_function)
+
 import stat
 from time import time
 from os.path import splitext
 
-from . import Widget
-from .pager import Pager
 from ranger.ext.widestring import WideString
-
 from ranger.core import linemode
 
-from ranger.gui.color import *
+from . import Widget
+from .pager import Pager
 
 
-class BrowserColumn(Pager):
+class BrowserColumn(Pager):  # pylint: disable=too-many-instance-attributes
     main_column = False
     display_infostring = False
-    display_vcsstate   = True
+    display_vcsstate = True
     scroll_begin = 0
     target = None
     last_redraw_time = -1
@@ -39,13 +38,13 @@ class BrowserColumn(Pager):
         level <0 => parent directories
         """
         Pager.__init__(self, win)
-        Widget.__init__(self, win)
+        Widget.__init__(self, win)  # pylint: disable=non-parent-init-called
         self.level = level
         self.tab = tab
         self.original_level = level
 
         self.settings.signal_bind('setopt.display_size_in_main_column',
-                self.request_redraw, weak=True)
+                                  self.request_redraw, weak=True)
 
     def request_redraw(self):
         self.need_redraw = True
@@ -182,14 +181,14 @@ class BrowserColumn(Pager):
             Pager.close(self)
             return
 
-        f = self.target.get_preview_source(self.wid, self.hei)
-        if f is None:
+        path = self.target.get_preview_source(self.wid, self.hei)
+        if path is None:
             Pager.close(self)
         else:
             if self.target.is_image_preview():
-                self.set_image(f)
+                self.set_image(path)
             else:
-                self.set_source(f)
+                self.set_source(path)
             Pager.draw(self)
 
     def _format_line_number(self, linum_format, i, selected_i):
@@ -201,7 +200,8 @@ class BrowserColumn(Pager):
 
         return linum_format.format(line_number)
 
-    def _draw_directory(self):
+    def _draw_directory(  # pylint: disable=too-many-locals,too-many-branches,too-many-statements
+            self):
         """Draw the contents of a directory"""
         if self.image:
             self.image = None
@@ -273,7 +273,8 @@ class BrowserColumn(Pager):
 
             # Extract linemode-related information from the drawn object
             metadata = None
-            current_linemode = drawn.linemode_dict[drawn._linemode]
+            current_linemode = \
+                drawn.linemode_dict[drawn._linemode]  # pylint: disable=protected-access
             if current_linemode.uses_metadata:
                 metadata = self.fm.metadata.get_metadata(drawn.path)
                 if not all(getattr(metadata, tag)
@@ -303,7 +304,7 @@ class BrowserColumn(Pager):
             text = current_linemode.filetitle(drawn, metadata)
 
             if drawn.marked and (self.main_column or
-                    self.settings.display_tags_in_all_columns):
+                                 self.settings.display_tags_in_all_columns):
                 text = " " + text
 
             # Computing predisplay data. predisplay contains a list of lists
@@ -366,13 +367,13 @@ class BrowserColumn(Pager):
                 predisplay_left.append([' ' * space, []])
             elif space < 0:
                 raise Exception("Error: there is not enough space to write "
-                        "the text. I have computed spaces wrong.")
+                                "the text. I have computed spaces wrong.")
 
             # Computing display data. Now we compute the display_data list
             # ready to display in curses. It is a list of lists [string, attr]
 
             this_color = base_color + list(drawn.mimetype_tuple) + \
-                    self._draw_directory_color(i, drawn, copied)
+                self._draw_directory_color(i, drawn, copied)
             display_data = []
             drawn.display_data[key] = display_data
 
@@ -387,11 +388,11 @@ class BrowserColumn(Pager):
     def _get_index_of_selected_file(self):
         if self.fm.ui.viewmode == 'multipane' and hasattr(self, 'tab'):
             return self.tab.pointer
-        else:
-            return self.target.pointer
+        return self.target.pointer
 
-    def _total_len(self, predisplay):
-        return sum([len(WideString(s)) for s, L in predisplay])
+    @staticmethod
+    def _total_len(predisplay):
+        return sum([len(WideString(s)) for s, _ in predisplay])
 
     def _draw_text_display(self, text, space):
         wtext = WideString(text)
@@ -479,7 +480,7 @@ class BrowserColumn(Pager):
 
         return this_color
 
-    def _get_scroll_begin(self):
+    def _get_scroll_begin(self):  # pylint: disable=too-many-return-statements
         """Determines scroll_begin (the position of the first displayed file)"""
         offset = self.settings.scroll_offset
         dirsize = len(self.target)
@@ -509,12 +510,10 @@ class BrowserColumn(Pager):
             return original
 
         if projected > upper_limit:
-            return min(dirsize - winsize,
-                    original + (projected - upper_limit))
+            return min(dirsize - winsize, original + (projected - upper_limit))
 
         if projected < upper_limit:
-            return max(0,
-                    original - (lower_limit - projected))
+            return max(0, original - (lower_limit - projected))
 
         return original
 
diff --git a/ranger/gui/widgets/console.py b/ranger/gui/widgets/console.py
index db04a9c8..3c056aa9 100644
--- a/ranger/gui/widgets/console.py
+++ b/ranger/gui/widgets/console.py
@@ -3,6 +3,8 @@
 
 """The Console widget implements a vim-like console"""
 
+from __future__ import (absolute_import, print_function)
+
 import curses
 import re
 from collections import deque
@@ -14,7 +16,7 @@ from ranger.container.history import History, HistoryEmptyException
 import ranger
 
 
-class Console(Widget):
+class Console(Widget):  # pylint: disable=too-many-instance-attributes,too-many-public-methods
     visible = False
     last_cursor_mode = None
     history_search_pattern = None
@@ -32,20 +34,20 @@ class Console(Widget):
 
     def __init__(self, win):
         Widget.__init__(self, win)
-        self.clear()
+        self.pos = 0
+        self.line = ''
         self.history = History(self.settings.max_console_history_size)
         # load history from files
-        if not ranger.arg.clean:
+        if not ranger.args.clean:
             self.historypath = self.fm.confpath('history')
             try:
-                f = open(self.historypath, 'r')
+                fobj = open(self.historypath, 'r')
             except Exception:
                 pass
             else:
-                for line in f:
+                for line in fobj:
                     self.history.add(line[:-1])
-                f.close()
-        self.line = ""
+                fobj.close()
         self.history_backup = History(self.history)
 
         # NOTE: the console is considered in the "question mode" when the
@@ -63,20 +65,20 @@ class Console(Widget):
 
     def destroy(self):
         # save history to files
-        if ranger.arg.clean or not self.settings.save_console_history:
+        if ranger.args.clean or not self.settings.save_console_history:
             return
         if self.historypath:
             try:
-                f = open(self.historypath, 'w')
+                fobj = open(self.historypath, 'w')
             except Exception:
                 pass
             else:
                 for entry in self.history_backup:
                     try:
-                        f.write(entry + '\n')
+                        fobj.write(entry + '\n')
                     except UnicodeEncodeError:
                         pass
-                f.close()
+                fobj.close()
         Widget.destroy(self)
 
     def draw(self):
@@ -178,7 +180,7 @@ class Console(Widget):
         if not self.question_queue:
             return False
         question = self.question_queue[0]
-        text, callback, answers = question
+        _, callback, answers = question
         if answer in answers:
             self.question_queue.pop(0)
             callback(answer)
@@ -269,23 +271,23 @@ class Console(Widget):
             # Ensure that the pointer is moved utf-char-wise
             if self.fm.py3:
                 self.pos = direction.move(
-                        direction=direction.right(),
-                        minimum=0,
-                        maximum=len(self.line) + 1,
-                        current=self.pos)
+                    direction=direction.right(),
+                    minimum=0,
+                    maximum=len(self.line) + 1,
+                    current=self.pos)
             else:
                 if self.fm.py3:
-                    uc = list(self.line)
+                    uchar = list(self.line)
                     upos = len(self.line[:self.pos])
                 else:
-                    uc = list(self.line.decode('utf-8', 'ignore'))
+                    uchar = list(self.line.decode('utf-8', 'ignore'))
                     upos = len(self.line[:self.pos].decode('utf-8', 'ignore'))
                 newupos = direction.move(
-                        direction=direction.right(),
-                        minimum=0,
-                        maximum=len(uc) + 1,
-                        current=upos)
-                self.pos = len(''.join(uc[:newupos]).encode('utf-8', 'ignore'))
+                    direction=direction.right(),
+                    minimum=0,
+                    maximum=len(uchar) + 1,
+                    current=upos)
+                self.pos = len(''.join(uchar[:newupos]).encode('utf-8', 'ignore'))
 
     def move_word(self, **keywords):
         direction = Direction(keywords)
@@ -304,7 +306,7 @@ class Console(Widget):
         ...     # it works fine in ranger, even with unicode input...
         ...     line = "ohai world,  this is dog"
         ... else:
-        ...     line = "\u30AA\u30CF\u30E8\u30A6 world,  this is dog"
+        ...     line = "\\u30AA\\u30CF\\u30E8\\u30A6 world,  this is dog"
         >>> Console.move_by_word(line, 0, -1)
         0
         >>> Console.move_by_word(line, 0, 1)
@@ -378,7 +380,8 @@ class Console(Widget):
             if backward:
                 right_part = self.line[self.pos:]
                 i = self.pos - 2
-                while i >= 0 and re.match(r'[\w\d]', self.line[i], re.U):
+                while i >= 0 and re.match(
+                        r'[\w\d]', self.line[i], re.UNICODE):  # pylint: disable=no-member
                     i -= 1
                 self.copy = self.line[i + 1:self.pos]
                 self.line = self.line[:i + 1] + right_part
@@ -386,7 +389,8 @@ class Console(Widget):
             else:
                 left_part = self.line[:self.pos]
                 i = self.pos + 1
-                while i < len(self.line) and re.match(r'[\w\d]', self.line[i], re.U):
+                while i < len(self.line) and re.match(
+                        r'[\w\d]', self.line[i], re.UNICODE):  # pylint: disable=no-member
                     i += 1
                 self.copy = self.line[self.pos:i]
                 if i >= len(self.line):
@@ -409,11 +413,11 @@ class Console(Widget):
             self.pos = len(left_part)
             self.line = left_part + self.line[self.pos + 1:]
         else:
-            uc = list(self.line.decode('utf-8', 'ignore'))
+            uchar = list(self.line.decode('utf-8', 'ignore'))
             upos = len(self.line[:self.pos].decode('utf-8', 'ignore')) + mod
-            left_part = ''.join(uc[:upos]).encode('utf-8', 'ignore')
+            left_part = ''.join(uchar[:upos]).encode('utf-8', 'ignore')
             self.pos = len(left_part)
-            self.line = left_part + ''.join(uc[upos + 1:]).encode('utf-8', 'ignore')
+            self.line = left_part + ''.join(uchar[upos + 1:]).encode('utf-8', 'ignore')
         self.on_line_change()
 
     def execute(self, cmd=None):
@@ -455,8 +459,7 @@ class Console(Widget):
             cmd = self._get_cmd()
             if cmd:
                 return cmd.tab(tabnum)
-            else:
-                return None
+            return None
 
         return self.fm.commands.command_generator(self.line)
 
@@ -494,7 +497,7 @@ class Console(Widget):
                 cmd.quickly_executed = True
                 self.execute(cmd)
 
-    def ask(self, text, callback, choices=['y', 'n']):
+    def ask(self, text, callback, choices=None):
         """Open a question prompt with predefined choices
 
         The "text" is displayed as the question text and should include a list
@@ -507,7 +510,9 @@ class Console(Widget):
         The first choice is used when the user presses <Enter>, the second
         choice is used when the user presses <ESC>.
         """
-        self.question_queue.append((text, callback, choices))
+        self.question_queue.append(
+            (text, callback, choices if choices is not None else ['y', 'n']))
+
 
 if __name__ == '__main__':
     import doctest
diff --git a/ranger/gui/widgets/pager.py b/ranger/gui/widgets/pager.py
index 0c81079b..4182b189 100644
--- a/ranger/gui/widgets/pager.py
+++ b/ranger/gui/widgets/pager.py
@@ -3,16 +3,18 @@
 
 """The pager displays text and allows you to scroll inside it."""
 
-from . import Widget
-from ranger.core.loader import CommandLoader
+from __future__ import (absolute_import, print_function)
+
 from ranger.gui import ansi
 from ranger.ext.direction import Direction
 from ranger.ext.img_display import ImgDisplayUnsupportedException
 
+from . import Widget
+
 # TODO: Scrolling in embedded pager
 
 
-class Pager(Widget):
+class Pager(Widget):  # pylint: disable=too-many-instance-attributes
     source = None
     source_is_stream = False
 
@@ -81,7 +83,7 @@ class Pager(Widget):
 
             if not self.image:
                 line_gen = self._generate_lines(
-                        starty=self.scroll_begin, startx=self.startx)
+                    starty=self.scroll_begin, startx=self.startx)
 
                 for line, i in zip(line_gen, range(self.hei)):
                     self._draw_line(i, line)
@@ -94,11 +96,11 @@ class Pager(Widget):
             self.need_redraw_image = False
             try:
                 self.fm.image_displayer.draw(self.image, self.x, self.y,
-                        self.wid, self.hei)
+                                             self.wid, self.hei)
             except ImgDisplayUnsupportedException:
                 self.fm.settings.preview_images = False
-            except Exception as e:
-                self.fm.notify(e, bad=True)
+            except Exception as ex:
+                self.fm.notify(ex, bad=True)
             else:
                 self.image_drawn = True
 
@@ -121,31 +123,31 @@ class Pager(Widget):
         direction = Direction(kw)
         if direction.horizontal():
             self.startx = direction.move(
-                    direction=direction.right(),
-                    override=narg,
-                    maximum=self.max_width,
-                    current=self.startx,
-                    pagesize=self.wid,
-                    offset=-self.wid + 1)
+                direction=direction.right(),
+                override=narg,
+                maximum=self.max_width,
+                current=self.startx,
+                pagesize=self.wid,
+                offset=-self.wid + 1)
         if direction.vertical():
             movement = dict(
-                    direction=direction.down(),
-                    override=narg,
-                    current=self.scroll_begin,
-                    pagesize=self.hei,
-                    offset=-self.hei + 1)
+                direction=direction.down(),
+                override=narg,
+                current=self.scroll_begin,
+                pagesize=self.hei,
+                offset=-self.hei + 1)
             if self.source_is_stream:
                 # For streams, we first pretend that the content ends much later,
                 # in case there are still unread lines.
                 desired_position = direction.move(
-                        maximum=len(self.lines) + 9999,
-                        **movement)
+                    maximum=len(self.lines) + 9999,
+                    **movement)
                 # Then, read the new lines as needed to produce a more accurate
                 # maximum for the movement:
                 self._get_line(desired_position + self.hei)
             self.scroll_begin = direction.move(
-                    maximum=len(self.lines),
-                    **movement)
+                maximum=len(self.lines),
+                **movement)
 
     def press(self, key):
         self.fm.ui.keymaps.use_keymap('pager')
@@ -190,13 +192,13 @@ class Pager(Widget):
         self.markup = 'ansi'
 
         if not self.source_is_stream and strip:
-            self.lines = map(lambda x: x.strip(), self.lines)
+            self.lines = [line.strip() for line in self.lines]
 
         self.source = source
         return True
 
     def click(self, event):
-        n = event.ctrl() and 1 or 3
+        n = 1 if event.ctrl() else 3
         direction = event.mouse_wheel_direction()
         if direction:
             self.move(down=direction * n)
@@ -209,10 +211,10 @@ class Pager(Widget):
         except (KeyError, IndexError):
             if attempt_to_read and self.source_is_stream:
                 try:
-                    for l in self.source:
-                        if len(l) > self.max_width:
-                            self.max_width = len(l)
-                        self.lines.append(l)
+                    for line in self.source:
+                        if len(line) > self.max_width:
+                            self.max_width = len(line)
+                        self.lines.append(line)
                         if len(self.lines) > n:
                             break
                 except (UnicodeError, IOError):
@@ -227,7 +229,7 @@ class Pager(Widget):
         while True:
             try:
                 line = self._get_line(i).expandtabs(4)
-                if self.markup is 'ansi':
+                if self.markup == 'ansi':
                     line = ansi.char_slice(line, startx, self.wid) + ansi.reset
                 else:
                     line = line[startx:self.wid + startx]
diff --git a/ranger/gui/widgets/statusbar.py b/ranger/gui/widgets/statusbar.py
index 0ac62d86..bb0b2d4c 100644
--- a/ranger/gui/widgets/statusbar.py
+++ b/ranger/gui/widgets/statusbar.py
@@ -8,18 +8,21 @@ print for the current file.  The right side shows directory information
 such as the space used by all the files in this directory.
 """
 
+from __future__ import (absolute_import, print_function)
+
 import os
+from os import getuid, readlink
 from pwd import getpwuid
 from grp import getgrgid
-from os import getuid, readlink
 from time import time, strftime, localtime
 
 from ranger.ext.human_readable import human_readable
-from . import Widget
 from ranger.gui.bar import Bar
 
+from . import Widget
+
 
-class StatusBar(Widget):
+class StatusBar(Widget):  # pylint: disable=too-many-instance-attributes
     __doc__ = __doc__
     owners = {}
     groups = {}
@@ -37,7 +40,7 @@ class StatusBar(Widget):
         Widget.__init__(self, win)
         self.column = column
         self.settings.signal_bind('setopt.display_size_in_status_bar',
-                self.request_redraw, weak=True)
+                                  self.request_redraw, weak=True)
 
     def request_redraw(self):
         self.need_redraw = True
@@ -111,7 +114,7 @@ class StatusBar(Widget):
     def _draw_message(self):
         self.win.erase()
         self.color('in_statusbar', 'message',
-                self.msg.bad and 'bad' or 'good')
+                   self.msg.bad and 'bad' or 'good')
         self.addnstr(0, 0, self.msg.text, self.wid)
 
     def _draw_hint(self):
@@ -133,7 +136,7 @@ class StatusBar(Widget):
             space_left -= len(string)
             starting_point += len(string)
 
-    def _get_left_part(self, bar):
+    def _get_left_part(self, bar):  # pylint: disable=too-many-branches,too-many-statements
         left = bar.left
 
         if self.column is not None and self.column.target is not None\
@@ -156,7 +159,7 @@ class StatusBar(Widget):
             perms = '--%s--' % self.fm.mode.upper()
         else:
             perms = target.get_permission_string()
-        how = getuid() == stat.st_uid and 'good' or 'bad'
+        how = 'good' if getuid() == stat.st_uid else 'bad'
         left.add(perms, 'permissions', how)
         left.add_space()
         left.add(str(stat.st_nlink), 'nlink')
@@ -166,7 +169,7 @@ class StatusBar(Widget):
         left.add(self._get_group(target), 'group')
 
         if target.is_link:
-            how = target.exists and 'good' or 'bad'
+            how = 'good' if target.exists else 'bad'
             try:
                 dest = readlink(target.path)
             except Exception:
@@ -230,7 +233,7 @@ class StatusBar(Widget):
             except KeyError:
                 return str(gid)
 
-    def _get_right_part(self, bar):
+    def _get_right_part(self, bar):  # pylint: disable=too-many-branches
         right = bar.right
         if self.column is None:
             return
@@ -261,8 +264,11 @@ class StatusBar(Widget):
             if len(target.marked_items) == target.size:
                 right.add(human_readable(target.disk_usage, separator=''))
             else:
-                sumsize = sum(f.size for f in target.marked_items if not
-                        f.is_directory or f._cumulative_size_calculated)
+                sumsize = sum(
+                    f.size for f in target.marked_items
+                    if not f.is_directory or
+                    f._cumulative_size_calculated  # pylint: disable=protected-access
+                )
                 right.add(human_readable(sumsize, separator=''))
             right.add("/" + str(len(target.marked_items)))
         else:
@@ -280,9 +286,8 @@ class StatusBar(Widget):
             # Indicate that there are marked files. Useful if you scroll
             # away and don't see them anymore.
             right.add('Mrk', base, 'marked')
-        elif len(target.files):
-            right.add(str(target.pointer + 1) + '/'
-                    + str(len(target.files)) + '  ', base)
+        elif target.files:
+            right.add(str(target.pointer + 1) + '/' + str(len(target.files)) + '  ', base)
             if max_pos <= 0:
                 right.add('All', base, 'all')
             elif pos == 0:
@@ -291,7 +296,7 @@ class StatusBar(Widget):
                 right.add('Bot', base, 'bot')
             else:
                 right.add('{0:0.0%}'.format(float(pos) / max_pos),
-                        base, 'percentage')
+                          base, 'percentage')
         else:
             right.add('0/0  All', base, 'all')
 
@@ -319,7 +324,7 @@ def get_free_space(path):
     return stat.f_bavail * stat.f_frsize
 
 
-class Message(object):
+class Message(object):  # pylint: disable=too-few-public-methods
     elapse = None
     text = None
     bad = False
diff --git a/ranger/gui/widgets/taskview.py b/ranger/gui/widgets/taskview.py
index f05606c9..d7c5571b 100644
--- a/ranger/gui/widgets/taskview.py
+++ b/ranger/gui/widgets/taskview.py
@@ -3,9 +3,12 @@
 
 """The TaskView allows you to modify what the loader is doing."""
 
-from . import Widget
+from __future__ import (absolute_import, print_function)
+
 from ranger.ext.accumulator import Accumulator
 
+from . import Widget
+
 
 class TaskView(Widget, Accumulator):
     old_lst = None
@@ -50,10 +53,8 @@ class TaskView(Widget, Accumulator):
                         clr.append('selected')
 
                     descr = obj.get_description()
-                    if obj.progressbar_supported and obj.percent >= 0 \
-                            and obj.percent <= 100:
-                        self.addstr(y, 0, "%3.2f%% - %s" %
-                                (obj.percent, descr), self.wid)
+                    if obj.progressbar_supported and obj.percent >= 0 and obj.percent <= 100:
+                        self.addstr(y, 0, "%3.2f%% - %s" % (obj.percent, descr), self.wid)
                         wid = int(self.wid / 100.0 * obj.percent)
                         self.color_at(y, 0, self.wid, tuple(clr))
                         self.color_at(y, 0, wid, tuple(clr), 'loaded')
@@ -79,7 +80,7 @@ class TaskView(Widget, Accumulator):
         if self.fm.loader.queue:
             self.fm.loader.remove(index=i)
 
-    def task_move(self, to, i=None):
+    def task_move(self, to, i=None):  # pylint: disable=invalid-name
         if i is None:
             i = self.pointer
 
diff --git a/ranger/gui/widgets/titlebar.py b/ranger/gui/widgets/titlebar.py
index d46fec62..fc5aeeab 100644
--- a/ranger/gui/widgets/titlebar.py
+++ b/ranger/gui/widgets/titlebar.py
@@ -6,11 +6,13 @@
 It displays the current path among other things.
 """
 
+from __future__ import (absolute_import, print_function)
+
 from os.path import basename
 
+from ranger.gui.bar import Bar
 
 from . import Widget
-from ranger.gui.bar import Bar
 
 
 class TitleBar(Widget):
@@ -41,8 +43,7 @@ class TitleBar(Widget):
         self._print_result(self.result)
         if self.wid > 2:
             self.color('in_titlebar', 'throbber')
-            self.addnstr(self.y, self.wid - 2 - self.tab_width,
-                    self.throbber, 1)
+            self.addnstr(self.y, self.wid - 2 - self.tab_width, self.throbber, 1)
 
     def click(self, event):
         """Handle a MouseEvent"""
@@ -56,7 +57,7 @@ class TitleBar(Widget):
             return False
 
         pos = self.wid - 1
-        for tabname in reversed(self.fm._get_tab_list()):
+        for tabname in reversed(self.fm._get_tab_list()):  # pylint: disable=protected-access
             tabtext = self._get_tab_text(tabname)
             pos -= len(tabtext)
             if event.x > pos:
@@ -123,13 +124,13 @@ class TitleBar(Widget):
 
     def _get_right_part(self, bar):
         # TODO: fix that pressed keys are cut off when chaining CTRL keys
-        kb = str(self.fm.ui.keybuffer)
-        self.old_keybuffer = kb
-        bar.addright(kb, 'keybuffer', fixed=True)
+        kbuf = str(self.fm.ui.keybuffer)
+        self.old_keybuffer = kbuf
+        bar.addright(kbuf, 'keybuffer', fixed=True)
         bar.addright('  ', 'space', fixed=True)
         self.tab_width = 0
         if len(self.fm.tabs) > 1:
-            for tabname in self.fm._get_tab_list():
+            for tabname in self.fm._get_tab_list():  # pylint: disable=protected-access
                 tabtext = self._get_tab_text(tabname)
                 self.tab_width += len(tabtext)
                 clr = 'good' if tabname == self.fm.current_tab else 'bad'
diff --git a/ranger/gui/widgets/view_base.py b/ranger/gui/widgets/view_base.py
index a50fb5ce..001f40b3 100644
--- a/ranger/gui/widgets/view_base.py
+++ b/ranger/gui/widgets/view_base.py
@@ -3,25 +3,30 @@
 
 """The base GUI element for views on the directory"""
 
+from __future__ import (absolute_import, print_function)
+
 import curses
-import _curses
 from ranger.ext.keybinding_parser import key_to_string
 from . import Widget
 from ..displayable import DisplayableContainer
 
 
-class ViewBase(Widget, DisplayableContainer):
+class ViewBase(Widget, DisplayableContainer):  # pylint: disable=too-many-instance-attributes
     draw_bookmarks = False
     need_clear = False
     draw_hints = False
     draw_info = False
 
-    def __init__(self, win):
+    def __init__(self, win):  # pylint: disable=super-init-not-called
         DisplayableContainer.__init__(self, win)
 
         self.fm.signal_bind('move', self.request_clear)
         self.old_draw_borders = self.settings.draw_borders
 
+        self.columns = None
+        self.main_column = None
+        self.pager = None
+
     def request_clear(self):
         self.need_clear = True
 
@@ -44,17 +49,17 @@ class ViewBase(Widget, DisplayableContainer):
             self._draw_info(self.draw_info)
 
     def finalize(self):
-        if hasattr(self, 'pager') and self.pager.visible:
+        if self.pager is not None and self.pager.visible:
             try:
                 self.fm.ui.win.move(self.main_column.y, self.main_column.x)
             except Exception:
                 pass
         else:
             try:
-                x = self.main_column.x
-                y = self.main_column.y + self.main_column.target.pointer\
-                        - self.main_column.scroll_begin
-                self.fm.ui.win.move(y, x)
+                col_x = self.main_column.x
+                col_y = self.main_column.y + self.main_column.target.pointer \
+                    - self.main_column.scroll_begin
+                self.fm.ui.win.move(col_y, col_x)
             except Exception:
                 pass
 
@@ -64,9 +69,14 @@ class ViewBase(Widget, DisplayableContainer):
         self.color_reset()
         self.need_clear = True
 
-        sorted_bookmarks = sorted((item for item in self.fm.bookmarks
-            if self.fm.settings.show_hidden_bookmarks or
-            '/.' not in item[1].path), key=lambda t: t[0].lower())
+        sorted_bookmarks = sorted(
+            (
+                item for item in self.fm.bookmarks
+                if self.fm.settings.show_hidden_bookmarks or
+                '/.' not in item[1].path
+            ),
+            key=lambda t: t[0].lower(),
+        )
 
         hei = min(self.hei - 1, len(sorted_bookmarks))
         ystart = self.hei - hei
@@ -101,21 +111,20 @@ class ViewBase(Widget, DisplayableContainer):
         self.columns[-1].clear_image(force=True)
         self.need_clear = True
         hints = []
-        for k, v in self.fm.ui.keybuffer.pointer.items():
-            k = key_to_string(k)
-            if isinstance(v, dict):
+        for key, value in self.fm.ui.keybuffer.pointer.items():
+            key = key_to_string(key)
+            if isinstance(value, dict):
                 text = '...'
             else:
-                text = v
+                text = value
             if text.startswith('hint') or text.startswith('chain hint'):
                 continue
-            hints.append((k, text))
+            hints.append((key, text))
         hints.sort(key=lambda t: t[1])
 
         hei = min(self.hei - 1, len(hints))
         ystart = self.hei - hei
-        self.addnstr(ystart - 1, 0, "key          command".ljust(self.wid),
-                self.wid)
+        self.addnstr(ystart - 1, 0, "key          command".ljust(self.wid), self.wid)
         try:
             self.win.chgat(ystart - 1, 0, curses.A_UNDERLINE)
         except Exception:
@@ -128,24 +137,6 @@ class ViewBase(Widget, DisplayableContainer):
             self.addnstr(i, 0, string, self.wid)
             i += 1
 
-    def _collapse(self):
-        # Should the last column be cut off? (Because there is no preview)
-        if not self.settings.collapse_preview or not self.preview \
-                or not self.stretch_ratios:
-            return False
-        result = not self.columns[-1].has_preview()
-        target = self.columns[-1].target
-        if not result and target and target.is_file:
-            if self.fm.settings.preview_script and \
-                    self.fm.settings.use_preview_script:
-                try:
-                    result = not self.fm.previews[target.realpath]['foundpreview']
-                except Exception:
-                    return self.old_collapse
-
-        self.old_collapse = result
-        return result
-
     def click(self, event):
         if DisplayableContainer.click(self, event):
             return True
@@ -154,7 +145,7 @@ class ViewBase(Widget, DisplayableContainer):
             self.main_column.scroll(direction)
         return False
 
-    def resize(self, y, x, hei, wid):
+    def resize(self, y, x, hei=None, wid=None):
         DisplayableContainer.resize(self, y, x, hei, wid)
 
     def poke(self):
diff --git a/ranger/gui/widgets/view_miller.py b/ranger/gui/widgets/view_miller.py
index 42013fe9..47e66060 100644
--- a/ranger/gui/widgets/view_miller.py
+++ b/ranger/gui/widgets/view_miller.py
@@ -3,17 +3,19 @@
 
 """ViewMiller arranges the view in miller columns"""
 
+from __future__ import (absolute_import, print_function)
+
 import curses
 import _curses
 from ranger.container import settings
-from ranger.ext.signals import Signal
+from ranger.gui.widgets.view_base import ViewBase
+
 from .browsercolumn import BrowserColumn
 from .pager import Pager
 from ..displayable import DisplayableContainer
-from ranger.gui.widgets.view_base import ViewBase
 
 
-class ViewMiller(ViewBase):
+class ViewMiller(ViewBase):  # pylint: disable=too-many-ancestors,too-many-instance-attributes
     ratios = None
     preview = True
     is_collapsed = False
@@ -33,11 +35,11 @@ class ViewMiller(ViewBase):
 
         for option in ('preview_directories', 'preview_files'):
             self.settings.signal_bind('setopt.' + option,
-                    self._request_clear_if_has_borders, weak=True)
+                                      self._request_clear_if_has_borders, weak=True)
 
         self.settings.signal_bind('setopt.column_ratios', self.request_clear)
         self.settings.signal_bind('setopt.column_ratios', self.rebuild,
-                priority=settings.SIGNAL_PRIORITY_AFTER_SYNC)
+                                  priority=settings.SIGNAL_PRIORITY_AFTER_SYNC)
 
         self.old_draw_borders = self.settings.draw_borders
 
@@ -60,17 +62,17 @@ class ViewMiller(ViewBase):
         last = 0.1 if self.settings.padding_right else 0
         if len(self.ratios) >= 2:
             self.stretch_ratios = self.ratios[:-2] + \
-                    ((self.ratios[-2] + self.ratios[-1] * 1.0 - last),
-                    (self.ratios[-1] * last))
+                ((self.ratios[-2] + self.ratios[-1] * 1.0 - last),
+                 (self.ratios[-1] * last))
 
         offset = 1 - len(ratios)
         if self.preview:
             offset += 1
 
         for level in range(len(ratios)):
-            fl = BrowserColumn(self.win, level + offset)
-            self.add_child(fl)
-            self.columns.append(fl)
+            column = BrowserColumn(self.win, level + offset)
+            self.add_child(column)
+            self.columns.append(column)
 
         try:
             self.main_column = self.columns[self.preview and -2 or -1]
@@ -122,18 +124,18 @@ class ViewMiller(ViewBase):
         # Shift the rightmost vertical line to the left to create a padding,
         # but only when padding_right is on, the preview column is collapsed
         # and we did not open the pager to "zoom" in to the file.
-        if self.settings.padding_right and not self.pager.visible and \
-                self.is_collapsed:
+        if self.settings.padding_right and not self.pager.visible and self.is_collapsed:
             right_end = self.columns[-1].x - 1
             if right_end < left_start:
                 right_end = self.wid - 1
 
         # Draw horizontal lines and the leftmost vertical line
         try:
+            # pylint: disable=no-member
             win.hline(0, left_start, curses.ACS_HLINE, right_end - left_start)
-            win.hline(self.hei - 1, left_start, curses.ACS_HLINE,
-                    right_end - left_start)
+            win.hline(self.hei - 1, left_start, curses.ACS_HLINE, right_end - left_start)
             win.vline(1, left_start, curses.ACS_VLINE, self.hei - 2)
+            # pylint: enable=no-member
         except _curses.error:
             pass
 
@@ -148,23 +150,29 @@ class ViewMiller(ViewBase):
             x = child.x + child.wid
             y = self.hei - 1
             try:
+                # pylint: disable=no-member
                 win.vline(1, x, curses.ACS_VLINE, y - 1)
                 self.addch(0, x, curses.ACS_TTEE, 0)
                 self.addch(y, x, curses.ACS_BTEE, 0)
+                # pylint: enable=no-member
             except Exception:
                 # in case it's off the boundaries
                 pass
 
         # Draw the last vertical line
         try:
+            # pylint: disable=no-member
             win.vline(1, right_end, curses.ACS_VLINE, self.hei - 2)
+            # pylint: enable=no-member
         except _curses.error:
             pass
 
+        # pylint: disable=no-member
         self.addch(0, left_start, curses.ACS_ULCORNER)
         self.addch(self.hei - 1, left_start, curses.ACS_LLCORNER)
         self.addch(0, right_end, curses.ACS_URCORNER)
         self.addch(self.hei - 1, right_end, curses.ACS_LRCORNER)
+        # pylint: enable=no-member
 
     def _collapse(self):
         # Should the last column be cut off? (Because there is no preview)
@@ -184,7 +192,7 @@ class ViewMiller(ViewBase):
         self.old_collapse = result
         return result
 
-    def resize(self, y, x, hei, wid):
+    def resize(self, y, x, hei=None, wid=None):
         """Resize all the columns according to the given ratio"""
         ViewBase.resize(self, y, x, hei, wid)
 
@@ -213,17 +221,14 @@ class ViewMiller(ViewBase):
                     continue
 
             if i == last_i - 1:
-                self.pager.resize(pad, left, hei - pad * 2,
-                        max(1, self.wid - left - pad))
+                self.pager.resize(pad, left, hei - pad * 2, max(1, self.wid - left - pad))
 
                 if cut_off:
-                    self.columns[i].resize(pad, left, hei - pad * 2,
-                            max(1, self.wid - left - pad))
+                    self.columns[i].resize(pad, left, hei - pad * 2, max(1, self.wid - left - pad))
                     continue
 
             try:
-                self.columns[i].resize(pad, left, hei - pad * 2,
-                        max(1, wid - 1))
+                self.columns[i].resize(pad, left, hei - pad * 2, max(1, wid - 1))
             except KeyError:
                 pass
 
@@ -257,7 +262,7 @@ class ViewMiller(ViewBase):
         # Show the preview column when it has a preview but has
         # been hidden (e.g. because of padding_right = False)
         if not self.columns[-1].visible and self.columns[-1].has_preview() \
-        and not self.pager.visible:
+                and not self.pager.visible:
             self.columns[-1].visible = True
 
         if self.preview and self.is_collapsed != self._collapse():
diff --git a/ranger/gui/widgets/view_multipane.py b/ranger/gui/widgets/view_multipane.py
index f8efd80f..ac2d5fac 100644
--- a/ranger/gui/widgets/view_multipane.py
+++ b/ranger/gui/widgets/view_multipane.py
@@ -1,11 +1,14 @@
 # This file is part of ranger, the console file manager.
 # License: GNU GPL version 3, see the file "AUTHORS" for details.
 
+from __future__ import (absolute_import, print_function)
+
 from ranger.gui.widgets.view_base import ViewBase
 from ranger.gui.widgets.browsercolumn import BrowserColumn
 
 
-class ViewMultipane(ViewBase):
+class ViewMultipane(ViewBase):  # pylint: disable=too-many-ancestors
+
     def __init__(self, win):
         ViewBase.__init__(self, win)
 
@@ -40,12 +43,12 @@ class ViewMultipane(ViewBase):
             self.add_child(column)
         self.resize(self.y, self.x, self.hei, self.wid)
 
-    def resize(self, y, x, hei, wid):
+    def resize(self, y, x, hei=None, wid=None):
         ViewBase.resize(self, y, x, hei, wid)
         column_width = int((float(wid) - len(self.columns) + 1) / len(self.columns))
         left = 0
         top = 0
-        for i, column in enumerate(self.columns):
+        for column in self.columns:
             column.resize(top, left, hei, max(1, column_width))
             left += column_width + 1
             column.need_redraw = True
diff --git a/setup.py b/setup.py
index 6838cdc0..6e86a516 100755
--- a/setup.py
+++ b/setup.py
@@ -2,8 +2,11 @@
 # This file is part of ranger, the console file manager.
 # License: GNU GPL version 3, see the file "AUTHORS" for details.
 
-import distutils.core
+from __future__ import (absolute_import, print_function)
+
+import distutils.core  # pylint: disable=import-error,no-name-in-module
 import os.path
+
 import ranger
 
 
@@ -11,8 +14,9 @@ def _findall(directory):
     return [os.path.join(directory, f) for f in os.listdir(directory)
             if os.path.isfile(os.path.join(directory, f))]
 
+
 if __name__ == '__main__':
-    distutils.core.setup(
+    distutils.core.setup(  # pylint: disable=no-member
         name='ranger',
         description='Vim-like file manager',
         long_description=ranger.__doc__,
@@ -24,23 +28,27 @@ if __name__ == '__main__':
         scripts=['scripts/ranger', 'scripts/rifle'],
         data_files=[
             ('share/applications',
-                ['doc/ranger.desktop']),
+             ['doc/ranger.desktop']),
             ('share/man/man1',
-                ['doc/ranger.1',
-                 'doc/rifle.1']),
+             ['doc/ranger.1',
+              'doc/rifle.1']),
             ('share/doc/ranger',
-                ['README.md',
-                 'CHANGELOG.md',
-                 'HACKING.md',
-                 'doc/colorschemes.txt']),
+             ['README.md',
+              'CHANGELOG.md',
+              'HACKING.md',
+              'doc/colorschemes.txt']),
             ('share/doc/ranger/config/colorschemes',
-                _findall('doc/config/colorschemes')),
+             _findall('doc/config/colorschemes')),
             ('share/doc/ranger/config', _findall('doc/config')),
             ('share/doc/ranger/tools', _findall('doc/tools')),
             ('share/doc/ranger/examples', _findall('examples')),
         ],
-        package_data={'ranger': ['data/*', 'config/rc.conf',
-            'config/rifle.conf']},
+        package_data={
+            'ranger': [
+                'data/*', 'config/rc.conf',
+                'config/rifle.conf',
+            ],
+        },
         packages=('ranger',
                   'ranger.api',
                   'ranger.colorschemes',
diff --git a/tests/ranger/container/test_bookmarks.py b/tests/ranger/container/test_bookmarks.py
index a2cd446f..d5bafc6c 100644
--- a/tests/ranger/container/test_bookmarks.py
+++ b/tests/ranger/container/test_bookmarks.py
@@ -1,5 +1,8 @@
+from __future__ import (absolute_import, print_function)
+
 import os
 import time
+
 import pytest
 
 from ranger.container.bookmarks import Bookmarks
diff --git a/tests/ranger/container/test_container.py b/tests/ranger/container/test_container.py
index 2b823912..2af96592 100644
--- a/tests/ranger/container/test_container.py
+++ b/tests/ranger/container/test_container.py
@@ -1,3 +1,5 @@
+from __future__ import (absolute_import, print_function)
+
 from ranger.container import history
 
 
@@ -10,92 +12,92 @@ def testhistorybasic():
     # item added to it. It has a `current` index that serves as a cursor.
 
     # A history has a limited size, check that only `maxlen` items are stored
-    h = history.History(maxlen=10)
+    hist = history.History(maxlen=10)
     for entry in HISTORY_TEST_ENTRIES:
-        h.add(entry)
+        hist.add(entry)
 
     # 10 items are stored
-    assert len(h) == 10
-    assert h.current() == "19"
-    assert h.top() == "19"
-    assert h.bottom() == "10"
+    assert len(hist) == 10
+    assert hist.current() == "19"
+    assert hist.top() == "19"
+    assert hist.bottom() == "10"
 
     # going back in time affects only changes current item
-    h.back()
-    assert len(h) == 10
-    assert h.current() == "18"
-    assert h.top() == "19"
-    assert h.bottom() == "10"
+    hist.back()
+    assert len(hist) == 10
+    assert hist.current() == "18"
+    assert hist.top() == "19"
+    assert hist.bottom() == "10"
 
     # __iter__ is actually an interator and we can iterate through the list
-    it = iter(h)
-    assert iter(it) == it
-    assert list(it) == HISTORY_TEST_ENTRIES[10:]
+    iterator = iter(hist)
+    assert iter(iterator) == iterator
+    assert list(iterator) == HISTORY_TEST_ENTRIES[10:]
 
     # search allows to go back in time as long as a pattern matches and we don't
     # go over a step limit
-    assert h.search("45", -9) == "18"
-    assert h.search("1", -5) == "13"
+    assert hist.search("45", -9) == "18"
+    assert hist.search("1", -5) == "13"
 
     # fast forward selects the last item
-    h.fast_forward()
-    assert h.current() == "19"
+    hist.fast_forward()
+    assert hist.current() == "19"
 
     # back followed by forward is a noop
-    h.back()
-    h.forward()
-    assert h.current() == "19"
+    hist.back()
+    hist.forward()
+    assert hist.current() == "19"
 
     # move can be expressed as multiple calls to back and forward
-    h.move(-3)
-    h.forward()
-    h.forward()
-    h.forward()
-    assert h.current() == "19"
+    hist.move(-3)
+    hist.forward()
+    hist.forward()
+    hist.forward()
+    assert hist.current() == "19"
 
     # back, forward, move play well with boundaries
     for _ in range(30):
-        h.back()
+        hist.back()
 
     for _ in range(30):
-        h.forward()
+        hist.forward()
 
     for _ in range(30):
-        h.move(-2)
+        hist.move(-2)
 
     for _ in range(30):
-        h.move(2)
-    assert h.current() == "19"
+        hist.move(2)
+    assert hist.current() == "19"
 
     # we can create an history from another history
-    h = history.History(maxlen=10)
+    hist = history.History(maxlen=10)
     for entry in HISTORY_TEST_ENTRIES:
-        h.add(entry)
+        hist.add(entry)
     # XXX maxlen should not be used to refer to something that isn't a length
-    otherh = history.History(maxlen=h)
-    assert(list(h) == list(otherh))
+    otherh = history.History(maxlen=hist)
+    assert list(hist) == list(otherh)
 
     # Rebase replaces the past of the history with that of another
-    otherh = history.History(maxlen=h)
-    old_current_item = h.current()
+    otherh = history.History(maxlen=hist)
+    old_current_item = hist.current()
     for entry in OTHER_TEST_ENTRIES:
         otherh.add(entry)
     assert list(otherh)[-3:] == ["42", "43", "44"]
-    h.rebase(otherh)
-    assert h.current() == old_current_item
-    assert list(h)[-3:] == ['43', '44', old_current_item]
+    hist.rebase(otherh)
+    assert hist.current() == old_current_item
+    assert list(hist)[-3:] == ['43', '44', old_current_item]
 
     # modify, modifies the top of the stack
-    h.modify("23")
-    assert h.current() == "23"
+    hist.modify("23")
+    assert hist.current() == "23"
 
 
 def testhistoryunique():
     # Check that unique history refuses to store duplicated entries
-    h = history.History(maxlen=10, unique=True)
+    hist = history.History(maxlen=10, unique=True)
     for entry in HISTORY_TEST_ENTRIES:
-        h.add(entry)
-    assert h.current() == "19"
-    h.add("17")
-    assert list(h).count("17") == 1
-    assert h.current() == "17"
+        hist.add(entry)
+    assert hist.current() == "19"
+    hist.add("17")
+    assert list(hist).count("17") == 1
+    assert hist.current() == "17"
diff --git a/tests/ranger/container/test_fsobject.py b/tests/ranger/container/test_fsobject.py
index 73d2024a..8fe385c0 100644
--- a/tests/ranger/container/test_fsobject.py
+++ b/tests/ranger/container/test_fsobject.py
@@ -1,10 +1,11 @@
-import pytest
+from __future__ import (absolute_import, print_function)
+
 import operator
 
 from ranger.container.fsobject import FileSystemObject
 
 
-class MockFM(object):
+class MockFM(object):  # pylint: disable=too-few-public-methods
     """Used to fulfill the dependency by FileSystemObject."""
 
     default_linemodes = []
@@ -22,13 +23,13 @@ def test_basename_natural1():
     """Test filenames without extensions."""
     fsos = [create_filesystem_object(path)
             for path in ("hello", "hello1", "hello2")]
-    assert(fsos == sorted(fsos[::-1], key=operator.attrgetter("basename_natural")))
-    assert(fsos == sorted(fsos[::-1], key=operator.attrgetter("basename_natural_lower")))
+    assert fsos == sorted(fsos[::-1], key=operator.attrgetter("basename_natural"))
+    assert fsos == sorted(fsos[::-1], key=operator.attrgetter("basename_natural_lower"))
 
 
 def test_basename_natural2():
     """Test filenames with extensions."""
     fsos = [create_filesystem_object(path)
             for path in ("hello", "hello.txt", "hello1.txt", "hello2.txt")]
-    assert(fsos == sorted(fsos[::-1], key=operator.attrgetter("basename_natural")))
-    assert(fsos == sorted(fsos[::-1], key=operator.attrgetter("basename_natural_lower")))
+    assert fsos == sorted(fsos[::-1], key=operator.attrgetter("basename_natural"))
+    assert fsos == sorted(fsos[::-1], key=operator.attrgetter("basename_natural_lower"))
diff --git a/tox.ini b/tox.ini
new file mode 100644
index 00000000..f5072c08
--- /dev/null
+++ b/tox.ini
@@ -0,0 +1,3 @@
+[flake8]
+max-line-length = 99
+ignore = E221