about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/shellcheck.yml2
-rw-r--r--CHANGELOG.md2
-rw-r--r--LICENSE8
-rw-r--r--doc/ranger.14
-rw-r--r--doc/ranger.pod4
-rw-r--r--doc/rifle.pod2
-rwxr-xr-xdoc/tools/convert_papermode_to_metadata.py6
-rw-r--r--examples/plugin_ipc.py3
-rw-r--r--ranger/api/commands.py2
-rwxr-xr-xranger/config/commands.py11
-rw-r--r--ranger/container/bookmarks.py7
-rw-r--r--ranger/container/settings.py12
-rw-r--r--ranger/container/tags.py8
-rw-r--r--ranger/core/actions.py6
-rw-r--r--ranger/core/fm.py25
-rw-r--r--ranger/core/loader.py5
-rw-r--r--ranger/core/main.py6
-rw-r--r--ranger/core/metadata.py9
-rw-r--r--ranger/core/runner.py5
-rw-r--r--ranger/ext/keybinding_parser.py8
-rw-r--r--ranger/ext/open23.py6
-rw-r--r--ranger/ext/popen_forked.py4
-rwxr-xr-xranger/ext/rifle.py2
-rw-r--r--ranger/ext/signals.py4
-rw-r--r--ranger/ext/spawn.py3
-rw-r--r--ranger/ext/vcs/vcs.py3
-rw-r--r--ranger/gui/colorscheme.py3
-rw-r--r--ranger/gui/ui.py4
-rw-r--r--ranger/gui/widgets/console.py5
-rwxr-xr-xtests/manpage_completion_test.py3
30 files changed, 100 insertions, 72 deletions
diff --git a/.github/workflows/shellcheck.yml b/.github/workflows/shellcheck.yml
index 783ff0fa..9fe4c1c4 100644
--- a/.github/workflows/shellcheck.yml
+++ b/.github/workflows/shellcheck.yml
@@ -1,6 +1,6 @@
 name: Shellcheck scope.sh
 
-on: 
+on:
   push:
     paths:
       - '.github/workflows/shellcheck.yml'
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 90c89763..35511b52 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -36,7 +36,7 @@ This log documents changes between stable versions.
 * Improved configurability of syntax highlighting previews
 * Improved coverage of unofficial MIME types, mostly audio formats
 * Improved documentation of `multipane` viewmode
-* Improved documentation of optional dependencies 
+* Improved documentation of optional dependencies
 * Improved documentation on `copymap`
 * Improved documentation on `tab_shift`
 * Improved documentation on `w3m_offset`
diff --git a/LICENSE b/LICENSE
index 94a9ed02..f288702d 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,7 +1,7 @@
                     GNU GENERAL PUBLIC LICENSE
                        Version 3, 29 June 2007
 
- Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
  Everyone is permitted to copy and distribute verbatim copies
  of this license document, but changing it is not allowed.
 
@@ -645,7 +645,7 @@ the "copyright" line and a pointer to where the full notice is found.
     GNU General Public License for more details.
 
     You should have received a copy of the GNU General Public License
-    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+    along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
 Also add information on how to contact you by electronic and paper mail.
 
@@ -664,11 +664,11 @@ might be different; for a GUI interface, you would use an "about box".
   You should also get your employer (if you work as a programmer) or school,
 if any, to sign a "copyright disclaimer" for the program, if necessary.
 For more information on this, and how to apply and follow the GNU GPL, see
-<http://www.gnu.org/licenses/>.
+<https://www.gnu.org/licenses/>.
 
   The GNU General Public License does not permit incorporating your program
 into proprietary programs.  If your program is a subroutine library, you
 may consider it more useful to permit linking proprietary applications with
 the library.  If this is what you want to do, use the GNU Lesser General
 Public License instead of this License.  But first, please read
-<http://www.gnu.org/philosophy/why-not-lgpl.html>.
+<https://www.gnu.org/licenses/why-not-lgpl.html>.
diff --git a/doc/ranger.1 b/doc/ranger.1
index 1fdcc010..b5c90d75 100644
--- a/doc/ranger.1
+++ b/doc/ranger.1
@@ -631,7 +631,7 @@ Reload everything
 Toggle \fIfreeze_files\fR setting.  When active (indicated by a cyan \fI\s-1FROZEN\s0\fR
 message in the status bar), directories and files will not be loaded, improving
 performance when all the files you need are already loaded.  This does not
-affect file previews, which can be toggled with \fIzI\fR.  Also try disabling the
+affect file previews, which can be toggled with \fIzp\fR.  Also try disabling the
 preview of directories with \fIzP\fR.
 .IP "^L" 14
 .IX Item "^L"
