Repository: scrapy/scrapy

Issue:
"DeprecationWarning: Use of 'SCRAPY_'-prefixed environment variables" always shows
`ScrapyDeprecationWarning: Use of 'SCRAPY_'-prefixed environment variables to override settings is deprecated.`

This deprecation warning can't be shut up inside a project.

https://github.com/scrapy/scrapy/blob/034e2c31c7d55333c3de208f80dcee1bf45ef9b9/scrapy/utils/project.py#L17-L19

This is always true, if inside a project. Because of
https://github.com/scrapy/scrapy/blob/034e2c31c7d55333c3de208f80dcee1bf45ef9b9/scrapy/utils/conf.py#L77-L84
We should probably stop "emulating" ENV vars there, and pass this somehow differently.

Additionally, the `ScrapyDeprecationWarning` for `env_overrides` is too generic: It never tells you _which_ variable(s) are actually set. This is plain annoying. Please make it more specific.


Discussion:

Resolving patch:
diff --git a/scrapy/utils/project.py b/scrapy/utils/project.py
--- a/scrapy/utils/project.py
+++ b/scrapy/utils/project.py
@@ -75,9 +75,24 @@ def get_project_settings():
                       "is deprecated.", ScrapyDeprecationWarning)
         settings.setdict(pickle.loads(pickled_settings), priority='project')
 
-    env_overrides = {k[7:]: v for k, v in os.environ.items() if
-                     k.startswith('SCRAPY_')}
-    if env_overrides:
-        warnings.warn("Use of 'SCRAPY_'-prefixed environment variables to override settings is deprecated.", ScrapyDeprecationWarning)
-        settings.setdict(env_overrides, priority='project')
+    scrapy_envvars = {k[7:]: v for k, v in os.environ.items() if
+                      k.startswith('SCRAPY_')}
+    valid_envvars = {
+        'CHECK',
+        'PICKLED_SETTINGS_TO_OVERRIDE',
+        'PROJECT',
+        'PYTHON_SHELL',
+        'SETTINGS_MODULE',
+    }
+    setting_envvars = {k for k in scrapy_envvars if k not in valid_envvars}
+    if setting_envvars:
+        setting_envvar_list = ', '.join(sorted(setting_envvars))
+        warnings.warn(
+            'Use of environment variables prefixed with SCRAPY_ to override '
+            'settings is deprecated. The following environment variables are '
+            'currently defined: {}'.format(setting_envvar_list),
+            ScrapyDeprecationWarning
+        )
+    settings.setdict(scrapy_envvars, priority='project')
+
     return settings


Test patch:
diff --git a/tests/test_utils_project.py b/tests/test_utils_project.py
--- a/tests/test_utils_project.py
+++ b/tests/test_utils_project.py
@@ -3,7 +3,11 @@
 import tempfile
 import shutil
 import contextlib
-from scrapy.utils.project import data_path
+
+from pytest import warns
+
+from scrapy.exceptions import ScrapyDeprecationWarning
+from scrapy.utils.project import data_path, get_project_settings
 
 
 @contextlib.contextmanager
@@ -41,3 +45,53 @@ def test_data_path_inside_project(self):
             )
             abspath = os.path.join(os.path.sep, 'absolute', 'path')
             self.assertEqual(abspath, data_path(abspath))
+
+
+@contextlib.contextmanager
+def set_env(**update):
+    modified = set(update.keys()) & set(os.environ.keys())
+    update_after = {k: os.environ[k] for k in modified}
+    remove_after = frozenset(k for k in update if k not in os.environ)
+    try:
+        os.environ.update(update)
+        yield
+    finally:
+        os.environ.update(update_after)
+        for k in remove_after:
+            os.environ.pop(k)
+
+
+class GetProjectSettingsTestCase(unittest.TestCase):
+
+    def test_valid_envvar(self):
+        value = 'tests.test_cmdline.settings'
+        envvars = {
+            'SCRAPY_SETTINGS_MODULE': value,
+        }
+        with set_env(**envvars), warns(None) as warnings:
+            settings = get_project_settings()
+        assert not warnings
+        assert settings.get('SETTINGS_MODULE') == value
+
+    def test_invalid_envvar(self):
+        envvars = {
+            'SCRAPY_FOO': 'bar',
+        }
+        with set_env(**envvars), warns(None) as warnings:
+            get_project_settings()
+        assert len(warnings) == 1
+        assert warnings[0].category == ScrapyDeprecationWarning
+        assert str(warnings[0].message).endswith(': FOO')
+
+    def test_valid_and_invalid_envvars(self):
+        value = 'tests.test_cmdline.settings'
+        envvars = {
+            'SCRAPY_FOO': 'bar',
+            'SCRAPY_SETTINGS_MODULE': value,
+        }
+        with set_env(**envvars), warns(None) as warnings:
+            settings = get_project_settings()
+        assert len(warnings) == 1
+        assert warnings[0].category == ScrapyDeprecationWarning
+        assert str(warnings[0].message).endswith(': FOO')
+        assert settings.get('SETTINGS_MODULE') == value