Repository: geopy/geopy
Pull request #288 (2018-05-07 08:14:26)

Add `geopy.geocoders.options` object with default params
The following has been done there:
- Moved `geopy.geocoders.DEFAULT_*` vars to a separate object (class) `geopy.geocoders.options`
- Removed the `geopy.geocoders.DEFAULT_*` constants (in geocoder initializers they've been replaced with an appropriate `None` or a sentinel value)
- Added a deprecation warning for `timeout=None` on geocoding calls (the old behaviour, that is falling back to the default timeout, is kept; however in future versions of geopy `None` would mean "no timeout" there)
- Pulled up param descriptions in geocoder initializers, PEP8-fied and isort-ed the touched code.

Usage:

    >>> import geopy.geocoders
    >>> geopy.geocoders.options.default_user_agent = 'my_app/1'
    >>> geopy.geocoders.options.default_timeout = 7
    >>>
    >>> from geopy.geocoders import Nominatim
    >>> geolocator = Nominatim()
    >>> print(geolocator.headers)
    {'User-Agent': 'my_app/1'}
    >>> print(geolocator.timeout)
    7

There're two reasons for introducing the global `options` object:
- There should be a convenient way to override default timeout and user-agent application-wide (from the current Roadmap #267)
- There should be a way to pass a custom ssl context, which should also be globally overridable. Although ssl stuff is out of the scope of this PR, introducing `options` is an important preliminary step for that.





Patch:
diff --git a/docs/index.rst b/docs/index.rst
index c38b8e4..1290676 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -10,6 +10,10 @@ Geocoders
 .. automodule:: geopy.geocoders
    :members: __doc__
 
+.. autoclass:: geopy.geocoders.options
+   :members:
+   :undoc-members:
+
 .. autofunction:: geopy.geocoders.get_geocoder_for_service
 
 .. autoclass:: geopy.geocoders.ArcGIS
diff --git a/geopy/geocoders/__init__.py b/geopy/geocoders/__init__.py
index a67b9dc..6055742 100644
--- a/geopy/geocoders/__init__.py
+++ b/geopy/geocoders/__init__.py
@@ -74,6 +74,7 @@ need to geocode locations in Cleveland, Ohio, you could do::
 
 __all__ = (
     "get_geocoder_for_service",
+    "options",
     # The order of classes below should correspond to the order of their
     # files in the ``geocoders`` directory ordered by name.
     #
@@ -123,7 +124,7 @@ from geopy.geocoders.smartystreets import LiveAddress
 from geopy.geocoders.what3words import What3Words
 from geopy.geocoders.yandex import Yandex
 
-
+from geopy.geocoders.base import options
 from geopy.exc import GeocoderNotFound
 
 
diff --git a/geopy/geocoders/arcgis.py b/geopy/geocoders/arcgis.py
index 79ef357..0fad66e 100644
--- a/geopy/geocoders/arcgis.py
+++ b/geopy/geocoders/arcgis.py
@@ -4,18 +4,21 @@
 
 import json
 from time import time
-from geopy.compat import urlencode, Request, string_compare
 
-from geopy.geocoders.base import Geocoder, DEFAULT_SCHEME, DEFAULT_TIMEOUT, \
-    DEFAULT_WKID, DEFAULT_FORMAT_STRING
-from geopy.exc import GeocoderServiceError, GeocoderAuthenticationFailure
-from geopy.exc import ConfigurationError
+from geopy.compat import Request, string_compare, urlencode
+from geopy.exc import (
+    ConfigurationError,
+    GeocoderAuthenticationFailure,
+    GeocoderServiceError,
+)
+from geopy.geocoders.base import DEFAULT_SENTINEL, Geocoder
 from geopy.location import Location
 from geopy.util import logger
 
-
 __all__ = ("ArcGIS", )
 
+DEFAULT_WKID = 4326
+
 
 class ArcGIS(Geocoder):  # pylint: disable=R0921,R0902,W0223
     """
@@ -33,11 +36,11 @@ class ArcGIS(Geocoder):  # pylint: disable=R0921,R0902,W0223
             password=None,
             referer=None,
             token_lifetime=60,
-            scheme=DEFAULT_SCHEME,
-            timeout=DEFAULT_TIMEOUT,
-            proxies=None,
+            scheme=None,
+            timeout=DEFAULT_SENTINEL,
+            proxies=DEFAULT_SENTINEL,
             user_agent=None,
-            format_string=DEFAULT_FORMAT_STRING,
+            format_string=None,
     ):
         """
         Create a ArcGIS-based geocoder.
@@ -57,26 +60,23 @@ class ArcGIS(Geocoder):  # pylint: disable=R0921,R0902,W0223
         :param int token_lifetime: Desired lifetime, in minutes, of an
             ArcGIS-issued token.
 
-        :param str scheme: Desired scheme. If authenticated mode is in use,
-            it must be 'https'.
+        :param str scheme:
+            See :attr:`geopy.geocoders.options.default_scheme`.
+            If authenticated mode is in use, it must be ``'https'``.
 
-        :param int timeout: Time, in seconds, to wait for the geocoding service
-            to respond before raising a :class:`geopy.exc.GeocoderTimedOut`
-            exception.
+        :param int timeout:
+            See :attr:`geopy.geocoders.options.default_timeout`.
 
-        :param dict proxies: If specified, routes this geocoder's requests
-            through the specified proxy. E.g., {"https": "192.0.2.0"}. For
-            more information, see documentation on
-            :class:`urllib2.ProxyHandler`.
+        :param dict proxies:
+            See :attr:`geopy.geocoders.options.default_proxies`.
 
-        :param str user_agent: Use a custom User-Agent header.
+        :param str user_agent:
+            See :attr:`geopy.geocoders.options.default_user_agent`.
 
             .. versionadded:: 1.12.0
 
-        :param str format_string: String containing '%s' where the
-            string to geocode should be interpolated before querying the
-            geocoder. For example: '%s, Mountain View, CA'. The default
-            is just '%s'.
+        :param str format_string:
+            See :attr:`geopy.geocoders.options.default_format_string`.
 
             .. versionadded:: 1.14.0
         """
@@ -118,7 +118,7 @@ class ArcGIS(Geocoder):  # pylint: disable=R0921,R0902,W0223
             'World/GeocodeServer/reverseGeocode' % self.scheme
         )
 
-    def _authenticated_call_geocoder(self, url, timeout=None):
+    def _authenticated_call_geocoder(self, url, timeout=DEFAULT_SENTINEL):
         """
         Wrap self._call_geocoder, handling tokens.
         """
@@ -130,7 +130,8 @@ class ArcGIS(Geocoder):  # pylint: disable=R0921,R0902,W0223
         )
         return self._base_call_geocoder(request, timeout=timeout)
 
-    def geocode(self, query, exactly_one=True, timeout=None, out_fields=None):
+    def geocode(self, query, exactly_one=True, timeout=DEFAULT_SENTINEL,
+                out_fields=None):
         """
         Geocode a location query.
 
@@ -192,7 +193,7 @@ class ArcGIS(Geocoder):  # pylint: disable=R0921,R0902,W0223
             return geocoded[0]
         return geocoded
 
-    def reverse(self, query, exactly_one=True, timeout=None, # pylint: disable=R0913,W0221
+    def reverse(self, query, exactly_one=True, timeout=DEFAULT_SENTINEL,
                 distance=None, wkid=DEFAULT_WKID):
         """
         Given a point, find an address.
diff --git a/geopy/geocoders/baidu.py b/geopy/geocoders/baidu.py
index 4a985c8..44ba95f 100644
--- a/geopy/geocoders/baidu.py
+++ b/geopy/geocoders/baidu.py
@@ -3,17 +3,15 @@
 """
 
 from geopy.compat import urlencode
-from geopy.geocoders.base import Geocoder, DEFAULT_TIMEOUT, DEFAULT_SCHEME, \
-    DEFAULT_FORMAT_STRING
 from geopy.exc import (
+    GeocoderAuthenticationFailure,
     GeocoderQueryError,
     GeocoderQuotaExceeded,
-    GeocoderAuthenticationFailure,
 )
+from geopy.geocoders.base import DEFAULT_SENTINEL, Geocoder
 from geopy.location import Location
 from geopy.util import logger
 
-
 __all__ = ("Baidu", )
 
 
@@ -26,11 +24,11 @@ class Baidu(Geocoder):
     def __init__(
             self,
             api_key,
-            scheme=DEFAULT_SCHEME,
-            timeout=DEFAULT_TIMEOUT,
-            proxies=None,
+            scheme=None,
+            timeout=DEFAULT_SENTINEL,
+            proxies=DEFAULT_SENTINEL,
             user_agent=None,
-            format_string=DEFAULT_FORMAT_STRING,
+            format_string=None,
     ):
         """
         Initialize a customized Baidu geocoder using the v2 API.
@@ -41,25 +39,25 @@ class Baidu(Geocoder):
             geocoding requests. API keys are managed through the Baidu APIs
             console (http://lbsyun.baidu.com/apiconsole/key).
 
-        :param str scheme: Use 'https' or 'http' as the API URL's scheme.
-            Default is https.
+        :param str scheme:
+            See :attr:`geopy.geocoders.options.default_scheme`.
 
             .. versionchanged:: 1.14.0
                Default scheme has been changed from ``http`` to ``https``.
 
-        :param dict proxies: If specified, routes this geocoder's requests
-            through the specified proxy. E.g., {"https": "192.0.2.0"}. For
-            more information, see documentation on
-            :class:`urllib2.ProxyHandler`.
+        :param int timeout:
+            See :attr:`geopy.geocoders.options.default_timeout`.
+
+        :param dict proxies:
+            See :attr:`geopy.geocoders.options.default_proxies`.
 
-        :param str user_agent: Use a custom User-Agent header.
+        :param str user_agent:
+            See :attr:`geopy.geocoders.options.default_user_agent`.
 
             .. versionadded:: 1.12.0
 
-        :param str format_string: String containing '%s' where the
-            string to geocode should be interpolated before querying the
-            geocoder. For example: '%s, Mountain View, CA'. The default
-            is just '%s'.
+        :param str format_string:
+            See :attr:`geopy.geocoders.options.default_format_string`.
 
             .. versionadded:: 1.14.0
         """
@@ -71,11 +69,8 @@ class Baidu(Geocoder):
             user_agent=user_agent,
         )
         self.api_key = api_key
-        self.scheme = scheme
-        self.doc = {}
         self.api = '%s://api.map.baidu.com/geocoder/v2/' % self.scheme
 
-
     @staticmethod
     def _format_components_param(components):
         """
@@ -89,8 +84,8 @@ class Baidu(Geocoder):
             self,
             query,
             exactly_one=True,
-            timeout=None
-        ):
+            timeout=DEFAULT_SENTINEL,
+    ):
         """
         Geocode a location query.
 
@@ -117,7 +112,7 @@ class Baidu(Geocoder):
             self._call_geocoder(url, timeout=timeout), exactly_one=exactly_one
         )
 
-    def reverse(self, query, timeout=None):  # pylint: disable=W0221
+    def reverse(self, query, timeout=DEFAULT_SENTINEL):
         """
         Given a point, find an address.
 
@@ -145,7 +140,6 @@ class Baidu(Geocoder):
             self._call_geocoder(url, timeout=timeout)
         )
 
-
     @staticmethod
     def _parse_reverse_json(page):
         """
@@ -159,7 +153,6 @@ class Baidu(Geocoder):
 
         return Location(location, (latitude, longitude), place)
 
-
     def _parse_json(self, page, exactly_one=True):
         """
         Returns location, (latitude, longitude) from JSON feed.
diff --git a/geopy/geocoders/base.py b/geopy/geocoders/base.py
index 59acb38..da0b622 100644
--- a/geopy/geocoders/base.py
+++ b/geopy/geocoders/base.py
@@ -5,6 +5,7 @@
 from ssl import SSLError
 from socket import timeout as SocketTimeout
 import json
+import warnings
 
 from geopy.compat import (
     string_compare,
@@ -33,19 +34,62 @@ from geopy.util import decode_page, __version__
 
 __all__ = (
     "Geocoder",
-    "DEFAULT_FORMAT_STRING",
-    "DEFAULT_SCHEME",
-    "DEFAULT_TIMEOUT",
-    "DEFAULT_WKID",
+    "options",
 )
 
 
-DEFAULT_FORMAT_STRING = '%s'
-DEFAULT_SCHEME = 'https'
-DEFAULT_TIMEOUT = 1
-DEFAULT_WKID = 4326
-DEFAULT_USER_AGENT = "geopy/%s" % __version__
+class options(object):
+    """The ``options`` object contains default configuration values for
+    geocoders, e.g. timeout and User-Agent.
+    Instead of passing a custom value to each geocoder individually, you can
+    override a default value in this object.
 
+    Please note that not all geocoders use all attributes of this object.
+    For example, some geocoders don't respect the ``default_scheme``
+    attribute. Refer to the specific geocoder's initializer doc for a list
+    of parameters which that geocoder accepts.
+
+    Example for overriding default ``timeout`` and ``user_agent``::
+
+        >>> import geopy.geocoders
+        >>> geopy.geocoders.options.default_user_agent = 'my_app/1'
+        >>> geopy.geocoders.options.default_timeout = 7
+        >>>
+        >>> from geopy.geocoders import Nominatim
+        >>> geolocator = Nominatim()
+        >>> print(geolocator.headers)
+        {'User-Agent': 'my_app/1'}
+        >>> print(geolocator.timeout)
+        7
+
+    """
+
+    default_format_string = '%s'
+    """String containing ``'%s'`` where the string to geocode should be
+    interpolated before querying the geocoder. Used by ``geocode`` calls only.
+    For example: ``'%s, Mountain View, CA'``."""
+
+    default_scheme = 'https'
+    """Use ``'https'`` or ``'http'`` as the API URL's scheme."""
+
+    default_timeout = 1
+    """Time, in seconds, to wait for the geocoding service to respond before
+    raising a :class:`geopy.exc.GeocoderTimedOut` exception. Pass ``None``
+    to disable timeout."""
+
+    default_proxies = None
+    """If specified, tunnel requests through the specified proxy.
+    E.g., ``{"https": "192.0.2.0"}``. For more information, see documentation
+    on :class:`urllib2.ProxyHandler`."""
+
+    default_user_agent = "geopy/%s" % __version__
+    """User-Agent header to send with the requests to geocoder API."""
+
+
+# Create an object which `repr` returns 'DEFAULT_SENTINEL'. Sphinx (docs) uses
+# this value when generating method's signature.
+DEFAULT_SENTINEL = type('object', (object,),
+                        {'__repr__': lambda self: 'DEFAULT_SENTINEL'})()
 
 ERROR_CODE_MAP = {
     400: GeocoderQueryError,
@@ -62,32 +106,34 @@ ERROR_CODE_MAP = {
 }
 
 
-class Geocoder(object): # pylint: disable=R0921
+class Geocoder(object):
     """
     Template object for geocoders.
     """
 
     def __init__(
             self,
-            format_string=DEFAULT_FORMAT_STRING,
-            scheme=DEFAULT_SCHEME,
-            timeout=DEFAULT_TIMEOUT,
-            proxies=None,
+            format_string=None,
+            scheme=None,
+            timeout=DEFAULT_SENTINEL,
+            proxies=DEFAULT_SENTINEL,
             user_agent=None,
-        ):
+    ):
         """
         Mostly-common geocoder validation, proxies, &c. Not all geocoders
         specify format_string and such.
         """
-        self.format_string = format_string
-        self.scheme = scheme
-        if self.scheme not in ('http', 'https'): # pragma: no cover
+        self.format_string = format_string or options.default_format_string
+        self.scheme = scheme or options.default_scheme
+        if self.scheme not in ('http', 'https'):
             raise ConfigurationError(
                 'Supported schemes are `http` and `https`.'
             )
-        self.proxies = proxies
-        self.timeout = timeout
-        self.headers = {'User-Agent': user_agent or DEFAULT_USER_AGENT}
+        self.timeout = (timeout if timeout is not DEFAULT_SENTINEL
+                        else options.default_timeout)
+        self.proxies = (proxies if proxies is not DEFAULT_SENTINEL
+                        else options.default_proxies)
+        self.headers = {'User-Agent': user_agent or options.default_user_agent}
 
         if self.proxies:
             opener = build_opener(
@@ -124,12 +170,12 @@ class Geocoder(object): # pylint: disable=R0921
     def _call_geocoder(
             self,
             url,
-            timeout=None,
+            timeout=DEFAULT_SENTINEL,
             raw=False,
             requester=None,
             deserializer=json.loads,
             **kwargs
-        ):
+    ):
         """
         For a generated query URL, get the results.
         """
@@ -148,8 +194,19 @@ class Geocoder(object): # pylint: disable=R0921
 
         requester = requester or self.urlopen
 
+        if timeout is None:
+            warnings.warn(
+                ('`timeout=None` has been passed to a geocoder call. Using '
+                 'default geocoder timeout. In future versions of geopy the '
+                 'behavior will be different: None will mean "no timeout" '
+                 'instead of "default geocoder timeout".'), DeprecationWarning)
+            timeout = DEFAULT_SENTINEL
+
+        timeout = (timeout if timeout is not DEFAULT_SENTINEL
+                   else self.timeout)
+
         try:
-            page = requester(req, timeout=(timeout or self.timeout), **kwargs)
+            page = requester(req, timeout=timeout, **kwargs)
         except Exception as error: # pylint: disable=W0703
             message = (
                 str(error) if not py3k
@@ -202,13 +259,13 @@ class Geocoder(object): # pylint: disable=R0921
         else:
             return page
 
-    def geocode(self, query, exactly_one=True, timeout=None):
+    def geocode(self, query, exactly_one=True, timeout=DEFAULT_SENTINEL):
         """
         Implemented in subclasses.
         """
         raise NotImplementedError()
 
-    def reverse(self, query, exactly_one=True, timeout=None):
+    def reverse(self, query, exactly_one=True, timeout=DEFAULT_SENTINEL):
         """
         Implemented in subclasses.
         """
diff --git a/geopy/geocoders/bing.py b/geopy/geocoders/bing.py
index 4802897..67c88c8 100644
--- a/geopy/geocoders/bing.py
+++ b/geopy/geocoders/bing.py
@@ -3,18 +3,16 @@
 """
 
 from geopy.compat import urlencode
-from geopy.geocoders.base import Geocoder, DEFAULT_FORMAT_STRING, \
-    DEFAULT_TIMEOUT, DEFAULT_SCHEME
-from geopy.location import Location
 from geopy.exc import (
     GeocoderAuthenticationFailure,
-    GeocoderQuotaExceeded,
     GeocoderInsufficientPrivileges,
-    GeocoderUnavailable,
+    GeocoderQuotaExceeded,
     GeocoderServiceError,
+    GeocoderUnavailable,
 )
-from geopy.util import logger, join_filter
-
+from geopy.geocoders.base import DEFAULT_SENTINEL, Geocoder
+from geopy.location import Location
+from geopy.util import join_filter, logger
 
 __all__ = ("Bing", )
 
@@ -36,40 +34,41 @@ class Bing(Geocoder):
     def __init__(
             self,
             api_key,
-            format_string=DEFAULT_FORMAT_STRING,
-            scheme=DEFAULT_SCHEME,
-            timeout=DEFAULT_TIMEOUT,
-            proxies=None,
+            format_string=None,
+            scheme=None,
+            timeout=DEFAULT_SENTINEL,
+            proxies=DEFAULT_SENTINEL,
             user_agent=None,
-        ):  # pylint: disable=R0913
+    ):
         """Initialize a customized Bing geocoder with location-specific
         address information and your Bing Maps API key.
 
         :param str api_key: Should be a valid Bing Maps API key.
 
-        :param str format_string: String containing '%s' where the
-            string to geocode should be interpolated before querying the
-            geocoder. For example: '%s, Mountain View, CA'. The default
-            is just '%s'.
+        :param str format_string:
+            See :attr:`geopy.geocoders.options.default_format_string`.
 
-        :param str scheme: Use 'https' or 'http' as the API URL's scheme.
-            Default is https. Note that SSL connections' certificates are not
-            verified.
+        :param str scheme:
+            See :attr:`geopy.geocoders.options.default_scheme`.
 
-        :param int timeout: Time, in seconds, to wait for the geocoding service
-            to respond before raising a :class:`geopy.exc.GeocoderTimedOut`
-            exception.
+        :param int timeout:
+            See :attr:`geopy.geocoders.options.default_timeout`.
 
-        :param dict proxies: If specified, routes this geocoder's requests
-            through the specified proxy. E.g., {"https": "192.0.2.0"}. For
-            more information, see documentation on
-            :class:`urllib2.ProxyHandler`.
+        :param dict proxies:
+            See :attr:`geopy.geocoders.options.default_proxies`.
 
-        :param str user_agent: Use a custom User-Agent header.
+        :param str user_agent:
+            See :attr:`geopy.geocoders.options.default_user_agent`.
 
             .. versionadded:: 1.12.0
         """
-        super(Bing, self).__init__(format_string, scheme, timeout, proxies, user_agent=user_agent)
+        super(Bing, self).__init__(
+            format_string=format_string,
+            scheme=scheme,
+            timeout=timeout,
+            proxies=proxies,
+            user_agent=user_agent,
+        )
         self.api_key = api_key
         self.api = "%s://dev.virtualearth.net/REST/v1/Locations" % self.scheme
 
@@ -78,19 +77,19 @@ class Bing(Geocoder):
             query,
             exactly_one=True,
             user_location=None,
-            timeout=None,
+            timeout=DEFAULT_SENTINEL,
             culture=None,
             include_neighborhood=None,
             include_country_code=False
-        ):  # pylint: disable=W0221
+    ):
         """
         Geocode an address.
 
         :param str query: The address or query you wish to geocode.
 
             For a structured query, provide a dictionary whose keys
-            are one of: `addressLine`, `locality` (city), `adminDistrict` (state), `countryRegion`, or
-            `postalcode`.
+            are one of: `addressLine`, `locality` (city),
+            `adminDistrict` (state), `countryRegion`, or `postalcode`.
 
         :param bool exactly_one: Return one result or a list of results, if
             available.
@@ -157,10 +156,10 @@ class Bing(Geocoder):
             self,
             query,
             exactly_one=True,
-            timeout=None,
+            timeout=DEFAULT_SENTINEL,
             culture=None,
             include_country_code=False
-        ):  # pylint: disable=W0221
+    ):
         """
         Reverse geocode a point.
 
@@ -219,7 +218,7 @@ class Bing(Geocoder):
                 raise GeocoderServiceError(err)
 
         resources = doc['resourceSets'][0]['resources']
-        if resources is None or not len(resources): # pragma: no cover
+        if resources is None or not len(resources):
             return None
 
         def parse_resource(resource):
diff --git a/geopy/geocoders/databc.py b/geopy/geocoders/databc.py
index 46ad1b0..1bdd3ab 100644
--- a/geopy/geocoders/databc.py
+++ b/geopy/geocoders/databc.py
@@ -3,14 +3,11 @@
 """
 
 from geopy.compat import urlencode
-
-from geopy.geocoders.base import Geocoder, DEFAULT_SCHEME, DEFAULT_TIMEOUT, \
-    DEFAULT_FORMAT_STRING
 from geopy.exc import GeocoderQueryError
+from geopy.geocoders.base import DEFAULT_SENTINEL, Geocoder
 from geopy.location import Location
 from geopy.util import logger
 
-
 __all__ = ("DataBC", )
 
 
@@ -22,34 +19,31 @@ class DataBC(Geocoder):
 
     def __init__(
             self,
-            scheme=DEFAULT_SCHEME,
-            timeout=DEFAULT_TIMEOUT,
-            proxies=None,
+            scheme=None,
+            timeout=DEFAULT_SENTINEL,
+            proxies=DEFAULT_SENTINEL,
             user_agent=None,
-            format_string=DEFAULT_FORMAT_STRING,
+            format_string=None,
     ):
         """
         Create a DataBC-based geocoder.
 
-        :param str scheme: Desired scheme.
+        :param str scheme:
+            See :attr:`geopy.geocoders.options.default_scheme`.
 
-        :param int timeout: Time, in seconds, to wait for the geocoding service
-            to respond before raising a :class:`geopy.exc.GeocoderTimedOut`
-            exception.
+        :param int timeout:
+            See :attr:`geopy.geocoders.options.default_timeout`.
 
-        :param dict proxies: If specified, routes this geocoder's requests
-            through the specified proxy. E.g., {"https": "192.0.2.0"}. For
-            more information, see documentation on
-            :class:`urllib2.ProxyHandler`.
+        :param dict proxies:
+            See :attr:`geopy.geocoders.options.default_proxies`.
 
-        :param str user_agent: Use a custom User-Agent header.
+        :param str user_agent:
+            See :attr:`geopy.geocoders.options.default_user_agent`.
 
             .. versionadded:: 1.12.0
 
-        :param str format_string: String containing '%s' where the
-            string to geocode should be interpolated before querying the
-            geocoder. For example: '%s, Mountain View, CA'. The default
-            is just '%s'.
+        :param str format_string:
+            See :attr:`geopy.geocoders.options.default_format_string`.
 
             .. versionadded:: 1.14.0
         """
@@ -69,8 +63,8 @@ class DataBC(Geocoder):
             set_back=0,
             location_descriptor='any',
             exactly_one=True,
-            timeout=None,
-        ):
+            timeout=DEFAULT_SENTINEL,
+    ):
         """
         Geocode a location query.
 
diff --git a/geopy/geocoders/geocodefarm.py b/geopy/geocoders/geocodefarm.py
index 68910f4..84f48cb 100644
--- a/geopy/geocoders/geocodefarm.py
+++ b/geopy/geocoders/geocodefarm.py
@@ -2,14 +2,15 @@
 :class:`.GeocodeFarm` geocoder.
 """
 
