Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions .github/workflows/checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,24 +21,24 @@ jobs:
- python-version: '3.13'
env:
TOXENV: docs
- python-version: '3.13'
- python-version: '3.14'
env:
TOXENV: pre-commit
- python-version: '3.13'
- python-version: '3.14'
env:
TOXENV: pylint
- python-version: '3.13'
- python-version: '3.14'
env:
TOXENV: typing
- python-version: '3.13'
- python-version: '3.14'
env:
TOXENV: twinecheck

steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python-version }}

Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ jobs:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5

- name: Set up Python 3.13
uses: actions/setup-python@v5
- name: Set up Python 3.14
uses: actions/setup-python@v6
with:
python-version: '3.13'
python-version: '3.14'

- name: Check Tag
id: check-release-tag
Expand Down
8 changes: 3 additions & 5 deletions .github/workflows/tests-macos.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,18 @@ jobs:
fail-fast: false
matrix:
python-version:
- '3.9'
- '3.10'
- '3.11'
- '3.12'
- '3.13'
- 3.14.0-rc.1
- pypy3.10
- '3.14'
- pypy3.11

steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python-version }}

Expand Down
8 changes: 3 additions & 5 deletions .github/workflows/tests-ubuntu.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,18 @@ jobs:
fail-fast: false
matrix:
python-version:
- '3.9'
- '3.10'
- '3.11'
- '3.12'
- '3.13'
- 3.14.0-rc.1
- pypy3.10
- '3.14'
- pypy3.11

steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python-version }}

Expand Down
8 changes: 3 additions & 5 deletions .github/workflows/tests-windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,18 @@ jobs:
fail-fast: false
matrix:
python-version:
- '3.9'
- '3.10'
- '3.11'
- '3.12'
- '3.13'
- 3.14.0-rc.1
- pypy3.10
- '3.14'
- pypy3.11

steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python-version }}

Expand Down
8 changes: 4 additions & 4 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
---
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.12.5
rev: v0.14.4
hooks:
- id: ruff-check
args: [--fix]
- id: ruff-format
- repo: https://github.com/adamchainz/blacken-docs
rev: 1.19.1
rev: 1.20.0
hooks:
- id: blacken-docs
additional_dependencies:
- black==25.1.0
- black==25.9.0
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
rev: v6.0.0
hooks:
- id: end-of-file-fixer
- id: trailing-whitespace
Expand Down
2 changes: 1 addition & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ This is a Python library of web-related functions, such as:
Requirements
============

Python 3.9+
Python 3.10+

Install
=======
Expand Down
2 changes: 1 addition & 1 deletion docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ Modules
Requirements
============

Python 3.9+
Python 3.10+

