From fa03921e51609f2a3cb75ae63b47a6db0654f9f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1n=20Chaves?= Date: Fri, 8 Mar 2019 15:40:16 +0100 Subject: [PATCH] Implement Item.deepcopy() --- docs/topics/items.rst | 25 +++++++++++++++---------- scrapy/item.py | 8 ++++++++ tests/test_item.py | 8 ++++++++ 3 files changed, 31 insertions(+), 10 deletions(-) diff --git a/docs/topics/items.rst b/docs/topics/items.rst index ae44aecd3e2..ffd8b498d63 100644 --- a/docs/topics/items.rst +++ b/docs/topics/items.rst @@ -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 @@ -158,16 +159,6 @@ To access all populated values, just use the typical `dict API`_:: 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 @@ -183,6 +174,20 @@ Creating items from dicts:: ... KeyError: 'Product does not support field: lala' +To copy an item, you must first decide whether you want a shallow copy or a +deep copy. See the `documentation of the copy module`_ for information about +the differences. + +.. _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()``). + Extending Items =============== diff --git a/scrapy/item.py b/scrapy/item.py index aa05e9c691e..497d7bc4864 100644 --- a/scrapy/item.py +++ b/scrapy/item.py @@ -6,6 +6,7 @@ from pprint import pformat from collections import MutableMapping +from copy import deepcopy from abc import ABCMeta import six @@ -96,6 +97,13 @@ def __repr__(self): def copy(self): return self.__class__(self) + def deepcopy(self): + """Returns 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): diff --git a/tests/test_item.py b/tests/test_item.py index 2c1eb0dd3b6..010d3b1413a 100644 --- a/tests/test_item.py +++ b/tests/test_item.py @@ -249,6 +249,14 @@ class TestItem(Item): 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):