-from geopy.geocoders.base import Geocoder, DEFAULT_FORMAT_STRING, \
-    DEFAULT_TIMEOUT
+from geopy.compat import urlencode
+from geopy.exc import (
+    GeocoderAuthenticationFailure,
+    GeocoderQuotaExceeded,
+    GeocoderServiceError,
+)
+from geopy.geocoders.base import DEFAULT_SENTINEL, Geocoder
 from geopy.location import Location
 from geopy.util import logger
-from geopy.exc import GeocoderAuthenticationFailure, GeocoderQuotaExceeded, \
-    GeocoderServiceError
-from geopy.compat import urlencode
-
 
 __all__ = ("GeocodeFarm", )
 
@@ -23,36 +24,39 @@ class GeocodeFarm(Geocoder):
     def __init__(
             self,
             api_key=None,
-            format_string=DEFAULT_FORMAT_STRING,
-            timeout=DEFAULT_TIMEOUT,
-            proxies=None,
+            format_string=None,
+            timeout=DEFAULT_SENTINEL,
+            proxies=DEFAULT_SENTINEL,
             user_agent=None,
-        ):  # pylint: disable=R0913
+    ):
         """
         Create a geocoder for GeocodeFarm.
 
         :param str api_key: The API key required by GeocodeFarm to perform
             geocoding requests.
 
-        :param str format_string: String containing '%s' where the
-            string to geocode should be interpolated before querying the
-            geocoder. For example: '%s, Mountain View, CA'. The default
-            is just '%s'.
+        :param str format_string:
+            See :attr:`geopy.geocoders.options.default_format_string`.
+
+        :param int timeout:
+            See :attr:`geopy.geocoders.options.default_timeout`.
 
-        :param dict proxies: If specified, routes this geocoder's requests
-            through the specified proxy. E.g., {"https": "192.0.2.0"}. For
-            more information, see documentation on
-            :class:`urllib2.ProxyHandler`.
+        :param dict proxies:
+            See :attr:`geopy.geocoders.options.default_proxies`.
 
-        :param str user_agent: Use a custom User-Agent header.
+        :param str user_agent:
+            See :attr:`geopy.geocoders.options.default_user_agent`.
 
             .. versionadded:: 1.12.0
         """
         super(GeocodeFarm, self).__init__(
-            format_string, 'https', timeout, proxies, user_agent=user_agent
+            format_string=format_string,
+            scheme='https',
+            timeout=timeout,
+            proxies=proxies,
+            user_agent=user_agent,
         )
         self.api_key = api_key
