Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-httptools for 
openSUSE:Factory checked in at 2026-06-29 17:29:19
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-httptools (Old)
 and      /work/SRC/openSUSE:Factory/.python-httptools.new.11887 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-httptools"

Mon Jun 29 17:29:19 2026 rev:9 rq:1362042 version:0.8.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-httptools/python-httptools.changes        
2026-03-30 18:29:42.199090362 +0200
+++ 
/work/SRC/openSUSE:Factory/.python-httptools.new.11887/python-httptools.changes 
    2026-06-29 17:29:22.027999239 +0200
@@ -1,0 +2,11 @@
+Sat Jun 27 20:53:02 UTC 2026 - Dirk Müller <[email protected]>
+
+- update to 0.8.0:
+  * Add http-parser and llhttp licenses into the wheels
+  * Mark cython module as free-threading compatible
+  * Fix all typing issues
+  * Bump llhttp to 9.4.1
+  * Security: fix URL truncation issue
+  * Allow building with latest setuptools
+
+-------------------------------------------------------------------

Old:
----
  httptools-0.7.1.tar.gz

New:
----
  httptools-0.8.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-httptools.spec ++++++
--- /var/tmp/diff_new_pack.e99u2I/_old  2026-06-29 17:29:22.804025467 +0200
+++ /var/tmp/diff_new_pack.e99u2I/_new  2026-06-29 17:29:22.812025737 +0200
@@ -18,7 +18,7 @@
 
 %{?sle15_python_module_pythons}
 Name:           python-httptools
-Version:        0.7.1
+Version:        0.8.0
 Release:        0
 Summary:        Python framework independent HTTP protocol utils
 License:        MIT

++++++ httptools-0.7.1.tar.gz -> httptools-0.8.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/httptools-0.7.1/.github/workflows/release.yml 
new/httptools-0.8.0/.github/workflows/release.yml
--- old/httptools-0.7.1/.github/workflows/release.yml   2025-10-10 
05:41:45.000000000 +0200
+++ new/httptools-0.8.0/.github/workflows/release.yml   2026-05-26 
00:02:50.000000000 +0200
@@ -78,6 +78,7 @@
           - "cp312"
           - "cp313"
           - "cp314"
+          - "cp314t"
         exclude:
           - os: ubuntu-latest
             cibw_arch: universal2
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/httptools-0.7.1/.github/workflows/tests.yml 
new/httptools-0.8.0/.github/workflows/tests.yml
--- old/httptools-0.7.1/.github/workflows/tests.yml     2025-10-10 
05:41:45.000000000 +0200
+++ new/httptools-0.8.0/.github/workflows/tests.yml     2026-05-26 
00:02:50.000000000 +0200
@@ -10,11 +10,29 @@
       - master
 
 jobs:
+  typecheck:
+    runs-on: ubuntu-latest
+
+    steps:
+    - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871  # v4.2.1
+      with:
+        fetch-depth: 50
+        submodules: true
+
+    - name: Set up Python ${{ matrix.python-version }}
+      uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405  # 
v6.2.0
+      with:
+        python-version: "3.9"
+
+    - name: Type check
+      run: make typecheck
+
+
   build:
     runs-on: ${{ matrix.os }}
     strategy:
       matrix:
-        python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"]
+        python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14", 
"3.14t"]
         os: [windows-latest, ubuntu-latest, macos-latest]
 
     env:
