Refactor and improve catching warnings in tests. (#7643)

This commit is contained in:
Andrey Rakhmatullin 2026-06-20 00:04:34 +05:00 committed by GitHub
parent 6393858c7e
commit c9f952c258
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
19 changed files with 275 additions and 354 deletions

View File

@ -11,7 +11,7 @@ from typing import TYPE_CHECKING, cast
from urllib.parse import urlparse from urllib.parse import urlparse
from warnings import warn from warnings import warn
from scrapy.exceptions import NotConfigured from scrapy.exceptions import NotConfigured, ScrapyDeprecationWarning
from scrapy.http import Request, Response from scrapy.http import Request, Response
from scrapy.spidermiddlewares.base import BaseSpiderMiddleware from scrapy.spidermiddlewares.base import BaseSpiderMiddleware
from scrapy.utils.misc import load_object from scrapy.utils.misc import load_object
@ -349,7 +349,7 @@ class RefererMiddleware(BaseSpiderMiddleware):
response = kwargs.pop("resp_or_url") response = kwargs.pop("resp_or_url")
warn( warn(
"Passing 'resp_or_url' is deprecated, use 'response' instead.", "Passing 'resp_or_url' is deprecated, use 'response' instead.",
DeprecationWarning, ScrapyDeprecationWarning,
stacklevel=2, stacklevel=2,
) )
if response is None: if response is None:
@ -360,7 +360,7 @@ class RefererMiddleware(BaseSpiderMiddleware):
warn( warn(
"Passing a response URL to RefererMiddleware.policy() instead " "Passing a response URL to RefererMiddleware.policy() instead "
"of a Response object is deprecated.", "of a Response object is deprecated.",
DeprecationWarning, ScrapyDeprecationWarning,
stacklevel=2, stacklevel=2,
) )
allow_import_path = True allow_import_path = True

View File

@ -110,6 +110,7 @@ class CrawlSpider(Spider):
"deprecated: it will be removed in future Scrapy releases. " "deprecated: it will be removed in future Scrapy releases. "
"Please override the CrawlSpider.parse_with_rules method " "Please override the CrawlSpider.parse_with_rules method "
"instead.", "instead.",
ScrapyDeprecationWarning,
stacklevel=2, stacklevel=2,
) )
@ -199,6 +200,7 @@ class CrawlSpider(Spider):
"The CrawlSpider._parse_response method is deprecated: " "The CrawlSpider._parse_response method is deprecated: "
"it will be removed in future Scrapy releases. " "it will be removed in future Scrapy releases. "
"Please use the CrawlSpider.parse_with_rules method instead.", "Please use the CrawlSpider.parse_with_rules method instead.",
ScrapyDeprecationWarning,
stacklevel=2, stacklevel=2,
) )
return self.parse_with_rules(response, callback, cb_kwargs, follow) return self.parse_with_rules(response, callback, cb_kwargs, follow)

View File

@ -3,7 +3,6 @@ from __future__ import annotations
import asyncio import asyncio
import logging import logging
import re import re
import warnings
from pathlib import Path from pathlib import Path
from typing import Any, ClassVar from typing import Any, ClassVar
@ -88,9 +87,7 @@ class TestCrawler(TestBaseCrawler):
self.assertOptionIsDefault(crawler.settings, "RETRY_ENABLED") self.assertOptionIsDefault(crawler.settings, "RETRY_ENABLED")
def test_crawler_accepts_None(self) -> None: def test_crawler_accepts_None(self) -> None:
with warnings.catch_warnings(): crawler = Crawler(DefaultSpider)
warnings.simplefilter("ignore", ScrapyDeprecationWarning)
crawler = Crawler(DefaultSpider)
self.assertOptionIsDefault(crawler.settings, "RETRY_ENABLED") self.assertOptionIsDefault(crawler.settings, "RETRY_ENABLED")
def test_crawler_rejects_spider_objects(self) -> None: def test_crawler_rejects_spider_objects(self) -> None:

View File

@ -3,8 +3,8 @@ import shutil
import sys import sys
import tempfile import tempfile
from pathlib import Path from pathlib import Path
from warnings import catch_warnings
import pytest
from testfixtures import LogCapture from testfixtures import LogCapture
from scrapy.core.scheduler import Scheduler from scrapy.core.scheduler import Scheduler
@ -260,11 +260,8 @@ class TestBaseDupeFilter:
dupefilter = _get_dupefilter( dupefilter = _get_dupefilter(
settings={"DUPEFILTER_CLASS": BaseDupeFilter}, settings={"DUPEFILTER_CLASS": BaseDupeFilter},
) )
with catch_warnings(record=True) as warning_list: with pytest.warns(
ScrapyDeprecationWarning,
match=r"Calling BaseDupeFilter\.log\(\) is deprecated.",
):
dupefilter.log(None, None) dupefilter.log(None, None)
assert len(warning_list) == 1
assert (
str(warning_list[0].message)
== "Calling BaseDupeFilter.log() is deprecated."
)
assert warning_list[0].category == ScrapyDeprecationWarning

View File

@ -460,11 +460,13 @@ class TestRequest:
def test_from_curl_ignore_unknown_options(self): def test_from_curl_ignore_unknown_options(self):
# By default: it works and ignores the unknown options: --foo and -z # By default: it works and ignores the unknown options: --foo and -z
with warnings.catch_warnings(): # avoid warning when executing tests with warnings.catch_warnings(): # avoid warning when executing tests
warnings.simplefilter("ignore") warnings.filterwarnings(
"ignore", category=UserWarning, message="Unrecognized options:"
)
r = self.request_class.from_curl( r = self.request_class.from_curl(
'curl -X DELETE "http://example.org" --foo -z', 'curl -X DELETE "http://example.org" --foo -z',
) )
assert r.method == "DELETE" assert r.method == "DELETE"
# If `ignore_unknown_options` is set to `False` it raises an error with # If `ignore_unknown_options` is set to `False` it raises an error with
# the unknown options: --foo and -z # the unknown options: --foo and -z

View File