-        self.format_string = format_string
         self.api = (
             "%s://www.geocode.farm/v3/json/forward/" % self.scheme
         )
@@ -60,7 +64,7 @@ class GeocodeFarm(Geocoder):
             "%s://www.geocode.farm/v3/json/reverse/" % self.scheme
         )
 
-    def geocode(self, query, exactly_one=True, timeout=None):
+    def geocode(self, query, exactly_one=True, timeout=DEFAULT_SENTINEL):
         """
         Geocode a location query.
 
@@ -85,7 +89,7 @@ class GeocodeFarm(Geocoder):
             self._call_geocoder(url, timeout=timeout), exactly_one
         )
 
-    def reverse(self, query, exactly_one=True, timeout=None):
+    def reverse(self, query, exactly_one=True, timeout=DEFAULT_SENTINEL):
         """
         Returns a reverse geocoded location.
 
diff --git a/geopy/geocoders/geonames.py b/geopy/geocoders/geonames.py
index fc5494f..1e8c41b 100644
--- a/geopy/geocoders/geonames.py
+++ b/geopy/geocoders/geonames.py
@@ -3,17 +3,15 @@
 """
 
 from geopy.compat import urlencode
-
-from geopy.geocoders.base import Geocoder, DEFAULT_TIMEOUT, DEFAULT_FORMAT_STRING
-from geopy.location import Location
 from geopy.exc import (
+    ConfigurationError,
     GeocoderInsufficientPrivileges,
     GeocoderServiceError,
-    ConfigurationError
 )
+from geopy.geocoders.base import DEFAULT_SENTINEL, Geocoder
+from geopy.location import Location
 from geopy.util import logger
 
-
 __all__ = ("GeoNames", )
 
 
@@ -30,33 +28,30 @@ class GeoNames(Geocoder): # pylint: disable=W0223
             self,
             country_bias=None,
             username=None,
-            timeout=DEFAULT_TIMEOUT,
-            proxies=None,
+            timeout=DEFAULT_SENTINEL,
+            proxies=DEFAULT_SENTINEL,
             user_agent=None,
-            format_string=DEFAULT_FORMAT_STRING,
+            format_string=None,
     ):
         """
         :param str country_bias:
 
-        :param str username:
+        :param str username: GeoNames username, required. Sign up here:
+            http://www.geonames.org/login
 
-        :param int timeout: Time, in seconds, to wait for the geocoding service
-            to respond before raising a :class:`geopy.exc.GeocoderTimedOut`
-            exception.
+        :param int timeout:
+            See :attr:`geopy.geocoders.options.default_timeout`.
 
-        :param dict proxies: If specified, routes this geocoder's requests
-            through the specified proxy. E.g., {"https": "192.0.2.0"}. For
-            more information, see documentation on
-            :class:`urllib2.ProxyHandler`.
+        :param dict proxies:
+            See :attr:`geopy.geocoders.options.default_proxies`.
 
-        :param str user_agent: Use a custom User-Agent header.
+        :param str user_agent:
+            See :attr:`geopy.geocoders.options.default_user_agent`.
 
             .. versionadded:: 1.12.0
 
