Merge branch 'master' into staging
[jackhill/guix/guix.git] / gnu / packages / python-web.scm
index 6fd430a..a0770df 100644 (file)
@@ -3,7 +3,7 @@
 ;;; Copyright © 2015, 2016, 2017, 2018, 2019, 2020 Efraim Flashner <efraim@flashner.co.il>
 ;;; Copyright © 2017 Christopher Baines <mail@cbaines.net>
 ;;; Copyright © 2016, 2017 Danny Milosavljevic <dannym+a@scratchpost.org>
-;;; Copyright © 2013, 2014, 2015, 2016 Andreas Enge <andreas@enge.fr>
+;;; Copyright © 2013, 2014, 2015, 2016, 2020 Andreas Enge <andreas@enge.fr>
 ;;; Copyright © 2016, 2017, 2020 Marius Bakke <mbakke@fastmail.com>
 ;;; Copyright © 2015, 2016, 2017, 2018, 2019, 2020 Ricardo Wurmus <rekado@elephly.net>
 ;;; Copyright © 2017 Roel Janssen <roel@gnu.org>
@@ -37,6 +37,8 @@
 ;;; Copyright © 2020 Holger Peters <holger.peters@posteo.de>
 ;;; Copyright © 2020 Noisytoot <noisytoot@gmail.com>
 ;;; Copyright © 2020 Edouard Klein <edk@beaver-labs.com>
+;;; Copyright © 2020 Vinicius Monego <monego@posteo.net>
+;;; Copyright © 2020 Konrad Hinsen <konrad.hinsen@fastmail.net>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
   #:use-module (gnu packages databases)
   #:use-module (gnu packages django)
   #:use-module (gnu packages groff)
+  #:use-module (gnu packages libevent)
   #:use-module (gnu packages libffi)
   #:use-module (gnu packages pkg-config)
   #:use-module (gnu packages python)
   #:use-module (gnu packages python-check)
+  #:use-module (gnu packages python-compression)
   #:use-module (gnu packages python-crypto)
   #:use-module (gnu packages python-xyz)
   #:use-module (gnu packages serialization)
 (define-public python-aiohttp
   (package
     (name "python-aiohttp")
-    (version "3.6.2")
+    (version "3.6.3")
     (source
      (origin
        (method url-fetch)
        (uri (pypi-uri "aiohttp" version))
        (sha256
-        (base32
-         "09pkw6f1790prnrq0k8cqgnf1qy57ll8lpmc6kld09q7zw4vi6i5"))
+        (base32 "0i9n7h8n06m2d8ryqyk4fv1si1m44ibq7blbfaxq46vx7jydg339"))
        (patches (search-patches "python-aiohttp-3.6.2-no-warning-fail.patch"))))
     (build-system python-build-system)
     (arguments
@@ -183,7 +186,7 @@ aiohttp.  It supports SOCKS4(a) and SOCKS5.")
         (base32
          "1snr5paql8dgvc676n8xq460wypjsb1xj53cf3px1s4wczf7lryq"))))
     (build-system python-build-system)
-    (inputs
+    (propagated-inputs
      `(("python-pycares" ,python-pycares)))
     (arguments
      `(#:tests? #f))                    ;tests require internet access
@@ -219,6 +222,60 @@ The package includes a module with full coverage of JSON RPC versions 1.0 and
 comes with a SOCKS proxy client.")
     (license (list license:expat license:bsd-2))))
 
+(define-public python-asgiref
+  (package
+    (name "python-asgiref")
+    (version "3.2.10")
+    (source (origin
+              (method url-fetch)
+              (uri (pypi-uri "asgiref" version))
+              (sha256
+               (base32
+                "06kg3hnnvh7qg0w9amkvk1hd6n6bs055r04b7if6ipa7w4g92lby"))))
+    (build-system python-build-system)
+    (arguments
+     '(#:phases (modify-phases %standard-phases
+                  (replace 'check
+                    (lambda _
+                      (setenv "PYTHONPATH"
+                              (string-append "./build/lib:"
+                                             (getenv "PYTHONPATH")))
+                      (invoke "pytest" "-vv"))))))
+    (native-inputs
+     `(("python-pytest" ,python-pytest)
+       ("python-pytest-asyncio" ,python-pytest-asyncio)))
+    (home-page "https://github.com/django/asgiref/")
+    (synopsis "ASGI specs, helper code, and adapters")
+    (description
+     "ASGI is a standard for Python asynchronous web apps and servers to
+communicate with each other, and positioned as an asynchronous successor to
+WSGI.  This package includes libraries for implementing ASGI servers.")
+    (license license:bsd-3)))
+
+(define-public python-css-html-js-minify
+  (package
+    (name "python-css-html-js-minify")
+    (version "2.5.5")
+    (source (origin
+              (method url-fetch)
+              (uri (pypi-uri "css-html-js-minify" version ".zip"))
+              (sha256
+               (base32
+                "0v3l2dqdk2y4r6ax259gs4ij1zzm9yxg6491s6254vs9w3vi37sa"))))
+    (build-system python-build-system)
+    ;; XXX: The git repository has no tags, and the PyPI releases do not
+    ;; contain tests.
+    (arguments '(#:tests? #f))
+    (native-inputs `(("unzip" ,unzip)))
+    (home-page "https://github.com/juancarlospaco/css-html-js-minify")
+    (synopsis "CSS/HTML/JS minifier")
+    (description
+     "This package provides a single-file minifier for CSS, HTML, and JavaScript.")
+    ;; XXX: The README just says "GNU GPL and GNU LGPL and MIT".  From
+    ;; <https://github.com/juancarlospaco/css-html-js-minify/issues/9> it
+    ;; looks like the user can choose a license.
+    (license (list license:gpl3+ license:lgpl3+ license:expat))))
+
 (define-public python-falcon
   (package
     (name "python-falcon")
@@ -464,6 +521,129 @@ follow links and submit forms.  It doesn’t do JavaScript.")
 (define-public python2-mechanicalsoup
   (package-with-python2 python-mechanicalsoup))
 
+(define-public python-hyperframe
+  (package
+    (name "python-hyperframe")
+    (version "5.2.0")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (pypi-uri "hyperframe" version))
+       (sha256
+        (base32 "07xlf44l1cw0ghxx46sbmkgzil8vqv8kxwy42ywikiy35izw3xd9"))))
+    (build-system python-build-system)
+    (arguments
+     `(#:phases
+       (modify-phases %standard-phases
+         (replace 'check
+           (lambda* (#:key inputs outputs #:allow-other-keys)
+             (add-installed-pythonpath inputs outputs)
+             (invoke "pytest" "-vv" "test"))))))
+    (native-inputs
+     `(("python-pytest" ,python-pytest)))
+    (home-page "https://github.com/python-hyper/hyperframe")
+    (synopsis "HTTP/2 framing layer for Python")
+    (description
+     "This library contains the HTTP/2 framing code used in the hyper project.
+It provides a pure-Python codebase that is capable of decoding a binary stream
+into HTTP/2 frames.")
+    (license license:expat)))
+
+(define-public python-hpack
+  (package
+    (name "python-hpack")
+    (version "3.0.0")
+    (source
+     (origin
+       ;; PyPI tarball is missing some files necessary for the tests.
+       (method git-fetch)
+       (uri (git-reference
+             (url "https://github.com/python-hyper/hpack")
+             (commit (string-append "v" version))))
+       (file-name (git-file-name name version))
+       (sha256
+        (base32 "0w8hkz50a6lzkmgi41ryicm0mh9ca9cx29pm3s0xlpn0vs29xrmd"))))
+    (build-system python-build-system)
+    (arguments
+     `(#:phases
+       (modify-phases %standard-phases
+         (replace 'check
+           (lambda* (#:key inputs outputs #:allow-other-keys)
+             (add-installed-pythonpath inputs outputs)
+             (invoke "pytest" "-vv" "test" "-k"
+                     ;; This test will be fixed in the next version. See:
+                     ;; https://github.com/python-hyper/hpack/issues/168.
+                     "not test_get_by_index_out_of_range"))))))
+    (native-inputs
+     `(("python-pytest" ,python-pytest)))
+    (home-page "https://hyper.rtfd.org")
+    (synopsis "Pure-Python HPACK header compression")
+    (description
+     "This module contains a pure-Python HTTP/2 header encoding (HPACK) logic
+for use in Python programs that implement HTTP/2.")
+    (license license:expat)))
+
+(define-public python-h11
+  (package
+    (name "python-h11")
+    (version "0.9.0")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (pypi-uri "h11" version))
+       (sha256
+        (base32 "1qfad70h59hya21vrzz8dqyyaiqhac0anl2dx3s3k80gpskvrm1k"))))
+    (build-system python-build-system)
+    (arguments
+     `(#:phases
+       (modify-phases %standard-phases
+         (replace 'check
+           (lambda _
+             (invoke "pytest" "-vv"))))))
+    (native-inputs
+     `(("python-pytest" ,python-pytest)))
+    (home-page "https://github.com/python-hyper/h11")
+    (synopsis "Pure-Python, bring-your-own-I/O implementation of HTTP/1.1")
+    (description
+     "This is a little HTTP/1.1 library written from scratch in Python, heavily
+inspired by hyper-h2.  It's a bring-your-own-I/O library; h11 contains no IO
+code whatsoever.  This means you can hook h11 up to your favorite network API,
+and that could be anything you want.")
+    (license license:expat)))
+
+(define-public python-h2
+  (package
+    (name "python-h2")
+    (version "3.2.0")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (pypi-uri "h2" version))
+       (sha256
+        (base32 "051gg30aca26rdxsmr9svwqm06pdz9bv21ch4n0lgi7jsvml2pw7"))))
+    (build-system python-build-system)
+    (arguments
+     `(#:phases
+       (modify-phases %standard-phases
+         (replace 'check
+           (lambda* (#:key inputs outputs #:allow-other-keys)
+             (add-installed-pythonpath inputs outputs)
+             (invoke "pytest" "-vv" "test"))))))
+    (native-inputs
+     `(("python-pytest" ,python-pytest)))
+    (propagated-inputs
+     `(("python-hpack" ,python-hpack)
+       ("python-hyperframe" ,python-hyperframe)))
+    (home-page "https://github.com/python-hyper/hyper-h2")
+    (synopsis "HTTP/2 State-Machine based protocol implementation")
+    (description
+     "This module contains a pure-Python implementation of a HTTP/2 protocol
+stack.  It does not provide a parsing layer, a network layer, or any rules
+about concurrency.  Instead, it's a purely in-memory solution, defined in
+terms of data actions and HTTP/2 frames.  This is one building block of a full
+Python HTTP implementation.")
+    (license license:expat)))
+
 (define-public python-sockjs-tornado
   (package
     (name "python-sockjs-tornado")
@@ -549,9 +729,9 @@ both of which are installed automatically if you install this library.")
     (home-page
       "https://github.com/html5lib/html5lib-python")
     (synopsis
-      "Python HTML parser based on the WHATWG HTML specifcation")
+      "Python HTML parser based on the WHATWG HTML specification")
     (description
-      "Html5lib is an HTML parser based on the WHATWG HTML specifcation
+      "Html5lib is an HTML parser based on the WHATWG HTML specification
 and written in Python.")
     (license license:expat)))
 
@@ -691,14 +871,14 @@ is Python’s.")
 (define-public python-openid
   (package
     (name "python-openid")
-    (version "3.1.0")
+    (version "3.2.0")
     (source
      (origin
        (method url-fetch)
        (uri (pypi-uri "python3-openid" version))
        (sha256
         (base32
-         "00l5hrjh19740w00b3fnsqldnla41wbr2rics09dl4kyd1fkd3b2"))))
+         "1bxf9a3ny1js422j962zfzl4a9dhj192pvai05whn7j0iy9gdyrk"))))
     (build-system python-build-system)
     (arguments
      `(#:phases
@@ -872,6 +1052,111 @@ teams extension for python-openid.")
 (define-public python2-openid-teams
   (package-with-python2 python-openid-teams))
 
+(define-public python-priority
+  (package
+    (name "python-priority")
+    (version "1.3.0")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (pypi-uri "priority" version))
+       (sha256
+        (base32 "1gpzn9k9zgks0iw5wdmad9b4dry8haiz2sbp6gycpjkzdld9dhbb"))))
+    (build-system python-build-system)
+    (arguments
+     `(#:phases
+       (modify-phases %standard-phases
+         (replace 'check
+           (lambda* (#:key inputs outputs #:allow-other-keys)
+             (add-installed-pythonpath inputs outputs)
+             (invoke "pytest" "-vv" "test" "-k"
+                     ;; This test exceeded the Hypothesis deadline.
+                     "not test_period_of_repetition"))))))
+    (native-inputs
+     `(("python-hypothesis" ,python-hypothesis)
+       ("python-pytest" ,python-pytest)
+       ("python-pytest-cov" ,python-pytest-cov)
+       ("python-pytest-xdist" ,python-pytest-xdist)))
+    (home-page "https://python-hyper.org/projects/priority/en/latest/")
+    (synopsis "Pure-Python implementation of the HTTP/2 priority tree")
+    (description
+     "Priority is a pure-Python implementation of the priority logic for HTTP/2,
+set out in RFC 7540 Section 5.3 (Stream Priority).")
+    (license license:expat)))
+
+(define-public python-wsproto
+  (package
+    (name "python-wsproto")
+    (version "0.15.0")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (pypi-uri "wsproto" version))
+       (sha256
+        (base32 "17gsxlli4w8am1wwwl3k90hpdfa213ax40ycbbvb7hjx1v1rhiv1"))))
+    (build-system python-build-system)
+    (arguments
+     `(#:phases
+       (modify-phases %standard-phases
+         (replace 'check
+           (lambda* (#:key inputs outputs #:allow-other-keys)
+             (add-installed-pythonpath inputs outputs)
+             (invoke "pytest" "-vv" "test"))))))
+    (native-inputs
+     `(("python-pytest" ,python-pytest)))
+    (propagated-inputs
+     `(("python-h11" ,python-h11)))
+    (home-page "https://github.com/python-hyper/wsproto/")
+    (synopsis "WebSockets state-machine based protocol implementation")
+    (description
+     "@code{wsproto} is a pure-Python implementation of a WebSocket protocol
+stack.  It's written from the ground up to be embeddable in whatever program you
+choose to use, ensuring that you can communicate via WebSockets, as defined in
+RFC6455, regardless of your programming paradigm.")
+    (license license:expat)))
+
+(define-public python-hypercorn
+  (package
+    (name "python-hypercorn")
+    (version "0.10.2")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (pypi-uri "Hypercorn" version))
+       (sha256
+        (base32 "15dgy47a18w2ls3hwykra1cyf7yzxmfjqnsqml482p12cxr2xwqr"))))
+    (build-system python-build-system)
+    (arguments
+     `(#:phases
+       (modify-phases %standard-phases
+         (replace 'check
+           (lambda* (#:key inputs outputs #:allow-other-keys)
+             (add-installed-pythonpath inputs outputs)
+             (invoke "pytest" "-vv"))))))
+    (propagated-inputs
+     `(("python-h11" ,python-h11)
+       ("python-h2" ,python-h2)
+       ("python-priority" ,python-priority)
+       ("python-toml" ,python-toml)
+       ("python-typing-extensions" ,python-typing-extensions)
+       ("python-wsproto" ,python-wsproto)))
+    (native-inputs
+     `(("python-hypothesis" ,python-hypothesis)
+       ("python-mock" ,python-mock)
+       ("python-pytest" ,python-pytest)
+       ("python-pytest-asyncio" ,python-pytest-asyncio)
+       ("python-pytest-cov" ,python-pytest-cov)
+       ("python-pytest-trio" ,python-pytest-trio)
+       ("python-trio" ,python-trio)))
+    (home-page "https://gitlab.com/pgjones/hypercorn/")
+    (synopsis "ASGI Server based on Hyper libraries")
+    (description
+     "Hypercorn is an ASGI web server based on the sans-io hyper, h11, h2, and
+wsproto libraries and inspired by Gunicorn.  It supports HTTP/1, HTTP/2,
+WebSockets (over HTTP/1 and HTTP/2), ASGI/2, and ASGI/3 specifications.  It can
+utilise asyncio, uvloop, or trio worker types.")
+    (license license:expat)))
+
 (define-public python-tornado
   (package
     (name "python-tornado")
@@ -1627,16 +1912,92 @@ WebSocket usage in Python programs.")
           ,python2-backport-ssl-match-hostname)
          ,@(package-native-inputs base))))))
 