@ -4,6 +4,8 @@ import json
import warnings import warnings
from unittest import mock from unittest import mock
import pytest
from scrapy.http import JsonRequest from scrapy.http import JsonRequest
from scrapy.utils.python import to_bytes from scrapy.utils.python import to_bytes
from tests.test_http_request import TestRequest from tests.test_http_request import TestRequest
@ -63,40 +65,40 @@ class TestJsonRequest(TestRequest):
data = { data = {
"name": "value", "name": "value",
} }
with warnings.catch_warnings(record=True) as _warnings: with pytest.warns(UserWarning, match="data will be ignored"):
r5 = self.request_class(url="http://www.example.com/", body=body, data=data) r5 = self.request_class(url="http://www.example.com/", body=body, data=data)
assert r5.body == body assert r5.body == body
assert r5.method == "GET" assert r5.method == "GET"
assert len(_warnings) == 1
assert "data will be ignored" in str(_warnings[0].message)
def test_empty_body_data(self): def test_empty_body_data(self):
"""passing any body value and data should result a warning""" """passing any body value and data should result a warning"""
data = { data = {
"name": "value", "name": "value",
} }
with warnings.catch_warnings(record=True) as _warnings: with pytest.warns(UserWarning, match="data will be ignored"):
r6 = self.request_class(url="http://www.example.com/", body=b"", data=data) r6 = self.request_class(url="http://www.example.com/", body=b"", data=data)
assert r6.body == b"" assert r6.body == b""
assert r6.method == "GET" assert r6.method == "GET"
assert len(_warnings) == 1
assert "data will be ignored" in str(_warnings[0].message)
def test_body_none_data(self): def test_body_none_data(self):
data = { data = {
"name": "value", "name": "value",
} }
with warnings.catch_warnings(record=True) as _warnings: with warnings.catch_warnings():
warnings.filterwarnings(
"error", category=UserWarning, message="Both body and data passed"
)
r7 = self.request_class(url="http://www.example.com/", body=None, data=data) r7 = self.request_class(url="http://www.example.com/", body=None, data=data)
assert r7.body == to_bytes(json.dumps(data)) assert r7.body == to_bytes(json.dumps(data))
assert r7.method == "POST" assert r7.method == "POST"
assert len(_warnings) == 0
def test_body_data_none(self): def test_body_data_none(self):
with warnings.catch_warnings(record=True) as _warnings: with warnings.catch_warnings():
warnings.filterwarnings(
"error", category=UserWarning, message="Both body and data passed"
)
r8 = self.request_class(url="http://www.example.com/", body=None, data=None) r8 = self.request_class(url="http://www.example.com/", body=None, data=None)
assert r8.method == "GET" assert r8.method == "GET"
assert len(_warnings) == 0
def test_dumps_sort_keys(self): def test_dumps_sort_keys(self):
"""Test that sort_keys=True is passed to json.dumps by default""" """Test that sort_keys=True is passed to json.dumps by default"""
@ -183,8 +185,5 @@ class TestJsonRequest(TestRequest):
} }
r1 = self.request_class(url="http://www.example.com/", data=data1, body=body1) r1 = self.request_class(url="http://www.example.com/", data=data1, body=body1)
with warnings.catch_warnings(record=True) as _warnings: with pytest.warns(UserWarning, match="data will be ignored"):
r1.replace(data=data2, body=body2) r1.replace(data=data2, body=body2)
assert "Both body and data passed. data will be ignored" in str(
_warnings[0].message
)

View File

@ -2,7 +2,6 @@ import dataclasses
import os import os
import random import random
import time import time
import warnings
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from datetime import datetime from datetime import datetime
from ftplib import FTP from ftplib import FTP
@ -786,12 +785,10 @@ class TestBuildFromCrawler:
class Pipeline(FilesPipeline): class Pipeline(FilesPipeline):
pass pass
with warnings.catch_warnings(record=True) as w: pipe = Pipeline.from_crawler(self.crawler)
pipe = Pipeline.from_crawler(self.crawler) assert pipe.crawler == self.crawler
assert pipe.crawler == self.crawler assert pipe._fingerprinter
assert pipe._fingerprinter assert pipe.store
assert len(w) == 0
assert pipe.store
def test_has_from_crawler_and_init(self): def test_has_from_crawler_and_init(self):
class Pipeline(FilesPipeline): class Pipeline(FilesPipeline):
@ -805,13 +802,11 @@ class TestBuildFromCrawler:
o._from_crawler_called = True o._from_crawler_called = True
return o return o
with warnings.catch_warnings(record=True) as w: pipe = Pipeline.from_crawler(self.crawler)
pipe = Pipeline.from_crawler(self.crawler) assert pipe.crawler == self.crawler
assert pipe.crawler == self.crawler assert pipe._fingerprinter
assert pipe._fingerprinter assert pipe.store
assert len(w) == 0 assert pipe._from_crawler_called
assert pipe.store
assert pipe._from_crawler_called
@pytest.mark.parametrize("store", [None, ""]) @pytest.mark.parametrize("store", [None, ""])

View File

@ -1,6 +1,5 @@
from __future__ import annotations from __future__ import annotations
import warnings
from unittest.mock import MagicMock from unittest.mock import MagicMock
import pytest import pytest
@ -425,11 +424,9 @@ class TestBuildFromCrawler:
class Pipeline(UserDefinedPipeline): class Pipeline(UserDefinedPipeline):
pass pass
with warnings.catch_warnings(record=True) as w: pipe = Pipeline.from_crawler(self.crawler)
pipe = Pipeline.from_crawler(self.crawler) assert pipe.crawler == self.crawler
assert pipe.crawler == self.crawler assert pipe._fingerprinter
assert pipe._fingerprinter
assert len(w) == 0
def test_has_from_crawler_and_init(self): def test_has_from_crawler_and_init(self):
class Pipeline(UserDefinedPipeline): class Pipeline(UserDefinedPipeline):
@ -447,13 +444,11 @@ class TestBuildFromCrawler:
o._from_crawler_called = True o._from_crawler_called = True
return o return o
with warnings.catch_warnings(record=True) as w: pipe = Pipeline.from_crawler(self.crawler)
pipe = Pipeline.from_crawler(self.crawler) assert pipe.crawler == self.crawler
assert pipe.crawler == self.crawler assert pipe._fingerprinter
assert pipe._fingerprinter assert pipe._from_crawler_called
assert len(w) == 0 assert pipe._init_called
assert pipe._from_crawler_called
assert pipe._init_called
def test_has_from_crawler(self): def test_has_from_crawler(self):
class Pipeline(UserDefinedPipeline): class Pipeline(UserDefinedPipeline):
@ -467,13 +462,10 @@ class TestBuildFromCrawler:
o.store_uri = settings["FILES_STORE"] o.store_uri = settings["FILES_STORE"]
return o return o
with warnings.catch_warnings(record=True) as w: pipe = Pipeline.from_crawler(self.crawler)
pipe = Pipeline.from_crawler(self.crawler) assert pipe.crawler == self.crawler
# this and the next assert will fail as MediaPipeline.from_crawler() wasn't called assert pipe._fingerprinter
assert pipe.crawler == self.crawler assert pipe._from_crawler_called
assert pipe._fingerprinter
assert len(w) == 0
assert pipe._from_crawler_called
class MediaFailedFailurePipeline(MockedMediaPipeline): class MediaFailedFailurePipeline(MockedMediaPipeline):

