Repository: scrapy/scrapy
Pull request #1601 (2015-11-15 11:35:05)

Fixed minor grammar issues.
Fixing grammar issues through http://languagetool.org.

codecov-io: ## [Current coverage][1] is `82.89%`
> Merging **#1601** into **master** will increase coverage by **+0.16%** as of [`bc9f5cc`][3]



[1]: https://codecov.io/github/scrapy/scrapy?ref=bc9f5cce67db29ba27ea8278dfb6bf35de8a8160
[2]: https://codecov.io/github/scrapy/scrapy/features/suggestions?ref=bc9f5cce67db29ba27ea8278dfb6bf35de8a8160
[3]: https://codecov.io/github/scrapy/scrapy/commit/bc9f5cce67db29ba27ea8278dfb6bf35de8a8160
[4]: https://codecov.io/github/scrapy/scrapy/compare/54216d7afe9d545031c57b5821f2c821faa2ccc3...bc9f5cce67db29ba27ea8278dfb6bf35de8a8160

> Powered by [Codecov](https://codecov.io). Updated on successful CI builds.
curita: Thanks @mvj3 for these corrections!

I think one of them (the one I commented above) isn't correct, but I'm not 100% sure, I'll need someone to verify it.

If you want you can delete that change from this pull request so we can merge the other changes sooner, and submit that particular correction in a separate pull request to discuss about it.

Patch:
diff --git a/docs/faq.rst b/docs/faq.rst
index 2e61f44ee..3d2bd8d4d 100644
--- a/docs/faq.rst
+++ b/docs/faq.rst
@@ -144,7 +144,7 @@ I get "Filtered offsite request" messages. How can I fix them?
 Those messages (logged with ``DEBUG`` level) don't necessarily mean there is a
 problem, so you may not need to fix them.
 
-Those message are thrown by the Offsite Spider Middleware, which is a spider
+Those messages are thrown by the Offsite Spider Middleware, which is a spider
 middleware (enabled by default) whose purpose is to filter out requests to
 domains outside the ones covered by the spider.
 
diff --git a/docs/topics/broad-crawls.rst b/docs/topics/broad-crawls.rst
index aaf46bc92..79f0b3b53 100644
--- a/docs/topics/broad-crawls.rst
+++ b/docs/topics/broad-crawls.rst
@@ -34,7 +34,7 @@ These are some common properties often found in broad crawls:
 
 As said above, Scrapy default settings are optimized for focused crawls, not
 broad crawls. However, due to its asynchronous architecture, Scrapy is very
-well suited for performing fast broad crawls. This page summarize some things
+well suited for performing fast broad crawls. This page summarizes some things
 you need to keep in mind when using Scrapy for doing broad crawls, along with
 concrete suggestions of Scrapy settings to tune in order to achieve an
 efficient broad crawl.
@@ -46,7 +46,7 @@ Concurrency is the number of requests that are processed in parallel. There is
 a global limit and a per-domain limit.
 
 The default global concurrency limit in Scrapy is not suitable for crawling
-many different  domains in parallel, so you will want to increase it. How much
+many different domains in parallel, so you will want to increase it. How much
 to increase it will depend on how much CPU you crawler will have available. A
 good starting point is ``100``, but the best way to find out is by doing some
 trials and identifying at what concurrency your Scrapy process gets CPU
diff --git a/docs/topics/downloader-middleware.rst b/docs/topics/downloader-middleware.rst
index cc0254d29..08d8f3edf 100644
--- a/docs/topics/downloader-middleware.rst
+++ b/docs/topics/downloader-middleware.rst
@@ -23,22 +23,20 @@ Here's an example::
         'myproject.middlewares.CustomDownloaderMiddleware': 543,
     }
 
-The :setting:`DOWNLOADER_MIDDLEWARES` setting is merged with the
-:setting:`DOWNLOADER_MIDDLEWARES_BASE` setting defined in Scrapy (and not meant
-to be overridden) and then sorted by order to get the final sorted list of
-enabled middlewares: the first middleware is the one closer to the engine and
-the last is the one closer to the downloader.
-
-To decide which order to assign to your middleware see the
-:setting:`DOWNLOADER_MIDDLEWARES_BASE` setting and pick a value according to
+The specified :setting:`DOWNLOADER_MIDDLEWARES` setting is merged with the
+default one (i.e. it does not overwrite it) and then sorted by order to get the
+final sorted list of enabled middlewares: the first middleware is the one
+closer to the engine and the last is the one closer to the downloader.
+
+To decide which order to assign to your middleware see the default
+:setting:`DOWNLOADER_MIDDLEWARES` setting and pick a value according to
 where you want to insert the middleware. The order does matter because each
 middleware performs a different action and your middleware could depend on some
 previous (or subsequent) middleware being applied.
 