+(define-public python-purl
+  (package
+    (name "python-purl")
+    (version "1.5")
+    (source
+      (origin
+        (method url-fetch)
+        (uri (pypi-uri "purl" version))
+        (sha256
+          (base32
+            "15ibnz1xrh5msmn04j0nr00sz4n7jwx6cwd6zlx99kkz3vpin53m"))))
+    (build-system python-build-system)
+    (propagated-inputs `(("python-six" ,python-six)))
+    (home-page
+      "https://github.com/codeinthehole/purl")
+    (synopsis
+      "Python package for URL manipulation")
+    (description
+      "Purl is a Python package for handling URLs.")
+    (license license:expat)))
+
+(define-public python-apiron
+  (package
+    (name "python-apiron")
+    (version "5.1.0")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (pypi-uri "apiron" version))
+       (sha256
+        (base32 "1qwbqn47sf0aqznj1snbv37v8ijx476qqkjf5l9pac7xjkxsr8qk"))))
+    (build-system python-build-system)
+    (arguments
+     `(#:phases
+       (modify-phases %standard-phases
+         (replace 'check
+           (lambda* (#:key inputs outputs #:allow-other-keys)
+             (add-installed-pythonpath inputs outputs)
+             (invoke "pytest" "-vv" "--cov" "-k"
+                     ;; This test tries to connect to the internet.
+                     "not test_call"))))))
+    (propagated-inputs
+     `(("python-requests" ,python-requests)))
+    (native-inputs
+     `(("python-pytest" ,python-pytest)
+       ("python-pytest-cov" ,python-pytest-cov)))
+    (home-page "https://github.com/ithaka/apiron")
+    (synopsis "Python wrapper for interacting with RESTful APIs")
+    (description
+     "@code{apiron} provides a declarative, structured configuration of
+services and endpoints with a unified interface for interacting with RESTful
+APIs.")
+    (license license:expat)))
+
+(define-public python-beren
+  (package
+    (name "python-beren")
+    (version "0.7.0")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (pypi-uri "beren" version))
+       (sha256
+        (base32 "1v3mdwfqsyza892zvs124ym9w1bkng1j56b7l4dwfjir3723xcgf"))))
+    (build-system python-build-system)
+    (arguments
+     ;; The test tries to open a connection to a remote server.
+     `(#:tests? #f))
+    (propagated-inputs
+     `(("python-apiron" ,python-apiron)))
+    (home-page "https://github.com/teffalump/beren")
+    (synopsis "REST client for Orthanc DICOM servers")
+    (description
+     "@code{beren} provides a REST client for Orthanc, a DICOM server.")
+    (license license:gpl3+)))
+
 (define-public python-requests
   (package
     (name "python-requests")
-    (version "2.23.0")
+    (version "2.24.0")
     (source (origin
              (method url-fetch)
              (uri (pypi-uri "requests" version))
              (sha256
               (base32
-               "1rhpg0jb08v0gd7f19jjiwlcdnxpmqi1fhvw7r4s9avddi4kvx5k"))))
+               "06r3017hz0hzxv42gpg73l8xvdjbzw7q904ljvp36b5p3l9rlmdk"))))
     (build-system python-build-system)
     (propagated-inputs
      `(("python-certifi" ,python-certifi)
@@ -1669,18 +2030,6 @@ than Python’s urllib2 library.")
               ("python-idna" ,python-idna-2.7)
               ,@(package-propagated-inputs python-requests)))))
 
-;; Some software requires an older version of Requests, notably Docker
-;; Compose.
-(define-public python-requests-2.7
-  (package (inherit python-requests)
-    (version "2.7.0")
-    (source (origin
-             (method url-fetch)
-             (uri (pypi-uri "requests" version))
-             (sha256
-              (base32
-               "0gdr9dxm24amxpbyqpbh3lbwxc2i42hnqv50sigx568qssv3v2ir"))))))
-
 (define-public python2-requests
   (package-with-python2 python-requests))
 
@@ -1711,14 +2060,14 @@ library.")
 (define-public python-requests-mock
   (package
     (name "python-requests-mock")
-    (version "1.3.0")
+    (version "1.8.0")
     (source
      (origin
        (method url-fetch)
        (uri (pypi-uri "requests-mock" version))
        (sha256
         (base32
-         "0jr997dvk6zbmhvbpcv3rajrgag69mcsm1ai3w3rgk2jdh6rg1mx"))))
+         "09nj8fmyj7xz2mgwyvbw0fl9zybmx2d3qd2hf529vvjc9s24d3z6"))))
     (build-system python-build-system)
     (propagated-inputs
      `(("python-requests" ,python-requests)
@@ -1729,9 +2078,10 @@ library.")
        ("python-docutils" ,python-docutils)
        ("python-fixtures" ,python-fixtures)
        ("python-mock" ,python-mock)
+       ("python-purl" ,python-purl)
+       ("python-pytest" ,python-pytest)
        ("python-sphinx" ,python-sphinx)
-       ("python-testrepository" ,python-testrepository)
-       ("python-testtools" ,python-testtools)))
+       ("python-testrepository" ,python-testrepository)))
     (home-page "https://requests-mock.readthedocs.org/")
     (synopsis "Mock out responses from the requests package")
     (description
@@ -1774,16 +2124,52 @@ with python-requests.")
 (define-public python2-requests-toolbelt
   (package-with-python2 python-requests-toolbelt))
 
+(define-public python-requests-toolbelt-0.9.1
+  (package
+    (inherit python-requests-toolbelt)
+    (version "0.9.1")
+    (source (origin
+             (method url-fetch)
+             (uri (pypi-uri "requests-toolbelt" version))
+             (sha256
+              (base32
+               "1h3gm88dcjbd7gm229a7x5qkkhnsqsjz0m0l2xyavm2ab3a8k04n"))))
+    (arguments
+     `(;; FIXME: Some tests require network access.
+       #:tests? #f))))
+
+(define-public python-requests-ftp
+  (package
+    (name "python-requests-ftp")
+    (version "0.3.1")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (pypi-uri "requests-ftp" version))
+       (sha256
+        (base32
+         "0yh5v21v36dsjsgv4y9dx4mmz35741l5jf6pbq9w19d8rfsww13m"))))
+    (build-system python-build-system)
+    (propagated-inputs
+     `(("python-requests" ,python-requests)))
+    (home-page
+     "https://github.com/Lukasa/requests-ftp")
+    (synopsis "FTP Transport Adapter for Requests")
+    (description
+     "Requests-FTP is an implementation of a simple FTP transport
+adapter for use with the Requests library.")
+    (license license:asl2.0)))
+
 (define-public python-oauthlib
   (package
     (name "python-oauthlib")
-    (version "3.0.1")
+    (version "3.1.0")
     (source (origin
               (method url-fetch)
               (uri (pypi-uri "oauthlib" version))
               (sha256
                (base32
-                "163jg4a8f7c5ki655grrr47kgljy12wri3qly7ijf64sk1fjrqqc"))))
+                "12gqnabwck30gdlpwm6af3s28qm9p2yc7b1w8s4fk9ncbz1irr5y"))))
     (build-system python-build-system)
     (arguments
      `(#:phases (modify-phases %standard-phases
@@ -1858,7 +2244,6 @@ authenticated session objects providing things like keep-alive.")
        ("python-certifi" ,python-certifi)
        ("python-cryptography" ,python-cryptography)
        ("python-idna" ,python-idna)
-       ("python-ipaddress" ,python-ipaddress)
        ("python-pyopenssl" ,python-pyopenssl)
        ("python-pysocks" ,python-pysocks)))
     (home-page "https://urllib3.readthedocs.io/")
@@ -1867,6 +2252,7 @@ authenticated session objects providing things like keep-alive.")
      "Urllib3 supports features left out of urllib and urllib2 libraries.  It
 can reuse the same socket connection for multiple requests, it can POST files,
 supports url redirection and retries, and also gzip and deflate decoding.")
+    (properties `((python2-variant . ,(delay python2-urllib3))))
     (license license:expat)))
 
 ;; Some software requires an older version of urllib3, notably Docker.
