mirror of https://github.com/scrapy/scrapy.git
Update tool versions (#7127)
This commit is contained in:
parent
61b4befc60
commit
804ae167df
|
|
@ -4,4 +4,4 @@ e211ec0aa26ecae0da8ae55d064ea60e1efe4d0d
|
||||||
# reapplying black to the code with default line length
|
# reapplying black to the code with default line length
|
||||||
303f0a70fcf8067adf0a909c2096a5009162383a
|
303f0a70fcf8067adf0a909c2096a5009162383a
|
||||||
# reapplying black again and removing line length on pre-commit black config
|
# reapplying black again and removing line length on pre-commit black config
|
||||||
c5cdd0d30ceb68ccba04af0e71d1b8e6678e2962
|
c5cdd0d30ceb68ccba04af0e71d1b8e6678e2962
|
||||||
|
|
|
||||||
|
|
@ -34,10 +34,10 @@ jobs:
|
||||||
TOXENV: twinecheck
|
TOXENV: twinecheck
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v5
|
||||||
|
|
||||||
- name: Set up Python ${{ matrix.python-version }}
|
- name: Set up Python ${{ matrix.python-version }}
|
||||||
uses: actions/setup-python@v5
|
uses: actions/setup-python@v6
|
||||||
with:
|
with:
|
||||||
python-version: ${{ matrix.python-version }}
|
python-version: ${{ matrix.python-version }}
|
||||||
|
|
||||||
|
|
@ -50,5 +50,5 @@ jobs:
|
||||||
pre-commit:
|
pre-commit:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v5
|
||||||
- uses: pre-commit/action@v3.0.1
|
- uses: pre-commit/action@v3.0.1
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,8 @@ jobs:
|
||||||
permissions:
|
permissions:
|
||||||
id-token: write
|
id-token: write
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v5
|
||||||
- uses: actions/setup-python@v5
|
- uses: actions/setup-python@v6
|
||||||
with:
|
with:
|
||||||
python-version: "3.13"
|
python-version: "3.13"
|
||||||
- run: |
|
- run: |
|
||||||
|
|
|
||||||
|
|
@ -19,10 +19,10 @@ jobs:
|
||||||
python-version: ["3.10", "3.11", "3.12", "3.13"]
|
python-version: ["3.10", "3.11", "3.12", "3.13"]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v5
|
||||||
|
|
||||||
- name: Set up Python ${{ matrix.python-version }}
|
- name: Set up Python ${{ matrix.python-version }}
|
||||||
uses: actions/setup-python@v5
|
uses: actions/setup-python@v6
|
||||||
with:
|
with:
|
||||||
python-version: ${{ matrix.python-version }}
|
python-version: ${{ matrix.python-version }}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -64,10 +64,10 @@ jobs:
|
||||||
TOXENV: botocore
|
TOXENV: botocore
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v5
|
||||||
|
|
||||||
- name: Set up Python ${{ matrix.python-version }}
|
- name: Set up Python ${{ matrix.python-version }}
|
||||||
uses: actions/setup-python@v5
|
uses: actions/setup-python@v6
|
||||||
with:
|
with:
|
||||||
python-version: ${{ matrix.python-version }}
|
python-version: ${{ matrix.python-version }}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -46,10 +46,10 @@ jobs:
|
||||||
TOXENV: extra-deps
|
TOXENV: extra-deps
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v5
|
||||||
|
|
||||||
- name: Set up Python ${{ matrix.python-version }}
|
- name: Set up Python ${{ matrix.python-version }}
|
||||||
uses: actions/setup-python@v5
|
uses: actions/setup-python@v6
|
||||||
with:
|
with:
|
||||||
python-version: ${{ matrix.python-version }}
|
python-version: ${{ matrix.python-version }}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,26 @@
|
||||||
|
exclude: |
|
||||||
|
(?x)(
|
||||||
|
^docs/_static|
|
||||||
|
^docs/_tests|
|
||||||
|
^tests/sample_data
|
||||||
|
)
|
||||||
repos:
|
repos:
|
||||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||||
rev: v0.12.2
|
rev: v0.14.2
|
||||||
hooks:
|
hooks:
|
||||||
- id: ruff-check
|
- id: ruff-check
|
||||||
args: [ --fix ]
|
args: [ --fix ]
|
||||||
- id: ruff-format
|
- id: ruff-format
|
||||||
- repo: https://github.com/adamchainz/blacken-docs
|
- repo: https://github.com/adamchainz/blacken-docs
|
||||||
rev: 1.19.1
|
rev: 1.20.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: blacken-docs
|
- id: blacken-docs
|
||||||
additional_dependencies:
|
additional_dependencies:
|
||||||
- black==25.1.0
|
- black==25.9.0
|
||||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||||
rev: v5.0.0
|
rev: v6.0.0
|
||||||
hooks:
|
hooks:
|
||||||
|
- id: end-of-file-fixer
|
||||||
- id: trailing-whitespace
|
- id: trailing-whitespace
|
||||||
- repo: https://github.com/sphinx-contrib/sphinx-lint
|
- repo: https://github.com/sphinx-contrib/sphinx-lint
|
||||||
rev: v1.0.0
|
rev: v1.0.0
|
||||||
|
|
|
||||||
|
|
@ -29,14 +29,14 @@ def is_setting_index(node: Node) -> bool:
|
||||||
if node.tagname == "index" and node["entries"]: # type: ignore[index,attr-defined]
|
if node.tagname == "index" and node["entries"]: # type: ignore[index,attr-defined]
|
||||||
# index entries for setting directives look like:
|
# index entries for setting directives look like:
|
||||||
# [('pair', 'SETTING_NAME; setting', 'std:setting-SETTING_NAME', '')]
|
# [('pair', 'SETTING_NAME; setting', 'std:setting-SETTING_NAME', '')]
|
||||||
entry_type, info, refid = node["entries"][0][:3] # type: ignore[index]
|
entry_type, info, _ = node["entries"][0][:3] # type: ignore[index]
|
||||||
return entry_type == "pair" and info.endswith("; setting")
|
return entry_type == "pair" and info.endswith("; setting")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def get_setting_name_and_refid(node: Node) -> tuple[str, str]:
|
def get_setting_name_and_refid(node: Node) -> tuple[str, str]:
|
||||||
"""Extract setting name from directive index node"""
|
"""Extract setting name from directive index node"""
|
||||||
entry_type, info, refid = node["entries"][0][:3] # type: ignore[index]
|
_, info, refid = node["entries"][0][:3] # type: ignore[index]
|
||||||
return info.replace("; setting", ""), refid
|
return info.replace("; setting", ""), refid
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -317,4 +317,3 @@ to identifying the correct request and replicating it in your spider.
|
||||||
.. _quotes.toscrape.com/scroll: https://quotes.toscrape.com/scroll
|
.. _quotes.toscrape.com/scroll: https://quotes.toscrape.com/scroll
|
||||||
.. _quotes.toscrape.com/api/quotes?page=10: https://quotes.toscrape.com/api/quotes?page=10
|
.. _quotes.toscrape.com/api/quotes?page=10: https://quotes.toscrape.com/api/quotes?page=10
|
||||||
.. _has-class-extension: https://parsel.readthedocs.io/en/latest/usage.html#other-xpath-extensions
|
.. _has-class-extension: https://parsel.readthedocs.io/en/latest/usage.html#other-xpath-extensions
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -121,4 +121,3 @@ DummyStatsCollector
|
||||||
setting, to disable stats collect in order to improve performance. However,
|
setting, to disable stats collect in order to improve performance. However,
|
||||||
the performance penalty of stats collection is usually marginal compared to
|
the performance penalty of stats collection is usually marginal compared to
|
||||||
other Scrapy workload like parsing pages.
|
other Scrapy workload like parsing pages.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -66,4 +66,3 @@ the :ref:`release notes <news>`.
|
||||||
|
|
||||||
|
|
||||||
.. _odd-numbered versions for development releases: https://en.wikipedia.org/wiki/Software_versioning#Odd-numbered_versions_for_development_releases
|
.. _odd-numbered versions for development releases: https://en.wikipedia.org/wiki/Software_versioning#Odd-numbered_versions_for_development_releases
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -374,8 +374,6 @@ ignore = [
|
||||||
"SIM115",
|
"SIM115",
|
||||||
# Yoda condition detected
|
# Yoda condition detected
|
||||||
"SIM300",
|
"SIM300",
|
||||||
# removed in recent ruff
|
|
||||||
"UP038",
|
|
||||||
|
|
||||||
# Ones that we may want to address (fix, ignore per-line or move to "don't want to fix")
|
# Ones that we may want to address (fix, ignore per-line or move to "don't want to fix")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ from __future__ import annotations
|
||||||
|
|
||||||
import inspect
|
import inspect
|
||||||
import logging
|
import logging
|
||||||
from typing import TYPE_CHECKING, Any, Literal, TypeVar, overload
|
from typing import TYPE_CHECKING, Any, TypeVar, overload
|
||||||
|
|
||||||
from scrapy.spiders import Spider
|
from scrapy.spiders import Spider
|
||||||
from scrapy.utils.defer import deferred_from_coro
|
from scrapy.utils.defer import deferred_from_coro
|
||||||
|
|
@ -76,7 +76,7 @@ def spidercls_for_request(
|
||||||
def spidercls_for_request(
|
def spidercls_for_request(
|
||||||
spider_loader: SpiderLoaderProtocol,
|
spider_loader: SpiderLoaderProtocol,
|
||||||
request: Request,
|
request: Request,
|
||||||
default_spidercls: Literal[None],
|
default_spidercls: None,
|
||||||
log_none: bool = ...,
|
log_none: bool = ...,
|
||||||
log_multiple: bool = ...,
|
log_multiple: bool = ...,
|
||||||
) -> type[Spider] | None: ...
|
) -> type[Spider] | None: ...
|
||||||
|
|
|
||||||
|
|
@ -21,4 +21,3 @@ Locality Name (eg, city) [New York]:The Internet
|
||||||
Organization Name (eg, company) [Example, LLC]:Scrapy
|
Organization Name (eg, company) [Example, LLC]:Scrapy
|
||||||
Common Name (e.g. server FQDN or YOUR name) [Example Company]:www.example.com
|
Common Name (e.g. server FQDN or YOUR name) [Example Company]:www.example.com
|
||||||
Email Address [test@example.com]:
|
Email Address [test@example.com]:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,4 +18,3 @@ Organization Name (eg, company) [Internet Widgits Pty Ltd]:Scrapy
|
||||||
Organizational Unit Name (eg, section) []:.
|
Organizational Unit Name (eg, section) []:.
|
||||||
Common Name (e.g. server FQDN or YOUR name) []:127.0.0.1
|
Common Name (e.g. server FQDN or YOUR name) []:127.0.0.1
|
||||||
Email Address []:.
|
Email Address []:.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,4 +18,3 @@ Organization Name (eg, company) [Internet Widgits Pty Ltd]:Scrapy
|
||||||
Organizational Unit Name (eg, section) []:.
|
Organizational Unit Name (eg, section) []:.
|
||||||
Common Name (e.g. server FQDN or YOUR name) []:localhost
|
Common Name (e.g. server FQDN or YOUR name) []:localhost
|
||||||
Email Address []:.
|
Email Address []:.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ class TestCmdlineCrawlPipeline:
|
||||||
return proc.returncode, stderr
|
return proc.returncode, stderr
|
||||||
|
|
||||||
def test_open_spider_normally_in_pipeline(self):
|
def test_open_spider_normally_in_pipeline(self):
|
||||||
returncode, stderr = self._execute("normal")
|
returncode, _ = self._execute("normal")
|
||||||
assert returncode == 0
|
assert returncode == 0
|
||||||
|
|
||||||
def test_exception_at_open_spider_in_pipeline(self):
|
def test_exception_at_open_spider_in_pipeline(self):
|
||||||
|
|
|
||||||
|
|
@ -172,7 +172,7 @@ class TestGenspiderStandaloneCommand:
|
||||||
def test_same_name_as_existing_file(self, force: bool, tmp_path: Path) -> None:
|
def test_same_name_as_existing_file(self, force: bool, tmp_path: Path) -> None:
|
||||||
file_name = "example"
|
file_name = "example"
|
||||||
file_path = Path(tmp_path, file_name + ".py")
|
file_path = Path(tmp_path, file_name + ".py")
|
||||||
p, out, err = proc("genspider", file_name, "example.com", cwd=tmp_path)
|
_, out, _ = proc("genspider", file_name, "example.com", cwd=tmp_path)
|
||||||
assert f"Created spider {file_name!r} using template 'basic' " in out
|
assert f"Created spider {file_name!r} using template 'basic' " in out
|
||||||
assert file_path.exists()
|
assert file_path.exists()
|
||||||
modify_time_before = file_path.stat().st_mtime
|
modify_time_before = file_path.stat().st_mtime
|
||||||
|
|
@ -180,7 +180,7 @@ class TestGenspiderStandaloneCommand:
|
||||||
|
|
||||||
if force:
|
if force:
|
||||||
# use different template to ensure contents were changed
|
# use different template to ensure contents were changed
|
||||||
p, out, err = proc(
|
_, out, _ = proc(
|
||||||
"genspider",
|
"genspider",
|
||||||
"--force",
|
"--force",
|
||||||
"-t",
|
"-t",
|
||||||
|
|
|
||||||
|
|
@ -232,7 +232,7 @@ class TestStartprojectTemplates:
|
||||||
project_dir.mkdir(parents=True)
|
project_dir.mkdir(parents=True)
|
||||||
|
|
||||||
existing_nodes = {
|
existing_nodes = {
|
||||||
oct(permissions)[2:] + extension: permissions
|
f"{permissions:o}{extension}": permissions
|
||||||
for extension in ("", ".d")
|
for extension in ("", ".d")
|
||||||
for permissions in (
|
for permissions in (
|
||||||
0o444,
|
0o444,
|
||||||
|
|
|
||||||
|
|
@ -612,7 +612,7 @@ class TestCrawlSpider:
|
||||||
@pytest.mark.only_asyncio
|
@pytest.mark.only_asyncio
|
||||||
@deferred_f_from_coro_f
|
@deferred_f_from_coro_f
|
||||||
async def test_async_def_deferred_wrapped(self):
|
async def test_async_def_deferred_wrapped(self):
|
||||||
log, items, _ = await self._run_spider(AsyncDefDeferredWrappedSpider)
|
_, items, _ = await self._run_spider(AsyncDefDeferredWrappedSpider)
|
||||||
assert items == [{"code": 200}]
|
assert items == [{"code": 200}]
|
||||||
|
|
||||||
@deferred_f_from_coro_f
|
@deferred_f_from_coro_f
|
||||||
|
|
|
||||||
|
|
@ -785,7 +785,7 @@ class ScriptRunnerMixin(ABC):
|
||||||
stdout=subprocess.PIPE,
|
stdout=subprocess.PIPE,
|
||||||
stderr=subprocess.PIPE,
|
stderr=subprocess.PIPE,
|
||||||
)
|
)
|
||||||
stdout, stderr = p.communicate()
|
_, stderr = p.communicate()
|
||||||
return stderr.decode("utf-8")
|
return stderr.decode("utf-8")
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -74,7 +74,7 @@ def test_spider_closed_sends_email(dummy_stats):
|
||||||
spider = DefaultSpider(name="dummy")
|
spider = DefaultSpider(name="dummy")
|
||||||
ext.spider_closed(spider)
|
ext.spider_closed(spider)
|
||||||
|
|
||||||
args, kwargs = mail.send.call_args
|
args, _ = mail.send.call_args
|
||||||
to, subject, body = args
|
to, subject, body = args
|
||||||
assert to == recipients
|
assert to == recipients
|
||||||
assert "Scrapy stats for: dummy" in subject
|
assert "Scrapy stats for: dummy" in subject
|
||||||
|
|
|
||||||
|
|
@ -56,12 +56,12 @@ class TestHeaders:
|
||||||
|
|
||||||
def test_encode_latin1(self):
|
def test_encode_latin1(self):
|
||||||
h = Headers({"key": "\xa3"}, encoding="latin1")
|
h = Headers({"key": "\xa3"}, encoding="latin1")
|
||||||
key, val = dict(h).popitem()
|
_, val = dict(h).popitem()
|
||||||
assert val[0] == b"\xa3"
|
assert val[0] == b"\xa3"
|
||||||
|
|
||||||
def test_encode_multiple(self):
|
def test_encode_multiple(self):
|
||||||
h = Headers({"key": ["\xa3"]}, encoding="utf-8")
|
h = Headers({"key": ["\xa3"]}, encoding="utf-8")
|
||||||
key, val = dict(h).popitem()
|
_, val = dict(h).popitem()
|
||||||
assert val[0] == b"\xc2\xa3"
|
assert val[0] == b"\xc2\xa3"
|
||||||
|
|
||||||
def test_delete_and_contains(self):
|
def test_delete_and_contains(self):
|
||||||
|
|
|
||||||
|
|
@ -881,7 +881,7 @@ class TestFormRequest(TestRequest):
|
||||||
)
|
)
|
||||||
with pytest.raises(
|
with pytest.raises(
|
||||||
ValueError,
|
ValueError,
|
||||||
match="Multiple elements found .* matching the criteria in clickdata",
|
match=r"Multiple elements found .* matching the criteria in clickdata",
|
||||||
):
|
):
|
||||||
self.request_class.from_response(response, clickdata={"type": "submit"})
|
self.request_class.from_response(response, clickdata={"type": "submit"})
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -813,7 +813,7 @@ class TestTextResponse(TestResponseBase):
|
||||||
text_body = b"""<html><body>text</body></html>"""
|
text_body = b"""<html><body>text</body></html>"""
|
||||||
text_response = self.response_class("http://www.example.com", body=text_body)
|
text_response = self.response_class("http://www.example.com", body=text_body)
|
||||||
with pytest.raises(
|
with pytest.raises(
|
||||||
ValueError, match="(Expecting value|Unexpected '<'): line 1"
|
ValueError, match=r"(Expecting value|Unexpected '<'): line 1"
|
||||||
):
|
):
|
||||||
text_response.json()
|
text_response.json()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -284,9 +284,9 @@ class TestItemMeta:
|
||||||
|
|
||||||
(first_call, second_call) = new_mock.call_args_list[-2:]
|
(first_call, second_call) = new_mock.call_args_list[-2:]
|
||||||
|
|
||||||
mcs, class_name, bases, attrs = first_call[0]
|
*_, attrs = first_call[0]
|
||||||
assert "__classcell__" not in attrs
|
assert "__classcell__" not in attrs
|
||||||
mcs, class_name, bases, attrs = second_call[0]
|
*_, attrs = second_call[0]
|
||||||
assert "__classcell__" in attrs
|
assert "__classcell__" in attrs
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -159,7 +159,7 @@ class TestImagesPipeline:
|
||||||
self.pipeline.thumbs = {"small": (20, 20)}
|
self.pipeline.thumbs = {"small": (20, 20)}
|
||||||
|
|
||||||
orig_im, buf = _create_image("JPEG", "RGB", (50, 50), (0, 0, 0))
|
orig_im, buf = _create_image("JPEG", "RGB", (50, 50), (0, 0, 0))
|
||||||
orig_thumb, orig_thumb_buf = _create_image("JPEG", "RGB", (20, 20), (0, 0, 0))
|
_, orig_thumb_buf = _create_image("JPEG", "RGB", (20, 20), (0, 0, 0))
|
||||||
resp = Response(url="https://dev.mydeco.com/mydeco.gif", body=buf.getvalue())
|
resp = Response(url="https://dev.mydeco.com/mydeco.gif", body=buf.getvalue())
|
||||||
req = Request(url="https://dev.mydeco.com/mydeco.gif")
|
req = Request(url="https://dev.mydeco.com/mydeco.gif")
|
||||||
|
|
||||||
|
|
@ -172,7 +172,7 @@ class TestImagesPipeline:
|
||||||
assert orig_im.copy() == new_im
|
assert orig_im.copy() == new_im
|
||||||
assert buf.getvalue() == new_buf.getvalue()
|
assert buf.getvalue() == new_buf.getvalue()
|
||||||
|
|
||||||
thumb_path, thumb_img, thumb_buf = next(get_images_gen)
|
thumb_path, _, thumb_buf = next(get_images_gen)
|
||||||
assert thumb_path == "thumbs/small/3fd165099d8e71b8a48b2683946e64dbfad8b52d.jpg"
|
assert thumb_path == "thumbs/small/3fd165099d8e71b8a48b2683946e64dbfad8b52d.jpg"
|
||||||
assert orig_thumb_buf.getvalue() == thumb_buf.getvalue()
|
assert orig_thumb_buf.getvalue() == thumb_buf.getvalue()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -371,13 +371,13 @@ class TestMiddlewareManagerSpider:
|
||||||
),
|
),
|
||||||
pytest.raises(
|
pytest.raises(
|
||||||
ValueError,
|
ValueError,
|
||||||
match="ItemPipelineManager needs to access self.crawler.spider but it is None",
|
match=r"ItemPipelineManager needs to access self\.crawler\.spider but it is None",
|
||||||
),
|
),
|
||||||
):
|
):
|
||||||
mwman.open_spider(DefaultSpider())
|
mwman.open_spider(DefaultSpider())
|
||||||
with pytest.raises(
|
with pytest.raises(
|
||||||
ValueError,
|
ValueError,
|
||||||
match="ItemPipelineManager needs to access self.crawler.spider but it is None",
|
match=r"ItemPipelineManager needs to access self\.crawler\.spider but it is None",
|
||||||
):
|
):
|
||||||
await mwman.open_spider_async()
|
await mwman.open_spider_async()
|
||||||
with (
|
with (
|
||||||
|
|
@ -387,13 +387,13 @@ class TestMiddlewareManagerSpider:
|
||||||
),
|
),
|
||||||
pytest.raises(
|
pytest.raises(
|
||||||
ValueError,
|
ValueError,
|
||||||
match="ItemPipelineManager needs to access self.crawler.spider but it is None",
|
match=r"ItemPipelineManager needs to access self\.crawler\.spider but it is None",
|
||||||
),
|
),
|
||||||
):
|
):
|
||||||
mwman.close_spider(DefaultSpider())
|
mwman.close_spider(DefaultSpider())
|
||||||
with pytest.raises(
|
with pytest.raises(
|
||||||
ValueError,
|
ValueError,
|
||||||
match="ItemPipelineManager needs to access self.crawler.spider but it is None",
|
match=r"ItemPipelineManager needs to access self\.crawler\.spider but it is None",
|
||||||
):
|
):
|
||||||
await mwman.close_spider_async()
|
await mwman.close_spider_async()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ class MinimalScheduler:
|
||||||
|
|
||||||
def next_request(self) -> Request | None:
|
def next_request(self) -> Request | None:
|
||||||
if self.has_pending_requests():
|
if self.has_pending_requests():
|
||||||
fp, request = self.requests.popitem()
|
_, request = self.requests.popitem()
|
||||||
return request
|
return request
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -311,7 +311,7 @@ class TestBaseSettings:
|
||||||
assert settings.getdict("TEST_DICT3", {"key1": 5}) == {"key1": 5}
|
assert settings.getdict("TEST_DICT3", {"key1": 5}) == {"key1": 5}
|
||||||
with pytest.raises(
|
with pytest.raises(
|
||||||
ValueError,
|
ValueError,
|
||||||
match="dictionary update sequence element #0 has length 3; 2 is required|sequence of pairs expected",
|
match=r"dictionary update sequence element #0 has length 3; 2 is required|sequence of pairs expected",
|
||||||
):
|
):
|
||||||
settings.getdict("TEST_LIST1")
|
settings.getdict("TEST_LIST1")
|
||||||
with pytest.raises(
|
with pytest.raises(
|
||||||
|
|
|
||||||
|
|
@ -568,7 +568,8 @@ class TestProcessSpiderException(TestBaseAsyncSpiderMiddleware):
|
||||||
|
|
||||||
async def _test_asyncgen_nodowngrade(self, *mw_classes: type[Any]) -> None:
|
async def _test_asyncgen_nodowngrade(self, *mw_classes: type[Any]) -> None:
|
||||||
with pytest.raises(
|
with pytest.raises(
|
||||||
_InvalidOutput, match="Async iterable returned from .+ cannot be downgraded"
|
_InvalidOutput,
|
||||||
|
match=r"Async iterable returned from .+ cannot be downgraded",
|
||||||
):
|
):
|
||||||
await self._get_middleware_result(*mw_classes)
|
await self._get_middleware_result(*mw_classes)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,13 +33,13 @@ def nonserializable_object_test(self):
|
||||||
q = self.queue()
|
q = self.queue()
|
||||||
with pytest.raises(
|
with pytest.raises(
|
||||||
ValueError,
|
ValueError,
|
||||||
match="unmarshallable object|Can't (get|pickle) local object|Can't pickle .*: it's not found as",
|
match=r"unmarshallable object|Can't (get|pickle) local object|Can't pickle .*: it's not found as",
|
||||||
):
|
):
|
||||||
q.push(lambda x: x)
|
q.push(lambda x: x)
|
||||||
# Selectors should fail (lxml.html.HtmlElement objects can't be pickled)
|
# Selectors should fail (lxml.html.HtmlElement objects can't be pickled)
|
||||||
sel = Selector(text="<html><body><p>some text</p></body></html>")
|
sel = Selector(text="<html><body><p>some text</p></body></html>")
|
||||||
with pytest.raises(
|
with pytest.raises(
|
||||||
ValueError, match="unmarshallable object|can't pickle Selector objects"
|
ValueError, match=r"unmarshallable object|can't pickle Selector objects"
|
||||||
):
|
):
|
||||||
q.push(sel)
|
q.push(sel)
|
||||||
|
|
||||||
|
|
@ -117,7 +117,7 @@ class PickleFifoDiskQueueTest(t.FifoDiskQueueTest, FifoDiskQueueTestMixin):
|
||||||
q = self.queue()
|
q = self.queue()
|
||||||
with pytest.raises(
|
with pytest.raises(
|
||||||
ValueError,
|
ValueError,
|
||||||
match="Can't (get|pickle) local object|Can't pickle .*: it's not found as",
|
match=r"Can't (get|pickle) local object|Can't pickle .*: it's not found as",
|
||||||
) as exc_info:
|
) as exc_info:
|
||||||
q.push(lambda x: x)
|
q.push(lambda x: x)
|
||||||
if hasattr(sys, "pypy_version_info"):
|
if hasattr(sys, "pypy_version_info"):
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ class TestBuildComponentList:
|
||||||
# Same priority raises ValueError
|
# Same priority raises ValueError
|
||||||
duplicate_bs.set("ONE", duplicate_bs["ONE"], priority=20)
|
duplicate_bs.set("ONE", duplicate_bs["ONE"], priority=20)
|
||||||
with pytest.raises(
|
with pytest.raises(
|
||||||
ValueError, match="Some paths in .* convert to the same object"
|
ValueError, match=r"Some paths in .* convert to the same object"
|
||||||
):
|
):
|
||||||
build_component_list(duplicate_bs, convert=lambda x: x.lower())
|
build_component_list(duplicate_bs, convert=lambda x: x.lower())
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -220,7 +220,7 @@ class TestCurlToRequestKwargs:
|
||||||
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):
|
||||||
with pytest.raises(ValueError, match="Unrecognized options:.*--bar.*--baz"):
|
with pytest.raises(ValueError, match=r"Unrecognized options:.*--bar.*--baz"):
|
||||||
curl_to_request_kwargs(
|
curl_to_request_kwargs(
|
||||||
"curl --bar --baz http://www.example.com", ignore_unknown_options=False
|
"curl --bar --baz http://www.example.com", ignore_unknown_options=False
|
||||||
)
|
)
|
||||||
|
|
|
||||||
24
tox.ini
24
tox.ini
|
|
@ -45,15 +45,15 @@ commands =
|
||||||
[testenv:typing]
|
[testenv:typing]
|
||||||
basepython = python3.10
|
basepython = python3.10
|
||||||
deps =
|
deps =
|
||||||
mypy==1.16.1
|
mypy==1.18.2
|
||||||
typing-extensions==4.14.1
|
typing-extensions==4.15.0
|
||||||
types-defusedxml==0.7.0.20250516
|
types-defusedxml==0.7.0.20250822
|
||||||
types-lxml==2025.3.30
|
types-lxml==2025.8.25
|
||||||
types-pexpect==4.9.0.20250516
|
types-pexpect==4.9.0.20250916
|
||||||
types-Pygments==2.19.0.20250516
|
types-Pygments==2.19.0.20250809
|
||||||
botocore-stubs==1.38.46
|
botocore-stubs==1.40.59
|
||||||
boto3-stubs[s3]==1.39.3
|
boto3-stubs[s3]==1.40.59
|
||||||
itemadapter==0.11.0
|
itemadapter==0.12.2
|
||||||
Protego==0.5.0
|
Protego==0.5.0
|
||||||
w3lib==2.3.1
|
w3lib==2.3.1
|
||||||
attrs >= 18.2.0
|
attrs >= 18.2.0
|
||||||
|
|
@ -83,15 +83,15 @@ commands =
|
||||||
basepython = python3
|
basepython = python3
|
||||||
deps =
|
deps =
|
||||||
{[testenv:extra-deps]deps}
|
{[testenv:extra-deps]deps}
|
||||||
pylint==3.3.7
|
pylint==4.0.2
|
||||||
commands =
|
commands =
|
||||||
pylint conftest.py docs extras scrapy tests
|
pylint conftest.py docs extras scrapy tests
|
||||||
|
|
||||||
[testenv:twinecheck]
|
[testenv:twinecheck]
|
||||||
basepython = python3
|
basepython = python3
|
||||||
deps =
|
deps =
|
||||||
twine==6.1.0
|
twine==6.2.0
|
||||||
build==1.2.2.post1
|
build==1.3.0
|
||||||
commands =
|
commands =
|
||||||
python -m build --sdist
|
python -m build --sdist
|
||||||
twine check dist/*
|
twine check dist/*
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue