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-03-30 18:29:40
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-httptools (Old)
 and      /work/SRC/openSUSE:Factory/.python-httptools.new.1999 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-httptools"

Mon Mar 30 18:29:40 2026 rev:8 rq:1343385 version:0.7.1

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-httptools/python-httptools.changes        
2024-01-07 21:38:55.068997417 +0100
+++ 
/work/SRC/openSUSE:Factory/.python-httptools.new.1999/python-httptools.changes  
    2026-03-30 18:29:42.199090362 +0200
@@ -1,0 +2,12 @@
+Fri Mar 27 13:52:03 UTC 2026 - Georg Pfuetzenreuter 
<[email protected]>
+
+- Update to 0.7.1:
+  * Drop Python 3.8, add Python 3.14
+  * Bump llhttp to 9.3.0 (by @ngoldbaum @Carreau @fantix in
+    59bf94f for #129)
+  * Static Type-checking for httptools (#100) (by @Vizonex
+    @KRRT7 in b55f5fe for #100)
+- Update vendored llhttp to 9.3.0
+- Remove test conditionals for obsolete distributions
+
+-------------------------------------------------------------------

Old:
----
  httptools-0.6.1.tar.gz
  llhttp-release-v6.0.6.tar.gz

New:
----
  httptools-0.7.1.tar.gz
  llhttp-release-v9.3.0.tar.gz

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

Other differences:
------------------
++++++ python-httptools.spec ++++++
--- /var/tmp/diff_new_pack.RaQUKs/_old  2026-03-30 18:29:42.935120953 +0200
+++ /var/tmp/diff_new_pack.RaQUKs/_new  2026-03-30 18:29:42.939121119 +0200
@@ -1,7 +1,7 @@
 #
 # spec file for package python-httptools
 #
-# Copyright (c) 2024 SUSE LLC
+# Copyright (c) 2026 SUSE LLC and contributors
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -18,16 +18,15 @@
 
 %{?sle15_python_module_pythons}
 Name:           python-httptools
-Version:        0.6.1
+Version:        0.7.1
 Release:        0
 Summary:        Python framework independent HTTP protocol utils
 License:        MIT
 Group:          Development/Languages/Python
 URL:            https://github.com/MagicStack/httptools
 Source0:        
https://github.com/MagicStack/httptools/archive/v%{version}.tar.gz#/httptools-%{version}.tar.gz
-Source1:        
https://github.com/nodejs/llhttp/archive/refs/tags/release/v6.0.6.tar.gz#/llhttp-release-v6.0.6.tar.gz
+Source1:        
https://github.com/nodejs/llhttp/archive/refs/tags/release/v9.3.0.tar.gz#/llhttp-release-v9.3.0.tar.gz
 Source2:        
https://github.com/nodejs/http-parser/archive/refs/tags/v2.9.4.tar.gz#/http-parser-2.9.4.tar.gz
-# BuildRequires:  %{python_module Cython >= 0.29.24 with %python-Cython < 3}
 BuildRequires:  %{python_module Cython}
 BuildRequires:  %{python_module pip}
 BuildRequires:  %{python_module pytest}
@@ -57,10 +56,7 @@
 %python_expand %fdupes %{buildroot}%{$python_sitearch}
 
 %check
-%if 0%{suse_version} >= 1550
-# pytest on suse <= 15.4 does not support the required pytest importlib import 
mode
-%pytest_arch -k 'not test_parser_response_1'
-%endif
+%pytest_arch
 
 %files %{python_files}
 %doc README.md

++++++ httptools-0.6.1.tar.gz -> httptools-0.7.1.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/httptools-0.6.1/.github/workflows/release.yml 
new/httptools-0.7.1/.github/workflows/release.yml
--- old/httptools-0.6.1/.github/workflows/release.yml   2023-10-16 
19:30:31.000000000 +0200
+++ new/httptools-0.7.1/.github/workflows/release.yml   2025-10-10 
05:41:45.000000000 +0200
@@ -5,7 +5,7 @@
     branches:
       - "master"
       - "ci"
-      - "[0-9]+.[0-9x]+*"
+      - "[0-9]+.[0-9]+.[0-9x]+*"
     paths:
       - "httptools/_version.py"
 
@@ -37,9 +37,9 @@
         mkdir -p dist/
         echo "${VERSION}" > dist/VERSION
 
-    - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32  
# v3.1.3
+    - uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882  
# v4.4.3
       with:
-        name: dist
+        name: dist-version
         path: dist/
 
   build-sdist:
@@ -47,22 +47,21 @@
     runs-on: ubuntu-latest
 
     steps:
-    - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608  # v4.1.0
+    - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871  # v4.2.1
       with:
         fetch-depth: 50
         submodules: true
 
-    - name: Set up Python
-      uses: actions/setup-python@65d7f2d534ac1bc67fcd62888c5f4f3d2cb2b236  # 
v4.7.1
+    - name: Install the latest version of uv
+      uses: astral-sh/setup-uv@eb1897b8dc4b5d5bfe39a428a8f2304605e0983c  # 
7.0.0
 
     - name: Build source distribution
       run: |
-        python -m pip install -U setuptools wheel pip
-        python setup.py sdist
+        uv build --sdist
 
-    - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32  
# v3.1.3
+    - uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882  
# v4.4.3
       with:
-        name: dist
+        name: dist-sdist
         path: dist/*.tar.*
 
   build-wheels:
@@ -73,19 +72,17 @@
         os: [ubuntu-latest, macos-latest, windows-latest]
         cibw_arch: ["auto64", "aarch64", "universal2"]
         cibw_python:
-          - "cp38-*"
-          - "cp39-*"
-          - "cp310-*"
-          - "cp311-*"
-          - "cp312-*"
+          - "cp39"
+          - "cp310"
+          - "cp311"
+          - "cp312"
+          - "cp313"
+          - "cp314"
         exclude:
           - os: ubuntu-latest
             cibw_arch: universal2
           - os: macos-latest
             cibw_arch: aarch64
-          - os: macos-latest
-            cibw_python: "cp37-*"
-            cibw_arch: universal2
           - os: windows-latest
             cibw_arch: universal2
           - os: windows-latest
@@ -99,30 +96,30 @@
       PIP_DISABLE_PIP_VERSION_CHECK: 1
 
     steps:
-    - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608  # v4.1.0
+    - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871  # v4.2.1
       with:
         fetch-depth: 50
         submodules: true
 
     - name: Set up QEMU
       if: matrix.os == 'ubuntu-latest' && matrix.cibw_arch == 'aarch64'
-      uses: docker/setup-qemu-action@68827325e0b33c7199eb31dd4e31fbe9023e06e3  
# v3.0.0
+      uses: docker/setup-qemu-action@49b3bc8e6bdd4a60e6116a5414239cba5943d3cf  
# v3.2.0
       with:
         platforms: arm64
 
-    - uses: pypa/cibuildwheel@fff9ec32ed25a9c576750c91e06b410ed0c15db7  # 
v2.16.2
+    - uses: pypa/cibuildwheel@7c619efba910c04005a835b110b057fc28fd6e93  # 
v3.2.0
       env:
         CIBW_BUILD_VERBOSITY: 1
-        CIBW_BUILD: ${{ matrix.cibw_python }}
+        CIBW_BUILD: ${{ matrix.cibw_python }}-*
         CIBW_ARCHS: ${{ matrix.cibw_arch }}
         CIBW_TEST_EXTRAS: "test"
         CIBW_TEST_COMMAND: "python {project}/tests/__init__.py"
         CIBW_TEST_COMMAND_WINDOWS: "python {project}\\tests\\__init__.py"
         CIBW_TEST_SKIP: "*universal2:arm64"
 
-    - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32  
# v3.1.3
+    - uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882  
# v4.4.3
       with:
-        name: dist
+        name: dist-${{ matrix.os }}-${{ matrix.cibw_arch }}-${{ 
matrix.cibw_python }}
         path: wheelhouse/*.whl
 
   publish:
@@ -130,14 +127,15 @@
     runs-on: ubuntu-latest
 
     steps:
-    - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608  # v4.1.0
+    - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871  # v4.2.1
       with:
         fetch-depth: 5
         submodules: false
 
-    - uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a 
 # v3.0.2
+    - uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 
 # v4.1.8
       with:
-        name: dist
+        pattern: dist-*
+        merge-multiple: true
         path: dist/
 
     - name: Extract Release Version
@@ -171,7 +169,7 @@
         ls -al dist/
 
     - name: Upload to PyPI
-      uses: 
pypa/gh-action-pypi-publish@b7f401de30cb6434a1e19f805ff006643653240e  # v1.8.10
+      uses: 
pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e  # v1.13.0
       with:
         user: __token__
         password: ${{ secrets.PYPI_TOKEN }}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/httptools-0.6.1/.github/workflows/tests.yml 
new/httptools-0.7.1/.github/workflows/tests.yml
--- old/httptools-0.6.1/.github/workflows/tests.yml     2023-10-16 
19:30:31.000000000 +0200
+++ new/httptools-0.7.1/.github/workflows/tests.yml     2025-10-10 
05:41:45.000000000 +0200
@@ -14,14 +14,14 @@
     runs-on: ${{ matrix.os }}
     strategy:
       matrix:
-        python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
+        python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"]
         os: [windows-latest, ubuntu-latest, macos-latest]
 
     env:
       PIP_DISABLE_PIP_VERSION_CHECK: 1
 
     steps:
-    - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608  # v4.1.0
+    - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871  # v4.2.1
       with:
         fetch-depth: 50
         submodules: true
@@ -37,7 +37,7 @@
           __version__\s*=\s*(?:['"])([[:PEP440:]])(?:['"])
 
     - name: Set up Python ${{ matrix.python-version }}
-      uses: actions/setup-python@65d7f2d534ac1bc67fcd62888c5f4f3d2cb2b236  # 
v4.7.1
+      uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3  # 
v5.2.0
       if: steps.release.outputs.version == 0
       with:
         python-version: ${{ matrix.python-version }}
@@ -46,5 +46,6 @@
       if: steps.release.outputs.version == 0
       run: |
         python -m pip install -U pip setuptools wheel
-        python -m pip install -e .[test]
-        python -m unittest -v tests.suite
+        python -m pip install .[test]
+        cd tests
+        python -m unittest -v
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/httptools-0.6.1/MANIFEST.in 
new/httptools-0.7.1/MANIFEST.in
--- old/httptools-0.6.1/MANIFEST.in     2023-10-16 19:30:31.000000000 +0200
+++ new/httptools-0.7.1/MANIFEST.in     2025-10-10 05:41:45.000000000 +0200
@@ -1,2 +1,3 @@
+recursive-include httptools *.pxd *.pyx
 recursive-include vendor *.c *.h LICENSE* README*
 include MANIFEST.in LICENSE
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/httptools-0.6.1/Makefile new/httptools-0.7.1/Makefile
--- old/httptools-0.6.1/Makefile        2023-10-16 19:30:31.000000000 +0200
+++ new/httptools-0.7.1/Makefile        2025-10-10 05:41:45.000000000 +0200
@@ -3,27 +3,26 @@
 
 PYTHON ?= python3
 ROOT = $(dir $(realpath $(firstword $(MAKEFILE_LIST))))
-
+UV := $(shell command -v uv 2> /dev/null)
+ifdef UV
+       PYTHON := uv run
+       PIP := uv pip
+else
+       PIP := pip
+endif
 
 compile:
-       python3 setup.py build_ext --inplace
-
-
-release: compile test
-       python3 setup.py sdist upload
-
+       $(PIP) install -e .
 
 test: compile
-       python3 -m unittest -v
+       $(PYTHON) -m unittest -v
 
 clean:
        find $(ROOT)/httptools/parser -name '*.c' | xargs rm -f
+       find $(ROOT)/httptools/parser -name '*.so' | xargs rm -f
        find $(ROOT)/httptools/parser -name '*.html' | xargs rm -f
+       rm -rf build
 
 distclean: clean
        git --git-dir="$(ROOT)/vendor/http-parser/.git" clean -dfx
        git --git-dir="$(ROOT)/vendor/llhttp/.git" clean -dfx
-
-
-testinstalled:
-       cd /tmp && $(PYTHON) $(ROOT)/tests/__init__.py
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/httptools-0.6.1/README.md 
new/httptools-0.7.1/README.md
--- old/httptools-0.6.1/README.md       2023-10-16 19:30:31.000000000 +0200
+++ new/httptools-0.7.1/README.md       2025-10-10 05:41:45.000000000 +0200
@@ -99,9 +99,7 @@
 
 3. Activate the environment with `source envname/bin/activate`
 
-4. Install development requirements with `pip install -e .[test]`
-
-5. Run `make` and `make test`.
+4. Run `make` and `make test`.
 
 
 # License
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/httptools-0.6.1/httptools/_version.py 
new/httptools-0.7.1/httptools/_version.py
--- old/httptools-0.6.1/httptools/_version.py   2023-10-16 19:30:31.000000000 
+0200
+++ new/httptools-0.7.1/httptools/_version.py   2025-10-10 05:41:45.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.6.1'
+__version__ = '0.7.1'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/httptools-0.6.1/httptools/parser/__init__.py 
new/httptools-0.7.1/httptools/parser/__init__.py
--- old/httptools-0.6.1/httptools/parser/__init__.py    2023-10-16 
19:30:31.000000000 +0200
+++ new/httptools-0.7.1/httptools/parser/__init__.py    2025-10-10 
05:41:45.000000000 +0200
@@ -1,3 +1,4 @@
+from .protocol import HTTPProtocol
 from .parser import *  # NoQA
 from .errors import *  # NoQA
 from .url_parser import *  # NoQA
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/httptools-0.6.1/httptools/parser/cparser.pxd 
new/httptools-0.7.1/httptools/parser/cparser.pxd
--- old/httptools-0.6.1/httptools/parser/cparser.pxd    2023-10-16 
19:30:31.000000000 +0200
+++ new/httptools-0.7.1/httptools/parser/cparser.pxd    2025-10-10 
05:41:45.000000000 +0200
@@ -154,3 +154,14 @@
     const char* llhttp_method_name(llhttp_method_t method)
 
     void llhttp_set_error_reason(llhttp_t* parser, const char* reason);
+
+    void llhttp_set_lenient_headers(llhttp_t* parser, bint enabled);
+    void llhttp_set_lenient_chunked_length(llhttp_t* parser, bint enabled);
+    void llhttp_set_lenient_keep_alive(llhttp_t* parser, bint enabled);
+    void llhttp_set_lenient_transfer_encoding(llhttp_t* parser, bint enabled);
+    void llhttp_set_lenient_version(llhttp_t* parser, bint enabled);
+    void llhttp_set_lenient_data_after_close(llhttp_t* parser, bint enabled);
+    void llhttp_set_lenient_optional_lf_after_cr(llhttp_t* parser, bint 
enabled);
+    void llhttp_set_lenient_optional_cr_before_lf(llhttp_t* parser, bint 
enabled);
+    void llhttp_set_lenient_optional_crlf_after_chunk(llhttp_t* parser, bint 
enabled);
+    void llhttp_set_lenient_spaces_after_chunk_size(llhttp_t* parser, bint 
enabled);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/httptools-0.6.1/httptools/parser/parser.pyi 
new/httptools-0.7.1/httptools/parser/parser.pyi
--- old/httptools-0.6.1/httptools/parser/parser.pyi     1970-01-01 
01:00:00.000000000 +0100
+++ new/httptools-0.7.1/httptools/parser/parser.pyi     2025-10-10 
05:41:45.000000000 +0200
@@ -0,0 +1,57 @@
+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):
+
+          - 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)
+        """
+
+    def get_http_version(self) -> str:
+        """Return an HTTP protocol version."""
+        ...
+
+    def should_keep_alive(self) -> bool:
+        """Return ``True`` if keep-alive mode is preferred."""
+        ...
+
+    def should_upgrade(self) -> bool:
+        """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:
+        """Feed data to the parser.
+
+        Will eventually trigger callbacks on the ``protocol``
+        object.
+
+        On HTTP upgrade, this method will raise an
+        ``HttpParserUpgrade`` exception, with its sole argument
+        set to the offset of the non-HTTP data in ``data``.
+        """
+
+class HttpRequestParser(HttpParser):
+    """Used for parsing http requests from the server's side"""
+
+    def get_method(self) -> bytes:
+        """Return HTTP request method (GET, HEAD, etc)"""
+
+class HttpResponseParser(HttpParser):
+    """Used for parsing http requests from the client's side"""
+
+    def get_status_code(self) -> int:
+        """Return the status code of the HTTP response"""
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/httptools-0.6.1/httptools/parser/parser.pyx 
new/httptools-0.7.1/httptools/parser/parser.pyx
--- old/httptools-0.6.1/httptools/parser/parser.pyx     2023-10-16 
19:30:31.000000000 +0200
+++ new/httptools-0.7.1/httptools/parser/parser.pyx     2025-10-10 
05:41:45.000000000 +0200
@@ -1,6 +1,8 @@
 #cython: language_level=3
 
 from __future__ import print_function
+from typing import Optional
+
 from cpython.mem cimport PyMem_Malloc, PyMem_Free
 from cpython cimport PyObject_GetBuffer, PyBuffer_Release, PyBUF_SIMPLE, \
                      Py_buffer, PyBytes_AsString
@@ -144,6 +146,51 @@
 
     ### Public API ###
 
+    def set_dangerous_leniencies(
+        self,
+        lenient_headers: Optional[bool] = None,
+        lenient_chunked_length: Optional[bool] = None,
+        lenient_keep_alive: Optional[bool] = None,
+        lenient_transfer_encoding: Optional[bool] = None,
+        lenient_version: Optional[bool] = None,
+        lenient_data_after_close: Optional[bool] = None,
+        lenient_optional_lf_after_cr: Optional[bool] = None,
+        lenient_optional_cr_before_lf: Optional[bool] = None,
+        lenient_optional_crlf_after_chunk: Optional[bool] = None,
+        lenient_spaces_after_chunk_size: Optional[bool] = None,
+    ):
+        cdef cparser.llhttp_t* parser = self._cparser
+        if lenient_headers is not None:
+            cparser.llhttp_set_lenient_headers(
+                parser, lenient_headers)
+        if lenient_chunked_length is not None:
+            cparser.llhttp_set_lenient_chunked_length(
+                parser, lenient_chunked_length)
+        if lenient_keep_alive is not None:
+            cparser.llhttp_set_lenient_keep_alive(
+                parser, lenient_keep_alive)
+        if lenient_transfer_encoding is not None:
+            cparser.llhttp_set_lenient_transfer_encoding(
+                parser, lenient_transfer_encoding)
+        if lenient_version is not None:
+            cparser.llhttp_set_lenient_version(
+                parser, lenient_version)
+        if lenient_data_after_close is not None:
+            cparser.llhttp_set_lenient_data_after_close(
+                parser, lenient_data_after_close)
+        if lenient_optional_lf_after_cr is not None:
+            cparser.llhttp_set_lenient_optional_lf_after_cr(
+                parser, lenient_optional_lf_after_cr)
+        if lenient_optional_cr_before_lf is not None:
+            cparser.llhttp_set_lenient_optional_cr_before_lf(
+                parser, lenient_optional_cr_before_lf)
+        if lenient_optional_crlf_after_chunk is not None:
+            cparser.llhttp_set_lenient_optional_crlf_after_chunk(
+                parser, lenient_optional_crlf_after_chunk)
+        if lenient_spaces_after_chunk_size is not None:
+            cparser.llhttp_set_lenient_spaces_after_chunk_size(
+                parser, lenient_spaces_after_chunk_size)
+
     def get_http_version(self):
         cdef cparser.llhttp_t* parser = self._cparser
         return '{}.{}'.format(parser.http_major, parser.http_minor)
@@ -161,7 +208,7 @@
             cparser.llhttp_errno_t err
             Py_buffer *buf
             bint owning_buf = False
-            char* err_pos
+            const char* err_pos
 
         if PyMemoryView_Check(data):
             buf = PyMemoryView_GET_BUFFER(data)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/httptools-0.6.1/httptools/parser/protocol.py 
new/httptools-0.7.1/httptools/parser/protocol.py
--- old/httptools-0.6.1/httptools/parser/protocol.py    1970-01-01 
01:00:00.000000000 +0100
+++ new/httptools-0.7.1/httptools/parser/protocol.py    2025-10-10 
05:41:45.000000000 +0200
@@ -0,0 +1,15 @@
+from typing import Protocol
+
+
+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: ...
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/httptools-0.6.1/httptools/parser/url_parser.pyi 
new/httptools-0.7.1/httptools/parser/url_parser.pyi
--- old/httptools-0.6.1/httptools/parser/url_parser.pyi 1970-01-01 
01:00:00.000000000 +0100
+++ new/httptools-0.7.1/httptools/parser/url_parser.pyi 2025-10-10 
05:41:45.000000000 +0200
@@ -0,0 +1,27 @@
+from typing import Union
+from array import array
+
+class URL:
+    schema: bytes
+    host: bytes
+    port: int
+    path: bytes
+    query: bytes
+    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
+    """
+    ...
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/httptools-0.6.1/pyproject.toml 
new/httptools-0.7.1/pyproject.toml
--- old/httptools-0.6.1/pyproject.toml  1970-01-01 01:00:00.000000000 +0100
+++ new/httptools-0.7.1/pyproject.toml  2025-10-10 05:41:45.000000000 +0200
@@ -0,0 +1,29 @@
+[build-system]
+build-backend = "setuptools.build_meta"
+requires = ["setuptools==80.9.0"]
+
+[project]
+name = "httptools"
+dynamic = ["version"]
+classifiers = [
+    "Intended Audience :: Developers",
+    "Programming Language :: Python :: 3",
+    "Operating System :: POSIX",
+    "Operating System :: MacOS :: MacOS X",
+    "Environment :: Web Environment",
+    "Development Status :: 5 - Production/Stable",
+]
+requires-python = ">=3.9"
+authors = [
+    {name = "Yury Selivanov", email="[email protected]"},
+]
+license = "MIT"
+license-files = ["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
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/httptools-0.6.1/setup.py new/httptools-0.7.1/setup.py
--- old/httptools-0.6.1/setup.py        2023-10-16 19:30:31.000000000 +0200
+++ new/httptools-0.7.1/setup.py        2025-10-10 05:41:45.000000000 +0200
@@ -1,21 +1,17 @@
 import sys
 
-vi = sys.version_info
-if vi < (3, 8):
-    raise RuntimeError('httptools require Python 3.8 or greater')
-else:
-    import os.path
-    import pathlib
+import os.path
+import pathlib
 
-    from setuptools import setup, Extension
-    from setuptools.command.build_ext import build_ext as build_ext
+from setuptools import setup, Extension
+from setuptools.command.build_ext import build_ext as build_ext
 
 
 CFLAGS = ['-O2']
 
 ROOT = pathlib.Path(__file__).parent
 
-CYTHON_DEPENDENCY = 'Cython(>=0.29.24,<0.30.0)'
+CYTHON_DEPENDENCY = 'Cython>=3.1.0'
 
 
 class httptools_build_ext(build_ext):
@@ -52,6 +48,8 @@
         self.cython_always = False
         self.cython_annotate = None
         self.cython_directives = None
+        if 'editable_wheel' in sys.argv:
+            self.inplace = True
 
     def finalize_options(self):
         # finalize_options() may be called multiple times on the
@@ -82,12 +80,9 @@
             try:
                 import Cython
             except ImportError:
-                raise RuntimeError(
-                    'please install Cython to compile httptools from source')
+                import setuptools.build_meta
 
-            if Cython.__version__ < '0.29':
-                raise RuntimeError(
-                    'httptools requires Cython version 0.29 or greater')
+                raise 
setuptools.build_meta.SetupRequirementsError([CYTHON_DEPENDENCY])
 
             from Cython.Build import cythonize
 
@@ -145,10 +140,6 @@
         super().build_extensions()
 
 
-with open(str(ROOT / 'README.md')) as f:
-    long_description = f.read()
-
-
 with open(str(ROOT / 'httptools' / '_version.py')) as f:
     for line in f:
         if line.startswith('__version__ ='):
@@ -160,36 +151,10 @@
             'unable to read the version from httptools/_version.py')
 
 
-setup_requires = []
-
-if (not (ROOT / 'httptools' / 'parser' / 'parser.c').exists() or
-        '--cython-always' in sys.argv):
-    # No Cython output, require Cython to build.
-    setup_requires.append(CYTHON_DEPENDENCY)
-
-
 setup(
-    name='httptools',
     version=VERSION,
-    description='A collection of framework independent HTTP protocol utils.',
-    long_description=long_description,
-    long_description_content_type='text/markdown',
-    url='https://github.com/MagicStack/httptools',
-    classifiers=[
-        'License :: OSI Approved :: MIT License',
-        'Intended Audience :: Developers',
-        'Programming Language :: Python :: 3',
-        'Operating System :: POSIX',
-        'Operating System :: MacOS :: MacOS X',
-        'Environment :: Web Environment',
-        'Development Status :: 5 - Production/Stable',
-    ],
     platforms=['macOS', 'POSIX', 'Windows'],
-    python_requires='>=3.8.0',
     zip_safe=False,
-    author='Yury Selivanov',
-    author_email='[email protected]',
-    license='MIT',
     packages=['httptools', 'httptools.parser'],
     cmdclass={
         'build_ext': httptools_build_ext,
@@ -212,11 +177,4 @@
     ],
     include_package_data=True,
     exclude_package_data={"": ["*.c", "*.h"]},
-    test_suite='tests.suite',
-    setup_requires=setup_requires,
-    extras_require={
-        'test': [
-            CYTHON_DEPENDENCY
-        ]
-    }
 )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/httptools-0.6.1/tests/test_parser.py 
new/httptools-0.7.1/tests/test_parser.py
--- old/httptools-0.6.1/tests/test_parser.py    2023-10-16 19:30:31.000000000 
+0200
+++ new/httptools-0.7.1/tests/test_parser.py    2025-10-10 05:41:45.000000000 
+0200
@@ -6,6 +6,18 @@
 
 RESPONSE1_HEAD = b'''HTTP/1.1 200 OK
 Date: Mon, 23 May 2005 22:38:34 GMT
+Server: Apache/1.3.3.7 (Unix) (Red-Hat/Linux)
+Last-Modified: Wed, 08 Jan 2003 23:11:55 GMT
+ETag: "3f80f-1b6-3e1cb03b"
+Content-Type: text/html; charset=UTF-8
+Content-Length: 130
+Accept-Ranges: bytes
+Connection: close
+
+'''.replace(b'\n', b'\r\n')
+
+RESPONSE1_SPACES_IN_HEAD = b'''HTTP/1.1 200 OK
+Date: Mon, 23 May 2005 22:38:34 GMT
 Server: Apache/1.3.3.7
         (Unix) (Red-Hat/Linux)
 Last-Modified: Wed, 08 Jan 2003 23:11:55 GMT
@@ -33,7 +45,7 @@
 User-Agent: Fooo\r
 Host: bar\r
 Transfer-Encoding: chunked\r
-
+\r
 5\r\nhello\r\n6\r\n world\r\n'''
 
 CHUNKED_REQUEST1_2 = b'''0\r\nVary: *\r\nUser-Agent: spam\r\n\r\n'''
@@ -42,7 +54,7 @@
 User-Agent: Fooo\r
 Host: bar\r
 Transfer-Encoding: chunked\r
-
+\r
 b\r\n+\xce\xcfM\xb5MI,I\x04\x00\r\n0\r\n\r\n'''
 
 
@@ -54,7 +66,7 @@
 Upgrade: WebSocket\r
 Sec-WebSocket-Key1: 4 @1  46546xW%0l 1 5\r
 Origin: http://example.com\r
-
+\r
 Hot diggity dogg'''
 
 UPGRADE_RESPONSE1 = b'''HTTP/1.1 101 Switching Protocols
@@ -89,7 +101,7 @@
         self.assertEqual(len(headers), 8)
         self.assertEqual(headers.get(b'Connection'), b'close')
         self.assertEqual(headers.get(b'Content-Type'),
-                         b'text/html;  charset=UTF-8')
+                         b'text/html; charset=UTF-8')
 
         self.assertFalse(m.on_body.called)
         p.feed_data(bytearray(RESPONSE1_BODY))
@@ -109,6 +121,53 @@
                 'Expected HTTP/'):
             p.feed_data(b'12123123')
 
+    def test_parser_response_leninent_headers_1(self):
+        m = mock.Mock()
+
+        headers = {}
+        m.on_header.side_effect = headers.__setitem__
+
+        p = httptools.HttpResponseParser(m)
+
+        with self.assertRaisesRegex(
+            httptools.HttpParserError,
+            "whitespace after header value",
+        ):
+            p.feed_data(memoryview(RESPONSE1_SPACES_IN_HEAD))
+
+    def test_parser_response_leninent_headers_2(self):
+        m = mock.Mock()
+
+        headers = {}
+        m.on_header.side_effect = headers.__setitem__
+
+        p = httptools.HttpResponseParser(m)
+
+        p.set_dangerous_leniencies(lenient_headers=True)
+        p.feed_data(memoryview(RESPONSE1_SPACES_IN_HEAD))
+
+        self.assertEqual(p.get_http_version(), '1.1')
+        self.assertEqual(p.get_status_code(), 200)
+
+        m.on_status.assert_called_once_with(b'OK')
+
+        m.on_headers_complete.assert_called_once_with()
+        self.assertEqual(m.on_header.call_count, 8)
+        self.assertEqual(len(headers), 8)
+        self.assertEqual(headers.get(b'Connection'), b'close')
+        self.assertEqual(headers.get(b'Content-Type'),
+                         b'text/html;  charset=UTF-8')
+
+        self.assertFalse(m.on_body.called)
+        p.feed_data(bytearray(RESPONSE1_BODY))
+        m.on_body.assert_called_once_with(RESPONSE1_BODY)
+
+        m.on_message_complete.assert_called_once_with()
+
+        self.assertFalse(m.on_url.called)
+        self.assertFalse(m.on_chunk_header.called)
+        self.assertFalse(m.on_chunk_complete.called)
+
     def test_parser_response_2(self):
         with self.assertRaisesRegex(TypeError, 'a bytes-like object'):
             httptools.HttpResponseParser(None).feed_data('')

++++++ llhttp-release-v6.0.6.tar.gz -> llhttp-release-v9.3.0.tar.gz ++++++
++++ 18929 lines of diff (skipped)

Reply via email to