mirror of https://github.com/scrapy/scrapy.git
Add Settings.copy, freeze and frozencopy method
This commit is contained in:
parent
a995727117
commit
3ae971468f
|
|
@ -264,6 +264,30 @@ Settings API
|
|||
:param default: the value to return if no setting is found
|
||||
:type default: any
|
||||
|
||||
.. method:: copy()
|
||||
|
||||
Make a deep copy of current settings.
|
||||
|
||||
This method returns a new instance of the :class:`Settings` class,
|
||||
populated with the same values and their priorities.
|
||||
|
||||
Modifications to the new object won't be reflected on the original
|
||||
settings.
|
||||
|
||||
.. method:: freeze()
|
||||
|
||||
Disable further changes to the current settings.
|
||||
|
||||
After calling this method, the present state of the settings will become
|
||||
immutable. Trying to change values through the :meth:`~set` method and
|
||||
its variants won't be possible and will be alerted.
|
||||
|
||||
.. method:: frozencopy()
|
||||
|
||||
Return an immutable copy of the current settings.
|
||||
|
||||
Alias for a :meth:`~freeze` call in the object returned by :meth:`copy`
|
||||
|
||||
.. _topics-api-signals:
|
||||
|
||||
Signals API
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import six
|
||||
import json
|
||||
import copy
|
||||
import warnings
|
||||
from collections import MutableMapping
|
||||
from importlib import import_module
|
||||
|
|
@ -46,6 +47,7 @@ class SettingsAttribute(object):
|
|||
class Settings(object):
|
||||
|
||||
def __init__(self, values=None, priority='project'):
|
||||
self.frozen = False
|
||||
self.attributes = {}
|
||||
self.setmodule(default_settings, priority='default')
|
||||
if values is not None:
|
||||
|
|
@ -93,6 +95,7 @@ class Settings(object):
|
|||
raise ValueError("Cannot convert value for setting '%s' to dict: '%s'" % (name, value))
|
||||
|
||||
def set(self, name, value, priority='project'):
|
||||
assert not self.frozen, "Trying to modify an immutable Settings object"
|
||||
if isinstance(priority, six.string_types):
|
||||
priority = SETTINGS_PRIORITIES[priority]
|
||||
if name not in self.attributes:
|
||||
|
|
@ -101,16 +104,29 @@ class Settings(object):
|
|||
self.attributes[name].set(value, priority)
|
||||
|
||||
def setdict(self, values, priority='project'):
|
||||
assert not self.frozen, "Trying to modify an immutable Settings object"
|
||||
for name, value in six.iteritems(values):
|
||||
self.set(name, value, priority)
|
||||
|
||||
def setmodule(self, module, priority='project'):
|
||||
assert not self.frozen, "Trying to modify an immutable Settings object"
|
||||
if isinstance(module, six.string_types):
|
||||
module = import_module(module)
|
||||
for key in dir(module):
|
||||
if key.isupper():
|
||||
self.set(key, getattr(module, key), priority)
|
||||
|
||||
def copy(self):
|
||||
return copy.deepcopy(self)
|
||||
|
||||
def freeze(self):
|
||||
self.frozen = True
|
||||
|
||||
def frozencopy(self):
|
||||
copy = self.copy()
|
||||
copy.freeze()
|
||||
return copy
|
||||
|
||||
@property
|
||||
def overrides(self):
|
||||
warnings.warn("`Settings.overrides` attribute is deprecated and won't "
|
||||
|
|
|
|||
|
|
@ -190,6 +190,42 @@ class SettingsTest(unittest.TestCase):
|
|||
self.assertEqual(settings.getdict('TEST_DICT3', {'key1': 5}), {'key1': 5})
|
||||
self.assertRaises(ValueError, settings.getdict, 'TEST_LIST1')
|
||||
|
||||
def test_copy(self):
|
||||
values = {
|
||||
'TEST_BOOL': True,
|
||||
'TEST_LIST': ['one', 'two'],
|
||||
'TEST_LIST_OF_LISTS': [['first_one', 'first_two'],
|
||||
['second_one', 'second_two']]
|
||||
}
|
||||
self.settings.setdict(values)
|
||||
copy = self.settings.copy()
|
||||
self.settings.set('TEST_BOOL', False)
|
||||
self.assertTrue(copy.get('TEST_BOOL'))
|
||||
|
||||
test_list = self.settings.get('TEST_LIST')
|
||||
test_list.append('three')
|
||||
self.assertListEqual(copy.get('TEST_LIST'), ['one', 'two'])
|
||||
|
||||
test_list_of_lists = self.settings.get('TEST_LIST_OF_LISTS')
|
||||
test_list_of_lists[0].append('first_three')
|
||||
self.assertListEqual(copy.get('TEST_LIST_OF_LISTS')[0],
|
||||
['first_one', 'first_two'])
|
||||
|
||||
def test_freeze(self):
|
||||
self.settings.freeze()
|
||||
with self.assertRaises(AssertionError) as cm:
|
||||
self.settings.set('TEST_BOOL', False)
|
||||
self.assertEqual(str(cm.exception),
|
||||
"Trying to modify an immutable Settings object")
|
||||
|
||||
def test_frozencopy(self):
|
||||
with mock.patch.object(self.settings, 'copy') as mock_copy:
|
||||
with mock.patch.object(mock_copy, 'freeze') as mock_freeze:
|
||||
mock_object = self.settings.frozencopy()
|
||||
mock_copy.assert_call_once()
|
||||
mock_freeze.assert_call_once()
|
||||
self.assertEqual(mock_object, mock_copy.return_value)
|
||||
|
||||
def test_deprecated_attribute_overrides(self):
|
||||
self.settings.set('BAR', 'fuz', priority='cmdline')
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
|
|
|
|||
Loading…
Reference in New Issue