-If you want to disable a built-in middleware (the ones defined in
-:setting:`DOWNLOADER_MIDDLEWARES_BASE` and enabled by default) you must define it
-in your project's :setting:`DOWNLOADER_MIDDLEWARES` setting and assign `None`
-as its value.  For example, if you want to disable the user-agent middleware::
+If you want to disable a built-in middleware you must define it in your
+project's :setting:`DOWNLOADER_MIDDLEWARES` setting and assign ``None`` as its
+value. For example, if you want to disable the user-agent middleware::
 
     DOWNLOADER_MIDDLEWARES = {
         'myproject.middlewares.CustomDownloaderMiddleware': 543,
@@ -164,7 +162,7 @@ middleware, see the :ref:`downloader middleware usage guide
 <topics-downloader-middleware>`.
 
 For a list of the components enabled by default (and their orders) see the
-:setting:`DOWNLOADER_MIDDLEWARES_BASE` setting.
+:setting:`DOWNLOADER_MIDDLEWARES` setting.
 
 .. _cookies-mw:
 
diff --git a/docs/topics/extensions.rst b/docs/topics/extensions.rst
index 847353868..f9e709514 100644
--- a/docs/topics/extensions.rst
+++ b/docs/topics/extensions.rst
@@ -17,7 +17,7 @@ Extensions use the :ref:`Scrapy settings <topics-settings>` to manage their
 settings, just like any other Scrapy code.
 
 It is customary for extensions to prefix their settings with their own name, to
-avoid collision with existing (and future) extensions. For example, an
+avoid collision with existing (and future) extensions. For example, a
 hypothetic extension to handle `Google Sitemaps`_ would use settings like
 `GOOGLESITEMAP_ENABLED`, `GOOGLESITEMAP_DEPTH`, and so on.
 
@@ -42,14 +42,13 @@ by a string: the full Python path to the extension's class name. For example::
 
 As you can see, the :setting:`EXTENSIONS` setting is a dict where the keys are
 the extension paths, and their values are the orders, which define the
-extension *loading* order. The :setting:`EXTENSIONS` setting is merged with the
-:setting:`EXTENSIONS_BASE` setting defined in Scrapy (and not meant to be
-overridden) and then sorted by order to get the final sorted list of enabled
-extensions.
+extension *loading* order. The specified :setting:`EXTENSIONS` setting is merged
+with the default one (i.e. it does not overwrite it) and then sorted by order
+to get the final sorted list of enabled extensions.
 
 As extensions typically do not depend on each other, their loading order is
-irrelevant in most cases. This is why the :setting:`EXTENSIONS_BASE` setting
-defines all extensions with the same order (``0``). However, this feature can
+irrelevant in most cases. This is why the default :setting:`EXTENSIONS` setting
+defines all extensions with the same order (``500``). However, this feature can
 be exploited if you need to add an extension which depends on other extensions
 already loaded.
 
@@ -64,7 +63,7 @@ Disabling an extension
 ======================
 
 In order to disable an extension that comes enabled by default (ie. those
-included in the :setting:`EXTENSIONS_BASE` setting) you must set its order to
+included in the default :setting:`EXTENSIONS` setting) you must set its order to
 ``None``. For example::
 
     EXTENSIONS = {
@@ -144,7 +143,7 @@ Here is the code of such extension::
             self.items_scraped += 1
             if self.items_scraped % self.item_count == 0:
                 logger.info("scraped %d items", self.items_scraped)
-                
+
 
 .. _topics-extensions-ref:
 
diff --git a/docs/topics/feed-exports.rst b/docs/topics/feed-exports.rst
index 03c6fb3fb..d8b8da166 100644
--- a/docs/topics/feed-exports.rst
+++ b/docs/topics/feed-exports.rst
@@ -265,16 +265,6 @@ Whether to export empty feeds (ie. feeds with no items).
 FEED_STORAGES
 -------------
 
-Default:: ``{}``
-
-A dict containing additional feed storage backends supported by your project.
-The keys are URI schemes and the values are paths to storage classes.
-
-.. setting:: FEED_STORAGES_BASE
-
-FEED_STORAGES_BASE
-------------------
-
 Default::
 
     {
@@ -285,30 +275,19 @@ Default::
         'ftp': 'scrapy.extensions.feedexport.FTPFeedStorage',
     }
 
-A dict containing the built-in feed storage backends supported by Scrapy. You
-can disable any of these backends by assigning ``None`` to their URI scheme in
-:setting:`FEED_STORAGES`. E.g., to disable the built-in FTP storage backend
-(without replacement), place this in your ``settings.py``::
+A dict containing all feed storage backends supported by your project. The keys
+are URI schemes and the values are paths to storage classes.
 
-    FEED_STORAGES = {
-        'ftp': None,
-    }
+When you set :setting:`FEED_STORAGES` manually, e.g. in your project's settings
+module, it will be merged with the default, not overwrite it. If you want to
+disable any of the default feed storage backends, you must assign ``None`` as
+their value.
 
 .. setting:: FEED_EXPORTERS
 
 FEED_EXPORTERS
 --------------
 
-Default:: ``{}``
-
-A dict containing additional exporters supported by your project. The keys are
-serialization formats and the values are paths to :ref:`Item exporter
-<topics-exporters>` classes.
-
-.. setting:: FEED_EXPORTERS_BASE
-
-FEED_EXPORTERS_BASE
--------------------
 Default::
 
     {
@@ -321,14 +300,14 @@ Default::
         'pickle': 'scrapy.exporters.PickleItemExporter',
     }
 
-A dict containing the built-in feed exporters supported by Scrapy. You can
-disable any of these exporters by assigning ``None`` to their serialization
-format in :setting:`FEED_EXPORTERS`. E.g., to disable the built-in CSV exporter
-(without replacement), place this in your ``settings.py``::
+A dict containing all feed exporters supported by your project. The keys are
+URI schemes and the values are paths to :ref:`Item exporter <topics-exporters>`
+classes.
 
-    FEED_EXPORTERS = {
-        'csv': None,
-    }
+When you set :setting:`FEED_EXPORTERS` manually, e.g. in your project's settings
+module, it will be merged with the default, not overwrite it. If you want to
+disable any of the default feed exporters, you must assign ``None`` as their
+value.
 
 .. _URI: http://en.wikipedia.org/wiki/Uniform_Resource_Identifier
 .. _Amazon S3: http://aws.amazon.com/s3/
diff --git a/docs/topics/item-pipeline.rst b/docs/topics/item-pipeline.rst
index f74400b4d..28969be61 100644
--- a/docs/topics/item-pipeline.rst
+++ b/docs/topics/item-pipeline.rst
@@ -95,7 +95,7 @@ contain a price::
 Write items to a JSON file
 --------------------------
 
-The following pipeline stores all scraped items (from all spiders) into a a
+The following pipeline stores all scraped items (from all spiders) into a
 single ``items.jl`` file, containing one item per line serialized in JSON
 format::
 
diff --git a/docs/topics/items.rst b/docs/topics/items.rst
index 21ec0ed8c..4a8f47e93 100644
--- a/docs/topics/items.rst
+++ b/docs/topics/items.rst
@@ -61,7 +61,7 @@ the example above.
 You can specify any kind of metadata for each field. There is no restriction on
 the values accepted by :class:`Field` objects. For this same
 reason, there is no reference list of all available metadata keys. Each key
-defined in :class:`Field` objects could be used by a different components, and
+defined in :class:`Field` objects could be used by a different component, and
 only those components know about it. You can also define and use any other
 :class:`Field` key in your project too, for your own needs. The main goal of
 :class:`Field` objects is to provide a way to define all field metadata in one
diff --git a/docs/topics/leaks.rst b/docs/topics/leaks.rst
index 735137ea2..92590c180 100644
--- a/docs/topics/leaks.rst
+++ b/docs/topics/leaks.rst
@@ -97,7 +97,7 @@ subclasses):
 A real example
 --------------
 