-        :param str format_string: String containing '%s' where the
-            string to geocode should be interpolated before querying the
-            geocoder. For example: '%s, Mountain View, CA'. The default
-            is just '%s'.
+        :param str format_string:
+            See :attr:`geopy.geocoders.options.default_format_string`.
 
             .. versionadded:: 1.14.0
         """
@@ -80,7 +75,7 @@ class GeoNames(Geocoder): # pylint: disable=W0223
             "%s://api.geonames.org/findNearbyPlaceNameJSON" % self.scheme
         )
 
-    def geocode(self, query, exactly_one=True, timeout=None): # pylint: disable=W0221
+    def geocode(self, query, exactly_one=True, timeout=DEFAULT_SENTINEL):
         """
         Geocode a location query.
 
@@ -113,8 +108,8 @@ class GeoNames(Geocoder): # pylint: disable=W0223
             self,
             query,
             exactly_one=False,
-            timeout=None,
-        ):
+            timeout=DEFAULT_SENTINEL,
+    ):
         """
         Given a point, find an address.
 
@@ -130,7 +125,8 @@ class GeoNames(Geocoder): # pylint: disable=W0223
 
         :param int timeout: Time, in seconds, to wait for the geocoding service
             to respond before raising a :class:`geopy.exc.GeocoderTimedOut`
-            exception.
+            exception. Set this only if you wish to override, on this call
+            only, the value set during the geocoder's initialization.
 
         """
         try:
diff --git a/geopy/geocoders/googlev3.py b/geopy/geocoders/googlev3.py
index c25a44b..e7f01c4 100644
--- a/geopy/geocoders/googlev3.py
+++ b/geopy/geocoders/googlev3.py
@@ -5,15 +5,15 @@
 import base64
 import hashlib
 import hmac
+
 from geopy.compat import urlencode
-from geopy.geocoders.base import Geocoder, DEFAULT_TIMEOUT, DEFAULT_SCHEME, \
-    DEFAULT_FORMAT_STRING
 from geopy.exc import (
-    GeocoderQuotaExceeded,
     ConfigurationError,
     GeocoderParseError,
     GeocoderQueryError,
+    GeocoderQuotaExceeded,
 )
+from geopy.geocoders.base import DEFAULT_SENTINEL, Geocoder
 from geopy.location import Location
 from geopy.util import logger
 
@@ -40,13 +40,13 @@ class GoogleV3(Geocoder):  # pylint: disable=R0902
             self,
             api_key=None,
             domain='maps.googleapis.com',
-            scheme=DEFAULT_SCHEME,
+            scheme=None,
             client_id=None,
             secret_key=None,
-            timeout=DEFAULT_TIMEOUT,
-            proxies=None,
+            timeout=DEFAULT_SENTINEL,
+            proxies=DEFAULT_SENTINEL,
             user_agent=None,
-            format_string=DEFAULT_FORMAT_STRING,
+            format_string=None,
             channel='',
     ):
         """
@@ -63,27 +63,26 @@ class GoogleV3(Geocoder):  # pylint: disable=R0902
             geocoding address in the UK (for example), you may want to set it
             to 'maps.google.co.uk' to properly bias results.
 
-        :param str scheme: Use 'https' or 'http' as the API URL's scheme.
-            Default is https. Note that SSL connections' certificates are not
-            verified.
+        :param str scheme:
+            See :attr:`geopy.geocoders.options.default_scheme`.
 
         :param str client_id: If using premier, the account client id.
 
         :param str secret_key: If using premier, the account secret key.
 
-        :param dict proxies: If specified, routes this geocoder's requests
-            through the specified proxy. E.g., {"https": "192.0.2.0"}. For
-            more information, see documentation on
-            :class:`urllib2.ProxyHandler`.
+        :param int timeout:
+            See :attr:`geopy.geocoders.options.default_timeout`.
+
+        :param dict proxies:
+            See :attr:`geopy.geocoders.options.default_proxies`.
 
-        :param str user_agent: Use a custom User-Agent header.
+        :param str user_agent:
+            See :attr:`geopy.geocoders.options.default_user_agent`.
 
             .. versionadded:: 1.12.0
 
-        :param str format_string: String containing '%s' where the
-            string to geocode should be interpolated before querying the
-            geocoder. For example: '%s, Mountain View, CA'. The default
-            is just '%s'.
+        :param str format_string:
+            See :attr:`geopy.geocoders.options.default_format_string`.
 
             .. versionadded:: 1.14.0
 
@@ -105,8 +104,6 @@ class GoogleV3(Geocoder):  # pylint: disable=R0902
 
         self.api_key = api_key
         self.domain = domain.strip('/')
-        self.scheme = scheme
-        self.doc = {}
 
         self.premier = bool(client_id and secret_key)
         self.client_id = client_id
@@ -164,13 +161,13 @@ class GoogleV3(Geocoder):  # pylint: disable=R0902
             self,
             query,
             exactly_one=True,
-            timeout=None,
+            timeout=DEFAULT_SENTINEL,
             bounds=None,
             region=None,
             components=None,
             language=None,
             sensor=False,
-        ):  # pylint: disable=W0221,R0913
+    ):
         """
         Geocode a location query.
 
@@ -232,10 +229,10 @@ class GoogleV3(Geocoder):  # pylint: disable=R0902
             self,
             query,
             exactly_one=False,
-            timeout=None,
+            timeout=DEFAULT_SENTINEL,
             language=None,
             sensor=False,
-        ):  # pylint: disable=W0221,R0913
+    ):
         """
         Given a point, find an address.
 
@@ -249,7 +246,8 @@ class GoogleV3(Geocoder):  # pylint: disable=R0902
 
         :param int timeout: Time, in seconds, to wait for the geocoding service
             to respond before raising a :class:`geopy.exc.GeocoderTimedOut`
-            exception.
+            exception. Set this only if you wish to override, on this call
+            only, the value set during the geocoder's initialization.
 
         :param str language: The language in which to return results.
 
@@ -275,7 +273,7 @@ class GoogleV3(Geocoder):  # pylint: disable=R0902
             self._call_geocoder(url, timeout=timeout), exactly_one
         )
 
-    def timezone(self, location, at_time=None, timeout=None):
+    def timezone(self, location, at_time=None, timeout=DEFAULT_SENTINEL):
         """
         **This is an unstable API.**
 
@@ -293,6 +291,11 @@ class GoogleV3(Geocoder):  # pylint: disable=R0902
             function is called in UTC.
         :type at_time: int or float or datetime
 
+        :param int timeout: Time, in seconds, to wait for the geocoding service
+            to respond before raising a :class:`geopy.exc.GeocoderTimedOut`
+            exception. Set this only if you wish to override, on this call
+            only, the value set during the geocoder's initialization.
+
         :rtype: pytz timezone
         """
         if not pytz_available:
@@ -381,4 +384,3 @@ class GoogleV3(Geocoder):  # pylint: disable=R0902
             raise GeocoderQueryError('Probably missing address or latlng.')
         else:
             raise GeocoderQueryError('Unknown error.')
-
diff --git a/geopy/geocoders/ignfrance.py b/geopy/geocoders/ignfrance.py
index 548cd4f..d6bd2c7 100644
--- a/geopy/geocoders/ignfrance.py
+++ b/geopy/geocoders/ignfrance.py
@@ -4,15 +4,10 @@
 
 import xml.etree.ElementTree as ET
 
-from geopy.compat import (urlencode, HTTPPasswordMgrWithDefaultRealm,
-                          HTTPBasicAuthHandler, build_opener, u,
-                          iteritems, Request)
-from geopy.geocoders.base import Geocoder, DEFAULT_TIMEOUT, DEFAULT_SCHEME, \
-    DEFAULT_FORMAT_STRING
-from geopy.exc import (
-    GeocoderQueryError,
-    ConfigurationError,
-)
+from geopy.compat import (HTTPBasicAuthHandler, HTTPPasswordMgrWithDefaultRealm, Request,
+                          build_opener, iteritems, u, urlencode)
+from geopy.exc import ConfigurationError, GeocoderQueryError
+from geopy.geocoders.base import DEFAULT_SENTINEL, Geocoder
 from geopy.location import Location
 from geopy.util import logger
 
@@ -48,11 +43,11 @@ class IGNFrance(Geocoder):   # pylint: disable=W0223
             password=None,
             referer=None,
             domain='wxs.ign.fr',
-            scheme=DEFAULT_SCHEME,
-            timeout=DEFAULT_TIMEOUT,
-            proxies=None,
+            scheme=None,
+            timeout=DEFAULT_SENTINEL,
+            proxies=DEFAULT_SENTINEL,
             user_agent=None,
-            format_string=DEFAULT_FORMAT_STRING,
+            format_string=None,
     ):
         """
         Initialize a customized IGN France geocoder.
@@ -75,28 +70,22 @@ class IGNFrance(Geocoder):   # pylint: disable=W0223
             be changed for testing purposes for developer API
             e.g gpp3-wxs.ign.fr at the moment.
 
-        :param str scheme: Use 'https' or 'http' as the API URL's scheme.
-            Default is https. Note that SSL connections' certificates are not
-            verified.
+        :param str scheme:
+            See :attr:`geopy.geocoders.options.default_scheme`.
 
-        :param int timeout: Time, in seconds, to wait for the geocoding service
-            to respond before raising a :class:`geopy.exc.GeocoderTimedOut`
-            exception. Set this only if you wish to override, on this call
-            only, the value set during the geocoder's initialization.
+        :param int timeout:
+            See :attr:`geopy.geocoders.options.default_timeout`.
 
-        :param dict proxies: If specified, routes this geocoder's requests
-            through the specified proxy. E.g., {"https": "192.0.2.0"}. For
-            more information, see documentation on
-            :class:`urllib2.ProxyHandler`.
+        :param dict proxies:
+            See :attr:`geopy.geocoders.options.default_proxies`.
 
-        :param str user_agent: Use a custom User-Agent header.
+        :param str user_agent:
+            See :attr:`geopy.geocoders.options.default_user_agent`.
 
             .. versionadded:: 1.12.0
 
-        :param str format_string: String containing '%s' where the
-            string to geocode should be interpolated before querying the
-            geocoder. For example: '%s, Mountain View, CA'. The default
-            is just '%s'.
+        :param str format_string:
+            See :attr:`geopy.geocoders.options.default_format_string`.
 
             .. versionadded:: 1.14.0
 
@@ -147,8 +136,8 @@ class IGNFrance(Geocoder):   # pylint: disable=W0223
             is_freeform=False,
             filtering=None,
             exactly_one=True,