@@ -947,7 +947,7 @@ with the preview column being as large as the other columns combined.
 .IP "confirm_on_delete [string]" 4
 .IX Item "confirm_on_delete [string]"
 Ask for a confirmation when running the \*(L"delete\*(R" command?  Valid values are
-\&\*(L"always\*(R" (default), \*(L"never\*(R", \*(L"multiple\*(R". With \*(L"multiple\*(R", ranger will ask only
+\&\*(L"always\*(R", \*(L"never\*(R", \*(L"multiple\*(R" (default). With \*(L"multiple\*(R", ranger will ask only
 if you delete multiple files at once.
 .IP "dirname_in_tabs [bool]" 4
 .IX Item "dirname_in_tabs [bool]"
diff --git a/doc/ranger.pod b/doc/ranger.pod
index 88cf82be..3fdc37d3 100644
--- a/doc/ranger.pod
+++ b/doc/ranger.pod
@@ -578,7 +578,7 @@ Reload everything
 Toggle I<freeze_files> setting.  When active (indicated by a cyan I<FROZEN>
 message in the status bar), directories and files will not be loaded, improving
 performance when all the files you need are already loaded.  This does not
-affect file previews, which can be toggled with I<zI>.  Also try disabling the
+affect file previews, which can be toggled with I<zp>.  Also try disabling the
 preview of directories with I<zP>.
 
 =item ^L
@@ -994,7 +994,7 @@ with the preview column being as large as the other columns combined.
 =item confirm_on_delete [string]
 
 Ask for a confirmation when running the "delete" command?  Valid values are
-"always" (default), "never", "multiple". With "multiple", ranger will ask only
+"always", "never", "multiple" (default). With "multiple", ranger will ask only
 if you delete multiple files at once.
 
 =item dirname_in_tabs [bool]
diff --git a/doc/rifle.pod b/doc/rifle.pod
index 0cd34478..63c8f9b3 100644
--- a/doc/rifle.pod
+++ b/doc/rifle.pod
@@ -72,7 +72,7 @@ rifle shares configuration files with ranger, though ranger is not required in
 order to use rifle. The default configuration file F<rifle.conf> is expected
 to be at F<~/.config/ranger/rifle.conf>. However, this can be overridden with
 the B<-c> option. Note that due to the nature of the configuration, rifle will
-only read one file, it will not read the defaults in addition. 
+only read one file, it will not read the defaults in addition.
 
 This file specifies patterns for determining the commands to open files with.
 The syntax is described in the comments of the default F<rifle.conf> that ships
diff --git a/doc/tools/convert_papermode_to_metadata.py b/doc/tools/convert_papermode_to_metadata.py
index 57459097..58371193 100755
--- a/doc/tools/convert_papermode_to_metadata.py
+++ b/doc/tools/convert_papermode_to_metadata.py
@@ -36,9 +36,10 @@ def replace(source, target):
             print("Skipping file `%s'" % source)
             return
 
-    result = dict()
+    result = {}
 
     # Read the input file and convert it to a dictionary
+    # pylint: disable=unspecified-encoding
     with open(".paperinfo", "r") as infile:
         reader = csv.reader(infile, skipinitialspace=True)
         for lineno, row in enumerate(reader):
@@ -59,6 +60,9 @@ def replace(source, target):
 
     # Write the obtained dictionary into the target file
     if result:
+        # There's no way to specify encoding in 2.x even though in this case we
+        # could choose to write in UTF-8.
+        # pylint: disable=unspecified-encoding
         with open(".metadata.json", "w") as outfile:
             json.dump(result, outfile, indent=2)
     else:
diff --git a/examples/plugin_ipc.py b/examples/plugin_ipc.py
index c6fc60c6..0e7de3bb 100644
--- a/examples/plugin_ipc.py
+++ b/examples/plugin_ipc.py
@@ -30,6 +30,9 @@ def hook_init(fm):
 
         def ipc_reader(filepath):
             while True:
+                # The IPC encoding depends on the system locale so we can't
+                # guess here.
+                # pylint: disable=unspecified-encoding
                 with open(filepath, 'r') as fifo:
                     line = fifo.read()
                     fm.execute_console(line.strip())
diff --git a/ranger/api/commands.py b/ranger/api/commands.py
index 32b33e61..7b76203b 100644
--- a/ranger/api/commands.py
+++ b/ranger/api/commands.py
@@ -405,7 +405,7 @@ def command_function_factory(func):
                 except TypeError:
                     return func()
 
-            args, kwargs = list(), dict()
+            args, kwargs = [], {}
             for arg in self.args[1:]:
                 equal_sign = arg.find("=")
                 value = arg if equal_sign == -1 else arg[equal_sign + 1:]
diff --git a/ranger/config/commands.py b/ranger/config/commands.py
index 2076dea3..327be5d1 100755
--- a/ranger/config/commands.py
+++ b/ranger/config/commands.py
@@ -882,11 +882,12 @@ class load_copy_buffer(Command):
 
     def execute(self):
         from ranger.container.file import File
+        from ranger.ext.open23 import open23
         from os.path import exists
         fname = self.fm.datapath(self.copy_buffer_filename)
         unreadable = OSError if PY3 else IOError
         try:
-            with open(fname, "r") as fobj:
+            with open23(fname, "r") as fobj:
                 self.fm.copy_buffer = set(
                     File(g) for g in fobj.read().split("\n") if exists(g)
                 )
@@ -906,11 +907,12 @@ class save_copy_buffer(Command):
     copy_buffer_filename = 'copy_buffer'
 
     def execute(self):
+        from ranger.ext.open23 import open23
         fname = None
         fname = self.fm.datapath(self.copy_buffer_filename)
         unwritable = OSError if PY3 else IOError
         try:
-            with open(fname, "w") as fobj:
+            with open23(fname, "w") as fobj:
                 fobj.write("\n".join(fobj.path for fobj in self.fm.copy_buffer))
         except unwritable:
             return self.fm.notify("Cannot open %s" %
@@ -956,13 +958,14 @@ class touch(Command):
     def execute(self):
         from os.path import join, expanduser, lexists, dirname
         from os import makedirs
+        from ranger.ext.open23 import open23
 
         fname = join(self.fm.thisdir.path, expanduser(self.rest(1)))
         dirname = dirname(fname)
         if not lexists(fname):
             if not lexists(dirname):
                 makedirs(dirname)
-            with open(fname, 'a'):
+            with open23(fname, 'a'):
                 pass  # Just create the file
         else:
             self.fm.notify("file/directory exists!", bad=True)
@@ -1888,7 +1891,7 @@ class meta(prompt_metadata):
 
     def execute(self):
         key = self.arg(1)
-        update_dict = dict()
+        update_dict = {}
         update_dict[key] = self.rest(2)
         selection = self.fm.thistab.get_selection()
         for fobj in selection:
diff --git a/ranger/container/bookmarks.py b/ranger/container/bookmarks.py
index 8d269df8..4407477e 100644
--- a/ranger/container/bookmarks.py
+++ b/ranger/container/bookmarks.py
@@ -8,6 +8,7 @@ import re
 import os
 
 from ranger.core.shared import FileManagerAware
+from ranger.ext.open23 import open23
 
 ALLOWED_KEYS = string.ascii_letters + string.digits + "`'"
 
@@ -175,7 +176,7 @@ class Bookmarks(FileManagerAware):
 
         path_new = self.path + '.new'
         try:
-            with open(path_new, 'w') as fobj:
+            with open23(path_new, 'w') as fobj:
                 for key, value in self.dct.items():
                     if isinstance(key, str) and key in ALLOWED_KEYS \
                             and key not in self.nonpersistent_bookmarks:
@@ -217,14 +218,14 @@ class Bookmarks(FileManagerAware):
 
         if not os.path.exists(self.path):
             try:
-                with open(self.path, 'w') as fobj:
+                with open23(self.path, 'w') as fobj:
                     pass
             except OSError as ex:
                 self.fm.notify('Bookmarks error: {0}'.format(str(ex)), bad=True)
                 return None
 
         try:
-            with open(self.path, 'r') as fobj:
+            with open23(self.path, 'r') as fobj:
                 dct = {}
                 for line in fobj:
                     if self.load_pattern.match(line):
diff --git a/ranger/container/settings.py b/ranger/container/settings.py
index e7d6775d..e083c5ac 100644
--- a/ranger/container/settings.py
+++ b/ranger/container/settings.py
@@ -136,10 +136,10 @@ class Settings(SignalDispatcher, FileManagerAware):
 
     def __init__(self):
         SignalDispatcher.__init__(self)
-        self.__dict__['_localsettings'] = dict()
-        self.__dict__['_localregexes'] = dict()
-        self.__dict__['_tagsettings'] = dict()
-        self.__dict__['_settings'] = dict()
+        self.__dict__['_localsettings'] = {}
+        self.__dict__['_localregexes'] = {}
+        self.__dict__['_tagsettings'] = {}
+        self.__dict__['_settings'] = {}
         for name in ALLOWED_SETTINGS:
             self.signal_bind('setopt.' + name, self._sanitize,
                              priority=SIGNAL_PRIORITY_SANITIZE)
@@ -285,7 +285,7 @@ class Settings(SignalDispatcher, FileManagerAware):
                 except re.error:  # Bad regular expression
                     return
                 self._localregexes[path] = regex
-                self._localsettings[path] = dict()
+                self._localsettings[path] = {}
             self._localsettings[path][name] = value
 
             # make sure name is in _settings, so __iter__ runs through
@@ -297,7 +297,7 @@ class Settings(SignalDispatcher, FileManagerAware):
         elif tags:
             for tag in tags:
                 if tag not in self._tagsettings:
-                    self._tagsettings[tag] = dict()
+                    self._tagsettings[tag] = {}
                 self._tagsettings[tag][name] = value
         else:
             self._settings[name] = value
diff --git a/ranger/container/tags.py b/ranger/container/tags.py
index e2395897..a8bd50b4 100644
--- a/ranger/container/tags.py
+++ b/ranger/container/tags.py
@@ -81,11 +81,11 @@ class Tags(FileManagerAware):
             if exists(self._filename):
                 self.fm.notify(err, bad=True)
             else:
-                self.tags = dict()
+                self.tags = {}
 
     def dump(self):
         try:
-            with open(self._filename, 'w') as fobj:
+            with open23(self._filename, 'w') as fobj:
                 self._compile(fobj)
         except OSError as err:
             self.fm.notify(err, bad=True)
@@ -99,7 +99,7 @@ class Tags(FileManagerAware):
                 fobj.write('{0}:{1}\n'.format(tag, path))
 
     def _parse(self, fobj):
-        result = dict()
+        result = {}
         for line in fobj:
             line = line.rstrip('\n')
             if len(line) > 2 and line[1] == ':':
@@ -140,7 +140,7 @@ class TagsDummy(Tags):
     """
 
     def __init__(self, filename):  # pylint: disable=super-init-not-called
-        self.tags = dict()
+        self.tags = {}
 
     def __contains__(self, item):
         return False
diff --git a/ranger/core/actions.py b/ranger/core/actions.py
index 594ce29d..91a482e3 100644
--- a/ranger/core/actions.py
+++ b/ranger/core/actions.py
@@ -32,6 +32,7 @@ from ranger.ext.get_executables import get_executables
 from ranger.ext.keybinding_parser import key_to_string, construct_keybinding
 from ranger.ext.macrodict import MacroDict, MACRO_FAIL, macro_val
 from ranger.ext.next_available_filename import next_available_filename
+from ranger.ext.open23 import open23
 from ranger.ext.relative_symlink import relative_symlink
 from ranger.ext.rifle import squash_flags, ASK_COMMAND
 from ranger.ext.safe_path import get_safe_path
@@ -371,6 +372,7 @@ class Actions(  # pylint: disable=too-many-instance-attributes,too-many-public-m
         """
         filename = os.path.expanduser(filename)
         LOG.debug("Sourcing config file '%s'", filename)
+        # pylint: disable=unspecified-encoding
         with open(filename, 'r') as fobj:
             for line in fobj:
                 line = line.strip(" \r\n")
@@ -401,7 +403,7 @@ class Actions(  # pylint: disable=too-many-instance-attributes,too-many-public-m
         # ranger can act as a file chooser when running with --choosefile=...
         if mode == 0 and 'label' not in kw:
             if ranger.args.choosefile:
-                with open(ranger.args.choosefile, 'w') as fobj:
+                with open23(ranger.args.choosefile, 'w') as fobj:
                     fobj.write(self.fm.thisfile.path)
 
             if ranger.args.choosefiles:
@@ -412,7 +414,7 @@ class Actions(  # pylint: disable=too-many-instance-attributes,too-many-public-m
                             paths += [fobj.path]
                 paths += [f.path for f in self.fm.thistab.get_selection() if f.path not in paths]
 
-                with open(ranger.args.choosefiles, 'w') as fobj:
+                with open23(ranger.args.choosefiles, 'w') as fobj:
                     fobj.write('\n'.join(paths) + '\n')
 
             if ranger.args.choosefile or ranger.args.choosefiles:
diff --git a/ranger/core/fm.py b/ranger/core/fm.py
index 57bc9af4..a9d5df7e 100644
--- a/ranger/core/fm.py
+++ b/ranger/core/fm.py
@@ -15,20 +15,21 @@ import stat
 import sys
 
 import ranger.api
-from ranger.core.actions import Actions
-from ranger.core.tab import Tab
 from ranger.container import settings
-from ranger.container.tags import Tags, TagsDummy
-from ranger.gui.ui import UI
 from ranger.container.bookmarks import Bookmarks
+from ranger.container.directory import Directory
+from ranger.container.tags import Tags, TagsDummy
+from ranger.core.actions import Actions
+from ranger.core.loader import Loader
+from ranger.core.metadata import MetadataManager
 from ranger.core.runner import Runner
+from ranger.core.tab import Tab
+from ranger.ext import logutils
 from ranger.ext.img_display import get_image_displayer
-from ranger.core.metadata import MetadataManager
+from ranger.ext.open23 import open23
 from ranger.ext.rifle import Rifle
-from ranger.container.directory import Directory
 from ranger.ext.signals import SignalDispatcher
-from ranger.core.loader import Loader
-from ranger.ext import logutils
+from ranger.gui.ui import UI
 
 
 class FM(Actions,  # pylint: disable=too-many-instance-attributes
@@ -49,7 +50,7 @@ class FM(Actions,  # pylint: disable=too-many-instance-attributes
         SignalDispatcher.__init__(self)
         self.ui = ui if ui is not None else UI()
         self.start_paths = paths if paths is not None else ['.']
-        self.directories = dict()
+        self.directories = {}
         self.bookmarks = bookmarks
         self.current_tab = 1
         self.tabs = {}
@@ -335,7 +336,7 @@ class FM(Actions,  # pylint: disable=too-many-instance-attributes
         Groups the paths into a dictionary with their dirnames as keys and a set of
         basenames as entries.
         """
-        groups = dict()
+        groups = {}
         for path in paths:
             abspath = os.path.abspath(os.path.expanduser(path))
             dirname, basename = os.path.split(abspath)
@@ -440,14 +441,14 @@ class FM(Actions,  # pylint: disable=too-many-instance-attributes
             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
-                with open(ranger.args.choosedir, 'w') as fobj:
+                with open23(ranger.args.choosedir, 'w') as fobj:
                     fobj.write(self.thisdir.path)
             self.bookmarks.remember(self.thisdir)
             self.bookmarks.save()
 
             # Save tabs
             if not ranger.args.clean and self.settings.save_tabs_on_exit and len(self.tabs) > 1:
-                with open(self.datapath('tabs'), 'a') as fobj:
+                with open23(self.datapath('tabs'), 'a') as fobj:
                     # Don't save active tab since launching ranger changes the active tab
                     fobj.write('\0'.join(v.path for t, v in self.tabs.items())
                                + '\0\0')
diff --git a/ranger/core/loader.py b/ranger/core/loader.py
index ec94b049..1ecfb2eb 100644
--- a/ranger/core/loader.py
+++ b/ranger/core/loader.py
@@ -19,9 +19,10 @@ except ImportError:
 
 from ranger import PY3
 from ranger.core.shared import FileManagerAware
+from ranger.ext.human_readable import human_readable
+from ranger.ext.open23 import open23
 from ranger.ext.safe_path import get_safe_path
 from ranger.ext.signals import SignalDispatcher
-from ranger.ext.human_readable import human_readable
 
 
 class Loadable(object):
@@ -177,7 +178,7 @@ class CommandLoader(  # pylint: disable=too-many-instance-attributes
         # pylint: disable=consider-using-with
         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')
+        popenargs['stdin'] = PIPE if self.input else open23(os.devnull, 'r')
         self.process = process = Popen(self.args, **popenargs)
         self.signal_emit('before', process=process, loader=self)
         if self.input:
diff --git a/ranger/core/main.py b/ranger/core/main.py
index 03c9f9b6..d55f871b 100644
--- a/ranger/core/main.py
+++ b/ranger/core/main.py
@@ -156,11 +156,11 @@ def main(
             tabs_datapath = fm.datapath('tabs')
             if fm.settings.save_tabs_on_exit and os.path.exists(tabs_datapath) and not args.paths:
                 try:
-                    with open(tabs_datapath, 'r') as fobj:
+                    with open23(tabs_datapath, 'r') as fobj:
                         tabs_saved = fobj.read().partition('\0\0')
                         fm.start_paths += tabs_saved[0].split('\0')
                     if tabs_saved[-1]:
-                        with open(tabs_datapath, 'w') as fobj:
+                        with open23(tabs_datapath, 'w') as fobj:
                             fobj.write(tabs_saved[-1])
                     else:
                         os.remove(tabs_datapath)
@@ -443,7 +443,7 @@ def load_settings(  # pylint: disable=too-many-locals,too-many-branches,too-many
 
             if not os.path.exists(fm.confpath('plugins', '__init__.py')):
                 LOG.debug("Creating missing '__init__.py' file in plugin folder")
-                with open(fm.confpath('plugins', '__init__.py'), 'w'):
+                with open23(fm.confpath('plugins', '__init__.py'), 'w'):
                     # Create the file if it doesn't exist.
                     pass
 
diff --git a/ranger/core/metadata.py b/ranger/core/metadata.py
index 75f7ba3c..833d6e3e 100644
--- a/ranger/core/metadata.py
+++ b/ranger/core/metadata.py
@@ -15,6 +15,7 @@ from __future__ import (absolute_import, division, print_function)
 
 import copy
 from os.path import join, dirname, exists, basename
+from ranger.ext.open23 import open23
 from ranger.ext.openstruct import DefaultOpenStruct as ostruct
 
 
@@ -26,9 +27,9 @@ class MetadataManager(object):
 
     def __init__(self):
         # metadata_cache maps filenames to dicts containing their metadata
-        self.metadata_cache = dict()
+        self.metadata_cache = {}
         # metafile_cache maps .metadata.json filenames to their entries
-        self.metafile_cache = dict()
+        self.metafile_cache = {}
         self.deep_search = DEEP_SEARCH_DEFAULT
 
     def reset(self):
@@ -84,7 +85,7 @@ class MetadataManager(object):
         self.metadata_cache[filename] = entry
         self.metafile_cache[metafile] = entries
 
-        with open(metafile, "w") as fobj:
+        with open23(metafile, "w") as fobj:
             json.dump(entries, fobj, check_circular=True, indent=2)
 
     def _get_entry(self, filename):
@@ -117,7 +118,7 @@ class MetadataManager(object):
             return self.metafile_cache[metafile]
 
         if exists(metafile):
-            with open(metafile, "r") as fobj:
+            with open23(metafile, "r") as fobj:
                 try:
                     entries = json.load(fobj)
                 except ValueError:
diff --git a/ranger/core/runner.py b/ranger/core/runner.py
index 0a3aa171..f785448a 100644
--- a/ranger/core/runner.py
+++ b/ranger/core/runner.py
@@ -29,6 +29,7 @@ import os
 import sys
 from subprocess import Popen, PIPE, STDOUT
 from ranger.ext.get_executables import get_executables, get_term
+from ranger.ext.open23 import open23
 from ranger.ext.popen_forked import Popen_forked
 
 
@@ -192,8 +193,8 @@ class Runner(object):  # pylint: disable=too-few-public-methods
         if 's' in context.flags:
             # Using a with-statement for these is inconvenient.
             # pylint: disable=consider-using-with
-            devnull_writable = open(os.devnull, 'w')
-            devnull_readable = open(os.devnull, 'r')
+            devnull_writable = open23(os.devnull, 'w')
+            devnull_readable = open23(os.devnull, 'r')
             for key in ('stdout', 'stderr'):
                 popen_kws[key] = devnull_writable
             toggle_ui = False
diff --git a/ranger/ext/keybinding_parser.py b/ranger/ext/keybinding_parser.py
index e7dbcfe0..52e1d506 100644
--- a/ranger/ext/keybinding_parser.py
+++ b/ranger/ext/keybinding_parser.py
@@ -170,7 +170,7 @@ class KeyMaps(dict):
         self.used_keymap = None
 
     def use_keymap(self, keymap_name):
-        self.keybuffer.keymap = self.get(keymap_name, dict())
+        self.keybuffer.keymap = self.get(keymap_name, {})
         if self.used_keymap != keymap_name:
             self.used_keymap = keymap_name
             self.keybuffer.clear()
@@ -179,7 +179,7 @@ class KeyMaps(dict):
         try:
             pointer = self[context]
         except KeyError:
-            self[context] = pointer = dict()
+            self[context] = pointer = {}
         if PY3:
             keys = keys.encode('utf-8').decode('latin-1')
         return list(parse_keybinding(keys)), pointer
@@ -194,9 +194,9 @@ class KeyMaps(dict):
                 if isinstance(pointer[key], dict):
                     pointer = pointer[key]
                 else:
-                    pointer[key] = pointer = dict()
+                    pointer[key] = pointer = {}
             except KeyError:
-                pointer[key] = pointer = dict()
+                pointer[key] = pointer = {}
         pointer[last_key] = leaf
 
     def copy(self, context, source, target):
diff --git a/ranger/ext/open23.py b/ranger/ext/open23.py
index de60d516..912f9829 100644
--- a/ranger/ext/open23.py
+++ b/ranger/ext/open23.py
@@ -14,13 +14,15 @@ from ranger import PY3
 #         contextmanager hides away the lack of an errors keyword argument for
 #         python 2 and is now preferred. This can be safely dropped once we
 #         ditch python 2 support.
-# pylint: disable=too-many-arguments
+# TODO: The unspecified-encoding lint should only be disabled for the Python 2
+#       case but Pylint is failing to parse the second disable properly.
+# pylint: disable=too-many-arguments,unspecified-encoding
 @contextmanager
 def open23(
     file,
     mode="r",
     buffering=-1,
-    encoding=None,
+    encoding="UTF-8",
     errors=None,
     newline=None,
     closefd=True,
diff --git a/ranger/ext/popen_forked.py b/ranger/ext/popen_forked.py
index 4b171286..238e9a64 100644
--- a/ranger/ext/popen_forked.py
+++ b/ranger/ext/popen_forked.py
@@ -6,6 +6,8 @@ from __future__ import (absolute_import, division, print_function)
 import os
 from subprocess import Popen
 
+from ranger.ext.open23 import open23
+
 
 def Popen_forked(*args, **kwargs):  # pylint: disable=invalid-name
     """Forks process and runs Popen with the given args and kwargs.
@@ -18,7 +20,7 @@ def Popen_forked(*args, **kwargs):  # pylint: disable=invalid-name
         return False
     if pid == 0:
         os.setsid()
-        with open(os.devnull, 'r') as null_r, open(os.devnull, 'w') as null_w:
+        with open23(os.devnull, 'r') as null_r, open23(os.devnull, 'w') as null_w:
             kwargs['stdin'] = null_r
             kwargs['stdout'] = kwargs['stderr'] = null_w
             Popen(*args, **kwargs)  # pylint: disable=consider-using-with
diff --git a/ranger/ext/rifle.py b/ranger/ext/rifle.py
index 0d7b5650..fbfe7c5a 100755
--- a/ranger/ext/rifle.py
+++ b/ranger/ext/rifle.py
@@ -141,6 +141,7 @@ except ImportError:
             return False
         if pid == 0:
             os.setsid()
+            # pylint: disable=unspecified-encoding
             with open(os.devnull, "r") as null_r, open(
                 os.devnull, "w"
             ) as null_w:
@@ -223,6 +224,7 @@ class Rifle(object):  # pylint: disable=too-many-instance-attributes
         """Replace the current configuration with the one in config_file"""
         if config_file is None:
             config_file = self.config_file
+        # pylint: disable=unspecified-encoding
         with open(config_file, "r") as fobj:
             self.rules = []
             for line in fobj:
diff --git a/ranger/ext/signals.py b/ranger/ext/signals.py
index 0973249c..8d3f84c9 100644
--- a/ranger/ext/signals.py
+++ b/ranger/ext/signals.py
@@ -106,14 +106,14 @@ class SignalDispatcher(object):
     """This abstract class handles the binding and emitting of signals."""
 
     def __init__(self):
-        self._signals = dict()
+        self._signals = {}
 
     def signal_clear(self):
         """Remove all signals."""
         for handler_list in self._signals.values():
             for handler in handler_list:
                 handler.function = None
-        self._signals = dict()
+        self._signals = {}
 
     def signal_bind(self, signal_name, function, priority=0.5, weak=False, autosort=True):
         """Bind a function to the signal.
diff --git a/ranger/ext/spawn.py b/ranger/ext/spawn.py
index c237d88a..39d354d7 100644
--- a/ranger/ext/spawn.py
+++ b/ranger/ext/spawn.py
@@ -6,6 +6,7 @@ from __future__ import (absolute_import, division, print_function)
 from os import devnull
 from subprocess import PIPE, CalledProcessError
 
+from ranger.ext.open23 import open23
 from ranger.ext.popen23 import Popen23
 
 ENCODING = 'utf-8'
@@ -34,7 +35,7 @@ def check_output(popenargs, **kwargs):
         with Popen23(popenargs, **kwargs) as process:
             stdout, _ = process.communicate()
     else:
-        with open(devnull, mode='w') as fd_devnull:
+        with open23(devnull, mode='w') as fd_devnull:
             with Popen23(popenargs, stderr=fd_devnull, **kwargs) as process:
                 stdout, _ = process.communicate()
 
diff --git a/ranger/ext/vcs/vcs.py b/ranger/ext/vcs/vcs.py
index 89259b5e..490aaaf4 100644
--- a/ranger/ext/vcs/vcs.py
+++ b/ranger/ext/vcs/vcs.py
@@ -11,6 +11,7 @@ import threading
 import time
 
 from ranger.ext import spawn
+from ranger.ext.open23 import open23
 
 # Python 2 compatibility
 try:
@@ -129,7 +130,7 @@ class Vcs(object):  # pylint: disable=too-many-instance-attributes
                     return output[:-1]
                 return output
             else:
-                with open(os.devnull, mode='w') as fd_devnull:
+                with open23(os.devnull, mode='w') as fd_devnull:
                     subprocess.check_call(cmd, cwd=path, stdout=fd_devnull, stderr=fd_devnull)
                 return None
         except (subprocess.CalledProcessError, OSError):
diff --git a/ranger/gui/colorscheme.py b/ranger/gui/colorscheme.py
index 0e68c5ff..cd88ccee 100644
--- a/ranger/gui/colorscheme.py
+++ b/ranger/gui/colorscheme.py
@@ -35,6 +35,7 @@ from ranger.gui.context import Context
 from ranger.core.main import allow_access_to_confdir
 from ranger.ext.cached_function import cached_function
 from ranger.ext.iter_tools import flatten
+from ranger.ext.open23 import open23
 
 
 class ColorSchemeError(Exception):
@@ -108,7 +109,7 @@ def _colorscheme_name_to_class(signal):  # pylint: disable=too-many-branches
         if os.path.exists(signal.fm.confpath('colorschemes')):
             initpy = signal.fm.confpath('colorschemes', '__init__.py')
             if not os.path.exists(initpy):
-                with open(initpy, "a"):
+                with open23(initpy, "a"):
                     # Just create the file
                     pass
 
diff --git a/ranger/gui/ui.py b/ranger/gui/ui.py
index 686b624e..db12d6dc 100644
--- a/ranger/gui/ui.py
+++ b/ranger/gui/ui.py
@@ -51,12 +51,12 @@ def _setup_mouse(signal):
 
 
 def _in_tmux():
-    return ('TMUX' in os.environ
+    return (os.environ.get("TMUX", "")
             and 'tmux' in get_executables())
 
 
 def _in_screen():
-    return ('screen' in os.environ['TERM']
+    return ('screen' in os.environ.get("TERM", "")
             and 'screen' in get_executables())
 
 
diff --git a/ranger/gui/widgets/console.py b/ranger/gui/widgets/console.py
index 02676f45..a6b90a35 100644
--- a/ranger/gui/widgets/console.py
+++ b/ranger/gui/widgets/console.py
@@ -13,6 +13,7 @@ from collections import deque
 from ranger import PY3
 from ranger.gui.widgets import Widget
 from ranger.ext.direction import Direction
+from ranger.ext.open23 import open23
 from ranger.ext.widestring import uwid, WideString
 from ranger.container.history import History, HistoryEmptyException
 import ranger
@@ -44,7 +45,7 @@ class Console(Widget):  # pylint: disable=too-many-instance-attributes,too-many-
             self.historypath = self.fm.datapath('history')
             if os.path.exists(self.historypath):
                 try:
-                    with open(self.historypath, "r") as fobj:
+                    with open23(self.historypath, "r") as fobj:
                         try:
                             for line in fobj:
                                 self.history.add(line[:-1])
@@ -79,7 +80,7 @@ class Console(Widget):  # pylint: disable=too-many-instance-attributes,too-many-
             return
         if self.historypath:
             try:
-                with open(self.historypath, 'w') as fobj:
+                with open23(self.historypath, 'w') as fobj:
                     for entry in self.history_backup:
                         try:
                             fobj.write(entry + '\n')
diff --git a/tests/manpage_completion_test.py b/tests/manpage_completion_test.py
index f5e5c335..1a01f944 100755
--- a/tests/manpage_completion_test.py
+++ b/tests/manpage_completion_test.py
@@ -26,6 +26,7 @@ def get_path_of_man_page():
 
 def read_manpage():
     path = get_path_of_man_page()
+    # pylint: disable=unspecified-encoding
     with open(path, 'r') as man_page:
         return man_page.read()
 
@@ -33,7 +34,7 @@ def read_manpage():
 def get_sections():
     manpage = read_manpage()
     parts = manpage.split('=head1 ')
-    sections = dict()
+    sections = {}
     for part in parts:
         if '\n' in part:
             section_name, section_content = part.split('\n', 1)