-Let's see a concrete example of an hypothetical case of memory leaks.
+Let's see a concrete example of a hypothetical case of memory leaks.
 Suppose we have some spider with a line similar to this one::
 
     return Request("http://www.somenastyspider.com/product.php?pid=%d" % product_id,
diff --git a/docs/topics/practices.rst b/docs/topics/practices.rst
index 9ae34f423..60fe2267c 100644
--- a/docs/topics/practices.rst
+++ b/docs/topics/practices.rst
@@ -228,7 +228,7 @@ with varying degrees of sophistication. Getting around those measures can be
 difficult and tricky, and may sometimes require special infrastructure. Please
 consider contacting `commercial support`_ if in doubt.
 
-Here are some tips to keep in mind when dealing with these kind of sites:
+Here are some tips to keep in mind when dealing with these kinds of sites:
 
 * rotate your user agent from a pool of well-known ones from browsers (google
   around to get a list of them)
diff --git a/docs/topics/selectors.rst b/docs/topics/selectors.rst
index 273cae0f8..8dc82dfe5 100644
--- a/docs/topics/selectors.rst
+++ b/docs/topics/selectors.rst
@@ -579,7 +579,7 @@ Built-in Selectors reference
     is used together with ``text``.
 
     If ``type`` is ``None`` and a ``response`` is passed, the selector type is
-    inferred from the response type as follow:
+    inferred from the response type as follows:
 
         * ``"html"`` for :class:`~scrapy.http.HtmlResponse` type
         * ``"xml"`` for :class:`~scrapy.http.XmlResponse` type
@@ -757,7 +757,7 @@ nodes can be accessed directly by their names::
      <Selector xpath='//link' data=u'<link xmlns="http://www.w3.org/2005/Atom'>,
      ...
 
-If you wonder why the namespace removal procedure isn't called always by default
+If you wonder why the namespace removal procedure isn't always called by default
 instead of having to call it manually, this is because of two reasons, which, in order
 of relevance, are:
 
diff --git a/docs/topics/settings.rst b/docs/topics/settings.rst
index aa0417e1a..8908fae7e 100644
--- a/docs/topics/settings.rst
+++ b/docs/topics/settings.rst
@@ -269,6 +269,11 @@ Default::
 The default headers used for Scrapy HTTP Requests. They're populated in the
 :class:`~scrapy.downloadermiddlewares.defaultheaders.DefaultHeadersMiddleware`.
 
+When you set :setting:`DEFAULT_REQUEST_HEADERS` manually, e.g. in your
+project's settings module, it will be merged with the default, not overwrite it.
+If you want to disable any of the default request headers (and not replace them)
+you must assign ``None`` as their value.
+
 .. setting:: DEPTH_LIMIT
 
 DEPTH_LIMIT
@@ -350,16 +355,6 @@ The downloader to use for crawling.
 DOWNLOADER_MIDDLEWARES
 ----------------------
 
-Default:: ``{}``
-
-A dict containing the downloader middlewares enabled in your project, and their
-orders. For more info see :ref:`topics-downloader-middleware-setting`.
-
-.. setting:: DOWNLOADER_MIDDLEWARES_BASE
-
-DOWNLOADER_MIDDLEWARES_BASE
----------------------------
-
 Default::
 
     {
@@ -380,11 +375,16 @@ Default::
         'scrapy.downloadermiddlewares.httpcache.HttpCacheMiddleware': 900,
     }
 
-A dict containing the downloader middlewares enabled by default in Scrapy. Low
-orders are closer to the engine, high orders are closer to the downloader. You
-should never modify this setting in your project, modify
-:setting:`DOWNLOADER_MIDDLEWARES` instead.  For more info see
-:ref:`topics-downloader-middleware-setting`.
+A dict containing the downloader middlewares enabled in your project, and their
+orders. Low orders are closer to the engine, high orders are closer to the
+downloader.
+
+When you set :setting:`DOWNLOADER_MIDDLEWARES` manually, e.g. in your project's
+settings module, it will be merged with the default, not overwrite it. If you
+want to disable any of the default downloader middlewares you must assign
+``None`` as their value.
+
+For more info see :ref:`topics-downloader-middleware-setting`.
 
 .. setting:: DOWNLOADER_STATS
 
@@ -425,16 +425,6 @@ spider attribute.
 DOWNLOAD_HANDLERS
 -----------------
 
-Default: ``{}``
-
-A dict containing the request downloader handlers enabled in your project.
-See :setting:`DOWNLOAD_HANDLERS_BASE` for example format.
-
-.. setting:: DOWNLOAD_HANDLERS_BASE
-
-DOWNLOAD_HANDLERS_BASE
-----------------------
-
 Default::
 
     {
@@ -446,16 +436,15 @@ Default::
     }
 
 
-A dict containing the request download handlers enabled by default in Scrapy.
-You should never modify this setting in your project, modify
-:setting:`DOWNLOAD_HANDLERS` instead.
+A dict containing the request downloader handlers enabled in your project.
 
-You can disable any of these download handlers by assigning ``None`` to their
-URI scheme in :setting:`DOWNLOAD_HANDLERS`. E.g., to disable the built-in FTP
-handler (without replacement), place this in your ``settings.py``::
+When you set :setting:`DOWNLOAD_HANDLERS` manually, e.g. in your project's
+settings module, it will be merged with the default, not overwrite it. If you
+want to disable any of the default download handlers you must assign ``None``
+as their value. For example, if you want to disable the file download handler::
 
     DOWNLOAD_HANDLERS = {
-        'ftp': None,
+        'file': None,
     }
 
 .. setting:: DOWNLOAD_TIMEOUT
@@ -555,15 +544,6 @@ to ``vi`` (on Unix systems) or the IDLE editor (on Windows).
 EXTENSIONS
 ----------
 
-Default:: ``{}``
-
-A dict containing the extensions enabled in your project, and their orders.
-
-.. setting:: EXTENSIONS_BASE
-
-EXTENSIONS_BASE
----------------
-
 Default::
 
     {
@@ -578,10 +558,15 @@ Default::
         'scrapy.extensions.throttle.AutoThrottle': 0,
     }
 
-A dict containing the extensions available by default in Scrapy, and their
-orders. This setting contains all stable built-in extensions. Keep in mind that
+A dict containing the extensions enabled in your project, and their orders. By
+default, this setting contains all stable built-in extensions. Keep in mind that
 some of them need to be enabled through a setting.
 
+When you set :setting:`EXTENSIONS` manually, e.g. in your project's settings
+module, it will be merged with the default, not overwrite it. If you want to
+disable any of the default enabled extensions you must assign ``None`` as their
+value.
+
 For more information See the :ref:`extensions user guide  <topics-extensions>`
 and the :ref:`list of available extensions <topics-extensions-ref>`.
 
@@ -604,16 +589,6 @@ Example::
        'mybot.pipelines.validate.StoreMyItem': 800,
    }
 