-            timeout=None
-    ):  # pylint: disable=W0221,R0913
+            timeout=DEFAULT_SENTINEL,
+    ):
         """
         Geocode a location query.
 
@@ -250,8 +239,8 @@ class IGNFrance(Geocoder):   # pylint: disable=W0223
             maximum_responses=25,
             filtering='',
             exactly_one=False,
-            timeout=None
-    ):  # pylint: disable=W0221,R0913
+            timeout=DEFAULT_SENTINEL,
+    ):
         """
         Given a point, find an address.
 
@@ -526,7 +515,6 @@ class IGNFrance(Geocoder):   # pylint: disable=W0223
 
         return raw_xml
 
-
     @staticmethod
     def _parse_place(place, is_freeform=None):
         """
diff --git a/geopy/geocoders/mapzen.py b/geopy/geocoders/mapzen.py
index f61b8df..2a3f500 100644
--- a/geopy/geocoders/mapzen.py
+++ b/geopy/geocoders/mapzen.py
@@ -2,17 +2,11 @@
 Mapzen geocoder, contributed by Michal Migurski of Mapzen.
 """
 
-from geopy.geocoders.base import (
-    Geocoder,
-    DEFAULT_FORMAT_STRING,
-    DEFAULT_TIMEOUT,
-    DEFAULT_SCHEME,
-)
 from geopy.compat import urlencode
+from geopy.geocoders.base import DEFAULT_SENTINEL, Geocoder
 from geopy.location import Location
 from geopy.util import logger
 
-
 __all__ = ("Mapzen", )
 
 
@@ -29,47 +23,51 @@ class Mapzen(Geocoder):
     def __init__(
             self,
             api_key=None,
-            format_string=DEFAULT_FORMAT_STRING,
+            format_string=None,
             boundary_rect=None,
             country_bias=None,
-            timeout=DEFAULT_TIMEOUT,
-            proxies=None,
+            timeout=DEFAULT_SENTINEL,
+            proxies=DEFAULT_SENTINEL,
             user_agent=None,
             domain='search.mapzen.com',
-            scheme=DEFAULT_SCHEME,
-    ):  # pylint: disable=R0913
+            scheme=None,
+    ):
         """
-        :param str format_string: String containing '%s' where the
-            string to geocode should be interpolated before querying the
-            geocoder. For example: '%s, Mountain View, CA'. The default
-            is just '%s'.
+        :param str api_key: Mapzen API key, optional.
+
+        :param str format_string:
+            See :attr:`geopy.geocoders.options.default_format_string`.
 
         :param tuple boundary_rect: Coordinates to restrict search within,
             given as (west, south, east, north) coordinate tuple.
 
         :param str country_bias: Bias results to this country (ISO alpha-3).
 
-        :param dict proxies: If specified, routes this geocoder's requests
-            through the specified proxy. E.g., {"https": "192.0.2.0"}. For
-            more information, see documentation on
-            :class:`urllib2.ProxyHandler`.
+        :param int timeout:
+            See :attr:`geopy.geocoders.options.default_timeout`.
+
+        :param dict proxies:
+            See :attr:`geopy.geocoders.options.default_proxies`.
 
-        :param str user_agent: Use a custom User-Agent header.
+        :param str user_agent:
+            See :attr:`geopy.geocoders.options.default_user_agent`.
 
             .. versionadded:: 1.12.0
 
         :param str domain: Specify a custom domain for Mapzen API.
 
-        :param str scheme: Use 'https' or 'http' as the API URL's scheme.
-            Default is https. Note that SSL connections' certificates are not
-            verified.
+        :param str scheme:
+            See :attr:`geopy.geocoders.options.default_scheme`.
 
         """
         super(Mapzen, self).__init__(
-            format_string, scheme, timeout, proxies, user_agent=user_agent
+            format_string=format_string,
+            scheme=scheme,
+            timeout=timeout,
+            proxies=proxies,
+            user_agent=user_agent,
         )
         self.country_bias = country_bias
-        self.format_string = format_string
         self.boundary_rect = boundary_rect
         self.api_key = api_key
         self.domain = domain.strip('/')
@@ -81,8 +79,8 @@ class Mapzen(Geocoder):
             self,
             query,
             exactly_one=True,
-            timeout=None,
-    ):  # pylint: disable=R0913,W0221
+            timeout=DEFAULT_SENTINEL,
+    ):
         """
         Geocode a location query.
 
@@ -123,8 +121,8 @@ class Mapzen(Geocoder):
             self,
             query,
             exactly_one=True,
-            timeout=None,
-    ):  # pylint: disable=W0221
+            timeout=DEFAULT_SENTINEL,
+    ):
         """
         Returns a reverse geocoded location.
 
diff --git a/geopy/geocoders/opencage.py b/geopy/geocoders/opencage.py
index 2e30bf6..f5ad0ea 100644
--- a/geopy/geocoders/opencage.py
+++ b/geopy/geocoders/opencage.py
@@ -3,16 +3,11 @@
 """
 
 from geopy.compat import urlencode
-from geopy.geocoders.base import Geocoder, DEFAULT_TIMEOUT, DEFAULT_SCHEME, \
-    DEFAULT_FORMAT_STRING
-from geopy.exc import (
-    GeocoderQueryError,
-    GeocoderQuotaExceeded,
-)
+from geopy.exc import GeocoderQueryError, GeocoderQuotaExceeded
+from geopy.geocoders.base import DEFAULT_SENTINEL, Geocoder
 from geopy.location import Location
 from geopy.util import logger
 
-
 __all__ = ("OpenCage", )
 
 
@@ -28,11 +23,11 @@ class OpenCage(Geocoder):
             self,
             api_key,
             domain='api.opencagedata.com',
-            scheme=DEFAULT_SCHEME,
-            timeout=DEFAULT_TIMEOUT,
-            proxies=None,
+            scheme=None,
+            timeout=DEFAULT_SENTINEL,
+            proxies=DEFAULT_SENTINEL,
             user_agent=None,
-            format_string=DEFAULT_FORMAT_STRING,
+            format_string=None,
     ):
         """
         Initialize a customized OpenCageData geocoder.
@@ -44,23 +39,22 @@ class OpenCage(Geocoder):
         :param str domain: Currently it is 'api.opencagedata.com', can
             be changed for testing purposes.
 
-        :param str scheme: Use 'https' or 'http' as the API URL's scheme.
-            Default is https. Note that SSL connections' certificates are not
-            verified.
+        :param str scheme:
+            See :attr:`geopy.geocoders.options.default_scheme`.
+
+        :param int timeout:
+            See :attr:`geopy.geocoders.options.default_timeout`.
 
-        :param dict proxies: If specified, routes this geocoder's requests
-            through the specified proxy. E.g., {"https": "192.0.2.0"}. For
-            more information, see documentation on
-            :class:`urllib2.ProxyHandler`.
+        :param dict proxies:
+            See :attr:`geopy.geocoders.options.default_proxies`.
 
-        :param str user_agent: Use a custom User-Agent header.
+        :param str user_agent:
+            See :attr:`geopy.geocoders.options.default_user_agent`.
 
             .. versionadded:: 1.12.0
 
-        :param str format_string: String containing '%s' where the
-            string to geocode should be interpolated before querying the
-            geocoder. For example: '%s, Mountain View, CA'. The default
-            is just '%s'.
+        :param str format_string:
+            See :attr:`geopy.geocoders.options.default_format_string`.
 
             .. versionadded:: 1.14.0
 
@@ -75,7 +69,6 @@ class OpenCage(Geocoder):
 
         self.api_key = api_key
         self.domain = domain.strip('/')
-        self.scheme = scheme
         self.api = '%s://%s/geocode/v1/json' % (self.scheme, self.domain)
 
     def geocode(
@@ -85,8 +78,8 @@ class OpenCage(Geocoder):
             country=None,
             language=None,
             exactly_one=True,
-            timeout=None,
-    ):  # pylint: disable=W0221,R0913
+            timeout=DEFAULT_SENTINEL,
+    ):
         """
         Geocode a location query.
 
@@ -145,8 +138,8 @@ class OpenCage(Geocoder):
             query,
             language=None,
             exactly_one=False,
-            timeout=None,
-    ):  # pylint: disable=W0221,R0913
+            timeout=DEFAULT_SENTINEL,
+    ):
         """
         Given a point, find an address.
 
diff --git a/geopy/geocoders/openmapquest.py b/geopy/geocoders/openmapquest.py
index 0d9153b..734c31f 100644
--- a/geopy/geocoders/openmapquest.py
+++ b/geopy/geocoders/openmapquest.py
@@ -4,16 +4,10 @@
 
 from geopy.compat import urlencode
 from geopy.exc import ConfigurationError
-from geopy.geocoders.base import (
-    Geocoder,
-    DEFAULT_FORMAT_STRING,
-    DEFAULT_TIMEOUT,
-    DEFAULT_SCHEME
-)
+from geopy.geocoders.base import DEFAULT_SENTINEL, Geocoder
 from geopy.location import Location
 from geopy.util import logger
 
-
 __all__ = ("OpenMapQuest", )
 
 
@@ -26,46 +20,45 @@ class OpenMapQuest(Geocoder): # pylint: disable=W0223
     def __init__(
             self,
             api_key=None,
-            format_string=DEFAULT_FORMAT_STRING,
-            scheme=DEFAULT_SCHEME,
-            timeout=DEFAULT_TIMEOUT,
-            proxies=None,
+            format_string=None,
+            scheme=None,
+            timeout=DEFAULT_SENTINEL,
+            proxies=DEFAULT_SENTINEL,
             user_agent=None,
-        ):  # pylint: disable=R0913
+    ):
         """
         Initialize an Open MapQuest geocoder with location-specific
         address information.
 
-        :param str api_key: API key provided by MapQuest.
+        :param str api_key: API key provided by MapQuest, required.
 
             .. versionchanged:: 1.12.0
                OpenMapQuest now requires an API key. Using an empty key will
                result in a :class:`geopy.exc.ConfigurationError`.
 
-        :param str format_string: String containing '%s' where
-            the string to geocode should be interpolated before querying
-            the geocoder. For example: '%s, Mountain View, CA'. The default
-            is just '%s'.
+        :param str format_string:
+            See :attr:`geopy.geocoders.options.default_format_string`.
 
-        :param str scheme: Use 'https' or 'http' as the API URL's scheme.
-            Default is https. Note that SSL connections' certificates are not
-            verified.
+        :param str scheme:
+            See :attr:`geopy.geocoders.options.default_scheme`.
 
-        :param int timeout: Time, in seconds, to wait for the geocoding service
-            to respond before raising a :class:`geopy.exc.GeocoderTimedOut`
-            exception.
+        :param int timeout:
+            See :attr:`geopy.geocoders.options.default_timeout`.
 
-        :param dict proxies: If specified, routes this geocoder's requests
-            through the specified proxy. E.g., {"https": "192.0.2.0"}. For
-            more information, see documentation on
-            :class:`urllib2.ProxyHandler`.
+        :param dict proxies:
+            See :attr:`geopy.geocoders.options.default_proxies`.
 
-        :param str user_agent: Use a custom User-Agent header.
+        :param str user_agent:
+            See :attr:`geopy.geocoders.options.default_user_agent`.
 
             .. versionadded:: 1.12.0
         """
         super(OpenMapQuest, self).__init__(
-            format_string, scheme, timeout, proxies, user_agent=user_agent
+            format_string=format_string,
+            scheme=scheme,
+            timeout=timeout,
+            proxies=proxies,
+            user_agent=user_agent,
         )
         if not api_key:
             raise ConfigurationError('OpenMapQuest requires an API key')
