gnu: Add python-identify.
[jackhill/guix/guix.git] / gnu / packages / python-xyz.scm
index cdc09bc..031ce91 100644 (file)
   #:use-module (gnu packages terminals)
   #:use-module (gnu packages tex)
   #:use-module (gnu packages texinfo)
+  #:use-module (gnu packages textutils)
   #:use-module (gnu packages time)
   #:use-module (gnu packages tls)
   #:use-module (gnu packages version-control)
@@ -420,13 +421,13 @@ data for video and audio files.")
 (define-public python-psutil
   (package
     (name "python-psutil")
-    (version "5.7.0")
+    (version "5.7.2")
     (source
      (origin
        (method url-fetch)
        (uri (pypi-uri "psutil" version))
        (sha256
-        (base32 "03jykdi3dgf1cdal9bv4fq9zjvzj9l9bs99gi5ar81sdl5nc2pk8"))))
+        (base32 "1svv985vmqsls35kmvp3vhh26nsgz229324s9k29awf6qgqhm6ch"))))
     (build-system python-build-system)
     (arguments
      ;; FIXME: some tests do not return and time out.  Some tests fail because
@@ -1124,14 +1125,14 @@ multiple Unicode code points, e.g. \"G\" + acute-accent)
 (define-public python-humanfriendly
   (package
     (name "python-humanfriendly")
-    (version "4.4.1")
+    (version "8.2")
     (source
      (origin
        (method url-fetch)
        (uri (pypi-uri "humanfriendly" version))
        (sha256
         (base32
-         "0pisgizjql86785jchfjv217g0lsgk114g2lja5j4y3lsc3b9szi"))))
+         "04ixg8b7p6xc8x8lffhi7wfl77xhszakhd0s6j0cf6a84j8yqlmz"))))
     (build-system python-build-system)
     (arguments
      `(;; XXX: Tests depend on coloredlogs, which in turn depends on humanfriendly.
@@ -2429,14 +2430,14 @@ interfaces.")
 (define-public python-click
   (package
     (name "python-click")
-    (version "7.0")
+    (version "7.1.2")
     (source
      (origin
        (method url-fetch)
        (uri (pypi-uri "click" version))
        (sha256
         (base32
-         "1mzjixd4vjbjvzb6vylki9w1556a9qmdh35kzmq6cign46av952v"))))
+         "06kbzd6sjfkqan3miwj9wqyddfxc2b6hi7p5s4dvqjb3gif2bdfj"))))
     (build-system python-build-system)
     (arguments
      `(#:phases
@@ -2445,12 +2446,13 @@ interfaces.")
            (lambda* (#:key inputs #:allow-other-keys)
              (let ((glibc (assoc-ref inputs ,(if (%current-target-system)
                                                  "cross-libc" "libc"))))
-               (substitute* "click/_unicodefun.py"
+               (substitute* "src/click/_unicodefun.py"
                  (("'locale'")
                   (string-append "'" glibc "/bin/locale'"))))
              #t))
          (replace 'check
            (lambda _
+             (setenv "PYTHONPATH" (string-append "./src:" (getenv "PYTHONPATH")))
              (invoke "python" "-m" "pytest"))))))
     (native-inputs
      `(("python-pytest" ,python-pytest)))
@@ -6035,6 +6037,29 @@ all the newest features of the standard @code{pathlib} can be used also on
 older Python versions.")
     (license license:expat)))
 
+(define-public python-importlib-resources
+  (package
+    (name "python-importlib-resources")
+    (version "3.0.0")
+    (source
+      (origin
+        (method url-fetch)
+        (uri (pypi-uri "importlib_resources" version))
+        (sha256
+         (base32
+          "1hq626mx5jl9zfl0wdrjkxsnh8qd98fqv322n68b9251xjk4bxqr"))))
+    (build-system python-build-system)
+    (native-inputs
+     `(("python-setuptools-scm" ,python-setuptools-scm)
+       ("python-toml" ,python-toml)))
+    (home-page "http://importlib-resources.readthedocs.io/")
+    (synopsis "Read resources from Python packages")
+    (description
+     "@code{importlib_resources} is a backport of Python 3's standard library
+@code{importlib.resources} module for Python 2.7, and Python 3.")
+    (properties `((python2-variant . ,(delay python2-importlib-resources))))
+    (license license:asl2.0)))
+
 (define-public python2-importlib-resources
   (package
     (name "python2-importlib-resources")
@@ -12063,13 +12088,13 @@ docstring and colored output.")
 (define-public python-tomlkit
   (package
     (name "python-tomlkit")
-    (version "0.5.11")
+    (version "0.6.0")
     (source
      (origin
        (method url-fetch)
        (uri (pypi-uri "tomlkit" version))
        (sha256
-        (base32 "1kq1663iqxgwrmb883n55ypi5axnixla2hrby9g2x227asifsi7h"))))
+        (base32 "16jf0060csn8p500jnxa7m5h1sl3pzispvd11961dzrhh287dybl"))))
     (build-system python-build-system)
     (native-inputs
      `(("python-pytest" ,python-pytest)))
@@ -12227,7 +12252,7 @@ database, file, dict stores.  Cachy supports python versions 2.7+ and 3.2+.")
 (define-public poetry
   (package
     (name "poetry")
-    (version "1.0.9")
+    (version "1.0.10")
     ;; Poetry can only be built from source with Poetry.
     (source
      (origin
@@ -12235,7 +12260,7 @@ database, file, dict stores.  Cachy supports python versions 2.7+ and 3.2+.")
        (uri (pypi-uri "poetry" version))
        (sha256
         (base32
-         "1avp0db1a4hf6lz3wrzhpdvj4rpmzr4in3myrd3lp5j66nc5ck0a"))))
+         "1wm66xlsls4f0q4skmq96yb7aahjsqwgwvbrw4iax6rd4xfqj6sb"))))
     (build-system python-build-system)
     (arguments
      `(#:tests? #f ;; Pypi does not have tests.
@@ -12320,6 +12345,37 @@ It supports TSIG authenticated messages and EDNS0.")
 (define-public python2-dnspython
   (package-with-python2 python-dnspython))
 
+(define-public python-py3dns
+  (package
+    (name "python-py3dns")
+    (version "3.2.1")
+    (source
+      (origin
+        (method url-fetch)
+        (uri (pypi-uri "py3dns" version))
+        (sha256
+         (base32
+          "1r25f0ys5p37bhld7m7n4gb0lrysaym3w318w2f8bncq7r3d81qz"))))
+    (build-system python-build-system)
+    ;; This package wants to read /etc/resolv.conf. We can't patch it without
+    ;; removing functionality so we copy from Nix and "just don't build it".
+    (arguments
+     `(#:phases
+       (modify-phases %standard-phases
+         (add-after 'unpack 'patch-source
+           (lambda _
+             (substitute* "setup.py"
+               (("import DNS") "")
+               (("DNS.__version__") (string-append "\"" ,version "\"")))
+             #t)))
+       #:tests? #f)) ; Also skip the tests.
+    (home-page "https://launchpad.net/py3dns")
+    (synopsis "Python 3 DNS library")
+    (description "This Python 3 module provides a DNS API for looking up DNS
+entries from within Python 3 modules and applications.  This module is a
+simple, lightweight implementation.")
+    (license license:psfl)))
+
 (define-public python-email-validator
   (package
     (name "python-email-validator")
@@ -13490,6 +13546,93 @@ network.")
 (define-public python2-argcomplete
   (package-with-python2 python-argcomplete))
 
+(define-public python-csscompressor
+  (package
+    (name "python-csscompressor")
+    (version "0.9.5")
+    (source
+      (origin
+        (method url-fetch)
+        (uri (pypi-uri "csscompressor" version))
+        (sha256
+         (base32
+          "018ssffvlpnc1salmnpyl52c11glzzwj4k9f757hl4pkpjnjp8mg"))))
+    (build-system python-build-system)
+    (arguments
+     '(#:phases
+       (modify-phases %standard-phases
+         (replace 'check
+           (lambda _
+             (invoke "py.test"))))))
+    (native-inputs
+     `(("python-pytest" ,python-pytest)))
+    (home-page "https://github.com/sprymix/csscompressor")
+    (synopsis "Python port of YUI CSS Compressor")
+    (description
+     "This package provides a python port of YUI CSS Compressor.")
+    (license license:bsd-3)))
+
+(define-public python-rcssmin
+  (package
+    (name "python-rcssmin")
+    (version "1.0.6")
+    (source
+      (origin
+        (method url-fetch)
+        (uri (pypi-uri "rcssmin" version))
+        (sha256
+         (base32
+          "0w42l4dhxghcz7pj3q7hkxp015mvb8z2cq9sfxbl31npsfavd1ya"))))
+    (build-system python-build-system)
+    (arguments
+     '(#:phases
+       (modify-phases %standard-phases
+         (replace 'check
+           (lambda _
+             (invoke "python" "run_tests.py" "tests"))))))
+    (home-page "http://opensource.perlig.de/rcssmin/")
+    (synopsis "CSS Minifier")
+    (description "The minifier is based on the semantics of the YUI compressor,
+which itself is based on the rule list by Isaac Schlueter.")
+    (license license:asl2.0)))
+
+(define-public python-rjsmin
+  (package
+    (name "python-rjsmin")
+    (version "1.1.0")
+    (source
+      (origin
+        (method url-fetch)
+        (uri (pypi-uri "rjsmin" version))
+        (sha256
+         (base32
+          "0cmc72rlkvzz8fl89bc83czkx0pcvhzj7yn7m29r8pgnf5fcfpdi"))
+        (modules '((guix build utils)))
+        (snippet
+         '(begin
+            (for-each delete-file (find-files "bench" "\\.js$"))
+            #t))))
+    (build-system python-build-system)
+    (arguments
+     '(#:tests? #f  ; Not all test files included.
+       #:phases
+       (modify-phases %standard-phases
+         (replace 'check
+           (lambda* (#:key inputs outputs tests? #:allow-other-keys)
+             (add-installed-pythonpath inputs outputs)
+             (if tests?
+               (invoke "py.test" "-vv" "tests")
+               #t))))))
+    (native-inputs
+     `(("python-pytest" ,python-pytest)))
+    (home-page "http://opensource.perlig.de/rjsmin/")
+    (synopsis "Javascript Minifier")
+    (description "@code{rJSmin} is a javascript minifier written in Python.  The
+minifier is based on the semantics of jsmin.c by Douglas Crockford.  The module
+is a re-implementation aiming for speed, so it can be used at runtime (rather
+than during a preprocessing step).")
+    (license license:asl2.0)))
+
 (define-public python-xopen
   (package
     (name "python-xopen")
@@ -14313,6 +14456,27 @@ builds partial trees by inspecting living objects.")
         ,@(alist-delete "python-typed-ast"
                         (package-propagated-inputs base)))))))
 
+(define-public python-isbnlib
+  (package
+    (name "python-isbnlib")
+    (version "3.10.3")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (pypi-uri "isbnlib" version))
+       (sha256
+        (base32
+         "07qhykv0x60d5rsx5pj6s4q15ri4znczscll3xmpf6gyclac1592"))))
+    (build-system python-build-system)
+    (arguments '(#:tests? #f))  ; No test
+    (home-page "https://github.com/xlcnd/isbnlib")
+    (synopsis "Python library to work with ISBN strings")
+    (description "@code{python-isbnlib} is a (pure) python library that provides
+several useful methods and functions to validate, clean, transform, hyphenate and
+get metadata for ISBN strings.  Its origin was as the core of isbntools.  This short
+version, is suitable to be include as a dependency in other projects.")
+    (license license:lgpl3+)))
+
 (define-public python-isort
   (package
     (name "python-isort")
@@ -14396,6 +14560,28 @@ in other versions.")
 (define-public python2-configparser
   (package-with-python2 python-configparser))
 
+(define-public python-mamba
+  (package
+    (name "python-mamba")
+    (version "0.11.0")
+    (source (origin
+              (method url-fetch)
+              (uri (pypi-uri "mamba" version))
+              (sha256
+               (base32
+                "0bpbgz9v63rpanjjpc8bnvrr8fkms5rzylh77xrcki1x6az7gnsz"))))
+    (build-system python-build-system)
+    (arguments `(#:tests? #f))  ; No test
+    (propagated-inputs
+     `(("python-clint" ,python-clint)
+       ("python-coverage" ,python-coverage)))
+    (home-page "https://nestorsalceda.com/mamba/")
+    (synopsis "Test runner for Python")
+    (description
+     "Mamba is a Behaviour-Driven Development tool for Python developers.
+Is heavily influenced from RSpec, Mocha, Jasmine or Ginkgo.")
+    (license license:expat)))
+
 (define-public python-mando
   (package
     (name "python-mando")
@@ -16631,14 +16817,14 @@ and other tools.")
 (define-public python-typing-extensions
   (package
     (name "python-typing-extensions")
-    (version "3.7.4.1")
+    (version "3.7.4.2")
     (source
      (origin
        (method url-fetch)
        (uri (pypi-uri "typing_extensions" version))
        (sha256
         (base32
-         "1wj1vcgbnm20aiinmphyxfrbv3qi9xdhvw89ab3qm42y9n4wq7h9"))))
+         "1bk9b60s3rm1c8cwhv0bl3gh0x43153xxa6jpyllk9mc7jd5ivkr"))))
     (build-system python-build-system)
     (home-page
      "https://github.com/python/typing/blob/master/typing_extensions/README.rst")
@@ -17240,19 +17426,20 @@ inferring type information using compile-time introspection.")
 (define-public python-fasteners
   (package
     (name "python-fasteners")
-    (version "0.14.1")
+    (version "0.15")
     (source
      (origin
        (method url-fetch)
        (uri (pypi-uri "fasteners" version))
        (sha256
         (base32
-         "063y20kx01ihbz2mziapmjxi2cd0dq48jzg587xdsdp07xvpcz22"))))
+         "1vzmz1xh38b84dv0f4hlp7arwmx8wjlih6lf964bpy8dnyk6s5rs"))))
     (build-system python-build-system)
     (propagated-inputs
      `(("python-monotonic" ,python-monotonic)
-       ("python-six" ,python-six)
-       ("python-testtools" ,python-testtools)))
+       ("python-six" ,python-six)))
+    (native-inputs
+     `(("python-testtools" ,python-testtools)))
     (home-page "https://github.com/harlowja/fasteners")
     (synopsis "Python package that provides useful locks")
     (description
@@ -17301,6 +17488,40 @@ library to allow local file system access via @code{file://} URLs.")
 (define-public python2-requests-file
   (package-with-python2 python-requests-file))
 
+(define-public python-identify
+  (package
+    (name "python-identify")
+    (version "1.4.25")
+    (source
+     (origin
+       ;; There are no tests in the PyPI tarball.
+       (method git-fetch)
+       (uri (git-reference
+             (url "https://github.com/chriskuehl/identify")
+             (commit (string-append "v" version))))
+       (file-name (git-file-name name version))
+       (sha256
+        (base32 "1fqgci6skckcq0x5pnxh6k2qjzn1ndsrgha1j6wwv1ld4g9bd3hz"))))
+    (build-system python-build-system)
+    (arguments
+     `(#:phases
+       (modify-phases %standard-phases
+         (replace 'check
+           (lambda _
+             (invoke "pytest" "-vv"))))))
+    (native-inputs
+     `(("python-coverage" ,python-coverage)
+       ("python-pytest" ,python-pytest)))
+    (propagated-inputs
+     `(("python-editdistance" ,python-editdistance)))
+    (home-page "https://github.com/chriskuehl/identify")
+    (synopsis "File identification library for Python")
+    (description
+     "@code{identify} is a file identification library for Python.  Given
+a file (or some information about a file), return a set of standardized tags
+identifying what the file is.")
+    (license license:expat)))
+
 (define-public python-tldextract
   (package
     (name "python-tldextract")
@@ -17392,6 +17613,38 @@ Let's Encrypt.")
 (define-public python2-dns-lexicon
   (package-with-python2 python-dns-lexicon))
 
+(define-public python-cfgv
+  (package
+    (name "python-cfgv")
+    (version "3.1.0")
+    (source
+     (origin
+       ;; There are no tests in the PyPI tarball.
+       (method git-fetch)
+       (uri (git-reference
+             (url "https://github.com/asottile/cfgv")
+             (commit (string-append "v" version))))
+       (file-name (git-file-name name version))
+       (sha256
+        (base32 "1vvkkqw92sak4b28bpscpppq483amy52ch2yqy1i2m23q7xjkabx"))))
+    (build-system python-build-system)
+    (arguments
+     `(#:phases
+       (modify-phases %standard-phases
+         (replace 'check
+           (lambda _
+             (invoke "pytest" "-vv"))))))
+    (native-inputs
+     `(("python-covdefaults" ,python-covdefaults)
+       ("python-coverage" ,python-coverage)
+       ("python-pytest" ,python-pytest)))
+    (home-page "https://github.com/asottile/cfgv")
+    (synopsis "Configuration validation library")
+    (description
+     "This library helps to validate configuration files and produce human
+readable error messages.")
+    (license license:expat)))
+
 (define-public python-commandlines
   (package
     (name "python-commandlines")
@@ -19236,9 +19489,9 @@ and cuts down boilerplate code when testing libraries for asyncio.")
              (commit (string-append "v" version))))
        (file-name (git-file-name name version))
        (sha256
-        (base32 "1sk9i8czxgsbrswsf1nlb4c82vgnlzi8zrvrxdip92w2z8hqh43y"))))
+        (base32 "1sk9i8czxgsbrswsf1nlb4c82vgnlzi8zrvrxdip92w2z8hqh43y"))
+       (patches (search-patches "python-aionotify-0.2.0-py3.8.patch"))))
     (build-system python-build-system)
-    (native-inputs `(("python-asynctest" ,python-asynctest)))
     (home-page "https://github.com/rbarrois/aionotify")
     (synopsis "Asyncio-powered inotify library")
     (description
@@ -19749,17 +20002,22 @@ logging in Python.  It also provides some custom formatters and handlers.")
 (define-public python-pifpaf
   (package
     (name "python-pifpaf")
-    (version "2.4.0")
+    (version "2.5.0")
     (source
      (origin
        (method url-fetch)
        (uri (pypi-uri "pifpaf" version))
        (sha256
         (base32
-         "150av2pylsjy8ykrpyi0vzy2q24s9rhh2ya01zvwnvj9j5dspviz"))))
+         "1gy9p4nqf70fh38wn4icyfm7i9wrvx22wnjpg71g89wxbz27igaa"))))
     (build-system python-build-system)
     (arguments
-     `(#:tests? #f))
+     '(#:phases
+       (modify-phases %standard-phases
+         (replace 'check
+           (lambda _
+             (invoke "python" "setup.py" "testr" "--slowest"
+                     "--testr-args=until-failure"))))))
     (propagated-inputs
      `(("python-click" ,python-click)
        ("python-daiquiri" ,python-daiquiri)
@@ -20504,3 +20762,256 @@ For the most part it's transliterated from C, the major differences are:
 @end itemize
 ")
     (license license:gpl3+)))
+
+(define-public python-jinxed
+  (package
+    (name "python-jinxed")
+    (version "1.0.0")
+    (source
+      (origin
+        (method url-fetch)
+        (uri (pypi-uri "jinxed" version))
+        (sha256
+         (base32
+          "1n7vl03rhjd0xhjgbjlh8x9f8yfbhamcwkgvs4jg7g5qj8f0wk89"))))
+    (build-system python-build-system)
+    (arguments
+     '(#:phases
+       (modify-phases %standard-phases
+         (add-before 'check 'set-environment-variables
+           (lambda* (#:key inputs #:allow-other-keys)
+             (let ((ncurses (assoc-ref inputs "ncurses")))
+               (setenv "TERM" "LINUX")
+               (setenv "TERMINFO" (string-append ncurses "/share/terminfo"))
+               #t))))
+       #:tests? #f)) ; _curses.error: setupterm: could not find terminal
+    (native-inputs
+     `(("ncurses" ,ncurses)))
+    (home-page "https://github.com/Rockhopper-Technologies/jinxed")
+    (synopsis "Jinxed Terminal Library")
+    (description
+     "Jinxed is an implementation of a subset of the Python curses library.")
+    (license license:mpl2.0)))
+
+(define-public python-blessed
+  (package
+    (name "python-blessed")
+    (version "1.17.8")
+    (source
+      (origin
+        (method url-fetch)
+        (uri (pypi-uri "blessed" version))
+        (sha256
+         (base32
+          "1wdj342sk22hfrg0n91x2qnqsbzbiyq9y009v3pxnvfzn9bx0wbn"))
+        (modules '((guix build utils)))
+        (snippet
+         '(begin
+            ;; Don't get hung up on Windows test failures.
+            (delete-file "blessed/win_terminal.py") #t))))
+    (build-system python-build-system)
+    (propagated-inputs
+     `(("python-jinxed" ,python-jinxed)
+       ("python-six" ,python-six)
+       ("python-wcwidth" ,python-wcwidth)))
+    (native-inputs
+     `(("python-mock" ,python-mock)
+       ("python-pytest" ,python-pytest)))
+    (home-page "https://github.com/jquast/blessed")
+    (synopsis "Wrapper around terminal capabilities")
+    (description
+     "Blessed is a thin, practical wrapper around terminal styling, screen
+positioning, and keyboard input.")
+    (license license:expat)))
+
+(define-public python-readme-renderer
+  (package
+    (name "python-readme-renderer")
+    (version "26.0")
+    (source
+      (origin
+        (method url-fetch)
+        (uri (pypi-uri "readme_renderer" version))
+        (sha256
+         (base32
+          "13fnrv7z3y0yfafzcjbl55cqxncvbxadr72ql4l29pgyvrqxpsfb"))))
+    (build-system python-build-system)
+    (propagated-inputs
+     `(("python-bleach" ,python-bleach)
+       ("python-docutils" ,python-docutils)
+       ("python-pygments" ,python-pygments)
+       ("python-six" ,python-six)))
+    (native-inputs
+     `(("python-mock" ,python-mock)
+       ("python-pytest" ,python-pytest)))
+    (home-page "https://github.com/pypa/readme_renderer")
+    (synopsis "Render README files in Warehouse")
+    (description
+     "Readme Renderer is a library that will safely render arbitrary README
+files into HTML.  It is designed to be used in Warehouse to render the
+@code{long_description} for packages.  It can handle Markdown, reStructuredText,
+and plain text.")
+    (license license:asl2.0)))
+
+(define-public python-lazr-delegates
+  (package
+    (name "python-lazr-delegates")
+    (version "2.0.4")
+    (source
+      (origin
+        (method url-fetch)
+        (uri (pypi-uri "lazr.delegates" version))
+        (sha256
+         (base32
+          "1rdnl85j9ayp8n85l0ciip621j9dcziz5qnmv2m7krgwgcn31vfx"))))
+    (build-system python-build-system)
+    (arguments
+     '(#:phases
+       (modify-phases %standard-phases
+         (replace 'check
+           (lambda _
+             (invoke "python" "setup.py" "nosetests"))))))
+    (native-inputs
+     `(("python-nose" ,python-nose)))
+    (propagated-inputs
+     `(("python-zope-interface" ,python-zope-interface)))
+    (home-page "https://launchpad.net/lazr.delegates")
+    (synopsis "Easily write objects that delegate behavior")
+    (description
+     "The @code{lazr.delegates} package makes it easy to write objects that
+delegate behavior to another object.  The new object adds some property or
+behavior on to the other object, while still providing the underlying interface,
+and delegating behavior.")
+    (license license:lgpl3)))
+
+(define-public python-lazr-config
+  (package
+    (name "python-lazr-config")
+    (version "2.2.2")
+    (source
+      (origin
+        (method url-fetch)
+        (uri (pypi-uri "lazr.config" version))
+        (sha256
+         (base32
+          "11xpddgyhyj7sf27wbmrq5lnqk21wnprx3ajycgwlxjamh6sgffd"))))
+    (build-system python-build-system)
+    (arguments
+     '(#:phases
+       (modify-phases %standard-phases
+         (replace 'check
+           (lambda _
+             (invoke "python" "-s" "-m" "nose" "-P" "lazr"))))))
+    (native-inputs
+     `(("python-nose" ,python-nose)))
+    (propagated-inputs
+     `(("python-lazr-delegates" ,python-lazr-delegates)
+       ("python-zope-interface" ,python-zope-interface)))
+    (home-page "https://launchpad.net/lazr.config")
+    (synopsis "Create configuration schemas and process and validate configurations")
+    (description
+     "The LAZR config system is typically used to manage process configuration.
+Process configuration is for saying how things change when we run systems on
+different machines, or under different circumstances.  This system uses ini-like
+file format of section, keys, and values.  The config file supports inheritance
+to minimize duplication of information across files.  The format supports schema
+validation.")
+    (license license:lgpl3)))
+
+(define-public python-flufl-bounce
+  (package
+    (name "python-flufl-bounce")
+    (version "3.0.1")
+    (source
+      (origin
+        (method url-fetch)
+        (uri (pypi-uri "flufl.bounce" version))
+        (sha256
+         (base32
+          "01lg1b0jpf8605mzaz9miq3nray6s7a7gc8n4wzg5nsxl8fglcp4"))))
+    (build-system python-build-system)
+    (propagated-inputs
+     `(("python-atpublic" ,python-atpublic)
+       ("python-zope-interface" ,python-zope-interface)))
+    (native-inputs
+     `(("python-nose2" ,python-nose2)))
+    (home-page "https://fluflbounce.readthedocs.io/en/latest/")
+    (synopsis "Email bounce detectors")
+    (description "The @code{flufl.bounce} library provides a set of heuristics
+and an API for detecting the original bouncing email addresses from a bounce
+message.  Many formats found in the wild are supported, as are VERP and
+RFC 3464.")
+    (license (list license:asl2.0
+                   license:lgpl3))))    ; only for setup_headers.py
+
+(define-public python-flufl-i18n
+  (package
+    (name "python-flufl-i18n")
+    (version "3.0")
+    (source
+      (origin
+        (method url-fetch)
+        (uri (pypi-uri "flufl.i18n" version))
+        (sha256
+         (base32
+          "1flwpn1xhgc957zj3zxw92dhdjh0lsy0hdvzq32dzqpsajfsvq1r"))))
+    (build-system python-build-system)
+    (propagated-inputs
+     `(("python-atpublic" ,python-atpublic)))
+    (home-page "https://flufli18n.readthedocs.io")
+    (synopsis "API for Python internationalization")
+    (description
+     "This package provides a high level, convenient API for managing
+internationalization translation contexts in Python application.  There is a
+simple API for single-context applications, such as command line scripts which
+only need to translate into one language during the entire course of thei
+execution.  There is a more flexible, but still convenient API for multi-context
+applications, such as servers, which may need to switch language contexts for
+different tasks.")
+    (license license:asl2.0)))
+
+(define-public python-flufl-lock
+  (package
+    (name "python-flufl-lock")
+    (version "4.0")
+    (source
+      (origin
+        (method url-fetch)
+        (uri (pypi-uri "flufl.lock" version))
+        (sha256
+         (base32
+          "055941zyma3wfx25jhm8wcsghpv3jc3iwi1gdrdjhzcnfhn62lxq"))))
+    (build-system python-build-system)
+    (propagated-inputs
+     `(("python-atpublic" ,python-atpublic)
+       ("python-psutil" ,python-psutil)))
+    (home-page "https://flufllock.readthedocs.io")
+    (synopsis "NFS-safe file locking with timeouts for POSIX systems")
+    (description
+     "The @dfn{flufl.lock} package provides NFS-safe file locking with
+timeouts for POSIX systems.  It is similar to the @code{O_EXCL} option of the
+@code{open} system call but uses a lockfile.  Lock objects support lock-breaking
+and have a maximum lifetime built-in.")
+    (license (list license:asl2.0
+                   license:lgpl3))))    ; only for setup_helpers.py
+
+(define-public python-flufl-testing
+  (package
+    (name "python-flufl-testing")
+    (version "0.8")
+    (source
+      (origin
+        (method url-fetch)
+        (uri (pypi-uri "flufl.testing" version))
+        (sha256
+         (base32
+          "1nkm95mhcfhl4x5jgs6y97ikszaxsfh07nyawsih6cxxm6l62641"))))
+    (build-system python-build-system)
+    (native-inputs
+     `(("python-nose2" ,python-nose2)))
+    (home-page "https://gitlab.com/warsaw/flufl.testing")
+    (synopsis "Collection of test tool plugins")
+    (description
+     "This package contains a small collection of test tool plugins for
+@code{nose2} and @code{flake8}.")
+    (license license:asl2.0)))