-.. setting:: ITEM_PIPELINES_BASE
-
-ITEM_PIPELINES_BASE
--------------------
-
-Default: ``{}``
-
-A dict containing the pipelines enabled by default in Scrapy. You should never
-modify this setting in your project, modify :setting:`ITEM_PIPELINES` instead.
-
 .. setting:: LOG_ENABLED
 
 LOG_ENABLED
@@ -903,16 +878,6 @@ The scheduler to use for crawling.
 SPIDER_CONTRACTS
 ----------------
 
-Default:: ``{}``
-
-A dict containing the spider contracts enabled in your project, used for
-testing spiders. For more info see :ref:`topics-contracts`.
-
-.. setting:: SPIDER_CONTRACTS_BASE
-
-SPIDER_CONTRACTS_BASE
----------------------
-
 Default::
 
     {
@@ -921,17 +886,13 @@ Default::
         'scrapy.contracts.default.ScrapesContract': 3,
     }
 
-A dict containing the scrapy contracts enabled by default in Scrapy. You should
-never modify this setting in your project, modify :setting:`SPIDER_CONTRACTS`
-instead. For more info see :ref:`topics-contracts`.
-
-You can disable any of these contracts by assigning ``None`` to their class
-path in :setting:`SPIDER_CONTRACTS`. E.g., to disable the built-in
-``ScrapesContract``, place this in your ``settings.py``::
+A dict containing the scrapy contracts enabled in your project, used for
+testing spiders. For more info see :ref:`topics-contracts`.
 
-    SPIDER_CONTRACTS = {
-        'scrapy.contracts.default.ScrapesContract': None,
-    }
+When you set :setting:`SPIDER_CONTRACTS` manually, e.g. in your project's
+settings module, it will be merged with the default, not overwrite it. If you
+want to disable any of the default contracts you must assign ``None`` as their
+value.
 
 .. setting:: SPIDER_LOADER_CLASS
 
@@ -948,16 +909,6 @@ The class that will be used for loading spiders, which must implement the
 SPIDER_MIDDLEWARES
 ------------------
 
-Default:: ``{}``
-
-A dict containing the spider middlewares enabled in your project, and their
-orders. For more info see :ref:`topics-spider-middleware-setting`.
-
-.. setting:: SPIDER_MIDDLEWARES_BASE
-
-SPIDER_MIDDLEWARES_BASE
------------------------
-
 Default::
 
     {
@@ -968,9 +919,14 @@ Default::
         'scrapy.spidermiddlewares.depth.DepthMiddleware': 900,
     }
 
-A dict containing the spider middlewares enabled by default in Scrapy, and
-their orders. Low orders are closer to the engine, high orders are closer to
-the spider. For more info see :ref:`topics-spider-middleware-setting`.
+A dict containing the spider middlewares enabled in your project, and their
+orders. Low orders are closer to the engine, high orders are closer to the
+spider. For more info see :ref:`topics-spider-middleware-setting`.
+
+When you set :setting:`SPIDER_MIDDLEWARES` manually, e.g. in your project's
+settings module, it will be merged with the default, not overwrite it. If you
+want to disable any of the default spider middlewares you must assign ``None``
+as their value.
 
 .. setting:: SPIDER_MODULES
 
diff --git a/docs/topics/spider-middleware.rst b/docs/topics/spider-middleware.rst
index 84daaaa55..d448801d3 100644
--- a/docs/topics/spider-middleware.rst
+++ b/docs/topics/spider-middleware.rst
@@ -24,22 +24,20 @@ Here's an example::
         'myproject.middlewares.CustomSpiderMiddleware': 543,
     }
 
-The :setting:`SPIDER_MIDDLEWARES` setting is merged with the
-:setting:`SPIDER_MIDDLEWARES_BASE` setting defined in Scrapy (and not meant to
-be overridden) and then sorted by order to get the final sorted list of enabled
-middlewares: the first middleware is the one closer to the engine and the last
-is the one closer to the spider.
-
-To decide which order to assign to your middleware see the
-:setting:`SPIDER_MIDDLEWARES_BASE` setting and pick a value according to where
+The specified :setting:`SPIDER_MIDDLEWARES` setting is merged with the default
+one (i.e. it does not overwrite it) and then sorted by order to get the final
+sorted list of enabled middlewares: the first middleware is the one closer to
+the engine and the last is the one closer to the spider.
+
+To decide which order to assign to your middleware see the default
+:setting:`SPIDER_MIDDLEWARES` setting and pick a value according to where
 you want to insert the middleware. The order does matter because each
 middleware performs a different action and your middleware could depend on some
 previous (or subsequent) middleware being applied.
 
