diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..2e64384
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+.coverage
+.tox/
+build/
diff --git a/.travis.yml b/.travis.yml
index 56d33a8..1631c84 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -5,11 +5,13 @@ jobs:
   - python: pypy
   include:
     - python: pypy
+    - python: 3.11
+    - python: 3.10
+    - python: 3.9
     - python: 3.8
     - python: 3.7
     - python: 3.6
     - python: 3.5
-    - python: 2.7
   fast_finish: true
 before_install:
   - sudo apt-get update -qq
diff --git a/README.rst b/README.rst
index 279783f..a918f2c 100644
--- a/README.rst
+++ b/README.rst
@@ -1,4 +1,4 @@
-executor: Programmer friendly subprocess wrapper
+executor: Programmer-friendly subprocess wrapper
 ================================================
 
 .. image:: https://travis-ci.org/xolox/python-executor.svg?branch=master
@@ -22,8 +22,9 @@ escaping of arguments and error checking:
   what's called a "command pool". The concurrency level can be customized and
   of course both local and remote commands are supported.
 
-The package is currently tested on Python 2.7, 3.5, 3.6, 3.7, 3.8 and PyPy. For
-usage instructions please refer to following sections and the documentation_.
+The package is currently tested on Python 3.5, 3.6, 3.7, 3.8, 3.9, 3.10, 3.11
+and PyPy. For usage instructions please refer to following sections and the
+documentation_.
 
 .. contents::
    :local:
diff --git a/docs/index.rst b/docs/index.rst
index fa02ba9..8cc80d5 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -1,4 +1,4 @@
-executor: Programmer friendly subprocess wrapper
+executor: Programmer-friendly subprocess wrapper
 ================================================
 
 Welcome to the documentation of `executor` version |release|!
diff --git a/executor/__init__.py b/executor/__init__.py
index dbe2eb7..f850fd0 100644
--- a/executor/__init__.py
+++ b/executor/__init__.py
@@ -1,6 +1,6 @@
 # vim: fileencoding=utf-8
 
-# Programmer friendly subprocess wrapper.
+# Programmer-friendly subprocess wrapper.
 #
 # Author: Peter Odding <peter@peterodding.com>
 # Last Change: November 19, 2020
@@ -213,7 +213,7 @@ def execute_prepared(command):
 class ExternalCommand(ControllableProcess):
 
     """
-    Programmer friendly :class:`subprocess.Popen` wrapper.
+    Programmer-friendly :class:`subprocess.Popen` wrapper.
 
     The :class:`ExternalCommand` class wraps :class:`subprocess.Popen` to make
     it easier to do the right thing (the simplicity of :func:`os.system()` with
@@ -1984,7 +1984,7 @@ def reset(self):
 
 def quote(*args):
     """
-    Quote a string or a sequence of strings to be used as command line argument(s).
+    Quote an object or a sequence of objects to be used as command line argument(s).
 
     This function is a simple wrapper around :func:`pipes.quote()` which
     adds support for quoting sequences of strings (lists and tuples). For
@@ -2007,7 +2007,7 @@ def quote(*args):
         value = args[0]
         if not isinstance(value, (list, tuple)):
             return pipes.quote(value)
-    return ' '.join(map(quote, value))
+    return ' '.join(map(quote, (str(e) for e in value)))
 
 
 def which(program, mode=os.F_OK | os.X_OK, path=None):
diff --git a/executor/chroot.py b/executor/chroot.py
index c7c79f2..88cdcb4 100644
--- a/executor/chroot.py
+++ b/executor/chroot.py
@@ -1,4 +1,4 @@
-# Programmer friendly subprocess wrapper.
+# Programmer-friendly subprocess wrapper.
 #
 # Author: Peter Odding <peter@peterodding.com>
 # Last Change: May 13, 2020
diff --git a/executor/concurrent.py b/executor/concurrent.py
index ba2d5e3..90c3ce9 100644
--- a/executor/concurrent.py
+++ b/executor/concurrent.py
@@ -1,4 +1,4 @@
-# Programmer friendly subprocess wrapper.
+# Programmer-friendly subprocess wrapper.
 #
 # Author: Peter Odding <peter@peterodding.com>
 # Last Change: May 14, 2020
diff --git a/executor/contexts.py b/executor/contexts.py
index 4874526..50f4eee 100644
--- a/executor/contexts.py
+++ b/executor/contexts.py
@@ -1,4 +1,4 @@
-# Programmer friendly subprocess wrapper.
+# Programmer-friendly subprocess wrapper.
 #
 # Author: Peter Odding <peter@peterodding.com>
 # Last Change: May 14, 2020
@@ -366,14 +366,7 @@ def lsb_release_variables(self):
         logger.debug("Parsing /etc/lsb-release contents: %r", contents)
         for lnum, line in enumerate(contents.splitlines()):
             name, delimiter, value = line.partition(u'=')
-            # The following encode/decode trick works around shlex.split() not
-            # properly supporting Unicode strings on Python 2.7, for details
-            # refer to https://stackoverflow.com/a/14219159/788200.
-            if PY2:
-                tokens = shlex.split(value.encode('UTF-8'))
-                parsed_value = [t.decode('UTF-8') for t in tokens]
-            else:
-                parsed_value = shlex.split(value)
+            parsed_value = shlex.split(value)
             # The null byte check below guards against a weird edge case
             # that has so far only manifested in the Python 2.6 environment
             # of Travis CI: The parsing of /etc/lsb-release results in the