@@ -73,7 +66,7 @@ class OpenMapQuest(Geocoder): # pylint: disable=W0223
         self.api = "%s://open.mapquestapi.com/nominatim/v1/search" \
                     "?format=json" % self.scheme
 
-    def geocode(self, query, exactly_one=True, timeout=None): # pylint: disable=W0221
+    def geocode(self, query, exactly_one=True, timeout=DEFAULT_SENTINEL):
         """
         Geocode a location query.
 
@@ -106,7 +99,7 @@ class OpenMapQuest(Geocoder): # pylint: disable=W0223
         """
         Parse display name, latitude, and longitude from an JSON response.
         """
-        if not len(resources): # pragma: no cover
+        if not len(resources):
             return None
         if exactly_one:
             return cls.parse_resource(resources[0])
diff --git a/geopy/geocoders/osm.py b/geopy/geocoders/osm.py
index aee7c81..407f015 100644
--- a/geopy/geocoders/osm.py
+++ b/geopy/geocoders/osm.py
@@ -2,17 +2,11 @@
 OpenStreetMap geocoder, contributed by Alessandro Pasotti of ItOpen.
 """
 
-from geopy.geocoders.base import (
-    Geocoder,
-    DEFAULT_FORMAT_STRING,
-    DEFAULT_TIMEOUT,
-    DEFAULT_SCHEME
-)
 from geopy.compat import urlencode
+from geopy.exc import GeocoderQueryError
+from geopy.geocoders.base import DEFAULT_SENTINEL, Geocoder
 from geopy.location import Location
 from geopy.util import logger
-from geopy.exc import GeocoderQueryError
-
 
 __all__ = ("Nominatim", )
 
@@ -41,29 +35,30 @@ class Nominatim(Geocoder):
 
     def __init__(
             self,
-            format_string=DEFAULT_FORMAT_STRING,
+            format_string=None,
             view_box=None,
             country_bias=None,
-            timeout=DEFAULT_TIMEOUT,
-            proxies=None,
+            timeout=DEFAULT_SENTINEL,
+            proxies=DEFAULT_SENTINEL,
             domain='nominatim.openstreetmap.org',
-            scheme=DEFAULT_SCHEME,
-            user_agent=None
-    ):  # pylint: disable=R0913
+            scheme=None,
+            user_agent=None,
+            # Make sure to synchronize the changes of this signature in the
+            # inheriting classes (e.g. PickPoint).
+    ):
         """
-        :param str format_string: String containing '%s' where the
-            string to geocode should be interpolated before querying the
-            geocoder. For example: '%s, Mountain View, CA'. The default
-            is just '%s'.
+        :param str format_string:
+            See :attr:`geopy.geocoders.options.default_format_string`.
 
         :param tuple view_box: Coordinates to restrict search within.
 
         :param str country_bias: Bias results to this country.
 
-        :param dict proxies: If specified, routes this geocoder's requests
-            through the specified proxy. E.g., {"https": "192.0.2.0"}. For
-            more information, see documentation on
-            :class:`urllib2.ProxyHandler`.
+        :param int timeout:
+            See :attr:`geopy.geocoders.options.default_timeout`.
+
+        :param dict proxies:
+            See :attr:`geopy.geocoders.options.default_proxies`.
 
         :param str domain: Should be the localized Openstreetmap domain to
             connect to. The default is 'nominatim.openstreetmap.org', but you
@@ -71,22 +66,25 @@ class Nominatim(Geocoder):
 
             .. versionadded:: 1.8.2
 
-        :param str scheme: Use 'https' or 'http' as the API URL's scheme.
-            Default is https. Note that SSL connections' certificates are not
-            verified.
+        :param str scheme:
+            See :attr:`geopy.geocoders.options.default_scheme`.
 
             .. versionadded:: 1.8.2
 
-        :param str user_agent: Use a custom User-Agent header.
+        :param str user_agent:
+            See :attr:`geopy.geocoders.options.default_user_agent`.
 
             .. versionadded:: 1.12.0
 
         """
         super(Nominatim, self).__init__(
-            format_string, scheme, timeout, proxies, user_agent=user_agent
+            format_string=format_string,
+            scheme=scheme,
+            timeout=timeout,
+            proxies=proxies,
+            user_agent=user_agent,
         )
         self.country_bias = country_bias
-        self.format_string = format_string
         self.view_box = view_box
         self.domain = domain.strip('/')
 
@@ -112,12 +110,12 @@ class Nominatim(Geocoder):
             self,
             query,
             exactly_one=True,
-            timeout=None,
+            timeout=DEFAULT_SENTINEL,
             limit=None,
             addressdetails=False,
             language=False,
             geometry=None
-    ):  # pylint: disable=R0913,W0221
+    ):
         """
         Geocode a location query.
 
@@ -230,10 +228,10 @@ class Nominatim(Geocoder):
             self,
             query,
             exactly_one=True,
-            timeout=None,
+            timeout=DEFAULT_SENTINEL,
             language=False,
             addressdetails=True
-    ):  # pylint: disable=W0221
+    ):
         """
         Returns a reverse geocoded location.
 
diff --git a/geopy/geocoders/photon.py b/geopy/geocoders/photon.py
index 40b66cd..f30beee 100644
--- a/geopy/geocoders/photon.py
+++ b/geopy/geocoders/photon.py
@@ -2,17 +2,11 @@
 :class:`.Photon` geocoder.
 """
 
-from geopy.compat import urlencode, string_compare
-from geopy.geocoders.base import (
-    Geocoder,
-    DEFAULT_FORMAT_STRING,
-    DEFAULT_TIMEOUT,
-    DEFAULT_SCHEME
-)
+from geopy.compat import string_compare, urlencode
+from geopy.geocoders.base import DEFAULT_SENTINEL, Geocoder
 from geopy.location import Location
 from geopy.util import logger
 
-
 __all__ = ("Photon", )
 
 
@@ -25,45 +19,44 @@ class Photon(Geocoder):  # pylint: disable=W0223
 
     def __init__(
             self,
-            format_string=DEFAULT_FORMAT_STRING,
-            scheme=DEFAULT_SCHEME,
-            timeout=DEFAULT_TIMEOUT,
-            proxies=None,
+            format_string=None,
+            scheme=None,
+            timeout=DEFAULT_SENTINEL,
+            proxies=DEFAULT_SENTINEL,
             domain='photon.komoot.de',
             user_agent=None,
-    ):   # pylint: disable=R0913
+    ):
         """
         Initialize a Photon/Komoot geocoder which aims to let you "search as
         you type with OpenStreetMap". No API Key is needed by this platform.
 
-        :param str format_string: String containing '%s' where
-            the string to geocode should be interpolated before querying
-            the geocoder. For example: '%s, Mountain View, CA'. The default
-            is just '%s'.
+        :param str format_string:
+            See :attr:`geopy.geocoders.options.default_format_string`.
 
-        :param str scheme: Use 'https' or 'http' as the API URL's scheme.
-            Default is https. Note that SSL connections' certificates are not
-            verified.
+        :param str scheme:
+            See :attr:`geopy.geocoders.options.default_scheme`.
 
-        :param int timeout: Time, in seconds, to wait for the geocoding service
-            to respond before raising a :class:`geopy.exc.GeocoderTimedOut`
-            exception.
+        :param int timeout:
+            See :attr:`geopy.geocoders.options.default_timeout`.
 
-        :param dict proxies: If specified, routes this geocoder's requests
-            through the specified proxy. E.g., {"https": "192.0.2.0"}. For
-            more information, see documentation on
-            :class:`urllib2.ProxyHandler`.
+        :param dict proxies:
+            See :attr:`geopy.geocoders.options.default_proxies`.
 
         :param str domain: Should be the localized Photon domain to
             connect to. The default is 'photon.komoot.de', but you
             can change it to a domain of your own.
 
-        :param str user_agent: Use a custom User-Agent header.
+        :param str user_agent:
+            See :attr:`geopy.geocoders.options.default_user_agent`.
 
             .. versionadded:: 1.12.0
         """
         super(Photon, self).__init__(
-            format_string, scheme, timeout, proxies, user_agent=user_agent
+            format_string=format_string,
+            scheme=scheme,
+            timeout=timeout,
+            proxies=proxies,
+            user_agent=user_agent,
         )
         self.domain = domain.strip('/')
         self.api = "%s://%s/api" % (self.scheme, self.domain)
@@ -73,12 +66,12 @@ class Photon(Geocoder):  # pylint: disable=W0223
             self,
             query,
             exactly_one=True,
-            timeout=None,
+            timeout=DEFAULT_SENTINEL,
             location_bias=None,
             language=False,
             limit=None,
             osm_tag=None
-        ):  # pylint: disable=W0221
+    ):
         """
         Geocode a location query.
 
@@ -149,10 +142,10 @@ class Photon(Geocoder):  # pylint: disable=W0223
             self,
             query,
             exactly_one=True,
-            timeout=None,
+            timeout=DEFAULT_SENTINEL,
             language=False,
             limit=None,
-        ):  # pylint: disable=W0221
+    ):
         """
         Returns a reverse geocoded location.
 
diff --git a/geopy/geocoders/pickpoint.py b/geopy/geocoders/pickpoint.py
index 52a12bb..0da392f 100644
--- a/geopy/geocoders/pickpoint.py
+++ b/geopy/geocoders/pickpoint.py
@@ -4,12 +4,7 @@ PickPoint geocoder
 
 from geopy.compat import urlencode
 from geopy.geocoders import Nominatim
-
-from geopy.geocoders.base import (
-    DEFAULT_FORMAT_STRING,
-    DEFAULT_TIMEOUT,
-    DEFAULT_SCHEME
-)
+from geopy.geocoders.base import DEFAULT_SENTINEL
 
 __all__ = ("PickPoint",)
 
@@ -26,38 +21,42 @@ class PickPoint(Nominatim):
     def __init__(
             self,
             api_key,
-            format_string=DEFAULT_FORMAT_STRING,
+            format_string=None,
             view_box=None,
             country_bias=None,
-            timeout=DEFAULT_TIMEOUT,
-            proxies=None,
+            timeout=DEFAULT_SENTINEL,
+            proxies=DEFAULT_SENTINEL,
             domain='api.pickpoint.io',
-            scheme=DEFAULT_SCHEME,
-            user_agent=None
+            scheme=None,
+            user_agent=None,
     ):
         """
 
