mirror of https://github.com/scrapy/scrapy.git
Merge remote-tracking branch 'origin/master' into faster-shutdown-2
This commit is contained in:
commit
32a69f9547
|
|
@ -27,6 +27,6 @@ repos:
|
|||
hooks:
|
||||
- id: sphinx-lint
|
||||
- repo: https://github.com/scrapy/sphinx-scrapy
|
||||
rev: 0.7.1
|
||||
rev: 0.8.3
|
||||
hooks:
|
||||
- id: sphinx-scrapy
|
||||
|
|
|
|||
|
|
@ -3,6 +3,31 @@
|
|||
Release notes
|
||||
=============
|
||||
|
||||
.. _release-2.15.1:
|
||||
|
||||
Scrapy 2.15.1 (2026-04-23)
|
||||
--------------------------
|
||||
|
||||
Bug fixes
|
||||
~~~~~~~~~
|
||||
|
||||
- Sharing of the SSL context between multiple connections, introduced in
|
||||
Scrapy 2.15.0, is reverted as it caused problems and wasn't actually
|
||||
needed.
|
||||
(:issue:`7445`, :issue:`7450`)
|
||||
|
||||
- Fixed :meth:`scrapy.settings.BaseSettings.getwithbase` failing on keys with
|
||||
dots that aren't import names. It now works the way it worked before Scrapy
|
||||
2.15.0, without trying to match class objects and import path. A separate
|
||||
method,
|
||||
:func:`~scrapy.settings.BaseSettings.get_component_priority_dict_with_base`,
|
||||
was added that does that, and it is now used for :ref:`component priority
|
||||
dictionaries <component-priority-dictionaries>`.
|
||||
(:issue:`7426`, :issue:`7449`)
|
||||
|
||||
- Documentation rendering improvements.
|
||||
(:issue:`7452`, :issue:`7454`)
|
||||
|
||||
.. _release-2.15.0:
|
||||
|
||||
Scrapy 2.15.0 (2026-04-09)
|
||||
|
|
|
|||
|
|
@ -5,4 +5,4 @@ sphinx
|
|||
sphinx-notfound-page
|
||||
sphinx-rtd-theme
|
||||
sphinx-rtd-dark-mode
|
||||
sphinx-scrapy @ git+https://github.com/scrapy/sphinx-scrapy.git@0.7.1
|
||||
sphinx-scrapy @ git+https://github.com/scrapy/sphinx-scrapy.git@0.8.3
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
# This file was autogenerated by uv via the following command:
|
||||
# uv pip compile requirements.in -o requirements.txt
|
||||
# uv pip compile -p 3.13 requirements.in -o requirements.txt
|
||||
alabaster==1.0.0
|
||||
# via sphinx
|
||||
annotated-types==0.7.0
|
||||
|
|
@ -130,6 +130,7 @@ sphinx==9.1.0
|
|||
# via
|
||||
# -r requirements.in
|
||||
# sphinx-copybutton
|
||||
# sphinx-last-updated-by-git
|
||||
# sphinx-llms-txt
|
||||
# sphinx-markdown-builder
|
||||
# sphinx-notfound-page
|
||||
|
|
@ -138,9 +139,11 @@ sphinx==9.1.0
|
|||
# sphinxcontrib-jquery
|
||||
sphinx-copybutton==0.5.2
|
||||
# via sphinx-scrapy
|
||||
sphinx-last-updated-by-git==0.3.8
|
||||
# via sphinx-sitemap
|
||||
sphinx-llms-txt @ git+https://github.com/zytedata/sphinx-llms-txt.git@5e8866cb0cc249aa2017ad9050b3b83a7ca16f69
|
||||
# via sphinx-scrapy
|
||||
sphinx-markdown-builder @ git+https://github.com/zytedata/sphinx-markdown-builder.git@ac9f8babfe622e4300099ab44b96d9d9228e742e
|
||||
sphinx-markdown-builder @ git+https://github.com/zytedata/sphinx-markdown-builder.git@cfe4c0bfd7b4542f7e6b65a58cdf9ec765829940
|
||||
# via sphinx-scrapy
|
||||
sphinx-notfound-page==1.1.0
|
||||
# via -r requirements.in
|
||||
|
|
@ -150,8 +153,10 @@ sphinx-rtd-theme==3.1.0
|
|||
# via
|
||||
# -r requirements.in
|
||||
# sphinx-rtd-dark-mode
|
||||
sphinx-scrapy @ git+https://github.com/scrapy/sphinx-scrapy.git@2b5f6c7de64c8317cb771fdeb2e5020d1c9c9dcf
|
||||
sphinx-scrapy @ git+https://github.com/scrapy/sphinx-scrapy.git@f20366277f2598d0c8a60e55fe282aff2da40dcf
|
||||
# via -r requirements.in
|
||||
sphinx-sitemap==2.9.0
|
||||
# via sphinx-scrapy
|
||||
sphinxcontrib-applehelp==2.0.0
|
||||
# via sphinx
|
||||
sphinxcontrib-devhelp==2.0.0
|
||||
|
|
|
|||
|
|
@ -154,7 +154,7 @@ module = [
|
|||
ignore_missing_imports = true
|
||||
|
||||
[tool.bumpversion]
|
||||
current_version = "2.15.0"
|
||||
current_version = "2.15.1"
|
||||
commit = true
|
||||
tag = true
|
||||
tag_name = "{new_version}"
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
2.15.0
|
||||
2.15.1
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@ def open_in_browser(
|
|||
if isinstance(response, HtmlResponse):
|
||||
if b"<base" not in body:
|
||||
_remove_html_comments(body)
|
||||
repl = rf'\0<base href="{response.url}">'
|
||||
repl = rf'\g<0><base href="{response.url}">'
|
||||
body = re.sub(rb"<head(?:[^<>]*?>)", to_bytes(repl), body, count=1)
|
||||
ext = ".html"
|
||||
elif isinstance(response, TextResponse):
|
||||
|
|
|
|||
|
|
@ -111,36 +111,27 @@ def test_response_status_message():
|
|||
assert response_status_message(573) == "573 Unknown Status"
|
||||
|
||||
|
||||
def test_inject_base_url():
|
||||
url = "http://www.example.com"
|
||||
|
||||
def check_base_url(burl):
|
||||
path = urlparse(burl).path
|
||||
if not path or not Path(path).exists():
|
||||
path = burl.replace("file://", "")
|
||||
bbody = Path(path).read_bytes()
|
||||
assert bbody.count(b'<base href="' + to_bytes(url) + b'">') == 1
|
||||
return True
|
||||
|
||||
r1 = HtmlResponse(
|
||||
url,
|
||||
body=b"""
|
||||
@pytest.mark.parametrize(
|
||||
"body",
|
||||
[
|
||||
pytest.param(
|
||||
b"""
|
||||
<html>
|
||||
<head><title>Dummy</title></head>
|
||||
<body><p>Hello world.</p></body>
|
||||
</html>""",
|
||||
)
|
||||
r2 = HtmlResponse(
|
||||
url,
|
||||
body=b"""
|
||||
id="Simple",
|
||||
),
|
||||
pytest.param(
|
||||
b"""
|
||||
<html>
|
||||
<head id="foo"><title>Dummy</title></head>
|
||||
<body>Hello world.</body>
|
||||
</html>""",
|
||||
)
|
||||
r3 = HtmlResponse(
|
||||
url,
|
||||
body=b"""
|
||||
id="<head> with attrs",
|
||||
),
|
||||
pytest.param(
|
||||
b"""
|
||||
<html>
|
||||
<head><title>Dummy</title></head>
|
||||
<body>
|
||||
|
|
@ -148,19 +139,19 @@ def test_inject_base_url():
|
|||
<p>Hello world.</p>
|
||||
</body>
|
||||
</html>""",
|
||||
)
|
||||
r4 = HtmlResponse(
|
||||
url,
|
||||
body=b"""
|
||||
id="Misleading tag",
|
||||
),
|
||||
pytest.param(
|
||||
b"""
|
||||
<html>
|
||||
<!-- <head>Dummy comment</head> -->
|
||||
<head><title>Dummy</title></head>
|
||||
<body><p>Hello world.</p></body>
|
||||
</html>""",
|
||||
)
|
||||
r5 = HtmlResponse(
|
||||
url,
|
||||
body=b"""
|
||||
id="Misleading comment",
|
||||
),
|
||||
pytest.param(
|
||||
b"""
|
||||
<html>
|
||||
<!--[if IE]>
|
||||
<head><title>IE head</title></head>
|
||||
|
|
@ -170,21 +161,24 @@ def test_inject_base_url():
|
|||
<!--<![endif]-->
|
||||
<body><p>Hello world.</p></body>
|
||||
</html>""",
|
||||
)
|
||||
id="Conditional comment",
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_inject_base_url(body: bytes) -> None:
|
||||
url = "http://www.example.com"
|
||||
|
||||
assert open_in_browser(r1, _openfunc=check_base_url), "Inject base url"
|
||||
assert open_in_browser(r2, _openfunc=check_base_url), (
|
||||
"Inject base url with argumented head"
|
||||
)
|
||||
assert open_in_browser(r3, _openfunc=check_base_url), (
|
||||
"Inject unique base url with misleading tag"
|
||||
)
|
||||
assert open_in_browser(r4, _openfunc=check_base_url), (
|
||||
"Inject unique base url with misleading comment"
|
||||
)
|
||||
assert open_in_browser(r5, _openfunc=check_base_url), (
|
||||
"Inject unique base url with conditional comment"
|
||||
)
|
||||
def check_base_url(burl):
|
||||
path = urlparse(burl).path
|
||||
if not path or not Path(path).exists():
|
||||
path = burl.replace("file://", "")
|
||||
bbody = Path(path).read_bytes()
|
||||
assert bbody.count(b'><base href="' + to_bytes(url) + b'">') == 1
|
||||
assert b"<head" in bbody
|
||||
return True
|
||||
|
||||
resp = HtmlResponse(url, body=body)
|
||||
assert open_in_browser(resp, _openfunc=check_base_url)
|
||||
|
||||
|
||||
def test_open_in_browser_redos_comment():
|
||||
|
|
|
|||
Loading…
Reference in New Issue