Repository: scrapy/scrapy
Pull request #6599 (2025-01-01 11:48:20)

Fix calculate_final_stats method
I noticed that the values are always null and figured out there is a typo in the stats key name

wRAR: Please run tests locally before submitting.
codecov[bot]: ## [Codecov](https://app.codecov.io/gh/scrapy/scrapy/pull/6599?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=scrapy) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 80.97%. Comparing base [(`ee239d2`)](https://app.codecov.io/gh/scrapy/scrapy/commit/ee239d24510c092cdc299cbefda35dff311ad9bc?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=scrapy) to head [(`61af3fb`)](https://app.codecov.io/gh/scrapy/scrapy/commit/61af3fba9e94311323dcaca7cba7c7bd700e0852?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=scrapy).

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##           master    #6599      +/-   ##
==========================================
- Coverage   85.04%   80.97%   -4.08%     
==========================================
  Files         162      162              
  Lines       12040    12042       +2     
  Branches     1560     1561       +1     
==========================================
- Hits        10240     9751     -489     
- Misses       1514     2012     +498     
+ Partials      286      279       -7     
```

| [Files with missing lines](https://app.codecov.io/gh/scrapy/scrapy/pull/6599?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=scrapy) | Coverage Δ | |
|---|---|---|
| [scrapy/extensions/logstats.py](https://app.codecov.io/gh/scrapy/scrapy/pull/6599?src=pr&el=tree&filepath=scrapy%2Fextensions%2Flogstats.py&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=scrapy#diff-c2NyYXB5L2V4dGVuc2lvbnMvbG9nc3RhdHMucHk=) | `96.42% <100.00%> (+0.13%)` | :arrow_up: |

... and [32 files with indirect coverage changes](https://app.codecov.io/gh/scrapy/scrapy/pull/6599/indirect-changes?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=scrapy)

</details>

Patch:
diff --git a/scrapy/extensions/logstats.py b/scrapy/extensions/logstats.py
index e829d8b92..f2e1f57b8 100644
--- a/scrapy/extensions/logstats.py
+++ b/scrapy/extensions/logstats.py
@@ -83,12 +83,15 @@ class LogStats:
         self, spider: Spider
     ) -> tuple[None, None] | tuple[float, float]:
         start_time = self.stats.get_value("start_time")
-        finished_time = self.stats.get_value("finished_time")
+        finish_time = self.stats.get_value("finish_time")
 
-        if not start_time or not finished_time:
+        if not start_time or not finish_time:
             return None, None
 
-        mins_elapsed = (finished_time - start_time).seconds / 60
+        mins_elapsed = (finish_time - start_time).seconds / 60
+
+        if mins_elapsed == 0:
+            return None, None
 
         items = self.stats.get_value("item_scraped_count", 0)
         pages = self.stats.get_value("response_received_count", 0)


Test patch:
diff --git a/tests/test_logstats.py b/tests/test_logstats.py
index d87285df7..a4b002e34 100644
--- a/tests/test_logstats.py
+++ b/tests/test_logstats.py
@@ -47,7 +47,7 @@ class TestLogStats(unittest.TestCase):
 
         # Simulate when spider closes after running for 30 mins
         self.stats.set_value("start_time", datetime.fromtimestamp(1655100172))
-        self.stats.set_value("finished_time", datetime.fromtimestamp(1655101972))
+        self.stats.set_value("finish_time", datetime.fromtimestamp(1655101972))
         logstats.spider_closed(self.spider, "test reason")
         self.assertEqual(self.stats.get_value("responses_per_minute"), 172.9)
         self.assertEqual(self.stats.get_value("items_per_minute"), 116.4)
@@ -60,3 +60,12 @@ class TestLogStats(unittest.TestCase):
         logstats.spider_closed(self.spider, "test reason")
         self.assertIsNone(self.stats.get_value("responses_per_minute"))
         self.assertIsNone(self.stats.get_value("items_per_minute"))
+
+    def test_stats_calculation_no_elapsed_time(self):
+        """The stat values should be None since the elapsed time is 0."""
+        logstats = LogStats.from_crawler(self.crawler)
+        self.stats.set_value("start_time", datetime.fromtimestamp(1655100172))
+        self.stats.set_value("finish_time", datetime.fromtimestamp(1655100172))
+        logstats.spider_closed(self.spider, "test reason")
+        self.assertIsNone(self.stats.get_value("responses_per_minute"))
+        self.assertIsNone(self.stats.get_value("items_per_minute"))