diff --git a/executor/process.py b/executor/process.py
index 7f3d359..6b3bd8a 100644
--- a/executor/process.py
+++ b/executor/process.py
@@ -1,4 +1,4 @@
-# Programmer friendly subprocess wrapper.
+# Programmer-friendly subprocess wrapper.
 #
 # Author: Peter Odding <peter@peterodding.com>
 # Last Change: March 2, 2020
diff --git a/executor/schroot.py b/executor/schroot.py
index 748b1c7..c745e31 100644
--- a/executor/schroot.py
+++ b/executor/schroot.py
@@ -1,4 +1,4 @@
-# Programmer friendly subprocess wrapper.
+# Programmer-friendly subprocess wrapper.
 #
 # Author: Peter Odding <peter@peterodding.com>
 # Last Change: June 10, 2017
diff --git a/executor/ssh/client.py b/executor/ssh/client.py
index 1817020..8213f14 100644
--- a/executor/ssh/client.py
+++ b/executor/ssh/client.py
@@ -1,4 +1,4 @@
-# Programmer friendly subprocess wrapper.
+# Programmer-friendly subprocess wrapper.
 #
 # Author: Peter Odding <peter@peterodding.com>
 # Last Change: November 19, 2020
diff --git a/executor/ssh/server.py b/executor/ssh/server.py
index 3177634..c65853e 100644
--- a/executor/ssh/server.py
+++ b/executor/ssh/server.py
@@ -1,4 +1,4 @@
-# Programmer friendly subprocess wrapper.
+# Programmer-friendly subprocess wrapper.
 #
 # Author: Peter Odding <peter@peterodding.com>
 # Last Change: May 4, 2018
diff --git a/executor/tcp.py b/executor/tcp.py
index 144c8ae..a5fd67a 100644
--- a/executor/tcp.py
+++ b/executor/tcp.py
@@ -1,4 +1,4 @@
-# Programmer friendly subprocess wrapper.
+# Programmer-friendly subprocess wrapper.
 #
 # Author: Peter Odding <peter@peterodding.com>
 # Last Change: March 2, 2020
diff --git a/executor/tests.py b/executor/tests.py
index 71d7791..c09941e 100644
--- a/executor/tests.py
+++ b/executor/tests.py
@@ -1101,12 +1101,6 @@ def test_lsb_release_variables(self):
             # laptop as well as Travis CI run Ubuntu LTS releases.
             assert variables['DISTRIB_ID'].lower() == u'ubuntu'
             assert variables['DISTRIB_CODENAME'].lower() in EXPECTED_CODENAMES
-            # Make sure all strings are Unicode strings, this tests against
-            # a regression of a bug caused by shlex.split() on Python 2.7
-            # automatically coercing Unicode strings to byte strings.
-            for key, value in context.lsb_release_variables.items():
-                assert isinstance(key, text_type)
-                assert isinstance(value, text_type)
 
     def test_local_context(self):
         """Test a local command context."""
diff --git a/setup.py b/setup.py
index d67418a..6926d1d 100755
--- a/setup.py
+++ b/setup.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 
-# Programmer friendly subprocess wrapper.
+# Programmer-friendly subprocess wrapper.
 #
 # Author: Peter Odding <peter@peterodding.com>
 # Last Change: February 29, 2020
@@ -61,7 +61,7 @@ def get_absolute_path(*args):
 
 setup(name='executor',
       version=get_version('executor', '__init__.py'),
-      description='Programmer friendly subprocess wrapper',
+      description='Programmer-friendly subprocess wrapper',
       long_description=get_contents('README.rst'),
       url='https://executor.readthedocs.io',
       author="Peter Odding",
@@ -76,7 +76,7 @@ def get_absolute_path(*args):
       tests_require=[
           'virtualenv',
       ],
-      python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*',
+      python_requires='>=3.5',
       classifiers=[
           'Development Status :: 5 - Production/Stable',
           'Environment :: Console',
@@ -88,13 +88,14 @@ def get_absolute_path(*args):
           'Operating System :: POSIX :: Linux',
           'Operating System :: Unix',
           'Programming Language :: Python',
-          'Programming Language :: Python :: 2',
-          'Programming Language :: Python :: 2.7',
           'Programming Language :: Python :: 3',
           'Programming Language :: Python :: 3.5',
           'Programming Language :: Python :: 3.6',
           'Programming Language :: Python :: 3.7',
           'Programming Language :: Python :: 3.8',
+          'Programming Language :: Python :: 3.9',
+          'Programming Language :: Python :: 3.10',
+          'Programming Language :: Python :: 3.11',
           'Programming Language :: Python :: Implementation :: CPython',
           'Programming Language :: Python :: Implementation :: PyPy',
           'Topic :: Internet',
diff --git a/tox.ini b/tox.ini
index 253abdd..29073cc 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,5 +1,5 @@
 [tox]
-envlist = py27, py35, py36, py37, py38, pypy
+envlist = py35, py36, py37, py38, py39, py310, py311, pypy
 
 [testenv]
 commands = py.test {posargs}