[AIRFLOW-4570] Remove future library (drop Python 2 support)
diff --git a/airflow/api/auth/backend/kerberos_auth.py b/airflow/api/auth/backend/kerberos_auth.py
index f95f4d257191c..8a6a76f018a78 100644
--- a/airflow/api/auth/backend/kerberos_auth.py
+++ b/airflow/api/auth/backend/kerberos_auth.py
@@ -24,8 +24,6 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-from future.standard_library import install_aliases
-
 from airflow.utils.log.logging_mixin import LoggingMixin
 
 import kerberos
@@ -43,8 +41,6 @@
 from requests_kerberos import HTTPKerberosAuth
 from socket import getfqdn
 
-install_aliases()
-
 client_auth = HTTPKerberosAuth(service='airflow')
 
 _SERVICE_NAME = None
diff --git a/airflow/api/client/json_client.py b/airflow/api/client/json_client.py
index e05913ebb4743..2b8440813a8d4 100644
--- a/airflow/api/client/json_client.py
+++ b/airflow/api/client/json_client.py
@@ -17,7 +17,8 @@
 # specific language governing permissions and limitations
 # under the License.
 
-from future.moves.urllib.parse import urljoin
+from urllib.parse import urljoin
+
 import requests
 
 from airflow.api.client import api_client
diff --git a/airflow/configuration.py b/airflow/configuration.py
index 7e0f8ad8a5855..af68c6bb77dd2 100644
--- a/airflow/configuration.py
+++ b/airflow/configuration.py
@@ -21,7 +21,6 @@
 from builtins import str
 from collections import OrderedDict
 import copy
-from future import standard_library
 import os
 import pathlib
 import shlex
@@ -36,8 +35,6 @@
 from airflow.exceptions import AirflowConfigException
 from airflow.utils.log.logging_mixin import LoggingMixin
 
-standard_library.install_aliases()
-
 log = LoggingMixin().log
 
 # show Airflow's deprecation warnings
diff --git a/airflow/contrib/auth/backends/ldap_auth.py b/airflow/contrib/auth/backends/ldap_auth.py
index 1639f43aec307..6729f9df2cee8 100644
--- a/airflow/contrib/auth/backends/ldap_auth.py
+++ b/airflow/contrib/auth/backends/ldap_auth.py
@@ -16,7 +16,6 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-from future.utils import native
 
 import flask_login
 from flask_login import login_required, current_user, logout_user  # noqa: F401
@@ -75,7 +74,7 @@ def get_ldap_connection(dn=None, password=None):
                     use_ssl=True,
                     tls=tls_configuration)
 
-    conn = Connection(server, native(dn), native(password))
+    conn = Connection(server, dn, password)
 
     if not conn.bind():
         log.error("Cannot bind to ldap server: %s ", conn.last_error)
@@ -87,8 +86,7 @@ def get_ldap_connection(dn=None, password=None):
 def group_contains_user(conn, search_base, group_filter, user_name_attr, username):
     search_filter = '(&({0}))'.format(group_filter)
 
-    if not conn.search(native(search_base), native(search_filter),
-                       attributes=[native(user_name_attr)]):
+    if not conn.search(search_base, search_filter, attributes=[user_name_attr]):
         log.warning("Unable to find group for %s %s", search_base, search_filter)
     else:
         for entry in conn.entries:
@@ -105,8 +103,7 @@ def groups_user(conn, search_base, user_filter, user_name_att, username):
         memberof_attr = configuration.conf.get("ldap", "group_member_attr")
     except Exception:
         memberof_attr = "memberOf"
-    res = conn.search(native(search_base), native(search_filter),
-                      attributes=[native(memberof_attr)])
+    res = conn.search(search_base, search_filter, attributes=[memberof_attr])
     if not res:
         log.info("Cannot find user %s", username)
         raise AuthenticationError("Invalid username or password")
@@ -210,9 +207,7 @@ def try_login(username, password):
 
         # todo: BASE or ONELEVEL?
 