-        :param string api_key: PickPoint API key obtained at https://pickpoint.io.
+        :param string api_key: PickPoint API key obtained at
+            https://pickpoint.io.
 
-        :param string format_string: String containing '%s' where the
-            string to geocode should be interpolated before querying the
-            geocoder. For example: '%s, Mountain View, CA'. The default
-            is just '%s'.
+        :param str format_string:
+            See :attr:`geopy.geocoders.options.default_format_string`.
 
         :param tuple view_box: Coordinates to restrict search within.
 
         :param string country_bias: Bias results to this country.
 
-        :param int timeout: Time, in seconds, to wait for the geocoding service
-            to respond before raising a :class:`geopy.exc.GeocoderTimedOut`
-            exception.
+        :param int timeout:
+            See :attr:`geopy.geocoders.options.default_timeout`.
+
+        :param dict proxies:
+            See :attr:`geopy.geocoders.options.default_proxies`.
+
+        :param str domain: Should be the localized Openstreetmap domain to
+            connect to. The default is 'api.pickpoint.io', but you
+            can change it to a domain of your own.
 
-        :param dict proxies: If specified, routes this geocoder's requests
-            through the specified proxy. E.g., {"https": "192.0.2.0"}. For
-            more information, see documentation on
-            :class:`urllib2.ProxyHandler`.
+        :param str scheme:
+            See :attr:`geopy.geocoders.options.default_scheme`.
 
-        :param str user_agent: Use a custom User-Agent header.
+        :param str user_agent:
+            See :attr:`geopy.geocoders.options.default_user_agent`.
         """
 
         super(PickPoint, self).__init__(
diff --git a/geopy/geocoders/smartystreets.py b/geopy/geocoders/smartystreets.py
index 6dd6f37..56dea97 100644
--- a/geopy/geocoders/smartystreets.py
+++ b/geopy/geocoders/smartystreets.py
@@ -2,14 +2,12 @@
 :class:`.LiveAddress` geocoder.
 """
 
-from geopy.geocoders.base import Geocoder, DEFAULT_TIMEOUT, DEFAULT_SCHEME, \
-    DEFAULT_FORMAT_STRING
 from geopy.compat import urlencode
-from geopy.location import Location
 from geopy.exc import ConfigurationError, GeocoderQuotaExceeded
+from geopy.geocoders.base import DEFAULT_SENTINEL, Geocoder
+from geopy.location import Location
 from geopy.util import logger
 
-
 __all__ = ("LiveAddress", )
 
 
@@ -26,11 +24,11 @@ class LiveAddress(Geocoder):  # pylint: disable=W0223
             auth_id,
             auth_token,
             candidates=1,
-            scheme=DEFAULT_SCHEME,
-            timeout=DEFAULT_TIMEOUT,
-            proxies=None,
+            scheme=None,
+            timeout=DEFAULT_SENTINEL,
+            proxies=DEFAULT_SENTINEL,
             user_agent=None,
-            format_string=DEFAULT_FORMAT_STRING,
+            format_string=None,
     ):
         """
         Initialize a customized SmartyStreets LiveAddress geocoder.
@@ -45,37 +43,38 @@ class LiveAddress(Geocoder):  # pylint: disable=W0223
             number of candidate addresses to return if a valid address
             could be found.
 
-        :param str scheme: Use 'https' or 'http' as the API URL's scheme.
-            Default is https. Note that SSL connections' certificates are not
-            verified.
+        :param str scheme: Must be ``https``.
+
+            .. deprecated:: 1.14.0
+               Don't use this parameter, it's going to be removed in the
+               future versions of geopy.
 
             .. versionchanged:: 1.8.0
                LiveAddress now requires `https`. Specifying `scheme=http` will
                result in a :class:`geopy.exc.ConfigurationError`.
 
-        :param int timeout: Time, in seconds, to wait for the geocoding service
-            to respond before raising an :class:`geopy.exc.GeocoderTimedOut`
-            exception.
+        :param int timeout:
+            See :attr:`geopy.geocoders.options.default_timeout`.
 
-        :param dict proxies: If specified, routes this geocoder's requests
-            through the specified proxy. E.g., {"https": "192.0.2.0"}. For
-            more information, see documentation on
-            :class:`urllib2.ProxyHandler`.
+        :param dict proxies:
+            See :attr:`geopy.geocoders.options.default_proxies`.
 
-        :param str user_agent: Use a custom User-Agent header.
+        :param str user_agent:
+            See :attr:`geopy.geocoders.options.default_user_agent`.
 
             .. versionadded:: 1.12.0
 
-        :param str format_string: String containing '%s' where the
-            string to geocode should be interpolated before querying the
-            geocoder. For example: '%s, Mountain View, CA'. The default
-            is just '%s'.
+        :param str format_string:
+            See :attr:`geopy.geocoders.options.default_format_string`.
 
             .. versionadded:: 1.14.0
         """
         super(LiveAddress, self).__init__(
             format_string=format_string,
-            scheme=scheme,
+            # The `scheme` argument is present for the legacy reasons only.
+            # If a custom value has been passed, it should be validated.
+            # Otherwise use `https` instead of the `options.default_scheme`.
+            scheme=(scheme or 'https'),
             timeout=timeout,
             proxies=proxies,
             user_agent=user_agent,
@@ -85,12 +84,12 @@ class LiveAddress(Geocoder):  # pylint: disable=W0223
         self.auth_id = auth_id
         self.auth_token = auth_token
         if candidates:
-            if not 1 <= candidates <= 10:
+            if not (1 <= candidates <= 10):
                 raise ValueError('candidates must be between 1 and 10')
         self.candidates = candidates
         self.api = '%s://api.smartystreets.com/street-address' % self.scheme
 
-    def geocode(self, query, exactly_one=True, timeout=None):  # pylint: disable=W0221
+    def geocode(self, query, exactly_one=True, timeout=DEFAULT_SENTINEL):
         """
         Geocode a location query.
 
@@ -98,6 +97,11 @@ class LiveAddress(Geocoder):  # pylint: disable=W0223
 
         :param bool exactly_one: Return one result or a list of results, if
             available.
+
+        :param int timeout: Time, in seconds, to wait for the geocoding service
+            to respond before raising a :class:`geopy.exc.GeocoderTimedOut`
+            exception. Set this only if you wish to override, on this call
+            only, the value set during the geocoder's initialization.
         """
         url = self._compose_url(self.format_string % query)
         logger.debug("%s.geocode: %s", self.__class__.__name__, url)
diff --git a/geopy/geocoders/what3words.py b/geopy/geocoders/what3words.py
index f408a3a..e039df2 100644
--- a/geopy/geocoders/what3words.py
+++ b/geopy/geocoders/what3words.py
@@ -3,17 +3,12 @@
 """
 
 import re
+
+from geopy import exc
 from geopy.compat import urlencode
-from geopy.geocoders.base import (
-    Geocoder,
-    DEFAULT_FORMAT_STRING,
-    DEFAULT_TIMEOUT,
-    DEFAULT_SCHEME
-)
+from geopy.geocoders.base import DEFAULT_SENTINEL, Geocoder
 from geopy.location import Location
-from geopy.util import logger, join_filter
-from geopy import exc
-
+from geopy.util import join_filter, logger
 
 __all__ = ("What3Words", )
 
@@ -32,10 +27,10 @@ class What3Words(Geocoder):
     def __init__(
             self,
             api_key,
-            format_string=DEFAULT_FORMAT_STRING,
-            scheme=DEFAULT_SCHEME,
-            timeout=DEFAULT_TIMEOUT,
-            proxies=None,
+            format_string=None,
+            scheme=None,
+            timeout=DEFAULT_SENTINEL,
+            proxies=DEFAULT_SENTINEL,
             user_agent=None,
     ):
         """
@@ -46,33 +41,28 @@ class What3Words(Geocoder):
 
         :param str api_key: Key provided by What3Words.
 
-        :param str format_string: String containing '%s' where the
-            string to geocode should be interpolated before querying the
-            geocoder. For example: '%s, piped.gains.jungle'. The default
-            is just '%s'.
+        :param str format_string:
+            See :attr:`geopy.geocoders.options.default_format_string`.
 
-        :param str scheme: Use 'https' or 'http' as the API URL's scheme.
-            Default is https. Note that SSL connections' certificates are not
-            verified.
+        :param str scheme:
+            See :attr:`geopy.geocoders.options.default_scheme`.
 
-        :param int timeout: Time, in seconds, to wait for the geocoding service
-            to respond before raising a :class:`geopy.exc.GeocoderTimedOut`
-            exception.
+        :param int timeout:
+            See :attr:`geopy.geocoders.options.default_timeout`.
 
-        :param dict proxies: If specified, routes this geocoder's requests
-            through the specified proxy. E.g., {"https": "192.0.2.0"}. For
-            more information, see documentation on
-            :class:`urllib2.ProxyHandler`.
+        :param dict proxies:
+            See :attr:`geopy.geocoders.options.default_proxies`.
 
-        :param str user_agent: Use a custom User-Agent header.
+        :param str user_agent:
+            See :attr:`geopy.geocoders.options.default_user_agent`.
 
             .. versionadded:: 1.12.0
         """
         super(What3Words, self).__init__(
-            format_string,
-            scheme,
-            timeout,
-            proxies,
+            format_string=format_string,
+            scheme=scheme,
+            timeout=timeout,
+            proxies=proxies,
             user_agent=user_agent,
         )
         self.api_key = api_key
@@ -94,7 +84,7 @@ class What3Words(Geocoder):
                 query,
                 lang='en',
                 exactly_one=True,
-                timeout=None):
+                timeout=DEFAULT_SENTINEL):
 
         """
         Geocode a "3 words" or "OneWord" query.
@@ -191,10 +181,10 @@ class What3Words(Geocoder):
             else:
                 raise exc.GeocoderParseError('Error parsing result.')
 
-
         return parse_resource(resources)
 
-    def reverse(self, query, lang='en', exactly_one=True, timeout=None):
+    def reverse(self, query, lang='en', exactly_one=True,
+                timeout=DEFAULT_SENTINEL):
         """
         Given a point, find the 3 word address.
 
@@ -230,7 +220,6 @@ class What3Words(Geocoder):
             self._call_geocoder(url, timeout=timeout),
         )
 
-
     @staticmethod
     def _parse_reverse_json(resources):
         """
@@ -256,10 +245,3 @@ class What3Words(Geocoder):
             return Location(words, (latitude, longitude), resource)
 
         return parse_resource(resources)
-
-
-
-
-
-
-
diff --git a/geopy/geocoders/yandex.py b/geopy/geocoders/yandex.py
index f248b69..cc7f642 100644
--- a/geopy/geocoders/yandex.py
+++ b/geopy/geocoders/yandex.py
@@ -3,17 +3,11 @@
 """
 
 from geopy.compat import urlencode
-
-from geopy.geocoders.base import Geocoder, DEFAULT_TIMEOUT, DEFAULT_SCHEME, \
-    DEFAULT_FORMAT_STRING
+from geopy.exc import GeocoderParseError, GeocoderServiceError
+from geopy.geocoders.base import DEFAULT_SENTINEL, Geocoder
 from geopy.location import Location
-from geopy.exc import (
-    GeocoderServiceError,
-    GeocoderParseError
-)
 from geopy.util import logger
 
-
 __all__ = ("Yandex", )
 
 
@@ -27,11 +21,11 @@ class Yandex(Geocoder): # pylint: disable=W0223
             self,
             api_key=None,
             lang=None,
-            timeout=DEFAULT_TIMEOUT,
-            proxies=None,
+            timeout=DEFAULT_SENTINEL,
+            proxies=DEFAULT_SENTINEL,
             user_agent=None,
-            scheme=DEFAULT_SCHEME,
-            format_string=DEFAULT_FORMAT_STRING,
+            scheme=None,
+            format_string=None,
     ):
         """
         Create a Yandex-based geocoder.
@@ -47,28 +41,24 @@ class Yandex(Geocoder): # pylint: disable=W0223
         :param str lang: response locale, the following locales are
             supported: "ru_RU" (default), "uk_UA", "be_BY", "en_US", "tr_TR"
 
-        :param int timeout: Time, in seconds, to wait for the geocoding service
-            to respond before raising a :class:`geopy.exc.GeocoderTimedOut`
-            exception.
+        :param int timeout:
+            See :attr:`geopy.geocoders.options.default_timeout`.
 
-        :param dict proxies: If specified, routes this geocoder's requests
-            through the specified proxy. E.g., {"https": "192.0.2.0"}. For
-            more information, see documentation on
-            :class:`urllib2.ProxyHandler`.
+        :param dict proxies:
+            See :attr:`geopy.geocoders.options.default_proxies`.
 
-        :param str user_agent: Use a custom User-Agent header.
+        :param str user_agent:
+            See :attr:`geopy.geocoders.options.default_user_agent`.
 
             .. versionadded:: 1.12.0
 
-        :param str scheme: Use 'https' or 'http' as the API URL's scheme.
-            Default is https.
+        :param str scheme:
+            See :attr:`geopy.geocoders.options.default_scheme`.
 
             .. versionadded:: 1.14.0
 
-        :param str format_string: String containing '%s' where the
-            string to geocode should be interpolated before querying the
-            geocoder. For example: '%s, Mountain View, CA'. The default
-            is just '%s'.
+        :param str format_string:
+            See :attr:`geopy.geocoders.options.default_format_string`.
 
             .. versionadded:: 1.14.0
         """
@@ -83,7 +73,7 @@ class Yandex(Geocoder): # pylint: disable=W0223
         self.lang = lang
         self.api = '%s://geocode-maps.yandex.ru/1.x/' % self.scheme
 
-    def geocode(self, query, exactly_one=True, timeout=None): # pylint: disable=W0221
+    def geocode(self, query, exactly_one=True, timeout=DEFAULT_SENTINEL):
         """
         Geocode a location query.
 
@@ -118,8 +108,8 @@ class Yandex(Geocoder): # pylint: disable=W0223
             self,
             query,
             exactly_one=False,
-            timeout=None,
-        ):
+            timeout=DEFAULT_SENTINEL,
+    ):
         """
         Given a point, find an address.
 
@@ -133,7 +123,8 @@ class Yandex(Geocoder): # pylint: disable=W0223
 
         :param int timeout: Time, in seconds, to wait for the geocoding service
             to respond before raising a :class:`geopy.exc.GeocoderTimedOut`
-            exception.
+            exception. Set this only if you wish to override, on this call
+            only, the value set during the geocoder's initialization.
 
         """
         try:


