Skip to content

Commit 3756d24

Browse files
authored
Merge pull request #159 from scrapy/3.14rc
Add Python 3.14 RC2 to CI, drop PyPy 3.10, bump tool versions
2 parents 948dd03 + 2334984 commit 3756d24

File tree

13 files changed

+138
-101
lines changed

13 files changed

+138
-101
lines changed

.git-blame-ignore-revs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
# applying pre-commit hooks to the project
2-
e91101b37f82558db84a6b8ee9a6dba1fd2ae0bb
2+
e91101b37f82558db84a6b8ee9a6dba1fd2ae0bb

.github/workflows/checks.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,10 @@ jobs:
2222
TOXENV: twinecheck
2323

2424
steps:
25-
- uses: actions/checkout@v4
25+
- uses: actions/checkout@v5
2626

2727
- name: Set up Python ${{ matrix.python-version }}
28-
uses: actions/setup-python@v5
28+
uses: actions/setup-python@v6
2929
with:
3030
python-version: ${{ matrix.python-version }}
3131

@@ -35,9 +35,9 @@ jobs:
3535
pip install -U pip
3636
pip install -U tox
3737
tox
38-
38+
3939
pre-commit:
4040
runs-on: ubuntu-latest
4141
steps:
42-
- uses: actions/checkout@v4
42+
- uses: actions/checkout@v5
4343
- uses: pre-commit/[email protected]

.github/workflows/publish.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@ jobs:
1616
id-token: write
1717

1818
steps:
19-
- uses: actions/checkout@v4
19+
- uses: actions/checkout@v5
2020

2121
- name: Set up Python
22-
uses: actions/setup-python@v5
22+
uses: actions/setup-python@v6
2323
with:
2424
python-version: 3.13
2525

.github/workflows/tests-macos.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@ jobs:
77
strategy:
88
fail-fast: false
99
matrix:
10-
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
10+
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14.0-rc.2"]
1111

1212
steps:
13-
- uses: actions/checkout@v4
13+
- uses: actions/checkout@v5
1414

1515
- name: Set up Python ${{ matrix.python-version }}
16-
uses: actions/setup-python@v5
16+
uses: actions/setup-python@v6
1717
with:
1818
python-version: ${{ matrix.python-version }}
1919

.github/workflows/tests-ubuntu.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,19 @@ jobs:
77
strategy:
88
fail-fast: false
99
matrix:
10-
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "pypy3.10", "pypy3.11"]
10+
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14.0-rc.2", "pypy3.11"]
1111

1212
steps:
13-
- uses: actions/checkout@v4
13+
- uses: actions/checkout@v5
1414

1515
- name: Install system libraries
16-
if: contains(matrix.python-version, 'pypy')
16+
if: contains(matrix.python-version, 'pypy') || contains(matrix.python-version, '3.14.0-rc')
1717
run: |
1818
sudo apt-get update
1919
sudo apt-get install libxml2-dev libxslt-dev
2020
2121
- name: Set up Python ${{ matrix.python-version }}
22-
uses: actions/setup-python@v5
22+
uses: actions/setup-python@v6
2323
with:
2424
python-version: ${{ matrix.python-version }}
2525

.github/workflows/tests-windows.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@ jobs:
77
strategy:
88
fail-fast: false
99
matrix:
10-
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
10+
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14.0-rc.2"]
1111

1212
steps:
13-
- uses: actions/checkout@v4
13+
- uses: actions/checkout@v5
1414

1515
- name: Set up Python ${{ matrix.python-version }}
16-
uses: actions/setup-python@v5
16+
uses: actions/setup-python@v6
1717
with:
1818
python-version: ${{ matrix.python-version }}
1919

.pre-commit-config.yaml

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,22 @@
11
repos:
22
- repo: https://github.com/astral-sh/ruff-pre-commit
3-
rev: v0.11.2
3+
rev: v0.13.0
44
hooks:
5-
- id: ruff
5+
- id: ruff-check
66
args: [ --fix ]
77
- id: ruff-format
8+
- repo: https://github.com/adamchainz/blacken-docs
9+
rev: 1.20.0
10+
hooks:
11+
- id: blacken-docs
12+
additional_dependencies:
13+
- black==25.1.0
14+
- repo: https://github.com/pre-commit/pre-commit-hooks
15+
rev: v6.0.0
16+
hooks:
17+
- id: end-of-file-fixer
18+
- id: trailing-whitespace
19+
- repo: https://github.com/sphinx-contrib/sphinx-lint
20+
rev: v1.0.0
21+
hooks:
22+
- id: sphinx-lint

cssselect/parser.py

Lines changed: 48 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -441,7 +441,7 @@ class Hash:
441441
Represents selector#id
442442
"""
443443

444-
def __init__(self, selector: Tree, id: str) -> None:
444+
def __init__(self, selector: Tree, id: str) -> None: # noqa: A002
445445
self.selector = selector
446446
self.id = id
447447

@@ -660,13 +660,13 @@ def parse_simple_selector(
660660
argument, argument_pseudo_element = parse_simple_selector(
661661
stream, inside_negation=True
662662
)
663-
next = stream.next()
663+
next_ = stream.next()
664664
if argument_pseudo_element:
665665
raise SelectorSyntaxError(
666-
f"Got pseudo-element ::{argument_pseudo_element} inside :not() at {next.pos}"
666+
f"Got pseudo-element ::{argument_pseudo_element} inside :not() at {next_.pos}"
667667
)
668-
if next != ("DELIM", ")"):
669-
raise SelectorSyntaxError(f"Expected ')', got {next}")
668+
if next_ != ("DELIM", ")"):
669+
raise SelectorSyntaxError(f"Expected ')', got {next_}")
670670
result = Negation(result, argument)
671671
elif ident.lower() == "has":
672672
combinator, arguments = parse_relative_selector(stream)
@@ -687,46 +687,46 @@ def parse_simple_selector(
687687
return result, pseudo_element
688688

689689

690-
def parse_arguments(stream: TokenStream) -> list[Token]:
690+
def parse_arguments(stream: TokenStream) -> list[Token]: # noqa: RET503
691691
arguments: list[Token] = []
692-
while 1: # noqa: RET503
692+
while 1:
693693
stream.skip_whitespace()
694-
next = stream.next()
695-
if next.type in ("IDENT", "STRING", "NUMBER") or next in [
694+
next_ = stream.next()
695+
if next_.type in ("IDENT", "STRING", "NUMBER") or next_ in [
696696
("DELIM", "+"),
697697
("DELIM", "-"),
698698
]:
699-
arguments.append(next)
700-
elif next == ("DELIM", ")"):
699+
arguments.append(next_)
700+
elif next_ == ("DELIM", ")"):
701701
return arguments
702702
else:
703-
raise SelectorSyntaxError(f"Expected an argument, got {next}")
703+
raise SelectorSyntaxError(f"Expected an argument, got {next_}")
704704

705705

706-
def parse_relative_selector(stream: TokenStream) -> tuple[Token, Selector]:
706+
def parse_relative_selector(stream: TokenStream) -> tuple[Token, Selector]: # noqa: RET503
707707
stream.skip_whitespace()
708708
subselector = ""
709-
next = stream.next()
709+
next_ = stream.next()
710710

711-
if next in [("DELIM", "+"), ("DELIM", "-"), ("DELIM", ">"), ("DELIM", "~")]:
712-
combinator = next
711+
if next_ in [("DELIM", "+"), ("DELIM", "-"), ("DELIM", ">"), ("DELIM", "~")]:
712+
combinator = next_
713713
stream.skip_whitespace()
714-
next = stream.next()
714+
next_ = stream.next()
715715
else:
716716
combinator = Token("DELIM", " ", pos=0)
717717

718-
while 1: # noqa: RET503
719-
if next.type in ("IDENT", "STRING", "NUMBER") or next in [
718+
while 1:
719+
if next_.type in ("IDENT", "STRING", "NUMBER") or next_ in [
720720
("DELIM", "."),
721721
("DELIM", "*"),
722722
]:
723-
subselector += cast("str", next.value)
724-
elif next == ("DELIM", ")"):
723+
subselector += cast("str", next_.value)
724+
elif next_ == ("DELIM", ")"):
725725
result = parse(subselector)
726726
return combinator, result[0]
727727
else:
728-
raise SelectorSyntaxError(f"Expected an argument, got {next}")
729-
next = stream.next()
728+
raise SelectorSyntaxError(f"Expected an argument, got {next_}")
729+
next_ = stream.next()
730730

731731

732732
def parse_simple_selector_arguments(stream: TokenStream) -> list[Tree]:
@@ -738,16 +738,16 @@ def parse_simple_selector_arguments(stream: TokenStream) -> list[Tree]:
738738
f"Got pseudo-element ::{pseudo_element} inside function"
739739
)
740740
stream.skip_whitespace()
741-
next = stream.next()
742-
if next in (("EOF", None), ("DELIM", ",")):
741+
next_ = stream.next()
742+
if next_ in (("EOF", None), ("DELIM", ",")):
743743
stream.next()
744744
stream.skip_whitespace()
745745
arguments.append(result)
746-
elif next == ("DELIM", ")"):
746+
elif next_ == ("DELIM", ")"):
747747
arguments.append(result)
748748
break
749749
else:
750-
raise SelectorSyntaxError(f"Expected an argument, got {next}")
750+
raise SelectorSyntaxError(f"Expected an argument, got {next_}")
751751
return arguments
752752

753753

@@ -772,26 +772,26 @@ def parse_attrib(selector: Tree, stream: TokenStream) -> Attrib:
772772
namespace = op = None
773773
if op is None:
774774
stream.skip_whitespace()
775-
next = stream.next()
776-
if next == ("DELIM", "]"):
775+
next_ = stream.next()
776+
if next_ == ("DELIM", "]"):
777777
return Attrib(selector, namespace, cast("str", attrib), "exists", None)
778-
if next == ("DELIM", "="):
778+
if next_ == ("DELIM", "="):
779779
op = "="
780-
elif next.is_delim("^", "$", "*", "~", "|", "!") and (
780+
elif next_.is_delim("^", "$", "*", "~", "|", "!") and (
781781
stream.peek() == ("DELIM", "=")
782782
):
783-
op = cast("str", next.value) + "="
783+
op = cast("str", next_.value) + "="
784784
stream.next()
785785
else:
786-
raise SelectorSyntaxError(f"Operator expected, got {next}")
786+
raise SelectorSyntaxError(f"Operator expected, got {next_}")
787787
stream.skip_whitespace()
788788
value = stream.next()
789789
if value.type not in ("IDENT", "STRING"):
790790
raise SelectorSyntaxError(f"Expected string or ident, got {value}")
791791
stream.skip_whitespace()
792-
next = stream.next()
793-
if next != ("DELIM", "]"):
794-
raise SelectorSyntaxError(f"Expected ']', got {next}")
792+
next_ = stream.next()
793+
if next_ != ("DELIM", "]"):
794+
raise SelectorSyntaxError(f"Expected ']', got {next_}")
795795
return Attrib(selector, namespace, cast("str", attrib), op, value)
796796

797797

@@ -1015,9 +1015,9 @@ def next(self) -> Token:
10151015
assert self.peeked is not None
10161016
self.used.append(self.peeked)
10171017
return self.peeked
1018-
next = self.next_token()
1019-
self.used.append(next)
1020-
return next
1018+
next_ = self.next_token()
1019+
self.used.append(next_)
1020+
return next_
10211021

10221022
def peek(self) -> Token:
10231023
if not self._peeking:
@@ -1027,18 +1027,18 @@ def peek(self) -> Token:
10271027
return self.peeked
10281028

10291029
def next_ident(self) -> str:
1030-
next = self.next()
1031-
if next.type != "IDENT":
1032-
raise SelectorSyntaxError(f"Expected ident, got {next}")
1033-
return cast("str", next.value)
1030+
next_ = self.next()
1031+
if next_.type != "IDENT":
1032+
raise SelectorSyntaxError(f"Expected ident, got {next_}")
1033+
return cast("str", next_.value)
10341034

10351035
def next_ident_or_star(self) -> str | None:
1036-
next = self.next()
1037-
if next.type == "IDENT":
1038-
return next.value
1039-
if next == ("DELIM", "*"):
1036+
next_ = self.next()
1037+
if next_.type == "IDENT":
1038+
return next_.value
1039+
if next_ == ("DELIM", "*"):
10401040
return None
1041-
raise SelectorSyntaxError(f"Expected ident or '*', got {next}")
1041+
raise SelectorSyntaxError(f"Expected ident or '*', got {next_}")
10421042

10431043
def skip_whitespace(self) -> None:
10441044
peek = self.peek()

cssselect/xpath.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -825,7 +825,7 @@ def __init__(self, xhtml: bool = False) -> None:
825825
self.lower_case_element_names = True
826826
self.lower_case_attribute_names = True
827827

828-
def xpath_checked_pseudo(self, xpath: XPathExpr) -> XPathExpr: # type: ignore[override]
828+
def xpath_checked_pseudo(self, xpath: XPathExpr) -> XPathExpr:
829829
# FIXME: is this really all the elements?
830830
return xpath.add_condition(
831831
"(@selected and name(.) = 'option') or "
@@ -850,15 +850,15 @@ def xpath_lang_function(self, xpath: XPathExpr, function: Function) -> XPathExpr
850850
f"'-'), {arg})]"
851851
)
852852

853-
def xpath_link_pseudo(self, xpath: XPathExpr) -> XPathExpr: # type: ignore[override]
853+
def xpath_link_pseudo(self, xpath: XPathExpr) -> XPathExpr:
854854
return xpath.add_condition(
855855
"@href and (name(.) = 'a' or name(.) = 'link' or name(.) = 'area')"
856856
)
857857

858858
# Links are never visited, the implementation for :visited is the same
859859
# as in GenericTranslator
860860

861-
def xpath_disabled_pseudo(self, xpath: XPathExpr) -> XPathExpr: # type: ignore[override]
861+
def xpath_disabled_pseudo(self, xpath: XPathExpr) -> XPathExpr:
862862
# http://www.w3.org/TR/html5/section-index.html#attributes-1
863863
return xpath.add_condition(
864864
"""
@@ -888,7 +888,7 @@ def xpath_disabled_pseudo(self, xpath: XPathExpr) -> XPathExpr: # type: ignore[
888888
# FIXME: in the second half, add "and is not a descendant of that
889889
# fieldset element's first legend element child, if any."
890890

891-
def xpath_enabled_pseudo(self, xpath: XPathExpr) -> XPathExpr: # type: ignore[override]
891+
def xpath_enabled_pseudo(self, xpath: XPathExpr) -> XPathExpr:
892892
# http://www.w3.org/TR/html5/section-index.html#attributes-1
893893
return xpath.add_condition(
894894
"""

docs/conf.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242

4343
# General information about the project.
4444
project = "cssselect"
45-
copyright = "2012-2017, Simon Sapin, Scrapy developers"
45+
project_copyright = "2012-2017, Simon Sapin, Scrapy developers"
4646

4747
# The version info for the project you're documenting, acts as replacement for
4848
# |version| and |release|, also used in various other places throughout the

0 commit comments

Comments
 (0)