View File

@ -12,6 +12,7 @@ import pytest
from scrapy.core.downloader import Downloader from scrapy.core.downloader import Downloader
from scrapy.core.scheduler import BaseScheduler, Scheduler from scrapy.core.scheduler import BaseScheduler, Scheduler
from scrapy.crawler import Crawler from scrapy.crawler import Crawler
from scrapy.exceptions import ScrapyDeprecationWarning
from scrapy.http import Request from scrapy.http import Request
from scrapy.spiders import Spider from scrapy.spiders import Spider
from scrapy.utils.defer import ensure_awaitable from scrapy.utils.defer import ensure_awaitable
@ -396,7 +397,11 @@ class TestIncompatibility:
def test_incompatibility(self): def test_incompatibility(self):
with warnings.catch_warnings(): with warnings.catch_warnings():
warnings.filterwarnings("ignore") warnings.filterwarnings(
"ignore",
category=ScrapyDeprecationWarning,
message="The CONCURRENT_REQUESTS_PER_IP setting is deprecated",
)
with pytest.raises( with pytest.raises(
ValueError, match="does not support CONCURRENT_REQUESTS_PER_IP" ValueError, match="does not support CONCURRENT_REQUESTS_PER_IP"
): ):

View File

@ -1,15 +1,18 @@
import warnings from __future__ import annotations
import pytest
from scrapy.exceptions import ScrapyDeprecationWarning
def test_deprecated_concurrent_requests_per_ip_attribute(): def test_deprecated_concurrent_requests_per_ip_attribute() -> None:
with warnings.catch_warnings(record=True) as warns: with pytest.warns(
ScrapyDeprecationWarning,
match=r"scrapy\.settings\.default_settings\.CONCURRENT_REQUESTS_PER_IP attribute is deprecated",
):
from scrapy.settings.default_settings import ( # noqa: PLC0415 from scrapy.settings.default_settings import ( # noqa: PLC0415
CONCURRENT_REQUESTS_PER_IP, CONCURRENT_REQUESTS_PER_IP,
) )
assert CONCURRENT_REQUESTS_PER_IP is not None assert CONCURRENT_REQUESTS_PER_IP is not None
assert isinstance(CONCURRENT_REQUESTS_PER_IP, int) assert isinstance(CONCURRENT_REQUESTS_PER_IP, int)
assert (
"The scrapy.settings.default_settings.CONCURRENT_REQUESTS_PER_IP attribute is deprecated, use scrapy.settings.default_settings.CONCURRENT_REQUESTS_PER_DOMAIN instead."
in warns[0].message.args
)

View File

