mirror of https://github.com/scrapy/scrapy.git
commit
ee239d2451
|
|
@ -21,7 +21,7 @@ jobs:
|
||||||
- python-version: "3.9"
|
- python-version: "3.9"
|
||||||
env:
|
env:
|
||||||
TOXENV: typing-tests
|
TOXENV: typing-tests
|
||||||
- python-version: "3.12" # Keep in sync with .readthedocs.yml
|
- python-version: "3.13" # Keep in sync with .readthedocs.yml
|
||||||
env:
|
env:
|
||||||
TOXENV: docs
|
TOXENV: docs
|
||||||
- python-version: "3.13"
|
- python-version: "3.13"
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,16 @@
|
||||||
repos:
|
repos:
|
||||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||||
rev: v0.8.1
|
rev: v0.8.4
|
||||||
hooks:
|
hooks:
|
||||||
- id: ruff
|
- id: ruff
|
||||||
args: [ --fix ]
|
args: [ --fix ]
|
||||||
- repo: https://github.com/psf/black.git
|
- repo: https://github.com/psf/black.git
|
||||||
rev: 24.4.2
|
rev: 24.10.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: black
|
- id: black
|
||||||
- repo: https://github.com/pycqa/isort
|
|
||||||
rev: 5.13.2
|
|
||||||
hooks:
|
|
||||||
- id: isort
|
|
||||||
- repo: https://github.com/adamchainz/blacken-docs
|
- repo: https://github.com/adamchainz/blacken-docs
|
||||||
rev: 1.18.0
|
rev: 1.19.1
|
||||||
hooks:
|
hooks:
|
||||||
- id: blacken-docs
|
- id: blacken-docs
|
||||||
additional_dependencies:
|
additional_dependencies:
|
||||||
- black==24.4.2
|
- black==24.10.0
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ build:
|
||||||
tools:
|
tools:
|
||||||
# For available versions, see:
|
# For available versions, see:
|
||||||
# https://docs.readthedocs.io/en/stable/config-file/v2.html#build-tools-python
|
# https://docs.readthedocs.io/en/stable/config-file/v2.html#build-tools-python
|
||||||
python: "3.12" # Keep in sync with .github/workflows/checks.yml
|
python: "3.13" # Keep in sync with .github/workflows/checks.yml
|
||||||
|
|
||||||
python:
|
python:
|
||||||
install:
|
install:
|
||||||
|
|
|
||||||
|
|
@ -116,9 +116,6 @@ disable_warnings = ["include-ignored"]
|
||||||
# https://github.com/nedbat/coveragepy/issues/831#issuecomment-517778185
|
# https://github.com/nedbat/coveragepy/issues/831#issuecomment-517778185
|
||||||
exclude_lines = ["pragma: no cover", "if TYPE_CHECKING:"]
|
exclude_lines = ["pragma: no cover", "if TYPE_CHECKING:"]
|
||||||
|
|
||||||
[tool.isort]
|
|
||||||
profile = "black"
|
|
||||||
|
|
||||||
[tool.pylint.MASTER]
|
[tool.pylint.MASTER]
|
||||||
persistent = "no"
|
persistent = "no"
|
||||||
jobs = 1 # >1 hides results
|
jobs = 1 # >1 hides results
|
||||||
|
|
@ -173,6 +170,7 @@ disable = [
|
||||||
"too-many-instance-attributes",
|
"too-many-instance-attributes",
|
||||||
"too-many-lines",
|
"too-many-lines",
|
||||||
"too-many-locals",
|
"too-many-locals",
|
||||||
|
"too-many-positional-arguments",
|
||||||
"too-many-public-methods",
|
"too-many-public-methods",
|
||||||
"too-many-return-statements",
|
"too-many-return-statements",
|
||||||
"unbalanced-tuple-unpacking",
|
"unbalanced-tuple-unpacking",
|
||||||
|
|
@ -226,6 +224,8 @@ extend-select = [
|
||||||
"FA",
|
"FA",
|
||||||
# refurb
|
# refurb
|
||||||
"FURB",
|
"FURB",
|
||||||
|
# isort
|
||||||
|
"I",
|
||||||
# flake8-implicit-str-concat
|
# flake8-implicit-str-concat
|
||||||
"ISC",
|
"ISC",
|
||||||
# flake8-logging
|
# flake8-logging
|
||||||
|
|
|
||||||
|
|
@ -17,9 +17,14 @@ from twisted.internet.endpoints import TCP4ClientEndpoint
|
||||||
from twisted.internet.error import TimeoutError
|
from twisted.internet.error import TimeoutError
|
||||||
from twisted.internet.protocol import Factory, Protocol, connectionDone
|
from twisted.internet.protocol import Factory, Protocol, connectionDone
|
||||||
from twisted.python.failure import Failure
|
from twisted.python.failure import Failure
|
||||||
from twisted.web.client import URI, Agent, HTTPConnectionPool
|
from twisted.web.client import (
|
||||||
|
URI,
|
||||||
|
Agent,
|
||||||
|
HTTPConnectionPool,
|
||||||
|
ResponseDone,
|
||||||
|
ResponseFailed,
|
||||||
|
)
|
||||||
from twisted.web.client import Response as TxResponse
|
from twisted.web.client import Response as TxResponse
|
||||||
from twisted.web.client import ResponseDone, ResponseFailed
|
|
||||||
from twisted.web.http import PotentialDataLoss, _DataLoss
|
from twisted.web.http import PotentialDataLoss, _DataLoss
|
||||||
from twisted.web.http_headers import Headers as TxHeaders
|
from twisted.web.http_headers import Headers as TxHeaders
|
||||||
from twisted.web.iweb import UNKNOWN_LENGTH, IBodyProducer, IPolicyForHTTPS
|
from twisted.web.iweb import UNKNOWN_LENGTH, IBodyProducer, IPolicyForHTTPS
|
||||||
|
|
|
||||||
|
|
@ -131,25 +131,26 @@ class CookiesMiddleware:
|
||||||
decoded = {}
|
decoded = {}
|
||||||
flags = set()
|
flags = set()
|
||||||
for key in ("name", "value", "path", "domain"):
|
for key in ("name", "value", "path", "domain"):
|
||||||
if cookie.get(key) is None:
|
value = cookie.get(key)
|
||||||
|
if value is None:
|
||||||
if key in ("name", "value"):
|
if key in ("name", "value"):
|
||||||
msg = f"Invalid cookie found in request {request}: {cookie} ('{key}' is missing)"
|
msg = f"Invalid cookie found in request {request}: {cookie} ('{key}' is missing)"
|
||||||
logger.warning(msg)
|
logger.warning(msg)
|
||||||
return None
|
return None
|
||||||
continue
|
continue
|
||||||
# https://github.com/python/mypy/issues/7178, https://github.com/python/mypy/issues/9168
|
if isinstance(value, (bool, float, int, str)):
|
||||||
if isinstance(cookie[key], (bool, float, int, str)): # type: ignore[literal-required]
|
decoded[key] = str(value)
|
||||||
decoded[key] = str(cookie[key]) # type: ignore[literal-required]
|
|
||||||
else:
|
else:
|
||||||
|
assert isinstance(value, bytes)
|
||||||
try:
|
try:
|
||||||
decoded[key] = cookie[key].decode("utf8") # type: ignore[literal-required]
|
decoded[key] = value.decode("utf8")
|
||||||
except UnicodeDecodeError:
|
except UnicodeDecodeError:
|
||||||
logger.warning(
|
logger.warning(
|
||||||
"Non UTF-8 encoded cookie found in request %s: %s",
|
"Non UTF-8 encoded cookie found in request %s: %s",
|
||||||
request,
|
request,
|
||||||
cookie,
|
cookie,
|
||||||
)
|
)
|
||||||
decoded[key] = cookie[key].decode("latin1", errors="replace") # type: ignore[literal-required]
|
decoded[key] = value.decode("latin1", errors="replace")
|
||||||
for flag in ("secure",):
|
for flag in ("secure",):
|
||||||
value = cookie.get(flag, _UNSET)
|
value = cookie.get(flag, _UNSET)
|
||||||
if value is _UNSET or not value:
|
if value is _UNSET or not value:
|
||||||
|
|
|
||||||
|
|
@ -75,7 +75,7 @@ class TelnetConsole(protocol.ServerFactory):
|
||||||
def stop_listening(self) -> None:
|
def stop_listening(self) -> None:
|
||||||
self.port.stopListening()
|
self.port.stopListening()
|
||||||
|
|
||||||
def protocol(self) -> telnet.TelnetTransport: # type: ignore[override]
|
def protocol(self) -> telnet.TelnetTransport:
|
||||||
# these import twisted.internet.reactor
|
# these import twisted.internet.reactor
|
||||||
from twisted.conch import manhole, telnet
|
from twisted.conch import manhole, telnet
|
||||||
from twisted.conch.insults import insults
|
from twisted.conch.insults import insults
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,8 @@ from __future__ import annotations
|
||||||
|
|
||||||
import re
|
import re
|
||||||
import time
|
import time
|
||||||
from http.cookiejar import Cookie
|
from http.cookiejar import Cookie, CookiePolicy, DefaultCookiePolicy
|
||||||
from http.cookiejar import CookieJar as _CookieJar
|
from http.cookiejar import CookieJar as _CookieJar
|
||||||
from http.cookiejar import CookiePolicy, DefaultCookiePolicy
|
|
||||||
from typing import TYPE_CHECKING, Any, cast
|
from typing import TYPE_CHECKING, Any, cast
|
||||||
|
|
||||||
from scrapy.utils.httpobj import urlparse_cached
|
from scrapy.utils.httpobj import urlparse_cached
|
||||||
|
|
|
||||||
|
|
@ -44,10 +44,10 @@ if TYPE_CHECKING:
|
||||||
|
|
||||||
|
|
||||||
class VerboseCookie(TypedDict):
|
class VerboseCookie(TypedDict):
|
||||||
name: str
|
name: str | bytes
|
||||||
value: str
|
value: str | bytes | bool | float | int
|
||||||
domain: NotRequired[str]
|
domain: NotRequired[str | bytes]
|
||||||
path: NotRequired[str]
|
path: NotRequired[str | bytes]
|
||||||
secure: NotRequired[bool]
|
secure: NotRequired[bool]
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,13 +26,15 @@ class Sitemap:
|
||||||
)
|
)
|
||||||
self._root = lxml.etree.fromstring(xmltext, parser=xmlp) # noqa: S320
|
self._root = lxml.etree.fromstring(xmltext, parser=xmlp) # noqa: S320
|
||||||
rt = self._root.tag
|
rt = self._root.tag
|
||||||
self.type = self._root.tag.split("}", 1)[1] if "}" in rt else rt
|
assert isinstance(rt, str)
|
||||||
|
self.type = rt.split("}", 1)[1] if "}" in rt else rt
|
||||||
|
|
||||||
def __iter__(self) -> Iterator[dict[str, Any]]:
|
def __iter__(self) -> Iterator[dict[str, Any]]:
|
||||||
for elem in self._root.getchildren():
|
for elem in self._root.getchildren():
|
||||||
d: dict[str, Any] = {}
|
d: dict[str, Any] = {}
|
||||||
for el in elem.getchildren():
|
for el in elem.getchildren():
|
||||||
tag = el.tag
|
tag = el.tag
|
||||||
|
assert isinstance(tag, str)
|
||||||
name = tag.split("}", 1)[1] if "}" in tag else tag
|
name = tag.split("}", 1)[1] if "}" in tag else tag
|
||||||
|
|
||||||
if name == "link":
|
if name == "link":
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,8 @@
|
||||||
from urllib.parse import urlparse
|
from urllib.parse import urlparse
|
||||||
|
|
||||||
from twisted.internet import reactor
|
from twisted.internet import reactor
|
||||||
from twisted.names import cache
|
from twisted.names import cache, resolve
|
||||||
from twisted.names import hosts as hostsModule
|
from twisted.names import hosts as hostsModule
|
||||||
from twisted.names import resolve
|
|
||||||
from twisted.names.client import Resolver
|
from twisted.names.client import Resolver
|
||||||
from twisted.python.runtime import platform
|
from twisted.python.runtime import platform
|
||||||
|
|
||||||
|
|
|
||||||
14
tox.ini
14
tox.ini
|
|
@ -43,12 +43,12 @@ install_command =
|
||||||
[testenv:typing]
|
[testenv:typing]
|
||||||
basepython = python3
|
basepython = python3
|
||||||
deps =
|
deps =
|
||||||
mypy==1.12.0
|
mypy==1.14.0
|
||||||
typing-extensions==4.12.2
|
typing-extensions==4.12.2
|
||||||
types-lxml==2024.9.16
|
types-lxml==2024.12.13
|
||||||
types-Pygments==2.18.0.20240506
|
types-Pygments==2.18.0.20240506
|
||||||
botocore-stubs==1.35.39
|
botocore-stubs==1.35.90
|
||||||
boto3-stubs[s3]==1.35.39
|
boto3-stubs[s3]==1.35.90
|
||||||
attrs >= 18.2.0
|
attrs >= 18.2.0
|
||||||
Pillow >= 10.3.0
|
Pillow >= 10.3.0
|
||||||
pyOpenSSL >= 24.2.1
|
pyOpenSSL >= 24.2.1
|
||||||
|
|
@ -77,15 +77,15 @@ commands =
|
||||||
basepython = python3
|
basepython = python3
|
||||||
deps =
|
deps =
|
||||||
{[testenv:extra-deps]deps}
|
{[testenv:extra-deps]deps}
|
||||||
pylint==3.2.5
|
pylint==3.3.3
|
||||||
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==5.1.1
|
twine==6.0.1
|
||||||
build==1.2.1
|
build==1.2.2.post1
|
||||||
commands =
|
commands =
|
||||||
python -m build --sdist
|
python -m build --sdist
|
||||||
twine check dist/*
|
twine check dist/*
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue