Skip to content

Commit

Permalink
Drop Python 3.7 support (#280)
Browse files Browse the repository at this point in the history
  • Loading branch information
wRAR authored Jul 6, 2023
1 parent 8c39b2f commit 085fee9
Show file tree
Hide file tree
Showing 7 changed files with 51 additions and 67 deletions.
3 changes: 0 additions & 3 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,6 @@ jobs:
fail-fast: false
matrix:
include:
- python-version: "3.7"
env:
TOXENV: py
- python-version: "3.8"
env:
TOXENV: py
Expand Down
20 changes: 8 additions & 12 deletions parsel/csstranslator.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from functools import lru_cache
from typing import TYPE_CHECKING, Any, Optional
from typing import TYPE_CHECKING, Any, Optional, Protocol

from cssselect import GenericTranslator as OriginalGenericTranslator
from cssselect import HTMLTranslator as OriginalHTMLTranslator
Expand Down Expand Up @@ -67,17 +67,13 @@ def join(
return self


if TYPE_CHECKING:
# requires Python 3.8
from typing import Protocol

# e.g. cssselect.GenericTranslator, cssselect.HTMLTranslator
class TranslatorProtocol(Protocol):
def xpath_element(self, selector: Element) -> OriginalXPathExpr:
pass
# e.g. cssselect.GenericTranslator, cssselect.HTMLTranslator
class TranslatorProtocol(Protocol):
def xpath_element(self, selector: Element) -> OriginalXPathExpr:
pass

def css_to_xpath(self, css: str, prefix: str = ...) -> str:
pass
def css_to_xpath(self, css: str, prefix: str = ...) -> str:
pass


class TranslatorMixin:
Expand All @@ -87,7 +83,7 @@ class TranslatorMixin:
"""

def xpath_element(
self: "TranslatorProtocol", selector: Element
self: TranslatorProtocol, selector: Element
) -> XPathExpr:
# https://github.com/python/mypy/issues/12344
xpath = super().xpath_element(selector) # type: ignore[safe-super]
Expand Down
23 changes: 8 additions & 15 deletions parsel/selector.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,41 +9,34 @@
Any,
Dict,
List,
Literal,
Mapping,
Optional,
Pattern,
SupportsIndex,
Tuple,
Type,
TypedDict,
TypeVar,
Union,
)
from warnings import warn

try:
from typing import TypedDict # pylint: disable=ungrouped-imports
except ImportError: # Python 3.7
from typing_extensions import TypedDict

import jmespath
from lxml import etree, html
from packaging.version import Version

from .csstranslator import GenericTranslator, HTMLTranslator
from .utils import extract_regex, flatten, iflatten, shorten

if typing.TYPE_CHECKING:
# both require Python 3.8
from typing import Literal, SupportsIndex

# simplified _OutputMethodArg from types-lxml
_TostringMethodType = Literal[
"html",
"xml",
]


_SelectorType = TypeVar("_SelectorType", bound="Selector")
_ParserType = Union[etree.XMLParser, etree.HTMLParser]
# simplified _OutputMethodArg from types-lxml
_TostringMethodType = Literal[
"html",
"xml",
]

lxml_version = Version(etree.__version__)
lxml_huge_tree_version = Version("4.2")
Expand Down
4 changes: 1 addition & 3 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,9 @@
"jmespath",
"lxml",
"packaging",
"typing_extensions; python_version < '3.8'",
"w3lib>=1.19.0",
],
python_requires=">=3.7",
python_requires=">=3.8",
license="BSD",
zip_safe=False,
keywords="parsel",
Expand All @@ -45,7 +44,6 @@
"Topic :: Text Processing :: Markup :: HTML",
"Topic :: Text Processing :: Markup :: XML",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
Expand Down
61 changes: 30 additions & 31 deletions tests/test_selector_csstranslator.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,17 @@
Selector tests for cssselect backend
"""
import unittest
from typing import TYPE_CHECKING, Any, Callable, List, Type
from typing import Any, Callable, List, Type, Protocol, Tuple, Union

import cssselect
import pytest
from packaging.version import Version

from parsel.csstranslator import GenericTranslator, HTMLTranslator
from parsel.csstranslator import (
GenericTranslator,
HTMLTranslator,
TranslatorProtocol,
)
from parsel import Selector
from cssselect.parser import SelectorSyntaxError
from cssselect.xpath import ExpressionError
Expand Down Expand Up @@ -50,39 +54,34 @@
"""


if TYPE_CHECKING:
# requires Python 3.8
from typing import Protocol
class TranslatorTestProtocol(Protocol):
tr_cls: Type[TranslatorProtocol]
tr: TranslatorProtocol

from parsel.csstranslator import TranslatorProtocol
def c2x(self, css: str, prefix: str = ...) -> str:
pass

class TranslatorTestProtocol(Protocol):
tr_cls: Type[TranslatorProtocol]
tr: TranslatorProtocol
def assertEqual(self, first: Any, second: Any, msg: Any = ...) -> None:
pass

def c2x(self, css: str, prefix: str = ...) -> str:
pass

def assertEqual(self, first: Any, second: Any, msg: Any = ...) -> None:
pass

def assertRaises(
self,
expected_exception: type[BaseException]
| tuple[type[BaseException], ...],
callable: Callable[..., object],
*args: Any,
**kwargs: Any,
) -> None:
pass
def assertRaises(
self,
expected_exception: Union[
Type[BaseException], Tuple[Type[BaseException], ...]
],
callable: Callable[..., object],
*args: Any,
**kwargs: Any,
) -> None:
pass


class TranslatorTestMixin:
def setUp(self: "TranslatorTestProtocol") -> None:
def setUp(self: TranslatorTestProtocol) -> None:
self.tr = self.tr_cls()
self.c2x = self.tr.css_to_xpath

def test_attr_function(self: "TranslatorTestProtocol") -> None:
def test_attr_function(self: TranslatorTestProtocol) -> None:
cases = [
("::attr(name)", "descendant-or-self::*/@name"),
("a::attr(href)", "descendant-or-self::a/@href"),
Expand All @@ -95,7 +94,7 @@ def test_attr_function(self: "TranslatorTestProtocol") -> None:
for css, xpath in cases:
self.assertEqual(self.c2x(css), xpath, css)

def test_attr_function_exception(self: "TranslatorTestProtocol") -> None:
def test_attr_function_exception(self: TranslatorTestProtocol) -> None:
cases = [
("::attr(12)", ExpressionError),
("::attr(34test)", ExpressionError),
Expand All @@ -104,7 +103,7 @@ def test_attr_function_exception(self: "TranslatorTestProtocol") -> None:
for css, exc in cases:
self.assertRaises(exc, self.c2x, css)

def test_text_pseudo_element(self: "TranslatorTestProtocol") -> None:
def test_text_pseudo_element(self: TranslatorTestProtocol) -> None:
cases = [
("::text", "descendant-or-self::text()"),
("p::text", "descendant-or-self::p/text()"),
Expand Down Expand Up @@ -133,7 +132,7 @@ def test_text_pseudo_element(self: "TranslatorTestProtocol") -> None:
for css, xpath in cases:
self.assertEqual(self.c2x(css), xpath, css)

def test_pseudo_function_exception(self: "TranslatorTestProtocol") -> None:
def test_pseudo_function_exception(self: TranslatorTestProtocol) -> None:
cases = [
("::attribute(12)", ExpressionError),
("::text()", ExpressionError),
Expand All @@ -142,14 +141,14 @@ def test_pseudo_function_exception(self: "TranslatorTestProtocol") -> None:
for css, exc in cases:
self.assertRaises(exc, self.c2x, css)

def test_unknown_pseudo_element(self: "TranslatorTestProtocol") -> None:
def test_unknown_pseudo_element(self: TranslatorTestProtocol) -> None:
cases = [
("::text-node", ExpressionError),
]
for css, exc in cases:
self.assertRaises(exc, self.c2x, css)

def test_unknown_pseudo_class(self: "TranslatorTestProtocol") -> None:
def test_unknown_pseudo_class(self: TranslatorTestProtocol) -> None:
cases = [
(":text", ExpressionError),
(":attribute(name)", ExpressionError),
Expand Down
6 changes: 4 additions & 2 deletions tests/typing/selector.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Basic usage of the Selector, strongly typed to test the typing of parsel's API.
import re
from typing import List

from parsel import Selector


Expand All @@ -8,9 +10,9 @@ def correct() -> None:
text="<html><body><ul><li>1</li><li>2</li><li>3</li></ul></body></html>"
)

li_values: list[str] = selector.css("li").getall()
li_values: List[str] = selector.css("li").getall()
selector.re_first(re.compile(r"[32]"), "").strip()
xpath_values: list[str] = selector.xpath(
xpath_values: List[str] = selector.xpath(
"//somens:a/text()", namespaces={"somens": "http://scrapy.org"}
).extract()

Expand Down
1 change: 0 additions & 1 deletion tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ deps =
types-setuptools==67.2.0.1
py==1.11.0
mypy==1.0.0
typing-extensions==4.4.0
commands =
mypy {posargs:parsel tests} --strict

Expand Down

0 comments on commit 085fee9

Please sign in to comment.