@ -2,12 +2,12 @@
# (too many false positives) # (too many false positives)
import logging import logging
import warnings
from unittest import mock from unittest import mock
import pytest import pytest
from scrapy.core.downloader.handlers.file import FileDownloadHandler from scrapy.core.downloader.handlers.file import FileDownloadHandler
from scrapy.exceptions import ScrapyDeprecationWarning
from scrapy.settings import ( from scrapy.settings import (
SETTINGS_PRIORITIES, SETTINGS_PRIORITIES,
BaseSettings, BaseSettings,
@ -711,15 +711,13 @@ def test_remove_from_list(before, name, item, after):
def test_deprecated_concurrent_requests_per_ip_setting(): def test_deprecated_concurrent_requests_per_ip_setting():
with warnings.catch_warnings(record=True) as warns: settings = Settings({"CONCURRENT_REQUESTS_PER_IP": 1})
settings = Settings({"CONCURRENT_REQUESTS_PER_IP": 1}) with pytest.warns(
ScrapyDeprecationWarning,
match="The CONCURRENT_REQUESTS_PER_IP setting is deprecated",
):
settings.get("CONCURRENT_REQUESTS_PER_IP") settings.get("CONCURRENT_REQUESTS_PER_IP")
assert (
str(warns[0].message)
== "The CONCURRENT_REQUESTS_PER_IP setting is deprecated, use CONCURRENT_REQUESTS_PER_DOMAIN instead."
)
class Component1: class Component1:
pass pass

View File

@ -8,6 +8,7 @@ import pytest
from testfixtures import LogCapture from testfixtures import LogCapture
from w3lib.url import safe_url_string from w3lib.url import safe_url_string
from scrapy.exceptions import ScrapyDeprecationWarning
from scrapy.http import HtmlResponse, Request, TextResponse from scrapy.http import HtmlResponse, Request, TextResponse
from scrapy.linkextractors import LinkExtractor from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule, Spider from scrapy.spiders import CrawlSpider, Rule, Spider
@ -264,13 +265,16 @@ class TestCrawlSpider(TestSpider):
start_urls = "https://www.example.com" start_urls = "https://www.example.com"
_follow_links = False _follow_links = False
with warnings.catch_warnings(record=True) as w: with warnings.catch_warnings():
warnings.simplefilter("error", category=ScrapyDeprecationWarning)
spider = _CrawlSpider() spider = _CrawlSpider()
assert len(w) == 0 with pytest.warns(
ScrapyDeprecationWarning,
match=r"CrawlSpider\._parse_response method is deprecated",
):
spider._parse_response( spider._parse_response(
TextResponse(spider.start_urls, body=b""), None, None TextResponse(spider.start_urls, body=b""), None, None
) )
assert len(w) == 1
def test_parse_response_override(self): def test_parse_response_override(self):
class _CrawlSpider(CrawlSpider): class _CrawlSpider(CrawlSpider):
@ -281,26 +285,28 @@ class TestCrawlSpider(TestSpider):
start_urls = "https://www.example.com" start_urls = "https://www.example.com"
_follow_links = False _follow_links = False
with warnings.catch_warnings(record=True) as w: with pytest.warns(
assert len(w) == 0 ScrapyDeprecationWarning,
match=r"CrawlSpider\._parse_response method, which the",
):
spider = _CrawlSpider() spider = _CrawlSpider()
assert len(w) == 1 with warnings.catch_warnings():
warnings.simplefilter("error", category=ScrapyDeprecationWarning)
spider._parse_response( spider._parse_response(
TextResponse(spider.start_urls, body=b""), None, None TextResponse(spider.start_urls, body=b""), None, None
) )
assert len(w) == 1
def test_parse_with_rules(self): def test_parse_with_rules(self):
class _CrawlSpider(CrawlSpider): class _CrawlSpider(CrawlSpider):
name = "test" name = "test"
start_urls = "https://www.example.com" start_urls = "https://www.example.com"
with warnings.catch_warnings(record=True) as w: with warnings.catch_warnings():
warnings.simplefilter("error", category=ScrapyDeprecationWarning)
spider = _CrawlSpider() spider = _CrawlSpider()
spider.parse_with_rules( spider.parse_with_rules(
TextResponse(spider.start_urls, body=b""), None, None TextResponse(spider.start_urls, body=b""), None, None
) )
assert len(w) == 0
class TestDeprecation: class TestDeprecation:

View File

@ -1,7 +1,6 @@
import contextlib import contextlib
import shutil import shutil
import sys import sys
import warnings
from pathlib import Path from pathlib import Path
from unittest import mock from unittest import mock
@ -137,50 +136,38 @@ class TestSpiderLoader:
SpiderLoader.from_settings(settings) SpiderLoader.from_settings(settings)
def test_bad_spider_modules_warning(self): def test_bad_spider_modules_warning(self):
with warnings.catch_warnings(record=True) as w: module = "tests.test_spiderloader.test_spiders.doesnotexist"
module = "tests.test_spiderloader.test_spiders.doesnotexist" settings = Settings(
settings = Settings( {"SPIDER_MODULES": [module], "SPIDER_LOADER_WARN_ONLY": True}
{"SPIDER_MODULES": [module], "SPIDER_LOADER_WARN_ONLY": True} )
) with pytest.warns(RuntimeWarning, match="Could not load spiders from module"):
spider_loader = SpiderLoader.from_settings(settings) spider_loader = SpiderLoader.from_settings(settings)
if str(w[0].message).startswith("_SixMetaPathImporter"):
# needed on 3.10 because of https://github.com/benjaminp/six/issues/349,
# at least until all six versions we can import (including botocore.vendored.six)
# are updated to 1.16.0+
w.pop(0)
assert "Could not load spiders from module" in str(w[0].message)
spiders = spider_loader.list() spiders = spider_loader.list()
assert not spiders assert not spiders
def test_syntax_error_exception(self): def test_syntax_error_exception(self):
module = "tests.test_spiderloader.test_spiders.spider1" module = "tests.test_spiderloader.test_spiders.spider1"
settings = Settings({"SPIDER_MODULES": [module]})
with mock.patch.object(SpiderLoader, "_load_spiders") as m: with mock.patch.object(SpiderLoader, "_load_spiders") as m:
m.side_effect = SyntaxError m.side_effect = SyntaxError
settings = Settings({"SPIDER_MODULES": [module]})
with pytest.raises(SyntaxError): with pytest.raises(SyntaxError):
SpiderLoader.from_settings(settings) SpiderLoader.from_settings(settings)
def test_syntax_error_warning(self): def test_syntax_error_warning(self):
with ( module = "tests.test_spiderloader.test_spiders.spider1"
warnings.catch_warnings(record=True) as w, settings = Settings(
mock.patch.object(SpiderLoader, "_load_spiders") as m, {"SPIDER_MODULES": [module], "SPIDER_LOADER_WARN_ONLY": True}
): )
with mock.patch.object(SpiderLoader, "_load_spiders") as m:
m.side_effect = SyntaxError m.side_effect = SyntaxError
module = "tests.test_spiderloader.test_spiders.spider1" with pytest.warns(
settings = Settings( RuntimeWarning, match="Could not load spiders from module"
{"SPIDER_MODULES": [module], "SPIDER_LOADER_WARN_ONLY": True} ):
) spider_loader = SpiderLoader.from_settings(settings)
spider_loader = SpiderLoader.from_settings(settings)
if str(w[0].message).startswith("_SixMetaPathImporter"):
# needed on 3.10 because of https://github.com/benjaminp/six/issues/349,
# at least until all six versions we can import (including botocore.vendored.six)
# are updated to 1.16.0+
w.pop(0)
assert "Could not load spiders from module" in str(w[0].message)
spiders = spider_loader.list() spiders = spider_loader.list()
assert not spiders assert not spiders
class TestDuplicateSpiderNameLoader: class TestDuplicateSpiderNameLoader:
@ -190,21 +177,17 @@ class TestDuplicateSpiderNameLoader:
# copy 1 spider module so as to have duplicate spider name # copy 1 spider module so as to have duplicate spider name
shutil.copyfile(spiders_dir / "spider3.py", spiders_dir / "spider3dupe.py") shutil.copyfile(spiders_dir / "spider3.py", spiders_dir / "spider3dupe.py")
with warnings.catch_warnings(record=True) as w: msg = r"""There are several spiders with the same name:
Spider3 named 'spider3' \(in test_spiders_xxx\.spider3\)
Spider3 named 'spider3' \(in test_spiders_xxx\.spider3dupe\)
This can cause unexpected behavior\."""
with pytest.warns(UserWarning, match=msg):
spider_loader = SpiderLoader.from_settings(settings) spider_loader = SpiderLoader.from_settings(settings)
spiders = set(spider_loader.list())
assert len(w) == 1 assert spiders == {"spider1", "spider2", "spider3", "spider4"}
msg = str(w[0].message)
assert "several spiders with the same name" in msg
assert "'spider3'" in msg
assert msg.count("'spider3'") == 2
assert "'spider1'" not in msg
assert "'spider2'" not in msg
assert "'spider4'" not in msg
spiders = set(spider_loader.list())
assert spiders == {"spider1", "spider2", "spider3", "spider4"}
def test_multiple_dupename_warning(self, spider_loader_env): def test_multiple_dupename_warning(self, spider_loader_env):
settings, spiders_dir = spider_loader_env settings, spiders_dir = spider_loader_env
@ -213,23 +196,21 @@ class TestDuplicateSpiderNameLoader:
shutil.copyfile(spiders_dir / "spider1.py", spiders_dir / "spider1dupe.py") shutil.copyfile(spiders_dir / "spider1.py", spiders_dir / "spider1dupe.py")
shutil.copyfile(spiders_dir / "spider2.py", spiders_dir / "spider2dupe.py") shutil.copyfile(spiders_dir / "spider2.py", spiders_dir / "spider2dupe.py")
with warnings.catch_warnings(record=True) as w: msg = r"""There are several spiders with the same name:
Spider1 named 'spider1' \(in test_spiders_xxx\.spider1\)
Spider1 named 'spider1' \(in test_spiders_xxx\.spider1dupe\)
Spider2 named 'spider2' \(in test_spiders_xxx\.spider2\)
Spider2 named 'spider2' \(in test_spiders_xxx\.spider2dupe\)
This can cause unexpected behavior\."""
with pytest.warns(UserWarning, match=msg):
spider_loader = SpiderLoader.from_settings(settings) spider_loader = SpiderLoader.from_settings(settings)
spiders = set(spider_loader.list())
assert len(w) == 1 assert spiders == {"spider1", "spider2", "spider3", "spider4"}
msg = str(w[0].message)
assert "several spiders with the same name" in msg
assert "'spider1'" in msg
assert msg.count("'spider1'") == 2
assert "'spider2'" in msg
assert msg.count("'spider2'") == 2
assert "'spider3'" not in msg
assert "'spider4'" not in msg
spiders = set(spider_loader.list())
assert spiders == {"spider1", "spider2", "spider3", "spider4"}
class CustomSpiderLoader(SpiderLoader): class CustomSpiderLoader(SpiderLoader):

View File

@ -6,6 +6,7 @@ from urllib.parse import urlparse
import pytest import pytest
from scrapy.exceptions import ScrapyDeprecationWarning
from scrapy.http import Request, Response from scrapy.http import Request, Response
from scrapy.settings import Settings from scrapy.settings import Settings
from scrapy.spidermiddlewares.referer import ( from scrapy.spidermiddlewares.referer import (
@ -842,13 +843,14 @@ class TestRequestMetaSettingFallback:
response = Response(origin, headers=response_headers) response = Response(origin, headers=response_headers)
request = Request(target, meta=request_meta) request = Request(target, meta=request_meta)
with warnings.catch_warnings(record=True) as w: if check_warning:
with pytest.warns(
RuntimeWarning, match="Could not load referrer policy"
):
policy = mw.policy(response, request)
else:
policy = mw.policy(response, request) policy = mw.policy(response, request)
assert isinstance(policy, policy_class) assert isinstance(policy, policy_class)
if check_warning:
assert len(w) == 1
assert w[0].category is RuntimeWarning, w[0].message
class TestSettingsPolicyByName: class TestSettingsPolicyByName:
@ -973,49 +975,39 @@ class TestPolicyMethodResponseParamRename:
self.response = Response("http://www.example.com") self.response = Response("http://www.example.com")
def test_pos_string(self): def test_pos_string(self):
with warnings.catch_warnings(record=True) as w: with pytest.warns(
ScrapyDeprecationWarning,
match=r"Passing a response URL to RefererMiddleware\.policy\(\)",
):
self.mw.policy("http://old.com", self.request) self.mw.policy("http://old.com", self.request)
found = False
for warning in w:
if "Passing a response URL" in str(warning.message):
found = True
break
assert found
def test_pos_response(self): def test_pos_response(self):
with warnings.catch_warnings(record=True) as w: with warnings.catch_warnings():
warnings.filterwarnings(
"error",
category=ScrapyDeprecationWarning,
message=r"Passing 'resp_or_url' is deprecated",
)
self.mw.policy(self.response, self.request) self.mw.policy(self.response, self.request)
for warning in w:
assert "resp_or_url" not in str(warning.message)
def test_key_resp_or_url(self): def test_key_resp_or_url(self):
with warnings.catch_warnings(record=True) as w: with pytest.warns(
ScrapyDeprecationWarning, match=r"Passing 'resp_or_url' is deprecated"
):
self.mw.policy(resp_or_url=self.response, request=self.request) self.mw.policy(resp_or_url=self.response, request=self.request)
found = False
for warning in w:
if "Passing 'resp_or_url' is deprecated, use 'response' instead" in str(
warning.message
):
found = True
break
assert found
def test_key_response(self): def test_key_response(self):
with warnings.catch_warnings(record=True) as w: with warnings.catch_warnings():
warnings.filterwarnings(
"error",
category=ScrapyDeprecationWarning,
message=r"Passing 'resp_or_url' is deprecated",
)
self.mw.policy(response=self.response, request=self.request) self.mw.policy(response=self.response, request=self.request)
for warning in w:
assert "resp_or_url" not in str(warning.message)
def test_key_response_string(self): def test_key_response_string(self):
with warnings.catch_warnings(record=True) as w: with pytest.warns(ScrapyDeprecationWarning, match="Passing a response URL"):
warnings.simplefilter("always")
self.mw.policy(response="http://old.com", request=self.request) self.mw.policy(response="http://old.com", request=self.request)
found = False
for warning in w:
if "Passing a response URL" in str(warning.message):
found = True
break
assert found
def test_both_resp_or_url_and_response(self): def test_both_resp_or_url_and_response(self):
with pytest.raises( with pytest.raises(

View File

@ -213,10 +213,12 @@ class TestCurlToRequestKwargs:
def test_ignore_unknown_options(self): def test_ignore_unknown_options(self):
# case 1: ignore_unknown_options=True: # case 1: ignore_unknown_options=True:
curl_command = "curl --bar --baz http://www.example.com"
expected_result = {"method": "GET", "url": "http://www.example.com"}
with warnings.catch_warnings(): # avoid warning when executing tests with warnings.catch_warnings(): # avoid warning when executing tests
warnings.simplefilter("ignore") warnings.filterwarnings(
curl_command = "curl --bar --baz http://www.example.com" "ignore", category=UserWarning, message="Unrecognized options:"
expected_result = {"method": "GET", "url": "http://www.example.com"} )
assert curl_to_request_kwargs(curl_command) == expected_result assert curl_to_request_kwargs(curl_command) == expected_result
# case 2: ignore_unknown_options=False (raise exception): # case 2: ignore_unknown_options=False (raise exception):

View File

@ -1,5 +1,4 @@
import copy import copy
import warnings
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from collections.abc import Iterator, Mapping, MutableMapping from collections.abc import Iterator, Mapping, MutableMapping
from typing import Any from typing import Any
@ -227,18 +226,12 @@ class TestCaselessDict(TestCaseInsensitiveDictBase):
dict_class = CaselessDict dict_class = CaselessDict
def test_deprecation_message(self): def test_deprecation_message(self):
with warnings.catch_warnings(record=True) as caught: with pytest.warns(
warnings.filterwarnings("always", category=ScrapyDeprecationWarning) ScrapyDeprecationWarning,
match=r"scrapy.utils.datatypes.CaselessDict is deprecated",
):
self.dict_class({"foo": "bar"}) self.dict_class({"foo": "bar"})
assert len(caught) == 1
assert issubclass(caught[0].category, ScrapyDeprecationWarning)
assert (
str(caught[0].message)
== "scrapy.utils.datatypes.CaselessDict is deprecated,"
" please use scrapy.utils.datatypes.CaseInsensitiveDict instead"
)
class TestSequenceExclude: class TestSequenceExclude:
def test_list(self): def test_list(self):

View File

@ -1,7 +1,6 @@
import inspect import inspect
import warnings import warnings
from unittest import mock from unittest import mock
from warnings import WarningMessage
import pytest import pytest
@ -22,34 +21,26 @@ class NewName(SomeBaseClass):
class TestWarnWhenSubclassed: class TestWarnWhenSubclassed:
def _mywarnings(self, w: list[WarningMessage]) -> list[WarningMessage]:
return [x for x in w if x.category is MyWarning]
def test_no_warning_on_definition(self): def test_no_warning_on_definition(self):
with warnings.catch_warnings(record=True) as w: with warnings.catch_warnings():
warnings.simplefilter("error", category=ScrapyDeprecationWarning)
create_deprecated_class("Deprecated", NewName) create_deprecated_class("Deprecated", NewName)
w = self._mywarnings(w)
assert w == []
def test_subclassing_warning_message(self): def test_subclassing_warning_message(self):
msg = (
r"tests\.test_utils_deprecate\.UserClass inherits from "
r"deprecated class tests\.test_utils_deprecate\.Deprecated, "
r"please inherit from tests\.test_utils_deprecate\.NewName."
r" \(warning only on first subclass, there may be others\)"
)
Deprecated = create_deprecated_class( Deprecated = create_deprecated_class(
"Deprecated", NewName, warn_category=MyWarning "Deprecated", NewName, warn_category=MyWarning
) )
with pytest.warns(MyWarning, match=msg) as w:
with warnings.catch_warnings(record=True) as w:
class UserClass(Deprecated): class UserClass(Deprecated):
pass pass
w = self._mywarnings(w)
assert len(w) == 1
assert (
str(w[0].message) == "tests.test_utils_deprecate.UserClass inherits from "
"deprecated class tests.test_utils_deprecate.Deprecated, "
"please inherit from tests.test_utils_deprecate.NewName."
" (warning only on first subclass, there may be others)"
)
assert w[0].lineno == inspect.getsourcelines(UserClass)[1] assert w[0].lineno == inspect.getsourcelines(UserClass)[1]
def test_custom_class_paths(self): def test_custom_class_paths(self):
@ -61,62 +52,77 @@ class TestWarnWhenSubclassed:
warn_category=MyWarning, warn_category=MyWarning,
) )
with warnings.catch_warnings(record=True) as w: with pytest.warns(
MyWarning,
match=r"UserClass inherits from deprecated class bar\.OldClass, please inherit from foo\.NewClass",
):
class UserClass(Deprecated): class UserClass(Deprecated):
pass pass
with pytest.warns(
MyWarning,
match=r"bar\.OldClass is deprecated, instantiate foo\.NewClass instead",
):
_ = Deprecated() _ = Deprecated()
w = self._mywarnings(w)
assert len(w) == 2
assert "foo.NewClass" in str(w[0].message)
assert "bar.OldClass" in str(w[0].message)
assert "foo.NewClass" in str(w[1].message)
assert "bar.OldClass" in str(w[1].message)
def test_subclassing_warns_only_on_direct_children(self): def test_subclassing_warns_only_on_direct_children(self):
Deprecated = create_deprecated_class( Deprecated = create_deprecated_class(
"Deprecated", NewName, warn_once=False, warn_category=MyWarning "Deprecated", NewName, warn_once=False, warn_category=MyWarning
) )
with warnings.catch_warnings(record=True) as w: with pytest.warns(
MyWarning,
match="UserClass inherits from deprecated class",
):
class UserClass(Deprecated): class UserClass(Deprecated):
pass pass
with warnings.catch_warnings():
warnings.simplefilter("error", MyWarning)
class NoWarnOnMe(UserClass): class NoWarnOnMe(UserClass):
pass pass
w = self._mywarnings(w)
assert len(w) == 1
assert "UserClass" in str(w[0].message)
def test_subclassing_warns_once_by_default(self): def test_subclassing_warns_once_by_default(self):
Deprecated = create_deprecated_class( Deprecated = create_deprecated_class(
"Deprecated", NewName, warn_category=MyWarning "Deprecated", NewName, warn_category=MyWarning
) )
with warnings.catch_warnings(record=True) as w: with pytest.warns(
MyWarning,
match="UserClass inherits from deprecated class",
):
class UserClass(Deprecated): class UserClass(Deprecated):
pass pass
with warnings.catch_warnings():
warnings.simplefilter("error", MyWarning)
class FooClass(Deprecated): class FooClass(Deprecated):
pass pass
class BarClass(Deprecated): class BarClass(Deprecated):
pass pass
w = self._mywarnings(w)
assert len(w) == 1
assert "UserClass" in str(w[0].message)
def test_warning_on_instance(self): def test_warning_on_instance(self):
Deprecated = create_deprecated_class( Deprecated = create_deprecated_class(
"Deprecated", NewName, warn_category=MyWarning "Deprecated", NewName, warn_category=MyWarning
) )
with pytest.warns(MyWarning) as w:
_, lineno = Deprecated(), inspect.getlineno(inspect.currentframe())
w = [x for x in w if x.category is MyWarning]
assert len(w) == 1
assert (
str(w[0].message) == "tests.test_utils_deprecate.Deprecated is deprecated, "
"instantiate tests.test_utils_deprecate.NewName instead."
)
assert w[0].lineno == lineno
# ignore subclassing warnings # ignore subclassing warnings
with warnings.catch_warnings(): with warnings.catch_warnings():
warnings.simplefilter("ignore", MyWarning) warnings.simplefilter("ignore", MyWarning)
@ -124,29 +130,20 @@ class TestWarnWhenSubclassed:
class UserClass(Deprecated): class UserClass(Deprecated):
pass pass
with warnings.catch_warnings(record=True) as w: with warnings.catch_warnings():
_, lineno = Deprecated(), inspect.getlineno(inspect.currentframe()) warnings.simplefilter("error", MyWarning)
_ = UserClass() # subclass instances don't warn UserClass() # subclass instances don't warn
w = self._mywarnings(w)
assert len(w) == 1
assert (
str(w[0].message) == "tests.test_utils_deprecate.Deprecated is deprecated, "
"instantiate tests.test_utils_deprecate.NewName instead."
)
assert w[0].lineno == lineno
def test_warning_auto_message(self): def test_warning_auto_message(self):
with warnings.catch_warnings(record=True) as w: Deprecated = create_deprecated_class("Deprecated", NewName)
Deprecated = create_deprecated_class("Deprecated", NewName) with pytest.warns(
ScrapyDeprecationWarning,
match=r"UserClass2 inherits from deprecated class tests\.test_utils_deprecate\.Deprecated, please inherit from tests\.test_utils_deprecate\.NewName",
):
class UserClass2(Deprecated): class UserClass2(Deprecated):
pass pass
msg = str(w[0].message)
assert "tests.test_utils_deprecate.NewName" in msg
assert "tests.test_utils_deprecate.Deprecated" in msg
def test_issubclass(self): def test_issubclass(self):
with warnings.catch_warnings(): with warnings.catch_warnings():
warnings.simplefilter("ignore", ScrapyDeprecationWarning) warnings.simplefilter("ignore", ScrapyDeprecationWarning)
@ -222,8 +219,8 @@ class TestWarnWhenSubclassed:
create_deprecated_class("Deprecated", New) create_deprecated_class("Deprecated", New)
def test_deprecate_subclass_of_deprecated_class(self): def test_deprecate_subclass_of_deprecated_class(self):
with warnings.catch_warnings(record=True) as w: with warnings.catch_warnings():
warnings.simplefilter("always") warnings.simplefilter("error", MyWarning)
Deprecated = create_deprecated_class( Deprecated = create_deprecated_class(
"Deprecated", NewName, warn_category=MyWarning "Deprecated", NewName, warn_category=MyWarning
) )
@ -234,33 +231,26 @@ class TestWarnWhenSubclassed:
warn_category=MyWarning, warn_category=MyWarning,
) )
w = self._mywarnings(w) with pytest.warns(
assert len(w) == 0, [str(warning) for warning in w] MyWarning,
match=r"AlsoDeprecated is deprecated, instantiate foo\.Bar instead",
with warnings.catch_warnings(record=True) as w: ):
AlsoDeprecated() AlsoDeprecated()
with pytest.warns(
MyWarning,
match=r"UserClass inherits from deprecated class tests\.test_utils_deprecate\.AlsoDeprecated, please inherit from foo\.Bar",
):
class UserClass(AlsoDeprecated): class UserClass(AlsoDeprecated):
pass pass
w = self._mywarnings(w)
assert len(w) == 2
assert "AlsoDeprecated" in str(w[0].message)
assert "foo.Bar" in str(w[0].message)
assert "AlsoDeprecated" in str(w[1].message)
assert "foo.Bar" in str(w[1].message)
def test_inspect_stack(self): def test_inspect_stack(self):
with ( with (
mock.patch("inspect.stack", side_effect=IndexError), mock.patch("inspect.stack", side_effect=IndexError),
warnings.catch_warnings(record=True) as w, pytest.warns(UserWarning, match="Error detecting parent module"),
): ):
DeprecatedName = create_deprecated_class("DeprecatedName", NewName) create_deprecated_class("DeprecatedName", NewName)
class SubClass(DeprecatedName):
pass
assert "Error detecting parent module" in str(w[0].message)
@mock.patch( @mock.patch(
@ -272,12 +262,12 @@ class TestWarnWhenSubclassed:
) )
class TestUpdateClassPath: class TestUpdateClassPath:
def test_old_path_gets_fixed(self): def test_old_path_gets_fixed(self):
with warnings.catch_warnings(record=True) as w: with pytest.warns(
ScrapyDeprecationWarning,
match="`scrapy.contrib.debug.Debug` class is deprecated, use `scrapy.extensions.debug.Debug` instead",
):
output = update_classpath("scrapy.contrib.debug.Debug") output = update_classpath("scrapy.contrib.debug.Debug")
assert output == "scrapy.extensions.debug.Debug" assert output == "scrapy.extensions.debug.Debug"
assert len(w) == 1
assert "scrapy.contrib.debug.Debug" in str(w[0].message)
assert "scrapy.extensions.debug.Debug" in str(w[0].message)
def test_sorted_replacement(self): def test_sorted_replacement(self):
with warnings.catch_warnings(): with warnings.catch_warnings():
@ -286,10 +276,10 @@ class TestUpdateClassPath:
assert output == "scrapy.pipelines.Pipeline" assert output == "scrapy.pipelines.Pipeline"
def test_unmatched_path_stays_the_same(self): def test_unmatched_path_stays_the_same(self):
with warnings.catch_warnings(record=True) as w: with warnings.catch_warnings():
warnings.simplefilter("error", ScrapyDeprecationWarning)
output = update_classpath("scrapy.unmatched.Path") output = update_classpath("scrapy.unmatched.Path")
assert output == "scrapy.unmatched.Path" assert output == "scrapy.unmatched.Path"
assert len(w) == 0
def test_returns_nonstring(self): def test_returns_nonstring(self):
for notastring in [None, True, [1, 2, 3], object()]: for notastring in [None, True, [1, 2, 3], object()]:

View File

@ -93,29 +93,27 @@ https://example.org
assert is_generator_with_return_value(h1) assert is_generator_with_return_value(h1)
assert is_generator_with_return_value(i1) assert is_generator_with_return_value(i1)
with warnings.catch_warnings(record=True) as w: with pytest.warns(
UserWarning,
match='The "MockSpider.top_level_return_something" method is a generator',
):
warn_on_generator_with_return_value(mock_spider, top_level_return_something) warn_on_generator_with_return_value(mock_spider, top_level_return_something)
assert len(w) == 1 with pytest.warns(
assert ( UserWarning, match='The "MockSpider.f1" method is a generator'
'The "MockSpider.top_level_return_something" method is a generator' ):
in str(w[0].message)
)
with warnings.catch_warnings(record=True) as w:
warn_on_generator_with_return_value(mock_spider, f1) warn_on_generator_with_return_value(mock_spider, f1)
assert len(w) == 1 with pytest.warns(
assert 'The "MockSpider.f1" method is a generator' in str(w[0].message) UserWarning, match='The "MockSpider.g1" method is a generator'
with warnings.catch_warnings(record=True) as w: ):
warn_on_generator_with_return_value(mock_spider, g1) warn_on_generator_with_return_value(mock_spider, g1)
assert len(w) == 1 with pytest.warns(
assert 'The "MockSpider.g1" method is a generator' in str(w[0].message) UserWarning, match='The "MockSpider.h1" method is a generator'
with warnings.catch_warnings(record=True) as w: ):
warn_on_generator_with_return_value(mock_spider, h1) warn_on_generator_with_return_value(mock_spider, h1)
assert len(w) == 1 with pytest.warns(
assert 'The "MockSpider.h1" method is a generator' in str(w[0].message) UserWarning, match='The "MockSpider.i1" method is a generator'
with warnings.catch_warnings(record=True) as w: ):
warn_on_generator_with_return_value(mock_spider, i1) warn_on_generator_with_return_value(mock_spider, i1)
assert len(w) == 1
assert 'The "MockSpider.i1" method is a generator' in str(w[0].message)
def test_generators_return_none(self, mock_spider): def test_generators_return_none(self, mock_spider):
def f2(): def f2():
@ -160,32 +158,18 @@ https://example.org
assert not is_generator_with_return_value(k2) # not recursive assert not is_generator_with_return_value(k2) # not recursive
assert not is_generator_with_return_value(l2) assert not is_generator_with_return_value(l2)
with warnings.catch_warnings(record=True) as w: with warnings.catch_warnings():
warnings.simplefilter("error", UserWarning)
warn_on_generator_with_return_value(mock_spider, top_level_return_none) warn_on_generator_with_return_value(mock_spider, top_level_return_none)
assert len(w) == 0
with warnings.catch_warnings(record=True) as w:
warn_on_generator_with_return_value(mock_spider, f2) warn_on_generator_with_return_value(mock_spider, f2)
assert len(w) == 0
with warnings.catch_warnings(record=True) as w:
warn_on_generator_with_return_value(mock_spider, g2) warn_on_generator_with_return_value(mock_spider, g2)
assert len(w) == 0
with warnings.catch_warnings(record=True) as w:
warn_on_generator_with_return_value(mock_spider, h2) warn_on_generator_with_return_value(mock_spider, h2)
assert len(w) == 0
with warnings.catch_warnings(record=True) as w:
warn_on_generator_with_return_value(mock_spider, i2) warn_on_generator_with_return_value(mock_spider, i2)
assert len(w) == 0
with warnings.catch_warnings(record=True) as w:
warn_on_generator_with_return_value(mock_spider, j2) warn_on_generator_with_return_value(mock_spider, j2)
assert len(w) == 0
with warnings.catch_warnings(record=True) as w:
warn_on_generator_with_return_value(mock_spider, k2) warn_on_generator_with_return_value(mock_spider, k2)
assert len(w) == 0
with warnings.catch_warnings(record=True) as w:
warn_on_generator_with_return_value(mock_spider, l2) warn_on_generator_with_return_value(mock_spider, l2)
assert len(w) == 0
def test_generators_return_none_with_decorator(self, mock_spider): # noqa: PLR0915 def test_generators_return_none_with_decorator(self, mock_spider):
def decorator(func): def decorator(func):
def inner_func(): def inner_func():
func() func()
@ -241,39 +225,23 @@ https://example.org
assert not is_generator_with_return_value(k3) # not recursive assert not is_generator_with_return_value(k3) # not recursive
assert not is_generator_with_return_value(l3) assert not is_generator_with_return_value(l3)
with warnings.catch_warnings(record=True) as w: with warnings.catch_warnings():
warnings.simplefilter("error", UserWarning)
warn_on_generator_with_return_value(mock_spider, top_level_return_none) warn_on_generator_with_return_value(mock_spider, top_level_return_none)
assert len(w) == 0
with warnings.catch_warnings(record=True) as w:
warn_on_generator_with_return_value(mock_spider, f3) warn_on_generator_with_return_value(mock_spider, f3)
assert len(w) == 0
with warnings.catch_warnings(record=True) as w:
warn_on_generator_with_return_value(mock_spider, g3) warn_on_generator_with_return_value(mock_spider, g3)
assert len(w) == 0
with warnings.catch_warnings(record=True) as w:
warn_on_generator_with_return_value(mock_spider, h3) warn_on_generator_with_return_value(mock_spider, h3)
assert len(w) == 0
with warnings.catch_warnings(record=True) as w:
warn_on_generator_with_return_value(mock_spider, i3) warn_on_generator_with_return_value(mock_spider, i3)
assert len(w) == 0
with warnings.catch_warnings(record=True) as w:
warn_on_generator_with_return_value(mock_spider, j3) warn_on_generator_with_return_value(mock_spider, j3)
assert len(w) == 0
with warnings.catch_warnings(record=True) as w:
warn_on_generator_with_return_value(mock_spider, k3) warn_on_generator_with_return_value(mock_spider, k3)
assert len(w) == 0
with warnings.catch_warnings(record=True) as w:
warn_on_generator_with_return_value(mock_spider, l3) warn_on_generator_with_return_value(mock_spider, l3)
assert len(w) == 0
@mock.patch( @mock.patch(
"scrapy.utils.misc.is_generator_with_return_value", new=_indentation_error "scrapy.utils.misc.is_generator_with_return_value", new=_indentation_error
) )
def test_indentation_error(self, mock_spider): def test_indentation_error(self, mock_spider):
with warnings.catch_warnings(record=True) as w: with pytest.warns(UserWarning, match="Unable to determine"):
warn_on_generator_with_return_value(mock_spider, top_level_return_none) warn_on_generator_with_return_value(mock_spider, top_level_return_none)
assert len(w) == 1
assert "Unable to determine" in str(w[0].message)
def test_partial(self): def test_partial(self):
def cb(arg1, arg2): def cb(arg1, arg2):
@ -300,13 +268,11 @@ https://example.org
yield 1 yield 1
return "value" return "value"
with warnings.catch_warnings(record=True) as w: with warnings.catch_warnings():
warnings.simplefilter("error", UserWarning)
warn_on_generator_with_return_value(spider, gen_with_return) warn_on_generator_with_return_value(spider, gen_with_return)
assert len(w) == 0
spider.settings.settings_dict["WARN_ON_GENERATOR_RETURN_VALUE"] = True spider.settings.settings_dict["WARN_ON_GENERATOR_RETURN_VALUE"] = True
with warnings.catch_warnings(record=True) as w: with pytest.warns(UserWarning, match="is a generator"):
warn_on_generator_with_return_value(spider, gen_with_return) warn_on_generator_with_return_value(spider, gen_with_return)
assert len(w) == 1
assert "is a generator" in str(w[0].message)

View File

@ -1,5 +1,6 @@
import warnings import pytest
from scrapy.exceptions import ScrapyDeprecationWarning
from scrapy.utils.sitemap import Sitemap, sitemap_urls_from_robots from scrapy.utils.sitemap import Sitemap, sitemap_urls_from_robots
@ -204,7 +205,10 @@ Disallow: /forum/search/
Disallow: /forum/active/ Disallow: /forum/active/
""" """
with warnings.catch_warnings(record=True) as w: with pytest.warns(
ScrapyDeprecationWarning,
match="Passing `str` type as `robots_text` is deprecated",
):
assert list( assert list(
sitemap_urls_from_robots(robots, base_url="http://example.com") sitemap_urls_from_robots(robots, base_url="http://example.com")
) == [ ) == [
@ -213,9 +217,6 @@ Disallow: /forum/active/
"http://example.com/sitemap-uppercase.xml", "http://example.com/sitemap-uppercase.xml",
"http://example.com/sitemap-relative-url.xml", "http://example.com/sitemap-relative-url.xml",
] ]
assert "Passing `str` type as `robots_text` is deprecated, use `bytes`" in str(
w[0].message
)
def test_sitemap_blanklines(): def test_sitemap_blanklines():