-        res = conn.search(native(configuration.conf.get("ldap", "basedn")),
-                          native(search_filter),
-                          search_scope=native(search_scope))
+        res = conn.search(configuration.conf.get("ldap", "basedn"), search_filter, search_scope=search_scope)
 
         # todo: use list or result?
         if not res:
diff --git a/airflow/models/dag.py b/airflow/models/dag.py
index 3c337d97c432b..b25d6c2d57250 100644
--- a/airflow/models/dag.py
+++ b/airflow/models/dag.py
@@ -34,7 +34,6 @@
 import six
 from croniter import croniter
 from dateutil.relativedelta import relativedelta
-from future.standard_library import install_aliases
 from sqlalchemy import Column, String, Boolean, Integer, Text, func, or_
 
 from airflow import configuration, settings, utils
@@ -54,8 +53,6 @@
 from airflow.utils.sqlalchemy import UtcDateTime, Interval
 from airflow.utils.state import State
 
-install_aliases()
-
 ScheduleInterval = Union[str, timedelta, relativedelta]
 
 
diff --git a/airflow/www/utils.py b/airflow/www/utils.py
index e097499e38c07..39498691e98a8 100644
--- a/airflow/www/utils.py
+++ b/airflow/www/utils.py
@@ -17,9 +17,6 @@
 # specific language governing permissions and limitations
 # under the License.
 
-from future import standard_library  # noqa
-standard_library.install_aliases()  # noqa
-
 import inspect
 import json
 import time
diff --git a/setup.py b/setup.py
index 6970bcd326671..7a67635c711e9 100644
--- a/setup.py
+++ b/setup.py
@@ -323,7 +323,6 @@ def do_setup():
             'flask-swagger==0.2.13',
             'flask-wtf>=0.14.2, <0.15',
             'funcsigs==1.0.0',
-            'future>=0.16.0, <0.17',
             'gitpython>=2.0.2',
             'gunicorn>=19.5.0, <20.0',
             'iso8601>=0.1.12',

Make sure you have checked _all_ steps below.

### Jira

- [x] My PR addresses the following [Airflow Jira](https://issues.apache.org/jira/browse/AIRFLOW/) issues and references them in the PR title. For example, "\[AIRFLOW-XXX\] My Airflow PR"
  - https://issues.apache.org/jira/browse/AIRFLOW-4570
  - In case you are fixing a typo in the documentation you can prepend your commit with \[AIRFLOW-XXX\], code changes always need a Jira issue.
  - In case you are proposing a fundamental code change, you need to create an Airflow Improvement Proposal ([AIP](https://cwiki.apache.org/confluence/display/AIRFLOW/Airflow+Improvements+Proposals)).
  - In case you are adding a dependency, check if the license complies with the [ASF 3rd Party License Policy](https://www.apache.org/legal/resolved.html#category-x).

### Description

- [x] Here are some details about my PR, including screenshots of any UI changes:

Remove all usage of the future library because we're dropping Python 2 support.

### Tests

- [x] My PR adds the following unit tests __OR__ does not need testing for this extremely good reason:

### Commits

- [x] My commits all reference Jira issues in their subject lines, and I have squashed multiple commits if they address the same issue. In addition, my commits follow the guidelines from "[How to write a good git commit message](http://chris.beams.io/posts/git-commit/)":
  1. Subject is separated from body by a blank line
  1. Subject is limited to 50 characters (not including Jira issue reference)
  1. Subject does not end with a period
  1. Subject uses the imperative mood ("add", not "adding")
  1. Body wraps at 72 characters
  1. Body explains "what" and "why", not "how"

### Documentation

- [x] In case of new functionality, my PR adds documentation that describes how to use it.
  - All the public functions and the classes in the PR contain docstrings that explain what it does
  - If you implement backwards incompatible changes, please leave a note in the [Updating.md](https://github.com/apache/airflow/blob/master/UPDATING.md) so we can assign it to a appropriate release

### Code Quality

- [x] Passes `flake8`