-If you want to disable a builtin middleware (the ones defined in
-:setting:`SPIDER_MIDDLEWARES_BASE`, and enabled by default) you must define it
-in your project :setting:`SPIDER_MIDDLEWARES` setting and assign `None` as its
-value.  For example, if you want to disable the off-site middleware::
+If you want to disable a builtin middleware you must define it in your project's
+:setting:`SPIDER_MIDDLEWARES` setting and assign ``None`` as its value. For
+example, if you want to disable the off-site middleware::
 
     SPIDER_MIDDLEWARES = {
         'myproject.middlewares.CustomSpiderMiddleware': 543,
@@ -173,7 +171,7 @@ information on how to use them and how to write your own spider middleware, see
 the :ref:`spider middleware usage guide <topics-spider-middleware>`.
 
 For a list of the components enabled by default (and their orders) see the
-:setting:`SPIDER_MIDDLEWARES_BASE` setting.
+:setting:`SPIDER_MIDDLEWARES` setting.
 
 DepthMiddleware
 ---------------
diff --git a/scrapy/commands/check.py b/scrapy/commands/check.py
index b8a9ef989..a423ba2c9 100644
--- a/scrapy/commands/check.py
+++ b/scrapy/commands/check.py
@@ -58,7 +58,7 @@ class Command(ScrapyCommand):
 
     def run(self, args, opts):
         # load contracts
-        contracts = build_component_list(self.settings.getwithbase('SPIDER_CONTRACTS'))
+        contracts = build_component_list(self.settings._getcomposite('SPIDER_CONTRACTS'))
         conman = ContractsManager(load_object(c) for c in contracts)
         runner = TextTestRunner(verbosity=2 if opts.verbose else 1)
         result = TextTestResult(runner.stream, runner.descriptions, runner.verbosity)
diff --git a/scrapy/commands/crawl.py b/scrapy/commands/crawl.py
index 4b986bf9d..7f5c64c20 100644
--- a/scrapy/commands/crawl.py
+++ b/scrapy/commands/crawl.py
@@ -35,8 +35,7 @@ class Command(ScrapyCommand):
                 self.settings.set('FEED_URI', 'stdout:', priority='cmdline')
             else:
                 self.settings.set('FEED_URI', opts.output, priority='cmdline')
-            feed_exporters = without_none_values(
-                self.settings.getwithbase('FEED_EXPORTERS'))
+            feed_exporters = without_none_values(self.settings._getcomposite('FEED_EXPORTERS'))
             valid_output_formats = feed_exporters.keys()
             if not opts.output_format:
                 opts.output_format = os.path.splitext(opts.output)[1].replace(".", "")
diff --git a/scrapy/commands/runspider.py b/scrapy/commands/runspider.py
index 1da09e4da..72229bcf5 100644
--- a/scrapy/commands/runspider.py
+++ b/scrapy/commands/runspider.py
@@ -58,7 +58,7 @@ class Command(ScrapyCommand):
                 self.settings.set('FEED_URI', 'stdout:', priority='cmdline')
             else:
                 self.settings.set('FEED_URI', opts.output, priority='cmdline')
-            feed_exporters = without_none_values(self.settings.getwithbase('FEED_EXPORTERS'))
+            feed_exporters = without_none_values(self.settings._getcomposite('FEED_EXPORTERS'))
             valid_output_formats = feed_exporters.keys()
             if not opts.output_format:
                 opts.output_format = os.path.splitext(opts.output)[1].replace(".", "")
diff --git a/scrapy/core/downloader/handlers/__init__.py b/scrapy/core/downloader/handlers/__init__.py
index bc5cd742e..0e78e04f4 100644
--- a/scrapy/core/downloader/handlers/__init__.py
+++ b/scrapy/core/downloader/handlers/__init__.py
@@ -20,8 +20,7 @@ class DownloadHandlers(object):
         self._schemes = {}  # stores acceptable schemes on instancing
         self._handlers = {}  # stores instanced handlers for schemes
         self._notconfigured = {}  # remembers failed handlers
-        handlers = without_none_values(
-            crawler.settings.getwithbase('DOWNLOAD_HANDLERS'))
+        handlers = without_none_values(crawler.settings._getcomposite('DOWNLOAD_HANDLERS'))
         for scheme, clspath in six.iteritems(handlers):
             self._schemes[scheme] = clspath
 
diff --git a/scrapy/core/downloader/middleware.py b/scrapy/core/downloader/middleware.py
index c3b23e284..958113fc3 100644
--- a/scrapy/core/downloader/middleware.py
+++ b/scrapy/core/downloader/middleware.py
@@ -19,8 +19,7 @@ class DownloaderMiddlewareManager(MiddlewareManager):
 
     @classmethod
     def _get_mwlist_from_settings(cls, settings):
-        return build_component_list(
-            settings.getwithbase('DOWNLOADER_MIDDLEWARES'))
+        return build_component_list(settings._getcomposite('DOWNLOADER_MIDDLEWARES'))
 
     def _add_middleware(self, mw):
         if hasattr(mw, 'process_request'):
diff --git a/scrapy/core/spidermw.py b/scrapy/core/spidermw.py
index a206e4b0c..b5c80c350 100644
--- a/scrapy/core/spidermw.py
+++ b/scrapy/core/spidermw.py
@@ -18,7 +18,7 @@ class SpiderMiddlewareManager(MiddlewareManager):
 
     @classmethod
     def _get_mwlist_from_settings(cls, settings):
-        return build_component_list(settings.getwithbase('SPIDER_MIDDLEWARES'))
+        return build_component_list(settings._getcomposite('SPIDER_MIDDLEWARES'))
 
     def _add_middleware(self, mw):
         super(SpiderMiddlewareManager, self)._add_middleware(mw)
diff --git a/scrapy/extension.py b/scrapy/extension.py
index e39e456fa..4ceb32c68 100644
--- a/scrapy/extension.py
+++ b/scrapy/extension.py
@@ -12,4 +12,4 @@ class ExtensionManager(MiddlewareManager):
 
     @classmethod
     def _get_mwlist_from_settings(cls, settings):
-        return build_component_list(settings.getwithbase('EXTENSIONS'))
+        return build_component_list(settings._getcomposite('EXTENSIONS'))
diff --git a/scrapy/extensions/feedexport.py b/scrapy/extensions/feedexport.py
index daea551cb..1e27a1e7e 100644
--- a/scrapy/extensions/feedexport.py
+++ b/scrapy/extensions/feedexport.py
@@ -196,7 +196,7 @@ class FeedExporter(object):
         return item
 
     def _load_components(self, setting_prefix):
-        conf = without_none_values(self.settings.getwithbase(setting_prefix))
+        conf = without_none_values(self.settings._getcomposite(setting_prefix))
         d = {}
         for k, v in conf.items():
             try:
diff --git a/scrapy/http/request/form.py b/scrapy/http/request/form.py
index 4a9bd732e..a12a2fd07 100644
--- a/scrapy/http/request/form.py
+++ b/scrapy/http/request/form.py
@@ -11,7 +11,6 @@ from parsel.selector import create_root_node
 import six
 from scrapy.http.request import Request
 from scrapy.utils.python import to_bytes, is_listlike
-from scrapy.utils.response import get_base_url
 
 
 class FormRequest(Request):
@@ -45,7 +44,7 @@ class FormRequest(Request):
 
 def _get_form_url(form, url):
     if url is None:
-        return urljoin(form.base_url, form.action)
+        return form.action or form.base_url
     return urljoin(form.base_url, url)
 
 
@@ -59,7 +58,7 @@ def _urlencode(seq, enc):
 def _get_form(response, formname, formid, formnumber, formxpath):
     """Find the form element """
     text = response.body_as_unicode()
-    root = create_root_node(text, lxml.html.HTMLParser, base_url=get_base_url(response))
+    root = create_root_node(text, lxml.html.HTMLParser, base_url=response.url)
     forms = root.xpath('//form')
     if not forms:
         raise ValueError("No <form> element found in %s" % response)
diff --git a/scrapy/pipelines/__init__.py b/scrapy/pipelines/__init__.py
index 2ef8786d0..8df0d3154 100644
--- a/scrapy/pipelines/__init__.py
+++ b/scrapy/pipelines/__init__.py
@@ -13,7 +13,7 @@ class ItemPipelineManager(MiddlewareManager):
 
     @classmethod
     def _get_mwlist_from_settings(cls, settings):
-        return build_component_list(settings.getwithbase('ITEM_PIPELINES'))
+        return build_component_list(settings._getcomposite('ITEM_PIPELINES'))
 
     def _add_middleware(self, pipe):
         super(ItemPipelineManager, self)._add_middleware(pipe)
diff --git a/scrapy/settings/__init__.py b/scrapy/settings/__init__.py
index 342d2585e..13656298b 100644
--- a/scrapy/settings/__init__.py
+++ b/scrapy/settings/__init__.py
@@ -49,11 +49,14 @@ class SettingsAttribute(object):
 
     def set(self, value, priority):
         """Sets value if priority is higher or equal than current priority."""
-        if priority >= self.priority:
-            if isinstance(self.value, BaseSettings):
-                value = BaseSettings(value, priority=priority)
-            self.value = value
-            self.priority = priority
+        if isinstance(self.value, BaseSettings):
+            # Ignore self.priority if self.value has per-key priorities
+            self.value.update(value, priority)
+            self.priority = max(self.value.maxpriority(), priority)
+        else:
+            if priority >= self.priority:
+                self.value = value
+                self.priority = priority
 
     def __str__(self):
         return "<SettingsAttribute value={self.value!r} " \
@@ -90,9 +93,10 @@ class BaseSettings(MutableMapping):
         self.update(values, priority)
 
     def __getitem__(self, opt_name):
-        if opt_name not in self:
-            return None
-        return self.attributes[opt_name].value
+        value = None
+        if opt_name in self:
+            value = self.attributes[opt_name].value
+        return value
 
     def __contains__(self, name):
         return name in self.attributes
@@ -191,17 +195,25 @@ class BaseSettings(MutableMapping):
             value = json.loads(value)
         return dict(value)
 
-    def getwithbase(self, name):
-        """Get a composition of a dictionary-like setting and its `_BASE`
-        counterpart.
-
-        :param name: name of the dictionary-like setting
-        :type name: string
-        """
-        compbs = BaseSettings()
-        compbs.update(self[name + '_BASE'])
-        compbs.update(self[name])
-        return compbs
+    def _getcomposite(self, name):
+        # DO NOT USE THIS FUNCTION IN YOUR CUSTOM PROJECTS
+        # It's for internal use in the transition away from the _BASE settings
+        # and will be removed along with _BASE support in a future release
+        basename = name + "_BASE"
+        if basename in self:
+            warnings.warn('_BASE settings are deprecated.',
+                          category=ScrapyDeprecationWarning)
+            # When users defined a _BASE setting, they explicitly don't want to
+            # use any of Scrapy's defaults. Therefore, we only use these entries
+            # from self[name] (where the defaults now live) that have a priority
+            # higher than 'default'
+            compsett = BaseSettings(self[basename], priority='default')
+            for k in self[name]:
+                prio = self[name].getpriority(k)
+                if prio > get_settings_priority('default'):
+                    compsett.set(k, self[name][k], prio)
+            return compsett
+        return self[name]
 
     def getpriority(self, name):
         """
@@ -211,9 +223,10 @@ class BaseSettings(MutableMapping):
         :param name: the setting name
         :type name: string
         """
-        if name not in self:
-            return None
-        return self.attributes[name].priority
+        prio = None
+        if name in self:
+            prio = self.attributes[name].priority
+        return prio
 
     def maxpriority(self):
         """
diff --git a/scrapy/settings/default_settings.py b/scrapy/settings/default_settings.py
index 8435b0354..375efcdbb 100644
--- a/scrapy/settings/default_settings.py
+++ b/scrapy/settings/default_settings.py
@@ -63,8 +63,7 @@ DNS_TIMEOUT = 60
 
 DOWNLOAD_DELAY = 0
 
-DOWNLOAD_HANDLERS = {}
-DOWNLOAD_HANDLERS_BASE = {
+DOWNLOAD_HANDLERS = {
     'file': 'scrapy.core.downloader.handlers.file.FileDownloadHandler',
     'http': 'scrapy.core.downloader.handlers.http.HTTPDownloadHandler',
     'https': 'scrapy.core.downloader.handlers.http.HTTPDownloadHandler',
@@ -82,9 +81,7 @@ DOWNLOADER = 'scrapy.core.downloader.Downloader'
 DOWNLOADER_HTTPCLIENTFACTORY = 'scrapy.core.downloader.webclient.ScrapyHTTPClientFactory'
 DOWNLOADER_CLIENTCONTEXTFACTORY = 'scrapy.core.downloader.contextfactory.ScrapyClientContextFactory'
 
-DOWNLOADER_MIDDLEWARES = {}
-
-DOWNLOADER_MIDDLEWARES_BASE = {
+DOWNLOADER_MIDDLEWARES = {
     # Engine side
     'scrapy.downloadermiddlewares.robotstxt.RobotsTxtMiddleware': 100,
     'scrapy.downloadermiddlewares.httpauth.HttpAuthMiddleware': 300,
@@ -116,9 +113,7 @@ except KeyError:
     else:
         EDITOR = 'vi'
 
-EXTENSIONS = {}
-
-EXTENSIONS_BASE = {
+EXTENSIONS = {
     'scrapy.extensions.corestats.CoreStats': 0,
     'scrapy.extensions.telnet.TelnetConsole': 0,
     'scrapy.extensions.memusage.MemoryUsage': 0,
@@ -135,16 +130,14 @@ FEED_URI_PARAMS = None  # a function to extend uri arguments
 FEED_FORMAT = 'jsonlines'
 FEED_STORE_EMPTY = False
 FEED_EXPORT_FIELDS = None
-FEED_STORAGES = {}
-FEED_STORAGES_BASE = {
+FEED_STORAGES = {
     '': 'scrapy.extensions.feedexport.FileFeedStorage',
     'file': 'scrapy.extensions.feedexport.FileFeedStorage',
     'stdout': 'scrapy.extensions.feedexport.StdoutFeedStorage',
     's3': 'scrapy.extensions.feedexport.S3FeedStorage',
     'ftp': 'scrapy.extensions.feedexport.FTPFeedStorage',
 }
-FEED_EXPORTERS = {}
-FEED_EXPORTERS_BASE = {
+FEED_EXPORTERS = {
     'json': 'scrapy.exporters.JsonItemExporter',
     'jsonlines': 'scrapy.exporters.JsonLinesItemExporter',
     'jl': 'scrapy.exporters.JsonLinesItemExporter',
@@ -170,7 +163,6 @@ HTTPCACHE_GZIP = False
 ITEM_PROCESSOR = 'scrapy.pipelines.ItemPipelineManager'
 
 ITEM_PIPELINES = {}
-ITEM_PIPELINES_BASE = {}
 
 LOG_ENABLED = True
 LOG_ENCODING = 'utf-8'
@@ -229,9 +221,7 @@ SCHEDULER_MEMORY_QUEUE = 'scrapy.squeues.LifoMemoryQueue'
 
 SPIDER_LOADER_CLASS = 'scrapy.spiderloader.SpiderLoader'
 
-SPIDER_MIDDLEWARES = {}
-
-SPIDER_MIDDLEWARES_BASE = {
+SPIDER_MIDDLEWARES = {
     # Engine side
     'scrapy.spidermiddlewares.httperror.HttpErrorMiddleware': 50,
     'scrapy.spidermiddlewares.offsite.OffsiteMiddleware': 500,
@@ -258,8 +248,7 @@ TELNETCONSOLE_ENABLED = 1
 TELNETCONSOLE_PORT = [6023, 6073]
 TELNETCONSOLE_HOST = '127.0.0.1'
 
-SPIDER_CONTRACTS = {}
-SPIDER_CONTRACTS_BASE = {
+SPIDER_CONTRACTS = {
     'scrapy.contracts.default.UrlContract': 1,
     'scrapy.contracts.default.ReturnsContract': 2,
     'scrapy.contracts.default.ScrapesContract': 3,
diff --git a/scrapy/utils/conf.py b/scrapy/utils/conf.py
index e8af90f11..57f2b6322 100644
--- a/scrapy/utils/conf.py
+++ b/scrapy/utils/conf.py
@@ -10,7 +10,7 @@ from scrapy.utils.deprecate import update_classpath
 from scrapy.utils.python import without_none_values
 
 
-def build_component_list(compdict, custom=None, convert=update_classpath):
+def build_component_list(compdict, convert=update_classpath):
     """Compose a component list from a { class: order } dictionary."""
 
     def _check_components(complist):
@@ -34,15 +34,9 @@ def build_component_list(compdict, custom=None, convert=update_classpath):
             _check_components(compdict)
             return {convert(k): v for k, v in six.iteritems(compdict)}
 
-    # BEGIN Backwards compatibility for old (base, custom) call signature
-    if isinstance(custom, (list, tuple)):
-        _check_components(custom)
-        return type(custom)(convert(c) for c in custom)
-
-    if custom is not None:
-        compdict.update(custom)
-    # END Backwards compatibility
-
+    if isinstance(compdict, (list, tuple)):
+        _check_components(compdict)
+        return type(compdict)(convert(c) for c in compdict)
     compdict = without_none_values(_map_keys(compdict))
     return [k for k, v in sorted(six.iteritems(compdict), key=itemgetter(1))]
 


Test patch:
diff --git a/tests/test_cmdline/__init__.py b/tests/test_cmdline/__init__.py
index c2de4fbc8..5192fb0fa 100644
--- a/tests/test_cmdline/__init__.py
+++ b/tests/test_cmdline/__init__.py
@@ -1,11 +1,10 @@
-import json
 import os
-import pstats
-import shutil
-import six
-from subprocess import Popen, PIPE
+import json
 import sys
+import shutil
+import pstats
 import tempfile
+from subprocess import Popen, PIPE
 import unittest
 try:
     from cStringIO import StringIO
@@ -58,14 +57,14 @@ class CmdlineTest(unittest.TestCase):
             shutil.rmtree(path)
 
     def test_override_dict_settings(self):
-        EXT_PATH = "tests.test_cmdline.extensions.DummyExtension"
-        EXTENSIONS = {EXT_PATH: 200}
         settingsstr = self._execute('settings', '--get', 'EXTENSIONS', '-s',
-                                    'EXTENSIONS=' + json.dumps(EXTENSIONS))
+                                    ('EXTENSIONS={"tests.test_cmdline.extensions.TestExtension": '
+                                     '100, "tests.test_cmdline.extensions.DummyExtension": 200}'))
         # XXX: There's gotta be a smarter way to do this...
         self.assertNotIn("...", settingsstr)
         for char in ("'", "<", ">", 'u"'):
             settingsstr = settingsstr.replace(char, '"')
         settingsdict = json.loads(settingsstr)
-        six.assertCountEqual(self, settingsdict.keys(), EXTENSIONS.keys())
-        self.assertIn('value=200', settingsdict[EXT_PATH])
+        self.assertIn('tests.test_cmdline.extensions.DummyExtension', settingsdict)
+        self.assertIn('value=200', settingsdict['tests.test_cmdline.extensions.DummyExtension'])
+        self.assertIn('value=100', settingsdict['tests.test_cmdline.extensions.TestExtension'])
diff --git a/tests/test_http_request.py b/tests/test_http_request.py
index 60fd855dd..ff0941961 100644
--- a/tests/test_http_request.py
+++ b/tests/test_http_request.py
@@ -801,25 +801,6 @@ class FormRequestTest(RequestTest):
         self.assertEqual(fs[b'test2'], [b'val2'])
         self.assertEqual(fs[b'button1'], [b''])
 
-    def test_html_base_form_action(self):
-        response = _buildresponse(
-            """
-            <html>
-                <head>
-                    <base href="http://b.com/">
-                </head>
-                <body>
-                    <form action="test_form">
-                    </form>
-                </body>
-            </html>
-            """,
-            url='http://a.com/'
-        )
-        req = self.request_class.from_response(response)
-        self.assertEqual(req.url, 'http://b.com/test_form')
-
-
 def _buildresponse(body, **kwargs):
     kwargs.setdefault('body', body)
     kwargs.setdefault('url', 'http://example.com')
diff --git a/tests/test_settings/__init__.py b/tests/test_settings/__init__.py
index 44b9b6df3..4ef08bb0b 100644
--- a/tests/test_settings/__init__.py
+++ b/tests/test_settings/__init__.py
@@ -37,22 +37,21 @@ class SettingsAttributeTest(unittest.TestCase):
         self.assertEqual(self.attribute.value, 'value')
         self.assertEqual(self.attribute.priority, 10)
 
-    def test_overwrite_basesettings(self):
-        original_dict = {'one': 10, 'two': 20}
-        original_settings = BaseSettings(original_dict, 0)
-        attribute = SettingsAttribute(original_settings, 0)
+    def test_set_per_key_priorities(self):
+        attribute = SettingsAttribute(
+            BaseSettings({'one': 10, 'two': 20}, 0), 0)
 
-        new_dict = {'three': 11, 'four': 21}
+        new_dict = {'one': 11, 'two': 21}
         attribute.set(new_dict, 10)
-        self.assertIsInstance(attribute.value, BaseSettings)
-        six.assertCountEqual(self, attribute.value, new_dict)
-        six.assertCountEqual(self, original_settings, original_dict)
+        self.assertEqual(attribute.value['one'], 11)
+        self.assertEqual(attribute.value['two'], 21)
 
-        new_settings = BaseSettings({'five': 12}, 0)
-        attribute.set(new_settings, 0)  # Insufficient priority
-        six.assertCountEqual(self, attribute.value, new_dict)
-        attribute.set(new_settings, 10)
-        six.assertCountEqual(self, attribute.value, new_settings)
+        new_settings = BaseSettings()
+        new_settings.set('one', 12, 20)
+        new_settings.set('two', 12, 0)
+        attribute.set(new_settings, 0)
+        self.assertEqual(attribute.value['one'], 12)
+        self.assertEqual(attribute.value['two'], 21)
 
     def test_repr(self):
         self.assertEqual(repr(self.attribute),
@@ -264,15 +263,24 @@ class BaseSettingsTest(unittest.TestCase):
         self.assertEqual(settings.getpriority('key'), 99)
         self.assertEqual(settings.getpriority('nonexistentkey'), None)
 
-    def test_getwithbase(self):
-        s = BaseSettings({'TEST_BASE': BaseSettings({1: 1, 2: 2}, 'project'),
+    def test_getcomposite(self):
+        s = BaseSettings({'TEST_BASE': {1: 1, 2: 2},
                           'TEST': BaseSettings({1: 10, 3: 30}, 'default'),
-                          'HASNOBASE': BaseSettings({3: 3000}, 'default')})
-        s['TEST'].set(2, 200, 'cmdline')
-        six.assertCountEqual(self, s.getwithbase('TEST'),
-                             {1: 1, 2: 200, 3: 30})
-        six.assertCountEqual(self, s.getwithbase('HASNOBASE'), s['HASNOBASE'])
-        self.assertEqual(s.getwithbase('NONEXISTENT'), {})
+                          'HASNOBASE': BaseSettings({1: 1}, 'default')})
+        s['TEST'].set(4, 4, priority='project')
+        # When users specify a _BASE setting they explicitly don't want to use
+        # Scrapy's defaults, so we don't want to see anything that has a
+        # 'default' priority from TEST
+        cs = s._getcomposite('TEST')
+        self.assertEqual(len(cs), 3)
+        self.assertEqual(cs[1], 1)
+        self.assertEqual(cs[2], 2)
+        self.assertEqual(cs[4], 4)
+        cs = s._getcomposite('HASNOBASE')
+        self.assertEqual(len(cs), 1)
+        self.assertEqual(cs[1], 1)
+        cs = s._getcomposite('NONEXISTENT')
+        self.assertIsNone(cs)
 
     def test_maxpriority(self):
         # Empty settings should return 'default'
diff --git a/tests/test_utils_conf.py b/tests/test_utils_conf.py
index dab41ac8d..af15d3184 100644
--- a/tests/test_utils_conf.py
+++ b/tests/test_utils_conf.py
@@ -8,59 +8,46 @@ class BuildComponentListTest(unittest.TestCase):
 
     def test_build_dict(self):
         d = {'one': 1, 'two': None, 'three': 8, 'four': 4}
-        self.assertEqual(build_component_list(d, convert=lambda x: x),
+        self.assertEqual(build_component_list(d, lambda x: x),
                          ['one', 'four', 'three'])
 
-    def test_backwards_compatible_build_dict(self):
-        base = {'one': 1, 'two': 2, 'three': 3, 'five': 5, 'six': None}
-        custom = {'two': None, 'three': 8, 'four': 4}
-        self.assertEqual(build_component_list(base, custom,
-                                              convert=lambda x: x),
-                         ['one', 'four', 'five', 'three'])
-
     def test_return_list(self):
         custom = ['a', 'b', 'c']
-        self.assertEqual(build_component_list(None, custom,
-                                              convert=lambda x: x),
-                         custom)
+        self.assertEqual(build_component_list(custom, lambda x: x), custom)
 
     def test_map_dict(self):
         custom = {'one': 1, 'two': 2, 'three': 3}
-        self.assertEqual(build_component_list({}, custom,
-                                              convert=lambda x: x.upper()),
+        self.assertEqual(build_component_list(custom, lambda x: x.upper()),
                          ['ONE', 'TWO', 'THREE'])
 
     def test_map_list(self):
         custom = ['a', 'b', 'c']
-        self.assertEqual(build_component_list(None, custom,
-                                              lambda x: x.upper()),
+        self.assertEqual(build_component_list(custom, lambda x: x.upper()),
                          ['A', 'B', 'C'])
 
     def test_duplicate_components_in_dict(self):
         duplicate_dict = {'one': 1, 'two': 2, 'ONE': 4}
-        self.assertRaises(ValueError, build_component_list, {}, duplicate_dict,
-                          convert=lambda x: x.lower())
+        self.assertRaises(ValueError,
+                          build_component_list, duplicate_dict, lambda x: x.lower())
 
     def test_duplicate_components_in_list(self):
         duplicate_list = ['a', 'b', 'a']
-        self.assertRaises(ValueError, build_component_list, None,
-                          duplicate_list, convert=lambda x: x)
+        self.assertRaises(ValueError,
+                          build_component_list, duplicate_list, lambda x: x)
 
     def test_duplicate_components_in_basesettings(self):
         # Higher priority takes precedence
         duplicate_bs = BaseSettings({'one': 1, 'two': 2}, priority=0)
         duplicate_bs.set('ONE', 4, priority=10)
-        self.assertEqual(build_component_list(duplicate_bs,
-                                              convert=lambda x: x.lower()),
+        self.assertEqual(build_component_list(duplicate_bs, convert=lambda x: x.lower()),
                          ['two', 'one'])
         duplicate_bs.set('one', duplicate_bs['one'], priority=20)
-        self.assertEqual(build_component_list(duplicate_bs,
-                                              convert=lambda x: x.lower()),
+        self.assertEqual(build_component_list(duplicate_bs, convert=lambda x: x.lower()),
                          ['one', 'two'])
         # Same priority raises ValueError
         duplicate_bs.set('ONE', duplicate_bs['ONE'], priority=20)
-        self.assertRaises(ValueError, build_component_list, duplicate_bs,
-                          convert=lambda x: x.lower())
+        self.assertRaises(ValueError,
+                          build_component_list, duplicate_bs, convert=lambda x: x.lower())
 
 
 class UtilsConfTestCase(unittest.TestCase):