Install
=======
Expand Down
15 changes: 2 additions & 13 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ classifiers = [
"Operating System :: OS Independent",
"Programming Language :: Python",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
Expand All @@ -28,7 +27,7 @@ classifiers = [
"Topic :: Internet :: WWW/HTTP",
"Topic :: Software Development :: Libraries :: Python Modules",
]
requires-python = ">=3.9"
requires-python = ">=3.10"
dynamic = ["version"]

[project.urls]
Expand Down Expand Up @@ -66,18 +65,8 @@ filename = "docs/conf.py"
[tool.coverage.run]
branch = true

[tool.coverage.report]
exclude_also = [
"if TYPE_CHECKING:",
]

[tool.mypy]
check_untyped_defs = true

[[tool.mypy.overrides]]
# All non-tests functions must be typed.
module = "w3lib.*"
allow_untyped_defs = false
strict = true

[[tool.mypy.overrides]]
# Allow test functions to be untyped
Expand Down
6 changes: 3 additions & 3 deletions tests/test_encoding.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ class TestHtmlConversion:
def test_unicode_body(self):
unicode_string = "\u043a\u0438\u0440\u0438\u043b\u043b\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u0442\u0435\u043a\u0441\u0442"
original_string = unicode_string.encode("cp1251")
encoding, body_unicode = html_to_unicode(ct("cp1251"), original_string)
_, body_unicode = html_to_unicode(ct("cp1251"), original_string)
# check body_as_unicode
assert isinstance(body_unicode, str)
assert body_unicode == unicode_string
Expand Down Expand Up @@ -207,15 +207,15 @@ def test_utf8_unexpected_end_of_data_with_valid_utf8_BOM(self):

def test_replace_wrong_encoding(self):
"""Test invalid chars are replaced properly"""
encoding, body_unicode = html_to_unicode(ct("utf-8"), b"PREFIX\xe3\xabSUFFIX")
_, body_unicode = html_to_unicode(ct("utf-8"), b"PREFIX\xe3\xabSUFFIX")
# XXX: Policy for replacing invalid chars may suffer minor variations
# but it should always contain the unicode replacement char ('\ufffd')
assert "\ufffd" in body_unicode, repr(body_unicode)
assert "PREFIX" in body_unicode, repr(body_unicode)
assert "SUFFIX" in body_unicode, repr(body_unicode)

# Do not destroy html tags due to encoding bugs
encoding, body_unicode = html_to_unicode(ct("utf-8"), b"\xf0<span>value</span>")
_, body_unicode = html_to_unicode(ct("utf-8"), b"\xf0<span>value</span>")
assert "<span>value</span>" in body_unicode, repr(body_unicode)

def _assert_encoding_detected(
Expand Down
5 changes: 4 additions & 1 deletion tests/test_url.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import sys
from inspect import isclass
from pathlib import Path
from typing import Callable
from typing import TYPE_CHECKING
from urllib.parse import urlparse

import pytest
Expand Down Expand Up @@ -32,6 +32,9 @@
url_query_parameter,
)

if TYPE_CHECKING:
from collections.abc import Callable

# Test cases for URL-to-safe-URL conversions with a URL and an encoding as
# input parameters.
#
Expand Down
15 changes: 7 additions & 8 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,12 @@
# and then run "tox" from this directory.

[tox]
envlist = py39, py310, py311, py312, py313, py314, pypy3.10, pypy3.11, docs, pylint, typing, pre-commit, twinecheck
envlist = py310, py311, py312, py313, py314, pypy3.11, docs, pylint, typing, pre-commit, twinecheck

[testenv]
deps =
coverage >= 7.2.0
pytest !=3.1.1, !=3.1.2
pytest-cov
pytest-cov >= 7.0.0
commands =
python -m pytest \
--doctest-modules \
Expand All @@ -21,14 +20,14 @@ commands =
basepython = python3
deps =
pytest
mypy==1.17.0
mypy==1.18.2
commands =
mypy --strict {posargs: w3lib tests}
mypy {posargs: w3lib tests}

[testenv:pylint]
deps =
{[testenv]deps}
pylint==3.3.7
pylint==4.0.2
commands =
pylint docs tests w3lib

Expand All @@ -46,8 +45,8 @@ skip_install = true
[testenv:twinecheck]
basepython = python3
deps =
twine==6.1.0
build==1.2.2.post1
twine==6.2.0
build==1.3.0
commands =
python -m build --sdist
twine check dist/*
4 changes: 2 additions & 2 deletions w3lib/_types.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from __future__ import annotations

from typing import Union
from typing import TypeAlias

# the base class UnicodeError doesn't have attributes like start / end
AnyUnicodeError = Union[UnicodeEncodeError, UnicodeDecodeError]
AnyUnicodeError: TypeAlias = UnicodeEncodeError | UnicodeDecodeError
4 changes: 3 additions & 1 deletion w3lib/encoding.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@
import encodings
import re
from re import Match
from typing import TYPE_CHECKING, Callable, cast
from typing import TYPE_CHECKING, cast

import w3lib.util

if TYPE_CHECKING:
from collections.abc import Callable

from w3lib._types import AnyUnicodeError

_HEADER_ENCODING_RE = re.compile(r"charset=([\w-]+)", re.IGNORECASE)
Expand Down
6 changes: 3 additions & 3 deletions w3lib/http.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
from base64 import b64encode
from collections.abc import Mapping, MutableMapping, Sequence
from io import BytesIO
from typing import Any, Union, overload
from typing import Any, TypeAlias, overload

from w3lib.util import to_bytes, to_unicode

HeadersDictInput = Mapping[bytes, Union[Any, Sequence[bytes]]]
HeadersDictOutput = MutableMapping[bytes, list[bytes]]
HeadersDictInput: TypeAlias = Mapping[bytes, Any | Sequence[bytes]]
HeadersDictOutput: TypeAlias = MutableMapping[bytes, list[bytes]]


@overload
Expand Down
4 changes: 2 additions & 2 deletions w3lib/url.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
import re
import string
from pathlib import Path
from typing import TYPE_CHECKING, Callable, NamedTuple, cast, overload
from typing import TYPE_CHECKING, NamedTuple, cast, overload
from urllib.parse import ( # type: ignore[attr-defined]
ParseResult,
_coerce_args,
Expand All @@ -35,7 +35,7 @@
from .util import to_unicode

if TYPE_CHECKING:
from collections.abc import Sequence
from collections.abc import Callable, Sequence

from ._types import AnyUnicodeError

Expand Down