From 5735e93541d26ad3aef5e4fc45fa3d1c4dc0fa2a Mon Sep 17 00:00:00 2001 From: felipeboffnunes Date: Thu, 28 Jul 2022 18:37:21 -0300 Subject: [PATCH 1/4] fix_post_processing_feed_export --- scrapy/extensions/feedexport.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/scrapy/extensions/feedexport.py b/scrapy/extensions/feedexport.py index e7097b7a1..3e98a5a0b 100644 --- a/scrapy/extensions/feedexport.py +++ b/scrapy/extensions/feedexport.py @@ -350,13 +350,19 @@ class FeedExporter: return defer.DeferredList(deferred_list) if deferred_list else None def _close_slot(self, slot, spider): + + def get_file(slot_): + if isinstance(slot_.file, PostProcessingManager): + return slot_.file.file + return slot_.file + if not slot.itemcount and not slot.store_empty: # We need to call slot.storage.store nonetheless to get the file # properly closed. - return defer.maybeDeferred(slot.storage.store, slot.file) + return defer.maybeDeferred(slot.storage.store, get_file(slot)) slot.finish_exporting() logmsg = f"{slot.format} feed ({slot.itemcount} items) in: {slot.uri}" - d = defer.maybeDeferred(slot.storage.store, slot.file) + d = defer.maybeDeferred(slot.storage.store, get_file(slot)) d.addCallback( self._handle_store_success, logmsg, spider, type(slot.storage).__name__ From d599fff2b97ff96c3face707b980926b6eb48a2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1n=20Chaves?= Date: Fri, 29 Jul 2022 19:10:28 +0200 Subject: [PATCH 2/4] Test the life cycle of a storage file --- tests/test_feedexport.py | 55 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/tests/test_feedexport.py b/tests/test_feedexport.py index ecd1b59d3..a5fd1e467 100644 --- a/tests/test_feedexport.py +++ b/tests/test_feedexport.py @@ -1517,6 +1517,61 @@ class FeedExportTest(FeedExportTestBase): data = yield self.exported_data(items, settings) self.assertEqual(row['expected'], data[feed_options['format']]) + @defer.inlineCallbacks + def test_storage_file_no_postprocessing(self): + + @implementer(IFeedStorage) + class Storage: + + def __init__(self, uri, *, feed_options=None): + pass + + def open(self, spider): + Storage.open_file = tempfile.NamedTemporaryFile(prefix='feed-') + return Storage.open_file + + def store(self, file): + Storage.store_file = file + file.close() + + settings = { + 'FEEDS': {self._random_temp_filename(): {'format': 'jsonlines'}}, + 'FEED_STORAGES': {'file': Storage}, + } + yield self.exported_no_data(settings) + self.assertIs(Storage.open_file, Storage.store_file) + + @defer.inlineCallbacks + def test_storage_file_postprocessing(self): + + @implementer(IFeedStorage) + class Storage: + + def __init__(self, uri, *, feed_options=None): + pass + + def open(self, spider): + Storage.open_file = tempfile.NamedTemporaryFile(prefix='feed-') + return Storage.open_file + + def store(self, file): + Storage.store_file = file + file.close() + + settings = { + 'FEEDS': { + self._random_temp_filename(): { + 'format': 'jsonlines', + 'postprocessing': [ + 'scrapy.extensions.postprocessing.GzipPlugin', + ], + }, + }, + 'FEED_STORAGES': {'file': Storage}, + } + yield self.exported_no_data(settings) + self.assertIs(Storage.open_file, Storage.store_file) + class FeedPostProcessedExportsTest(FeedExportTestBase): __test__ = True From a0e2e36b52743c9bf1cc03408bf4eb66e68a1edc Mon Sep 17 00:00:00 2001 From: Felipe Boff Nunes Date: Thu, 6 Apr 2023 14:23:19 -0300 Subject: [PATCH 3/4] adjustments --- scrapy/extensions/feedexport.py | 2 -- tests/test_feedexport.py | 22 +++++++++------------- 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/scrapy/extensions/feedexport.py b/scrapy/extensions/feedexport.py index 67ff26764..0df32083f 100644 --- a/scrapy/extensions/feedexport.py +++ b/scrapy/extensions/feedexport.py @@ -115,7 +115,6 @@ class BlockingFeedStorage: @implementer(IFeedStorage) class StdoutFeedStorage: - def __init__(self, uri, _stdout=None, *, feed_options=None): if not _stdout: _stdout = sys.stdout.buffer @@ -384,7 +383,6 @@ class FeedExporter: return defer.DeferredList(deferred_list) if deferred_list else None def _close_slot(self, slot, spider): - def get_file(slot_): if isinstance(slot_.file, PostProcessingManager): return slot_.file.file diff --git a/tests/test_feedexport.py b/tests/test_feedexport.py index 45027171f..3124d9d67 100644 --- a/tests/test_feedexport.py +++ b/tests/test_feedexport.py @@ -1640,15 +1640,13 @@ class FeedExportTest(FeedExportTestBase): @defer.inlineCallbacks def test_storage_file_no_postprocessing(self): - @implementer(IFeedStorage) class Storage: - def __init__(self, uri, *, feed_options=None): pass def open(self, spider): - Storage.open_file = tempfile.NamedTemporaryFile(prefix='feed-') + Storage.open_file = tempfile.NamedTemporaryFile(prefix="feed-") return Storage.open_file def store(self, file): @@ -1656,23 +1654,21 @@ class FeedExportTest(FeedExportTestBase): file.close() settings = { - 'FEEDS': {self._random_temp_filename(): {'format': 'jsonlines'}}, - 'FEED_STORAGES': {'file': Storage}, + "FEEDS": {self._random_temp_filename(): {"format": "jsonlines"}}, + "FEED_STORAGES": {"file": Storage}, } yield self.exported_no_data(settings) self.assertIs(Storage.open_file, Storage.store_file) @defer.inlineCallbacks def test_storage_file_postprocessing(self): - @implementer(IFeedStorage) class Storage: - def __init__(self, uri, *, feed_options=None): pass def open(self, spider): - Storage.open_file = tempfile.NamedTemporaryFile(prefix='feed-') + Storage.open_file = tempfile.NamedTemporaryFile(prefix="feed-") return Storage.open_file def store(self, file): @@ -1680,15 +1676,15 @@ class FeedExportTest(FeedExportTestBase): file.close() settings = { - 'FEEDS': { + "FEEDS": { self._random_temp_filename(): { - 'format': 'jsonlines', - 'postprocessing': [ - 'scrapy.extensions.postprocessing.GzipPlugin', + "format": "jsonlines", + "postprocessing": [ + "scrapy.extensions.postprocessing.GzipPlugin", ], }, }, - 'FEED_STORAGES': {'file': Storage}, + "FEED_STORAGES": {"file": Storage}, } yield self.exported_no_data(settings) self.assertIs(Storage.open_file, Storage.store_file) From 23017e6e926116162cc8fbdaf38e02670ad5d5cb Mon Sep 17 00:00:00 2001 From: Felipe Boff Nunes Date: Mon, 10 Apr 2023 12:30:00 -0300 Subject: [PATCH 4/4] adjust --- scrapy/extensions/feedexport.py | 1 + 1 file changed, 1 insertion(+) diff --git a/scrapy/extensions/feedexport.py b/scrapy/extensions/feedexport.py index 0df32083f..da1a88299 100644 --- a/scrapy/extensions/feedexport.py +++ b/scrapy/extensions/feedexport.py @@ -385,6 +385,7 @@ class FeedExporter: def _close_slot(self, slot, spider): def get_file(slot_): if isinstance(slot_.file, PostProcessingManager): + slot_.file.close() return slot_.file.file return slot_.file