@@ -1882,7 +2268,12 @@ supports url redirection and retries, and also gzip and deflate decoding.")
 
 
 (define-public python2-urllib3
-  (package-with-python2 python-urllib3))
+  (let ((base (package-with-python2 (strip-python2-variant python-urllib3))))
+    (package/inherit
+     base
+     (propagated-inputs
+      `(("python-ipaddress" ,python2-ipaddress)
+        ,@(package-propagated-inputs base))))))
 
 (define-public awscli
   (package
@@ -1956,13 +2347,13 @@ and to spawn subprocesses to handle requests.")
 (define-public python-pastedeploy
   (package
     (name "python-pastedeploy")
-    (version "2.1.0")
+    (version "2.1.1")
     (source
      (origin
        (method url-fetch)
        (uri (pypi-uri "PasteDeploy" version))
        (sha256
-        (base32 "16qsq5y6mryslmbp5pn35x4z8z3ndp5rpgl42h226879nrw9hmg7"))))
+        (base32 "05s88qdjdwd9d9qs13fap7nqgxs7qs5qfzzjbrc5va13k2mxdskd"))))
     (build-system python-build-system)
     (arguments
      '(#:test-target "pytest"))
@@ -2545,13 +2936,13 @@ applications.")
 (define-public python-flask-sqlalchemy
   (package
     (name "python-flask-sqlalchemy")
-    (version "2.4.3")
+    (version "2.4.4")
     (source (origin
               (method url-fetch)
               (uri (pypi-uri "Flask-SQLAlchemy" version))
               (sha256
                (base32
-                "19apnn2m9bl1d1h2nc52pnmiyx993mwzmfjrv04l3wn5hyznyr8b"))))
+                "1rgsj49gnx361hnb3vn6c1h17497qh22yc3r70l1r6w0mw71bixz"))))
     (build-system python-build-system)
     (propagated-inputs
      `(("python-flask" ,python-flask)
@@ -2786,15 +3177,29 @@ for Flask.")
 (define-public python-webassets
   (package
     (name "python-webassets")
-    (version "0.12.1")
+    (version "2.0")
     (source
      (origin
        (method url-fetch)
        (uri (pypi-uri "webassets" version))
        (sha256
         (base32
-         "1nrqkpb7z46h2b77xafxihqv3322cwqv6293ngaky4j3ff4cing7"))))
+         "1kc1042jydgk54xpgcp0r1ib4gys91nhy285jzfcxj3pfqrk4w8n"))))
     (build-system python-build-system)
+    (arguments
+     '(#:phases (modify-phases %standard-phases
+                  (add-before 'check 'disable-some-tests
+                    (lambda _
+                      ;; This test requires 'postcss' and 'babel' which are
+                      ;; not yet available in Guix.
+                      (delete-file "tests/test_filters.py")
+                      #t))
+                  (replace 'check
+                    (lambda _
+                      (setenv "PYTHONPATH"
+                              (string-append "./build/lib:"
+                                             (getenv "PYTHONPATH")))
+                      (invoke "pytest" "-vv"))))))
     (native-inputs
      `(("python-jinja2" ,python-jinja2)
        ("python-mock" ,python-mock)
@@ -3000,14 +3405,14 @@ authentication for Flask routes.")
 (define-public python-uritemplate
   (package
     (name "python-uritemplate")
-    (version "3.0.0")
+    (version "3.0.1")
     (source
      (origin
        (method url-fetch)
        (uri (pypi-uri "uritemplate" version))
        (sha256
         (base32
-         "0781gm9g34wa0asc19dx81ng0nqq07igzv3bbvdqmz13pv7469n0"))))
+         "1bkwmgr0ia9gcn4bszs2xlvml79f0bi2s4a87xg22ky9rq8avy2s"))))
     (build-system python-build-system)
     (home-page "https://uritemplate.readthedocs.org")
     (synopsis "Library to deal with URI Templates")
@@ -3522,17 +3927,13 @@ Python.")
 (define-public python-slugify
   (package
     (name "python-slugify")
-    (version "3.0.4")
+    (version "4.0.1")
     (source
      (origin
        (method url-fetch)
        (uri (pypi-uri "python-slugify" version))
        (sha256
-        (base32 "0dv97yi5fq074q5qyqbin09pmi8ixg36caf5nkpw2bqkd8jh6pap"))
-       (patches
-        (search-patches "python-slugify-depend-on-unidecode.patch"))))
-    (native-inputs
-     `(("python-wheel" ,python-wheel)))
+        (base32 "0w22fapghmzk3xdasc4dn7h8sl58l08d1h5zbf72dh80drv1g9b9"))))
     (propagated-inputs
      `(("python-unidecode" ,python-unidecode)))
     (arguments
@@ -3638,6 +4039,43 @@ XPath and therefore does not have all the correctness corner cases that are
 hard or impossible to fix in cssselect.")
     (license license:bsd-3)))
 
+(define-public python-uvloop
+  (package
+    (name "python-uvloop")
+    (version "0.14.0")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (pypi-uri "uvloop" version))
+       (sha256
+        (base32 "07j678z9gf41j98w72ysrnb5sa41pl5yxd7ib17lcwfxqz0cjfhj"))))
+    (build-system python-build-system)
+    (arguments
+     '(#:tests? #f ;FIXME: tests hang and with some errors in the way
+       #:phases
+       (modify-phases %standard-phases
+         (add-after 'unpack 'preparations
+           (lambda _
+             ;; Use packaged libuv.
+             (substitute* "setup.py" (("self.use_system_libuv = False")
+                                      "self.use_system_libuv = True"))
+             #t)))))
+    (native-inputs
+     `(("python-aiohttp" ,python-aiohttp)
+       ("python-cython" ,python-cython)
+       ("python-flake8" ,python-flake8)
+       ("python-psutil" ,python-psutil)
+       ("python-pyopenssl" ,python-pyopenssl)
+       ("python-twine" ,python-twine)))
+    (inputs
+     `(("libuv" ,libuv)))
+    (home-page "https://github.com/MagicStack/uvloop")
+    (synopsis "Fast implementation of asyncio event loop on top of libuv")
+    (description
+     "@code{uvloop} is a fast, drop-in replacement of the built-in asyncio
+event loop.  It is implemented in Cython and uses libuv under the hood.")
+    (license license:expat)))
+
 (define-public gunicorn
   (package
     (name "gunicorn")
@@ -3684,7 +4122,7 @@ hard or impossible to fix in cssselect.")
              #t)))))
     (native-inputs
      `(("binutils" ,binutils)  ;; for ctypes.util.find_library()
-       ("python-aiohttp"python-aiohttp)
+       ("python-aiohttp" ,python-aiohttp)
        ("python-pytest" ,python-pytest)
        ("python-pytest-cov" ,python-pytest-cov)
        ("python-sphinx" ,python-sphinx)
@@ -3704,10 +4142,108 @@ and fairly speedy.")
   (package
     (inherit gunicorn)
     (name "gunicorn")
-       (arguments `(#:tests? #f))
-       (properties '((hidden? . #t)))
+    (arguments `(#:tests? #f))
+    (properties '((hidden? . #t)))
     (native-inputs `())))
 
+(define-public python-httptools
+  (package
+    (name "python-httptools")
+    (version "0.1.1")
+    (source
+     (origin
+       ;; PyPI tarball comes with a vendored http-parser and no tests.
+       (method git-fetch)
+       (uri (git-reference
+             (url "https://github.com/MagicStack/httptools")
+             (commit (string-append "v" version))))
+       (file-name (git-file-name name version))
+       (sha256
+        (base32 "0g08128x2ixsiwrzskxc6c8ymgzs39wbzr5mhy0mjk30q9pqqv77"))))
+    (build-system python-build-system)
+    (arguments
+     '(#:phases
+       (modify-phases %standard-phases
+         (add-after 'unpack 'preparations
+           (lambda _
+             ;; Skip a failing test (AssertionError).  Bug report:
+             ;; https://github.com/MagicStack/httptools/issues/10.
+             (substitute* "tests/test_parser.py"
+               (("    def test_parser_response_1")
+                (string-append
+                 "    @unittest.skip(\"Disabled.\")\n"
+                 "    def test_parser_response_1")))
+             ;; Use packaged http-parser.
+             (substitute* "setup.py" (("self.use_system_http_parser = False")
+                                      "self.use_system_http_parser = True"))
+             ;; This path is hardcoded.  Hardcode our own.
+             (substitute* "httptools/parser/cparser.pxd"
+               (("../../vendor/http-parser")
+                (string-append (assoc-ref %build-inputs "http-parser")
+                               "/include")))
+             ;; Don't force Cython version.
+             (substitute* "setup.py" (("Cython==") "Cython>="))
+             #t)))))
+    (native-inputs
+     `(("python-cython" ,python-cython)
+       ("python-pytest" ,python-pytest)))
+    (inputs
+     `(("http-parser" ,http-parser)))
+    (home-page "https://github.com/MagicStack/httptools")
+    (synopsis "Collection of framework independent HTTP protocol utils")
+    (description
+     "@code{httptools} is a Python binding for the nodejs HTTP parser.")
+    (license license:expat)))
+
+(define-public python-uvicorn
+  (package
+    (name "python-uvicorn")
+    (version "0.11.8")
+    (source
+     (origin
+       ;; PyPI tarball has no tests.
+       (method git-fetch)
+       (uri (git-reference
+             (url "https://github.com/encode/uvicorn")
+             (commit version)))
+       (file-name (git-file-name name version))
+       (sha256
+        (base32 "00iidg5ysp7k00bw3kmkvr8mghnh4jdi0p2ryiarhryf8wz2r3fy"))))
+    (build-system python-build-system)
+    (arguments
+     `(#:phases
+       (modify-phases %standard-phases
+         (replace 'check
+           (lambda* (#:key inputs outputs tests? #:allow-other-keys)
+             (add-installed-pythonpath inputs outputs)
+             (invoke "pytest" "-vv"))))))
+    (native-inputs
+     `(("python-black" ,python-black)
+       ("python-codecov" ,python-codecov)
+       ("python-flake8" ,python-flake8)
+       ("python-isort" ,python-isort)
+       ("python-mypy" ,python-mypy)
+       ("python-pytest" ,python-pytest)
+       ("python-pytest-cov" ,python-pytest-cov)
+       ("python-pytest-mock" ,python-pytest-mock)
+       ("python-requests" ,python-requests)))
+    (propagated-inputs
+     `(("python-click" ,python-click)
+       ("python-h11" ,python-h11)
+       ("python-httptools" ,python-httptools)
+       ("python-pyyaml" ,python-pyyaml)
+       ("python-uvloop" ,python-uvloop)
+       ("python-watchgod" ,python-watchgod)
+       ("python-websockets" ,python-websockets)
+       ("python-wsproto" ,python-wsproto)))
+    (home-page "https://github.com/encode/uvicorn")
+    (synopsis "Fast ASGI server implementation")
+    (description
+     "@code{uvicorn} is a fast ASGI server implementation, using @code{uvloop}
+and @code{httptools}.  It currently supports HTTP/1.1 and WebSockets.  Support
+for HTTP/2 is planned.")
+    (license license:bsd-3)))
+
 (define-public python-translation-finder
   (package
     (name "python-translation-finder")
@@ -3921,6 +4457,176 @@ and serve updated contents upon changes to the directory.")
 @acronym{TLS, Transport Layer Security} support.")
     (license license:bsd-2)))
 
+(define-public python-httpcore
+  (package
+    (name "python-httpcore")
+    (version "0.11.0")
+    (source
+     (origin
+       ;; PyPI tarball does not contain tests.
+       (method git-fetch)
+       (uri (git-reference
+             (url "https://github.com/encode/httpcore")
+             (commit  version)))
+       (file-name (git-file-name name version))
+       (sha256
+        (base32 "01bhajcxqgkdzg7b7x0fqs2lwcfsajlgqwi1nlxx58jss7g2kxn9"))))
+    (build-system python-build-system)
+    (arguments
+     `(#:phases
+       (modify-phases %standard-phases
+         (add-after 'unpack 'remove-unavailable-tests
+           (lambda _
+             ;; These tests require 'mitmproxy' which is not packaged.
+             (for-each (lambda (f)
+                         (delete-file f))
+                       '("tests/conftest.py"
+                         "tests/sync_tests/test_interfaces.py"
+                         "tests/async_tests/test_interfaces.py"))
+             #t))
+         (add-after 'remove-unavailable-tests 'force-h11-version
+           ;; Allow build with h11 >= 0.10.
+           (lambda _
+             (substitute* "setup.py" (("h11>=0.8,<0.10") "h11"))
+             #t))
+         (replace 'check
+           (lambda* (#:key inputs outputs #:allow-other-keys)
+             (add-installed-pythonpath inputs outputs)
+             (invoke "pytest" "-vv" "--cov=httpcore"
+                     "--cov=tests" "tests"))))))
+    (native-inputs
+     `(;; ("mitmproxy" ,mitmproxy) ;; TODO: Package this.
+       ("python-autoflake" ,python-autoflake)
+       ("python-flake8" ,python-flake8)
+       ("python-flake8-bugbear" ,python-flake8-bugbear)
+       ("python-flake8-pie" ,python-flake8-pie)
+       ("python-isort" ,python-isort)
+       ("python-mypy" ,python-mypy)
+       ("python-pytest" ,python-pytest)
+       ("python-pytest-asyncio" ,python-pytest-asyncio)
+       ("python-pytest-cov" ,python-pytest-cov)
+       ("python-pytest-trio" ,python-pytest-trio)
+       ("python-uvicorn" ,python-uvicorn)
+       ("python-trustme" ,python-trustme)))
+    (propagated-inputs
+     `(("python-h11" ,python-h11)
+       ("python-h2" ,python-h2)
+       ("python-sniffio" ,python-sniffio)
+       ("python-trio" ,python-trio)
+       ("python-trio-typing" ,python-trio-typing)))
+    (home-page "https://github.com/encode/httpcore")
+    (synopsis "Minimal, low-level HTTP client")
+    (description
+     "HTTP Core provides a minimal and low-level HTTP client, which does one
+thing only: send HTTP requests.
+
+Some things HTTP Core does do:
+
+@itemize
+@item Sending HTTP requests.
+@item Provides both sync and async interfaces.
+@item Supports HTTP/1.1 and HTTP/2.
+@item Async backend support for asyncio and trio.
+@item Automatic connection pooling.
+@item HTTP(S) proxy support.
+@end itemize")
+    (license license:bsd-3)))
+
+(define-public python-httpx
+  (package
+    (name "python-httpx")
+    (version "0.15.4")
+    (source
+     (origin
+       ;; PyPI tarball does not contain tests.
+       (method git-fetch)
+       (uri (git-reference
+             (url "https://github.com/encode/httpx")
+             (commit version)))
+       (file-name (git-file-name name version))
+       (sha256
+        (base32 "1qr91xw6jxynvihmw953bi5446ssm9ffmb2c4nhfa77v7883sp21"))))
+    (build-system python-build-system)
+    (arguments
+     `(#:phases
+       (modify-phases %standard-phases
+         (replace 'check
+           (lambda _
+             (invoke "pytest" "-vv" "-k"
+                     ;; These tests try to open an outgoing connection.
+                     (string-append
+                      "not test_connect_timeout"
+                      " and not test_that_send_cause_async_client_to_be_not_"
+                      "closed"
+                      " and not test_that_async_client_caused_warning_when_"
+                      "being_deleted"
+                      " and not test_that_send_cause_client_to_be_not_closed"
+                      " and not test_async_proxy_close"
+                      " and not test_sync_proxy_close")))))))
+    (native-inputs
+     `(("python-autoflake" ,python-autoflake)
+       ("python-black" ,python-black)
+       ("python-cryptography" ,python-cryptography)
+       ("python-flake8" ,python-flake8)
+       ("python-flake8-bugbear" ,python-flake8-bugbear)
+       ("python-flake8-pie" ,python-flake8-pie)
+       ("python-isort" ,python-isort)
+       ("python-mypy" ,python-mypy)
+       ("python-pytest" ,python-pytest)
+       ("python-pytest-asyncio" ,python-pytest-asyncio)
+       ("python-pytest-trio" ,python-pytest-trio)
+       ("python-pytest-cov" ,python-pytest-cov)
+       ("python-trio" ,python-trio)
+       ("python-trio-typing" ,python-trio-typing)
+       ("python-trustme" ,python-trustme)
+       ("python-uvicorn" ,python-uvicorn)))
+    (propagated-inputs
+     `(("python-brotli" ,python-brotli)
+       ("python-certifi" ,python-certifi)
+       ("python-chardet" ,python-chardet)
+       ("python-httpcore" ,python-httpcore)
+       ("python-idna" ,python-idna)
+       ("python-rfc3986" ,python-rfc3986)
+       ("python-sniffio" ,python-sniffio)))
+    (home-page "https://www.python-httpx.org/")
+    (synopsis "HTTP client for Python")
+    (description
+     "HTTPX is a fully featured HTTP client for Python 3, which provides sync
+and async APIs, and support for both HTTP/1.1 and HTTP/2.
+
+HTTPX builds on the well-established usability of requests, and gives you:
+
+@itemize
+@item A broadly requests-compatible API.
+@item Standard synchronous interface, but with async support if you need it.
+@item HTTP/1.1 and HTTP/2 support.
+@item Ability to make requests directly to WSGI applications or ASGI applications.
+@item Strict timeouts everywhere.
+@item Fully type annotated.
+@item 99% test coverage.
+@end itemize
+
+Plus all the standard features of requests:
+
+@itemize
+@item International Domains and URLs
+@item Keep-Alive & Connection Pooling
+@item Sessions with Cookie Persistence
+@item Browser-style SSL Verification
+@item Basic/Digest Authentication
+@item Elegant Key/Value Cookies
+@item Automatic Decompression
+@item Automatic Content Decoding
+@item Unicode Response Bodies
+@item Multipart File Uploads
+@item HTTP(S) Proxy Support
+@item Connection Timeouts
+@item Streaming Downloads
+@item .netrc Support
+@item Chunked Requests
+@end itemize")
+    (license license:bsd-3)))
+
 (define-public python-websockets
   (package
     (name "python-websockets")
@@ -4029,7 +4735,7 @@ major web browsers.")
        ("python-pytest-cov" ,python-pytest-cov)))
     (arguments '(#:test-target "pytest"))
     (home-page "https://docs.pylonsproject.org/projects/venusian")
-    (synopsis "Library for defering decorator actions")
+    (synopsis "Library for deferring decorator actions")
     (description
      "Venusian is a library which allows framework authors to defer decorator
 actions.  Instead of taking actions when a function (or class) decorator is
@@ -4393,3 +5099,73 @@ Agent is a web crawler.  It uses the list of registered robots from
      "This module provides an interface that queries the Apache Solr server
 using a pure Python implementation.")
     (license license:bsd-3)))
+
+(define-public python-http-ece
+  (package
+    (name "python-http-ece")
+    (version "1.1.0")
+    (source
+      (origin
+        (method git-fetch)
+        (uri (git-reference
+               (url "https://github.com/web-push-libs/encrypted-content-encoding")
+               (commit (string-append "v" version))))
+        (file-name (git-file-name name version))
+        (sha256
+         (base32
+          "0bp4cc0xc123i72h80ax3qz3ixfwx3j7pw343kc7i6kdvfi8klx7"))))
+    (build-system python-build-system)
+    (arguments
+     `(#:phases
+       (modify-phases %standard-phases
+         (add-after 'unpack 'change-directory
+           (lambda _ (chdir "python") #t)))))
+    (propagated-inputs
+     `(("python-cryptography" ,python-cryptography)))
+    (native-inputs
+     `(("python-coverage" ,python-coverage)
+       ("python-flake8" ,python-flake8)
+       ("python-mock" ,python-mock)
+       ("python-nose" ,python-nose)))
+    (home-page "https://github.com/web-push-libs/encrypted-content-encoding")
+    (synopsis "Encrypted Content Encoding for HTTP")
+    (description
+     "This package provices a simple implementation of Encrypted Content
+Encoding for HTTP.")
+    (license license:expat)))
+
+(define-public python-cloudscraper
+  (package
+    (name "python-cloudscraper")
+    (version "1.2.46")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (pypi-uri "cloudscraper" version))
+       (sha256
+        (base32
+         "1br4p648yassywsd7whz1c7s10rwdysnd7wdqfjq9bksqfxrac3r"))
+       (modules '((guix build utils)))
+       (snippet
+        '(with-directory-excursion "cloudscraper"
+           (for-each delete-file
+                     '("captcha/2captcha.py"
+                       "captcha/9kw.py"
+                       "captcha/anticaptcha.py"
+                       "captcha/deathbycaptcha.py"
+                       "interpreters/js2py.py"
+                       "interpreters/v8.py"))
+           #t))))
+    (build-system python-build-system)
+    (propagated-inputs
+     `(("python-requests" ,python-requests)
+       ("python-requests-toolbelt" ,python-requests-toolbelt-0.9.1)
+       ("python-pyparsing" ,python-pyparsing-2.4.7)))
+    (native-inputs
+     `(("python-pytest" ,python-pytest)))
+    (home-page "https://github.com/venomous/cloudscraper")
+    (synopsis "Cloudflare anti-bot bypass")
+    (description
+     "This module acts as a webbrowser solving Cloudflare's Javascript
+challenges.")
+    (license license:expat)))