@@ -37,7 +55,7 @@
           __version__\s*=\s*(?:['"])([[:PEP440:]])(?:['"])
 
     - name: Set up Python ${{ matrix.python-version }}
-      uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3  # 
v5.2.0
+      uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405  # 
v6.2.0
       if: steps.release.outputs.version == 0
       with:
         python-version: ${{ matrix.python-version }}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/httptools-0.7.1/Makefile new/httptools-0.8.0/Makefile
--- old/httptools-0.7.1/Makefile        2025-10-10 05:41:45.000000000 +0200
+++ new/httptools-0.8.0/Makefile        2026-05-26 00:02:50.000000000 +0200
@@ -12,11 +12,14 @@
 endif
 
 compile:
-       $(PIP) install -e .
+       $(PIP) install -e . --group dev
 
 test: compile
        $(PYTHON) -m unittest -v
 
+typecheck: compile
+       $(PYTHON) -m pyright
+
 clean:
        find $(ROOT)/httptools/parser -name '*.c' | xargs rm -f
        find $(ROOT)/httptools/parser -name '*.so' | xargs rm -f
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/httptools-0.7.1/httptools/__init__.py 
new/httptools-0.8.0/httptools/__init__.py
--- old/httptools-0.7.1/httptools/__init__.py   2025-10-10 05:41:45.000000000 
+0200
+++ new/httptools-0.8.0/httptools/__init__.py   2026-05-26 00:02:50.000000000 
+0200
@@ -1,6 +1,35 @@
 from . import parser
-from .parser import *  # NOQA
+from .parser import (
+    HTTPProtocol,
+    HttpRequestParser,
+    HttpResponseParser,
+    HttpParserError,
+    HttpParserCallbackError,
+    HttpParserInvalidStatusError,
+    HttpParserInvalidMethodError,
+    HttpParserInvalidURLError,
+    HttpParserUpgrade,
+    parse_url,
+)
 
-from ._version import __version__  # NOQA
+from ._version import __version__
 
-__all__ = parser.__all__ + ('__version__',)  # NOQA
+__all__ = (
+    "parser",
+    # protocol
+    "HTTPProtocol",
+    # parser
+    "HttpRequestParser",
+    "HttpResponseParser",
+    # errors
+    "HttpParserError",
+    "HttpParserCallbackError",
+    "HttpParserInvalidStatusError",
+    "HttpParserInvalidMethodError",
+    "HttpParserInvalidURLError",
+    "HttpParserUpgrade",
+    # url parser
+    "parse_url",
+    # version
+    "__version__",
+)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/httptools-0.7.1/httptools/_version.py 
new/httptools-0.8.0/httptools/_version.py
--- old/httptools-0.7.1/httptools/_version.py   2025-10-10 05:41:45.000000000 
+0200
+++ new/httptools-0.8.0/httptools/_version.py   2026-05-26 00:02:50.000000000 
+0200
@@ -10,4 +10,4 @@
 # supported platforms, publish the packages on PyPI, merge the PR
 # to the target branch, create a Git tag pointing to the commit.
 
-__version__ = '0.7.1'
+__version__ = '0.8.0'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/httptools-0.7.1/httptools/parser/__init__.py 
new/httptools-0.8.0/httptools/parser/__init__.py
--- old/httptools-0.7.1/httptools/parser/__init__.py    2025-10-10 
05:41:45.000000000 +0200
+++ new/httptools-0.8.0/httptools/parser/__init__.py    2026-05-26 
00:02:50.000000000 +0200
@@ -1,6 +1,28 @@
 from .protocol import HTTPProtocol
-from .parser import *  # NoQA
-from .errors import *  # NoQA
-from .url_parser import *  # NoQA
+from .parser import HttpRequestParser, HttpResponseParser  # NoQA
+from .errors import (
+    HttpParserError,
+    HttpParserCallbackError,
+    HttpParserInvalidStatusError,
+    HttpParserInvalidMethodError,
+    HttpParserInvalidURLError,
+    HttpParserUpgrade,
+)
+from .url_parser import parse_url
 
-__all__ = parser.__all__ + errors.__all__ + url_parser.__all__  # NoQA
+__all__ = (
+    # protocol
+    "HTTPProtocol",
+    # parser
+    "HttpRequestParser",
+    "HttpResponseParser",
+    # errors
+    "HttpParserError",
+    "HttpParserCallbackError",
+    "HttpParserInvalidStatusError",
+    "HttpParserInvalidMethodError",
+    "HttpParserInvalidURLError",
+    "HttpParserUpgrade",
+    # url_parser
+    "parse_url",
+)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/httptools-0.7.1/httptools/parser/parser.pyi 
new/httptools-0.8.0/httptools/parser/parser.pyi
--- old/httptools-0.7.1/httptools/parser/parser.pyi     2025-10-10 
05:41:45.000000000 +0200
+++ new/httptools-0.8.0/httptools/parser/parser.pyi     2026-05-26 
00:02:50.000000000 +0200
@@ -1,43 +1,44 @@
-from typing import Union, Any
 from array import array
 from .protocol import HTTPProtocol
 
 class HttpParser:
-    def __init__(self, protocol: Union[HTTPProtocol, Any]) -> None:
-        """
-        protocol -- a Python object with the following methods
-        (all optional):
+    def __init__(self, protocol: HTTPProtocol | object) -> None:
+        """The HTTP parser.
 
-          - on_message_begin()
-          - on_url(url: bytes)
-          - on_header(name: bytes, value: bytes)
-          - on_headers_complete()
-          - on_body(body: bytes)
-          - on_message_complete()
-          - on_chunk_header()
-          - on_chunk_complete()
-          - on_status(status: bytes)
+        Args:
+            protocol (HTTPProtocol): Callback interface for the parser.
         """
 
+    def set_dangerous_leniencies(
+        self,
+        lenient_headers: bool | None = None,
+        lenient_chunked_length: bool | None = None,
+        lenient_keep_alive: bool | None = None,
+        lenient_transfer_encoding: bool | None = None,
+        lenient_version: bool | None = None,
+        lenient_data_after_close: bool | None = None,
+        lenient_optional_lf_after_cr: bool | None = None,
+        lenient_optional_cr_before_lf: bool | None = None,
+        lenient_optional_crlf_after_chunk: bool | None = None,
+        lenient_spaces_after_chunk_size: bool | None = None,
+    ) -> None:
+        """Set dangerous leniencies for the parser."""
+
     def get_http_version(self) -> str:
-        """Return an HTTP protocol version."""
-        ...
+        """Retrieve the HTTP protocol version e.g. "1.1"."""
 
     def should_keep_alive(self) -> bool:
-        """Return ``True`` if keep-alive mode is preferred."""
-        ...
+        """Return `True` if keep-alive mode is preferred."""
 
     def should_upgrade(self) -> bool:
-        """Return ``True`` if the parsed request is a valid Upgrade request.
+        """Return `True` if the parsed request is a valid Upgrade request.
         The method exposes a flag set just before on_headers_complete.
         Calling this method earlier will only yield `False`."""
-        ...
 
-    def feed_data(self, data: Union[bytes, bytearray, memoryview, array]) -> 
None:
+    def feed_data(self, data: bytes | bytearray | memoryview | array[int]) -> 
None:
         """Feed data to the parser.
 
-        Will eventually trigger callbacks on the ``protocol``
-        object.
+        Will eventually trigger callbacks on the ``protocol`` object.
 
         On HTTP upgrade, this method will raise an
         ``HttpParserUpgrade`` exception, with its sole argument
@@ -45,13 +46,13 @@
         """
 
 class HttpRequestParser(HttpParser):
-    """Used for parsing http requests from the server's side"""
+    """Used for parsing http requests from the server side."""
 
     def get_method(self) -> bytes:
-        """Return HTTP request method (GET, HEAD, etc)"""
+        """Retrieve the HTTP method of the request."""
 
 class HttpResponseParser(HttpParser):
-    """Used for parsing http requests from the client's side"""
+    """Used for parsing http responses from the client side."""
 
     def get_status_code(self) -> int:
-        """Return the status code of the HTTP response"""
+        """Retrieve the status code of the HTTP response."""
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/httptools-0.7.1/httptools/parser/protocol.py 
new/httptools-0.8.0/httptools/parser/protocol.py
--- old/httptools-0.7.1/httptools/parser/protocol.py    2025-10-10 
05:41:45.000000000 +0200
+++ new/httptools-0.8.0/httptools/parser/protocol.py    2026-05-26 
00:02:50.000000000 +0200
@@ -4,12 +4,12 @@
 class HTTPProtocol(Protocol):
     """Used for providing static type-checking when parsing through the http 
protocol"""
 
-    def on_message_begin() -> None: ...
-    def on_url(url: bytes) -> None: ...
-    def on_header(name: bytes, value: bytes) -> None: ...
-    def on_headers_complete() -> None: ...
-    def on_body(body: bytes) -> None: ...
-    def on_message_complete() -> None: ...
-    def on_chunk_header() -> None: ...
-    def on_chunk_complete() -> None: ...
-    def on_status(status: bytes) -> None: ...
+    def on_message_begin(self) -> None: ...
+    def on_url(self, url: bytes) -> None: ...
+    def on_header(self, name: bytes, value: bytes) -> None: ...
+    def on_headers_complete(self) -> None: ...
+    def on_body(self, body: bytes) -> None: ...
+    def on_message_complete(self) -> None: ...
+    def on_chunk_header(self) -> None: ...
+    def on_chunk_complete(self) -> None: ...
+    def on_status(self, status: bytes) -> None: ...
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/httptools-0.7.1/httptools/parser/url_parser.pyi 
new/httptools-0.8.0/httptools/parser/url_parser.pyi
--- old/httptools-0.7.1/httptools/parser/url_parser.pyi 2025-10-10 
05:41:45.000000000 +0200
+++ new/httptools-0.8.0/httptools/parser/url_parser.pyi 2026-05-26 
00:02:50.000000000 +0200
@@ -1,4 +1,3 @@
-from typing import Union
 from array import array
 
 class URL:
@@ -10,18 +9,5 @@
     fragment: bytes
     userinfo: bytes
 
-def parse_url(url: Union[bytes, bytearray, memoryview, array]) -> URL:
-    """Parse URL strings into a structured Python object.
-
-    Returns an instance of ``httptools.URL`` class with the
-    following attributes:
-
-      - schema: bytes
-      - host: bytes
-      - port: int
-      - path: bytes
-      - query: bytes
-      - fragment: bytes
-      - userinfo: bytes
-    """
-    ...
+def parse_url(url: bytes | bytearray | memoryview | array[int]) -> URL:
+    """Parse a URL string into a structured Python object."""
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/httptools-0.7.1/httptools/parser/url_parser.pyx 
new/httptools-0.8.0/httptools/parser/url_parser.pyx
--- old/httptools-0.7.1/httptools/parser/url_parser.pyx 2025-10-10 
05:41:45.000000000 +0200
+++ new/httptools-0.8.0/httptools/parser/url_parser.pyx 2026-05-26 
00:02:50.000000000 +0200
@@ -12,6 +12,8 @@
 
 __all__ = ('parse_url',)
 
+DEF MAX_URL_LENGTH = (1 << 16) - 1
+
 @cython.freelist(250)
 cdef class URL:
     cdef readonly bytes schema
@@ -63,6 +65,14 @@
 
     PyObject_GetBuffer(url, &py_buf, PyBUF_SIMPLE)
     try:
+        if py_buf.len > MAX_URL_LENGTH:
+            # http_parser stores URL field offsets/lengths as uint16_t,
+            # so URLs longer than this will cause silent truncation.
+            # See https://github.com/MagicStack/httptools/issues/142
+            raise HttpParserInvalidURLError(
+                "url is too long: url length of {} bytes exceeds the "
+                "maximum of {} bytes".format(py_buf.len, MAX_URL_LENGTH))
+
         buf_data = <char*>py_buf.buf
         res = uparser.http_parser_parse_url(buf_data, py_buf.len, 0, parsed)
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/httptools-0.7.1/pyproject.toml 
new/httptools-0.8.0/pyproject.toml
--- old/httptools-0.7.1/pyproject.toml  2025-10-10 05:41:45.000000000 +0200
+++ new/httptools-0.8.0/pyproject.toml  2026-05-26 00:02:50.000000000 +0200
@@ -1,6 +1,6 @@
 [build-system]
 build-backend = "setuptools.build_meta"
-requires = ["setuptools==80.9.0"]
+requires = ["setuptools>=80.9.0,<=82.0.1"]
 
 [project]
 name = "httptools"
@@ -18,12 +18,34 @@
     {name = "Yury Selivanov", email="[email protected]"},
 ]
 license = "MIT"
-license-files = ["LICENSE"]
+license-files = [
+    "LICENSE",
+    "vendor/http-parser/LICENSE-MIT",
+    "vendor/llhttp/LICENSE",
+]
 description = "A collection of framework independent HTTP protocol utils."
 readme = "README.md"
 
 [project.urls]
 Homepage = "https://github.com/MagicStack/httptools";
 
-[project.optional-dependencies]
-test = []  # for backward compatibility
+[dependency-groups]
+dev = [
+    # type checker
+    "pyright >= 1.1.406",
+    # tests
+    "pytest",
+    # build
+    "setuptools",
+    "wheel"
+]
+
+[tool.pyright]
+pythonVersion = "3.8"
+typeCheckingMode = "strict"
+reportMissingTypeStubs = false
+reportUnnecessaryIsInstance = false
+reportUnnecessaryTypeIgnoreComment = true
+reportMissingModuleSource = false
+include = ["httptools"]
+exclude = ["tests"]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/httptools-0.7.1/setup.py new/httptools-0.8.0/setup.py
--- old/httptools-0.7.1/setup.py        2025-10-10 05:41:45.000000000 +0200
+++ new/httptools-0.8.0/setup.py        2026-05-26 00:02:50.000000000 +0200
@@ -7,7 +7,7 @@
 from setuptools.command.build_ext import build_ext as build_ext
 
 
-CFLAGS = ['-O2']
+CFLAGS = ['-O2', '-DCYTHON_FREETHREADING_COMPATIBLE=1']
 
 ROOT = pathlib.Path(__file__).parent
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/httptools-0.7.1/tests/test_parser.py 
new/httptools-0.8.0/tests/test_parser.py
--- old/httptools-0.7.1/tests/test_parser.py    2025-10-10 05:41:45.000000000 
+0200
+++ new/httptools-0.8.0/tests/test_parser.py    2026-05-26 00:02:50.000000000 
+0200
@@ -686,3 +686,9 @@
     def test_parser_url_10(self):
         with self.assertRaisesRegex(TypeError, 'a bytes-like object'):
             self.parse('dsf://aaa')
+
+    def test_parser_url_too_long(self):
+        url = b'http://h/' + b'a' * 65535
+        with self.assertRaisesRegex(httptools.HttpParserInvalidURLError,
+                                    'url is too long'):
+            self.parse(url)

Reply via email to