Merge pull request #3671 from Gallaecio/item-deepcopy

Implement Item.deepcopy()
This commit is contained in:
Mikhail Korobov 2019-03-22 22:56:39 +05:00 committed by GitHub
commit 729580dae2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 50 additions and 10 deletions

View File

@ -40,6 +40,7 @@ objects. Here is an example::
name = scrapy.Field()
price = scrapy.Field()
stock = scrapy.Field()
tags = scrapy.Field()
last_updated = scrapy.Field(serializer=str)
.. note:: Those familiar with `Django`_ will notice that Scrapy Items are
@ -155,19 +156,42 @@ To access all populated values, just use the typical `dict API`_::
>>> product.items()
[('price', 1000), ('name', 'Desktop PC')]
Copying items
-------------
To copy an item, you must first decide whether you want a shallow copy or a
deep copy.
If your item contains mutable_ values like lists or dictionaries, a shallow
copy will keep references to the same mutable values across all different
copies.
.. _mutable: https://docs.python.org/glossary.html#term-mutable
For example, if you have an item with a list of tags, and you create a shallow
copy of that item, both the original item and the copy have the same list of
tags. Adding a tag to the list of one of the items will add the tag to the
other item as well.
If that is not the desired behavior, use a deep copy instead.
See the `documentation of the copy module`_ for more information.
.. _documentation of the copy module: https://docs.python.org/library/copy.html
To create a shallow copy of an item, you can either call
:meth:`~scrapy.item.Item.copy` on an existing item
(``product2 = product.copy()``) or instantiate your item class from an existing
item (``product2 = Product(product)``).
To create a deep copy, call :meth:`~scrapy.item.Item.deepcopy` instead
(``product2 = product.deepcopy()``).
Other common tasks
------------------
Copying items::
>>> product2 = Product(product)
>>> print(product2)
Product(name='Desktop PC', price=1000)
>>> product3 = product2.copy()
>>> print(product3)
Product(name='Desktop PC', price=1000)
Creating dicts from items::
>>> dict(product) # create a dict from all populated values

View File

@ -6,6 +6,7 @@ See documentation in docs/topics/item.rst
from pprint import pformat
from collections import MutableMapping
from copy import deepcopy
from abc import ABCMeta
import six
@ -96,6 +97,13 @@ class DictItem(MutableMapping, BaseItem):
def copy(self):
return self.__class__(self)
def deepcopy(self):
"""Return a `deep copy`_ of this item.
.. _deep copy: https://docs.python.org/library/copy.html#copy.deepcopy
"""
return deepcopy(self)
@six.add_metaclass(ItemMeta)
class Item(DictItem):

View File

@ -249,6 +249,14 @@ class ItemTest(unittest.TestCase):
copied_item['name'] = copied_item['name'].upper()
self.assertNotEqual(item['name'], copied_item['name'])
def test_deepcopy(self):
class TestItem(Item):
tags = Field()
item = TestItem({'tags': ['tag1']})
copied_item = item.deepcopy()
item['tags'].append('tag2')
assert item['tags'] != copied_item['tags']
class ItemMetaTest(unittest.TestCase):