Test patch:
diff --git a/test/geocoders/base.py b/test/geocoders/base.py
index 08493f6..1d586aa 100644
--- a/test/geocoders/base.py
+++ b/test/geocoders/base.py
@@ -1,12 +1,14 @@
 
 import unittest
 from mock import patch
+import warnings
 
-from geopy.point import Point
+import geopy.geocoders
 from geopy.exc import GeocoderNotFound
-from geopy.geocoders import get_geocoder_for_service, GoogleV3
-from geopy.geocoders.base import Geocoder, DEFAULT_TIMEOUT
-import geopy.geocoders.base
+from geopy.geocoders import GoogleV3, get_geocoder_for_service
+from geopy.geocoders.base import Geocoder
+from geopy.point import Point
+
 
 class GetGeocoderTestCase(unittest.TestCase):
 
@@ -34,28 +36,51 @@ class GeocoderTestCase(unittest.TestCase):
         cls.coordinates_str = "40.74113,-73.989656"
         cls.coordinates_address = "175 5th Avenue, NYC, USA"
 
-    def test_init(self):
-        """
-        Geocoder()
-        """
+    def test_init_with_args(self):
         format_string = '%s Los Angeles, CA USA'
         scheme = 'http'
-        timeout = DEFAULT_TIMEOUT + 1
+        timeout = 942
         proxies = {'https': '192.0.2.0'}
+        user_agent = 'test app'
+
         geocoder = Geocoder(
             format_string=format_string,
             scheme=scheme,
             timeout=timeout,
-            proxies=proxies
+            proxies=proxies,
+            user_agent=user_agent,
         )
         for attr in ('format_string', 'scheme', 'timeout', 'proxies'):
             self.assertEqual(locals()[attr], getattr(geocoder, attr))
+        self.assertEqual(user_agent, geocoder.headers['User-Agent'])
+
+    def test_init_with_defaults(self):
+        attr_to_option = {
+            'format_string': 'default_format_string',
+            'scheme': 'default_scheme',
+            'timeout': 'default_timeout',
+            'proxies': 'default_proxies',
+        }
 
+        geocoder = Geocoder()
+        for geocoder_attr, options_attr in attr_to_option.items():
+            self.assertEqual(getattr(geopy.geocoders.options, options_attr),
+                             getattr(geocoder, geocoder_attr))
+        self.assertEqual(geopy.geocoders.options.default_user_agent,
+                         geocoder.headers['User-Agent'])
+
+    @patch.object(geopy.geocoders.options, 'default_proxies', {'https': '192.0.2.0'})
+    @patch.object(geopy.geocoders.options, 'default_timeout', 10)
+    def test_init_with_none_overrides_default(self):
+        geocoder = Geocoder(proxies=None, timeout=None)
+        self.assertIsNone(geocoder.proxies)
+        self.assertIsNone(geocoder.timeout)
+
+    @patch.object(geopy.geocoders.options, 'default_user_agent', 'mocked_user_agent/0.0.0')
     def test_user_agent_default(self):
-        with patch('geopy.geocoders.base.DEFAULT_USER_AGENT', 'mocked_user_agent/0.0.0'):
-            self.assertEqual(geopy.geocoders.base.DEFAULT_USER_AGENT, 'mocked_user_agent/0.0.0')
-            geocoder = Geocoder()
-            self.assertEqual(geocoder.headers['User-Agent'], 'mocked_user_agent/0.0.0')
+        geocoder = Geocoder()
+        self.assertEqual(geocoder.headers['User-Agent'],
+                         'mocked_user_agent/0.0.0')
 
     def test_user_agent_custom(self):
         geocoder = Geocoder(
@@ -63,6 +88,29 @@ class GeocoderTestCase(unittest.TestCase):
         )
         self.assertEqual(geocoder.headers['User-Agent'], 'my_user_agent/1.0')
 
+    @patch.object(geopy.geocoders.options, 'default_timeout', 12)
+    def test_call_geocoder_timeout(self):
+        url = 'spam://ham/eggs'
+
+        g = Geocoder()
+        self.assertEqual(g.timeout, 12)
+
+        with patch.object(g, 'urlopen') as mock_urlopen:
+            g._call_geocoder(url, raw=True)
+            args, kwargs = mock_urlopen.call_args
+            self.assertEqual(kwargs['timeout'], 12)
+
+            g._call_geocoder(url, timeout=7, raw=True)
+            args, kwargs = mock_urlopen.call_args
+            self.assertEqual(kwargs['timeout'], 7)
+
+            with warnings.catch_warnings(record=True) as w:
+                warnings.simplefilter('always')
+                g._call_geocoder(url, timeout=None, raw=True)
+                args, kwargs = mock_urlopen.call_args
+                self.assertEqual(kwargs['timeout'], 12)
+                self.assertEqual(1, len(w))
+
     def test_point_coercion_point(self):
         """
         Geocoder._coerce_point_to_string Point
diff --git a/test/geocoders/nominatim.py b/test/geocoders/nominatim.py
index c2718cf..5a0b6d6 100644
--- a/test/geocoders/nominatim.py
+++ b/test/geocoders/nominatim.py
@@ -1,7 +1,9 @@
 from mock import patch
+
+import geopy.geocoders
 from geopy.compat import u
-from geopy.point import Point
 from geopy.geocoders import Nominatim
+from geopy.point import Point
 from test.geocoders.util import GeocoderTestBase
 
 
@@ -31,10 +33,12 @@ class NominatimTestCase(GeocoderTestBase): # pylint: disable=R0904,C0111
             {"latitude": 39.916, "longitude": 116.390},
         )
 
+    @patch.object(geopy.geocoders.options, 'default_user_agent',
+                  'mocked_user_agent/0.0.0')
     def test_user_agent_default(self):
-        with patch('geopy.geocoders.base.DEFAULT_USER_AGENT', 'mocked_user_agent/0.0.0'):
-            geocoder = Nominatim()
-            self.assertEqual(geocoder.headers['User-Agent'], 'mocked_user_agent/0.0.0')
+        geocoder = Nominatim()
+        self.assertEqual(geocoder.headers['User-Agent'],
+                         'mocked_user_agent/0.0.0')
 
     def test_user_agent_custom(self):
         geocoder = Nominatim(