From mboxrd@z Thu Jan 1 00:00:00 1970 From: "pelzflorian (Florian Pelz)" Subject: Mailman packaging (was: Re: Python package naming: Dots vs hyphens) Date: Wed, 6 Nov 2019 14:18:33 +0100 Message-ID: <20191106131833.5a2p7glowry2dhpk@pelzflorian.localdomain> References: <20191106064955.rks6qsypuym6v6pt@pelzflorian.localdomain> <20191106071917.GJ14453@E5400> Mime-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable Return-path: Received: from eggs.gnu.org ([2001:470:142:3::10]:39813) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iSLCp-0004Or-9g for guix-devel@gnu.org; Wed, 06 Nov 2019 08:18:42 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iSLCl-0004ko-It for guix-devel@gnu.org; Wed, 06 Nov 2019 08:18:39 -0500 Received: from pelzflorian.de ([5.45.111.108]:51320 helo=mail.pelzflorian.de) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1iSLCl-0004kM-69 for guix-devel@gnu.org; Wed, 06 Nov 2019 08:18:35 -0500 Content-Disposition: inline In-Reply-To: <20191106071917.GJ14453@E5400> List-Id: "Development of GNU Guix and the GNU System distribution." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: guix-devel-bounces+gcggd-guix-devel=m.gmane.org@gnu.org Sender: "Guix-devel" To: Efraim Flashner Cc: guix-devel@gnu.org, pjotr2019@thebird.nl Long e-mail / review follows. Feel free to disagree. On Wed, Nov 06, 2019 at 09:19:17AM +0200, Efraim Flashner wrote: > On Wed, Nov 06, 2019 at 07:49:56AM +0100, pelzflorian (Florian Pelz) wr= ote: > > I am in the process of packaging mailman 3 which according to the pyp= i > > importer needs packages like > >=20 > > python-flufl.bounce > > python-flufl.i18n > > python-flufl.lock > > python-lazr.config > > python-lazr.delegates > > python-zope.component > > python-zope.configuration > > python-zope.configuration > > python-zope.event > > python-zope.interface > >=20 >=20 > I've actually last week started working on that. I've only done the > python part, haven't searched for any javascript or font-awesome which > I'm pretty sure I saw. I've also started working on a service for it > which I haven't committed yet, but it looks like it's going to be > complex. >=20 > https://gitlab.com/genenetwork/guix-bioinformatics/blob/master/gn/packa= ges/mailman.scm >=20 Wow. That is good. You have the better setup and have packaged more of the Mailman Suite so please continue with yours. I too started last week. I have only looked at the python part of mailman core myself. Let me compare and complain about some of what I have done differently. Some things are clearly better your way. ;) You have come further. I will watch your repo now and try and test other mailman things tomorrow. You have: (define-public mailman (package ... (description "GNU Mailman is software for managing email discussion and mailing lists. Both users and administrators generally perform their actions in = a web interface, although email and command-line interfaces are also provid= ed. The system features built-in archiving, automatic bounce processing, cont= ent filtering, digest delivery, and more.") I have: (description "This is the core engine for the GNU Mailing List manage= r. It is part of the full GNU Mailman 3 suite. Mailman is the GNU Mailing List Manager, a program that manages electronic mail discussion groups.") Maybe your mailman description is more appropriate later for a service in doc/guix.texi instead of this package? Feel free to disagree. You have: (define-public python-aiosmtpd ... (arguments '(#:phases (modify-phases %standard-phases (add-after 'unpack 'delete-failing-test (lambda _ (delete-file "aiosmtpd/tests/test_smtps.py") #t)) (replace 'check (lambda _ (invoke "python" "-m" "nose2" "-v")))))) I have: (arguments `(#:phases (modify-phases %standard-phases (add-before 'check 'disable-failing-tests (lambda _ (delete-file "aiosmtpd/tests/test_smtps.py") #t)) (replace 'check (lambda _ (invoke "python" "-m" "unittest" "discover" "-v") #t))))) I had not used nose2 nor flufl.testing for 'check, but I think it may be better to use them like you did because nose is in their documentation. Mine =E2=80=9CRan 181 tests in 3.026s=E2=80=9D, except on= e test sometimes fails nondeterministically: ERROR: test_debug_0 (aiosmtpd.tests.test_main.TestMain) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/guix-build-python-aiosmtpd-1.2.drv-0/aiosmtpd-1.2/aiosmtpd/t= ests/test_main.py", line 122, in test_debug_0 main(('-n',)) File "/tmp/guix-build-python-aiosmtpd-1.2.drv-0/aiosmtpd-1.2/aiosmtpd/m= ain.py", line 140, in main loop.create_server(factory, host=3Dargs.host, port=3Dargs.port)) File "/gnu/store/78w7y0lxar70j512iqw8x3nimzj10yga-python-3.7.4/lib/pyth= on3.7/asyncio/base_events.py", line 577, in run_until_complete raise RuntimeError('Event loop stopped before Future completed.') RuntimeError: Event loop stopped before Future completed. But sometimes it succeeds. I had not packaged flufl.testing. Your package for flufl.testing looks good, including the license. You have: (define-public python-aiosmtpd ... (license license:asl2.0))) I have: (license (list license:asl2.0 license:lgpl3)))) ;only for setup_helpers.py You have: (define-public python-atpublic ... (arguments '(#:phases (modify-phases %standard-phases (replace 'check (lambda _ (invoke "python" "-m" "nose2" "-v")))))) (native-inputs `(("python-nose2" ,python-nose2))) I have: (arguments `(#:phases (modify-phases %standard-phases ;; Use faster C implementation instead of Python implementation. (add-before 'build 'enable-c-implementation (lambda _ (setenv "ATPUBLIC_BUILD_EXTENSION" "yes") #t))x (replace 'check (lambda _ (invoke "python" "-m" "unittest" "discover" "-v") #t))))) I would prefer using ATPUBLIC_BUILD_EXTENSION. I do not know about nose. You have: (define-public python-atpublic ... (synopsis "Python library for populating __all__") (description "This is a very simple decorator and function which populates a modu= les @code{__all__} and optionally the module globals. This provides both a pure-Python implementation and an optional C implementation.") (license license:asl2.0))) I have: (synopsis "@code{@@public} decorator for populating @code{__all__}") (description "This Python module adds a @code{@@public} decorator and function wh= ich populates a module's @code{__all__} and optionally the module globals. W= ith it, the declaration of a name's public export semantics are not separated= from the implementation of that name.") (license (list license:asl2.0 license:lgpl3)))) ;only for setup_helpers.py I prefer mine. You have: (define-public python-authheaders (package (name "python-authheaders") (version "0.12.0") (source (origin (method url-fetch) (uri (pypi-uri "authheaders" version)) (sha256 (base32 "1ljcp8vk2n4xwk8p758b6q5sgdicyj4gxxpkmh33mx21jscn6q4i")))) (build-system python-build-system) (propagated-inputs `(("python-authres" ,python-authres) ("python-dkimpy" ,python-dkimpy) ("python-dnspython" ,python-dnspython) ("python-publicsuffix" ,python-publicsuffix))) (home-page "https://github.com/ValiMail/authentication-headers") (synopsis "Library wrapping email authentication header verification = and generation") (description "A library wrapping email authentication header verification and gen= eration.") (license license:expat))) I have: (define-public python-authheaders (package (name "python-authheaders") (version "0.12.0") (source (origin (method url-fetch) (uri (pypi-uri "authheaders" version)) (sha256 (base32 "1ljcp8vk2n4xwk8p758b6q5sgdicyj4gxxpkmh33mx21jscn6q4i")) (snippet '(begin ;; Remove bundled public suffix list and its license. (delete-file "authheaders/public_suffix_list.txt") (delete-file "MPL-2.0") #t)))) (build-system python-build-system) (arguments `(#:modules ((guix build python-build-system) (guix build utils) (ice-9 textual-ports)) #:phases (modify-phases %standard-phases (add-before 'build 'configure-public-suffix-list ;; Use public suffix list from Guix package. (lambda* (#:key inputs #:allow-other-keys) (let ((publicsuffix (assoc-ref inputs "python-publicsuffix")= )) (invoke "python" "setup.py" "psllocal" (string-append "--path=3D" publicsuffix "/lib/pyth= on3.7" "/site-packages/publicsuffix" "/public_suffix_list.dat")) #t))) (replace 'check (lambda _ ;; Make it find the only test file. (invoke "python" "-m" "unittest" "-v" "test" "authheaders/test/test_authentication.py") #t))))) (propagated-inputs `(("python-authres" ,python-authres) ("python-dkimpy" ,python-dkimpy) ("python-dnspython" ,python-dnspython) ("python-publicsuffix" ,python-publicsuffix))) (home-page "https://github.com/ValiMail/authentication-headers") (synopsis "Library wrapping email authentication header verification and gener= ation") (description "This is a Python library for the generation of email authentication headers. The library can perform DKIM, SPF, and DMARC validation, and th= e results are packaged into the Authentication-Results header. The library= can DKIM and ARC sign messages and output the corresponding signature headers= .") ;; The package's metadata claims it were MIT licensed, but the source= file ;; headers disagree. (license (list license:zpl2.1 license:zlib)))) I mostly prefer my package. I do not know if tests run for yours. I like having a short description like you have, but I would prefer mentioning DKIM, SPF etc. You have: (define-public python-authres ... (synopsis "Authentication Results Header Module") (description "This package provides RFC 5451/7001/7601 Authentication-Results Hea= ders generation and parsing for Python.") (license license:asl2.0))) I have: (arguments `(#:phases (modify-phases %standard-phases (replace 'check (lambda _ ;; Run doctests as described in README. (invoke "python" "-m" "authres" "-v") #t))))) (home-page "https://launchpad.net/authentication-results-python") (synopsis "Email Authentication Results Headers generation and parsing") (description "This module can be used to generate and parse RFC 5451/7001/7601 Au= thentication-Results headers. It also supports Authentication Results extensions: @itemize @item RFC 5617 DKIM/ADSP @item RFC 6008 DKIM signature identification (header.b) @item RFC 6212 Vouch By Reference (VBR) @item RFC 6577 Sender Policy Framework (SPF) @item RFC 7281 Authentication-Results Registration for S/MIME @item RFC 7293 The Require-Recipient-Valid-Since Header Field @item RFC 7489 Domain-based Message Authentication, Reporting, and Confor= mance (DMARC) @item Authenticated Recieved Chain (ARC) (draft-ietf-dmarc-arc-protocol-0= 8) @end itemize Note: RFC 7601 obsoletes RFC 5451, 6577, 7001, and 7410. Authres support= s the current standard. No backward compatibility issues have been noted.") (license license:asl2.0))) I do not know if tests run for your package. I prefer your description though. You have: (define-public python-flufl.bounce ... (description "The @code{flufl.bounce} library provides a set of heurist= ics and an API for detecting the original bouncing email addresses from a bou= nce message. Many formats found in the wild are supported, as are VERP and RFC 3464.") (license license:asl2.0))) I have the same package inputs etc., except: (synopsis "Email bounce detectors") (description "The @dfn{flufl.bounce} library provides a set of heuris= tics and an API for detecting the original bouncing email addresses from a bou= nce message. Many formats found in the wild are supported, as are VERP and R= FC 3464 (DSN).") (license (list license:asl2.0 ;except for an emails used as test data ;which may be non-free license:lgpl3)))) ;only for setup_helpers.py I prefer your description without DSN at the end, but I prefer my license list. Our python-flufl.i18n are identical. You have: (define-public python-flufl.lock ... (synopsis "NFS-safe file locking with timeouts for POSIX systems") (description "This package provides NFS-safe file locking with timeouts for POSIX= systems.") (license license:asl2.0))) I have: (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 so that you can=E2=80=99t wedge a process forever. Locks h= ave a lifetime, which is the maximum length of time the process expects to reta= in the lock.") (license (list license:asl2.0 license:lgpl3)))) ;only for setup_helpers.py I think my description is too long and yours is too short. I prefer my license list. You have: (define-public python-gunicorn ... (arguments '(#:phases (modify-phases %standard-phases (add-after 'unpack 'loosen-verion-restrictions (lambda _ (substitute* "requirements_test.txt" (("coverage.*") "coverage\n") (("pytest.*") "pytest\n") (("pytest-cov.*") "pytest-cov\n")) #t))))) (native-inputs `(("python-coverage" ,python-coverage) ("python-pytest" ,python-pytest) ("python-pytest-cov" ,python-pytest-cov))) (home-page "https://gunicorn.org") (synopsis "WSGI HTTP Server for UNIX") (description "Gunicorn 'Green Unicorn' is a Python WSGI HTTP Server f= or UNIX. It's a pre-fork worker model ported from Ruby's Unicorn project. = The Gunicorn server is broadly compatible with various web frameworks, simply implemented, light on server resource usage, and fairly speedy.") (license license:expat))) I have: (define-public python-gunicorn ... (arguments `(#:phases (modify-phases %standard-phases (add-before 'check 'disable-failing-tests (lambda _ ;; The test for deprecated gaiohttp fails, cf. ;; https://github.com/benoitc/gunicorn/commit/97a45805f85830= d1f80bf769f5787704daa635d3 (delete-file "tests/test_gaiohttp.py") #t)) (replace 'check (lambda _ (invoke "python" "-m" "unittest" "discover" "-v" "-s" "tests= ") #t))))) (native-inputs `(("python-pytest" ,python-pytest))) (home-page "http://gunicorn.org") (synopsis "WSGI HTTP Server") (description "Gunicorn @dfn{Green Unicorn} is a Python WSGI HTTP Serv= er for UNIX. It's a pre-fork worker model. The Gunicorn server is broadly compatible with various web frameworks, simply implemented, light on serv= er resources, and fairly speedy.") (license (list license:expat ;; Some files have different licenses, cf. the NOTICE file in = the ;; sources. These licenses are: license:bsd-3 ;; License variants are the PSF and CWI License Agreements for ;; Python: license:psfl)))) The psfl license variants may not matter. I wonder if your tests run correctly. My package prints: > starting phase `check' > test_close (test_selectors.DefaultSelectorTestCase) ... ok > test_context_manager (test_selectors.DefaultSelectorTestCase) ... ok > test_fileno (test_selectors.DefaultSelectorTestCase) ... ok > test_get_key (test_selectors.DefaultSelectorTestCase) ... ok > test_get_map (test_selectors.DefaultSelectorTestCase) ... ok > test_modify (test_selectors.DefaultSelectorTestCase) ... ok > test_register (test_selectors.DefaultSelectorTestCase) ... ok > test_select (test_selectors.DefaultSelectorTestCase) ... ok > test_select_interrupt (test_selectors.DefaultSelectorTestCase) ... ok > test_selector (test_selectors.DefaultSelectorTestCase) ... ok > test_timeout (test_selectors.DefaultSelectorTestCase) ... ok > test_unregister (test_selectors.DefaultSelectorTestCase) ... ok > test_unregister_after_fd_close (test_selectors.DefaultSelectorTestCase)= ... ok > test_unregister_after_socket_close (test_selectors.DefaultSelectorTestC= ase) ... ok > test_above_fd_setsize (test_selectors.DevpollSelectorTestCase) ... skip= ped 'Test needs selectors.DevpollSelector' > test_close (test_selectors.DevpollSelectorTestCase) ... skipped 'Test n= eeds selectors.DevpollSelector' > test_context_manager (test_selectors.DevpollSelectorTestCase) ... skipp= ed 'Test needs selectors.DevpollSelector' > test_fileno (test_selectors.DevpollSelectorTestCase) ... skipped 'Test = needs selectors.DevpollSelector' > test_get_key (test_selectors.DevpollSelectorTestCase) ... skipped 'Test= needs selectors.DevpollSelector' > test_get_map (test_selectors.DevpollSelectorTestCase) ... skipped 'Test= needs selectors.DevpollSelector' > test_modify (test_selectors.DevpollSelectorTestCase) ... skipped 'Test = needs selectors.DevpollSelector' > test_register (test_selectors.DevpollSelectorTestCase) ... skipped 'Tes= t needs selectors.DevpollSelector' > test_select (test_selectors.DevpollSelectorTestCase) ... skipped 'Test = needs selectors.DevpollSelector' > test_select_interrupt (test_selectors.DevpollSelectorTestCase) ... skip= ped 'Test needs selectors.DevpollSelector' > test_selector (test_selectors.DevpollSelectorTestCase) ... skipped 'Tes= t needs selectors.DevpollSelector' > test_timeout (test_selectors.DevpollSelectorTestCase) ... skipped 'Test= needs selectors.DevpollSelector' > test_unregister (test_selectors.DevpollSelectorTestCase) ... skipped 'T= est needs selectors.DevpollSelector' > test_unregister_after_fd_close (test_selectors.DevpollSelectorTestCase)= ... skipped 'Test needs selectors.DevpollSelector' > test_unregister_after_socket_close (test_selectors.DevpollSelectorTestC= ase) ... skipped 'Test needs selectors.DevpollSelector' > test_above_fd_setsize (test_selectors.EpollSelectorTestCase) ... ok > test_close (test_selectors.EpollSelectorTestCase) ... ok > test_context_manager (test_selectors.EpollSelectorTestCase) ... ok > test_fileno (test_selectors.EpollSelectorTestCase) ... ok > test_get_key (test_selectors.EpollSelectorTestCase) ... ok > test_get_map (test_selectors.EpollSelectorTestCase) ... ok > test_modify (test_selectors.EpollSelectorTestCase) ... ok > test_register (test_selectors.EpollSelectorTestCase) ... ok > test_select (test_selectors.EpollSelectorTestCase) ... ok > test_select_interrupt (test_selectors.EpollSelectorTestCase) ... ok > test_selector (test_selectors.EpollSelectorTestCase) ... ok > test_timeout (test_selectors.EpollSelectorTestCase) ... ok > test_unregister (test_selectors.EpollSelectorTestCase) ... ok > test_unregister_after_fd_close (test_selectors.EpollSelectorTestCase) .= .. ok > test_unregister_after_socket_close (test_selectors.EpollSelectorTestCas= e) ... ok > test_above_fd_setsize (test_selectors.KqueueSelectorTestCase) ... skipp= ed 'Test needs selectors.KqueueSelector)' > test_close (test_selectors.KqueueSelectorTestCase) ... skipped 'Test ne= eds selectors.KqueueSelector)' > test_context_manager (test_selectors.KqueueSelectorTestCase) ... skippe= d 'Test needs selectors.KqueueSelector)' > test_fileno (test_selectors.KqueueSelectorTestCase) ... skipped 'Test n= eeds selectors.KqueueSelector)' > test_get_key (test_selectors.KqueueSelectorTestCase) ... skipped 'Test = needs selectors.KqueueSelector)' > test_get_map (test_selectors.KqueueSelectorTestCase) ... skipped 'Test = needs selectors.KqueueSelector)' > test_modify (test_selectors.KqueueSelectorTestCase) ... skipped 'Test n= eeds selectors.KqueueSelector)' > test_register (test_selectors.KqueueSelectorTestCase) ... skipped 'Test= needs selectors.KqueueSelector)' > test_select (test_selectors.KqueueSelectorTestCase) ... skipped 'Test n= eeds selectors.KqueueSelector)' > test_select_interrupt (test_selectors.KqueueSelectorTestCase) ... skipp= ed 'Test needs selectors.KqueueSelector)' > test_selector (test_selectors.KqueueSelectorTestCase) ... skipped 'Test= needs selectors.KqueueSelector)' > test_timeout (test_selectors.KqueueSelectorTestCase) ... skipped 'Test = needs selectors.KqueueSelector)' > test_unregister (test_selectors.KqueueSelectorTestCase) ... skipped 'Te= st needs selectors.KqueueSelector)' > test_unregister_after_fd_close (test_selectors.KqueueSelectorTestCase) = ... skipped 'Test needs selectors.KqueueSelector)' > test_unregister_after_socket_close (test_selectors.KqueueSelectorTestCa= se) ... skipped 'Test needs selectors.KqueueSelector)' > test_above_fd_setsize (test_selectors.PollSelectorTestCase) ... ok > test_close (test_selectors.PollSelectorTestCase) ... ok > test_context_manager (test_selectors.PollSelectorTestCase) ... ok > test_fileno (test_selectors.PollSelectorTestCase) ... ok > test_get_key (test_selectors.PollSelectorTestCase) ... ok > test_get_map (test_selectors.PollSelectorTestCase) ... ok > test_modify (test_selectors.PollSelectorTestCase) ... ok > test_register (test_selectors.PollSelectorTestCase) ... ok > test_select (test_selectors.PollSelectorTestCase) ... ok > test_select_interrupt (test_selectors.PollSelectorTestCase) ... ok > test_selector (test_selectors.PollSelectorTestCase) ... ok > test_timeout (test_selectors.PollSelectorTestCase) ... ok > test_unregister (test_selectors.PollSelectorTestCase) ... ok > test_unregister_after_fd_close (test_selectors.PollSelectorTestCase) ..= . ok > test_unregister_after_socket_close (test_selectors.PollSelectorTestCase= ) ... ok > test_close (test_selectors.SelectSelectorTestCase) ... ok > test_context_manager (test_selectors.SelectSelectorTestCase) ... ok > test_fileno (test_selectors.SelectSelectorTestCase) ... ok > test_get_key (test_selectors.SelectSelectorTestCase) ... ok > test_get_map (test_selectors.SelectSelectorTestCase) ... ok > test_modify (test_selectors.SelectSelectorTestCase) ... ok > test_register (test_selectors.SelectSelectorTestCase) ... ok > test_select (test_selectors.SelectSelectorTestCase) ... ok > test_select_interrupt (test_selectors.SelectSelectorTestCase) ... ok > test_selector (test_selectors.SelectSelectorTestCase) ... ok > test_timeout (test_selectors.SelectSelectorTestCase) ... ok > test_unregister (test_selectors.SelectSelectorTestCase) ... ok > test_unregister_after_fd_close (test_selectors.SelectSelectorTestCase) = ... ok > test_unregister_after_socket_close (test_selectors.SelectSelectorTestCa= se) ... ok >=20 > ---------------------------------------------------------------------- > Ran 88 tests in 12.463s >=20 > OK (skipped=3D30) You have: (define-public python-importlib-resources ... I have no such package because it is no longer needed, I think. I have not packaged all dependencies yet so I cannot try building mailman. You made a comment in your mailman package that importlib-resources is no longer needed. I have not yet written a lazr.config package that successfully runs its tests. I do not know if tests run for you. If not, I tried (arguments `(#:phases (modify-phases %standard-phases (replace 'check (lambda _ (invoke "python" "-m" "unittest" "discover" "-v" "-s" "src") #t))))) but apparently "-s" is wrong; I find = . You have python-zope.component. I don=E2=80=99t have own python-zope.* packages, but there is an outdated python-zope-component with a hyphen in python-web.scm. I have not looked at your other python-zope-* packages. You have: (define-public python-dkimpy ... (arguments '(#:phases (modify-phases %standard-phases (add-after 'patch-source-shebangs 'patch-more-source (lambda* (#:key inputs #:allow-other-keys) (let ((openssl (assoc-ref inputs "openssl"))) (substitute* "dkim/dknewkey.py" (("/usr/bin/openssl") (string-append openssl "/bin/opens= sl")))) #t)) (replace 'check (lambda _ (invoke "python" "test.py")))))) (propagated-inputs `(("python-dnspython" ,python-dnspython))) (native-inputs `(("python-authres" ,python-authres) ("python-pynacl" ,python-pynacl))) (inputs `(("openssl" ,openssl))) (home-page "https://launchpad.net/dkimpy") (synopsis "DKIM (DomainKeys Identified Mail)") (description "Python module that implements @dfn{DKIM} (DomainKeys Identified Mail) email signing and verification (RFC6376). It also provi= des helper scripts for command line signing and verification. It supports DK= IM signing/verifying of ed25519-sha256 signatures (RFC 8463). It also suppo= rts the RFC 8617 Authenticated Received Chain (ARC) protocol.") (license license:bsd-3))) I have: (define-public python-dkimpy ... (arguments `(;; Tests would need /etc/resolv.conf. #:tests? #f #:phases (modify-phases %standard-phases (add-after 'unpack 'fix-setup-py (lambda _ ;; We cannot import DNS because it would need /etc/resolv.co= nf. (substitute* "setup.py" (("import DNS") "")) #t))))) (propagated-inputs `(("python-py3dns" ,python-py3dns))) (native-inputs `(("python-authres" ,python-authres) ("python-pynacl" ,python-pynacl))) (home-page "https://launchpad.net/dkimpy") (synopsis "Implementation of DKIM (DomainKeys Identified Mail)") (description "Python module that implements DKIM (@dfn{DomainKeys Identified Mail}) email signing and verification (RFC 6376). It also pro= vides helper scripts for command line signing and verification. It supports DK= IM signing/verifying of ed25519-sha256 signatures (RFC 8463). It also suppo= rts the RFC 8617 Authenticated Received Chain (ARC) protocol.") (license license:zlib)));except for an email used as test data which may be n= on-free Yours seems much better, except the license header. Your python-lazr.delegates is clearly better at running tests and mine has no advantages. You have: (define-public python-py3dns ... (build-system python-build-system) ;; This package wants to read /etc/resolv.conf. We can't patch it wit= hout ;; removing functionality so we copy from Nix and "just don't build i= t". (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 "Python 3 DNS library") (license license:psfl))) I have: (define-public python-py3dns ... (arguments `(;; Tests would need /etc/resolv.conf. #:tests? #f #:phases (modify-phases %standard-phases (add-after 'unpack 'fix-setup-py (lambda _ ;; We cannot import DNS because it would need /etc/resolv.co= nf. (substitute* "setup.py" (("import DNS") "")) (substitute* "setup.py" (("DNS.__version__") ,(string-append "'" version "'"))) #t)) (add-after 'install 'install-license (lambda* (#:key outputs #:allow-other-keys) (let* ((out (assoc-ref outputs "out")) (doc-dir (string-append out "/share/doc/python-py3dns= "))) (mkdir-p doc-dir) (copy-file "LICENSE" (string-append doc-dir "/LICENSE")) #t)))))) (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 variant is the CNRI License Agreement for Python: (license license:psfl))) Yours is better except the description and possibly license. Lastly, I have put the HTTP and DNS packages in the python-web.scm module and the rest in python-xyz.scm, except mailman itself which I put in mail.scm. I do not know if that is right but I suppose you plan to do that too. Regards, Florian