Python packaging

Cleanups

  • PEP517 MR's https://gitlab.archlinux.org/groups/archlinux/packaging/packages/-/merge_requests?scope=all&state=opened&search=PEP+517
  • drop python-pytest-runner
  • drop python-exceptiongroup => https://archlinux.org/todo/drop-python-exceptiongroup/
  • drop more felix unmaintained packages
  • drop python-nose
  • drop python-pytest7
  • drop python-six
  • drop python-future
  • drop using python-pytest-cov in our tests
  • drop python-importlib-metdata
  • drop python-importlib_resources
  • fix packages with checkdepends without running check()
  • build with PEP517
  • update felix maintained packages like urllib3
  • update packaging guidelines and remove nose
  • backport package python-typing_extensions
  • backport package python-unicodedata2 => https://fonttools.readthedocs.io/en/latest/optional.html#fonttools-unicode
  • python3.13 logger.warn: rg -uuu -A 1 -B 1 "logging.warn\(" -g '*.py'
  • python3.13 deprecations
    • logger.warn
    • mailcap
    • nnlt

remove python-py

  • python-nox - dropped https://github.com/wntrblm/nox/commit/cdd0f3bdbd83f4d2e426b096750e281998ac4900
  • python-pytest-aiohttp - does not depend on it?
  • python-pytest-xprocess https://github.com/pytest-dev/pytest-xprocess/commit/1847ca771201229b3607dcbdf9f29c6becc50d83
  • python-openpyxl
  • python-execnet
  • python-pytest-forked https://github.com/pytest-dev/pytest-forked/blob/master/setup.py#L22 - create bug report https://github.com/pytest-dev/pytest-forked/issues/88
  • python-kubernetes

nose

Needs bug reports

  • python-pyqrcode
  • vigra
  • python-mohawk
  • python-sure
  • python-django-haystack
  • shadowsocks

cython0

  • python-jq
  • urh
  • brltty
  • python-grpcio-tools
  • python-pyliblo
  • vidcutter
  • python-kivy
  • python-asyncpg
  • php-grpc
  • python-basemap-common
  • python-h5py-openmpi
  • python-basemap
  • python-bintrees
  • python-h5py
  • grpc
  • cbindgen
  • opendht
  • python-pandas
  • python-uvloop
  • brltty-udev-generic
  • python-yaml
  • rdma-core
  • python-pyscipopt
  • python-pystemmer
  • python-statsmodels
  • python-grpcio
  • grpc-cli
  • python-pyarrow
  • php-legacy-grpc
  • python-hidapi
  • python-pycapnp

Drop nosetest

Convert packages to use either pytest or python -m unittest

Drop pytest-coverage as checkdepends

Either use -o addopts='' when possible or sed it out.

3.13 compat check

Read https://docs.python.org/3.13/whatsnew/3.13.html

Major release

Arch's Python modules store the version number in the module path meaning they won't be picked up by a new Python release for example 3.11 => 3.12.

  • bump Python and rebuild it in a separate branch
  • bootstrap
  • find incompatible packages upfront?

Package: python-bootstrap-evil

Rebuild order

The python package repo has a script called genrebuild this should include all packages required for the rebuild:

Figuring out the order: (TODO: exclude bootstraped build packages)

./genrebuild > rebuild-list.txt
cat rebuild-list.txt | xargs expac -Sv %n | sort | uniq > final.txt

For some reason our files.db include old packages which are no longer in the repos, arch-rebuild-order hard fails on missing packages so we clean those out with an ugly expac hack.

We can use arch-rebuild-order, it does not handle cyclic depenendencies but should be good enough (tm):

arch-rebuild-order --no-reverse-depends $(cat ./final.txt)

Python bootstrapping

Custom repository:

https://pkgbuild.com/~jelle/python3.11

cp /usr/share/devtools/pacman-staging.conf /usr/share/devtools/pacman-python.conf

Edit the config file and add above [staging]

[python]
SigLevel = Optional
Server = https://pkgbuild.com/~jelle/python3.11
sudo ln -s /usr/bin/archbuild /usr/bin/python-x86_64-build
repo-add python.db.tar.gz *.pkg.tar.zst
sudo python-x86_64-build --  -- --nocheck

Bootstrappping

  1. First build python-bootstrap (from svn-packages) with Python 3.X
  2. Yeet the packages into a pacman repository
  3. Build flit-core with bootstrapped build and installer
  4. Build python-installer comment out the sphinx build and repo-add it
  5. Build python-packaging (requires build,installer,flit-core). HACK: PYTHONPATH=src python -m build -nw required by python-build!
  6. Build python-build comment out the sphinx build and repo-add it
  7. Build python-pyproject-hooks and repo-add it
  8. build python-jaraco.text (requirement for bootstrap build of setuptools)
  9. build python-setuptools => bootstrap python-jaraco.text and tons more...
  10. Or build python-setuptools with export PYTHONPATH=/usr/lib/python3.10/site-packages/
  11. Wheel needs jaraco.functools and shit..

3.13

logging.warn

  • afew - pr made
  • pyzo -pr made
  • gnome-tweak-tool - pr made
  • python-fiona - PR made
  • python-fido2 - PR made
  • glusterfs - PR made
  • fusesoc - PR made
  • python-edalize - PR made
  • klipper - PR made
  • nss-pam-ldapd - PR made
  • libvirt-python - MR made
  • python-setuptools-gettext - PR made
  • python-pipx => fixed upstream
  • shadowsocks => needs felix patching
  • offlineimap
  • pmbootstrap
  • python-gflags
  • sugar
  • sugar-toolkit-gtk3
  • subversion
  • bullet
  • tensorboard
  • csound
  • python-py => dead package but needed for pytest-forked
  • dart
  • pycharm-community-edition
  • tensorflow
  • python-tensorflow-estimator

Crypt module deprecated

  • cloud-init
  • python-pytest-testinfra
  • python-pyftpdlib
  • sqlmap
  • salt
  • python-twisted
  • samba

mailcap module deprecated

  • alot
  • visidata

cgi module removal

  • electrum
  • gpsd
  • python-boto
  • python-distlib
  • python-eventlet
  • python-lxml
  • python-mako
  • python-treq => fixed in git
  • python-webob
  • python-zeep
  • rhythmbox
  • python-repoze.profile
  • python-setuptools
  • python-softlayer-zeep
  • python-pytorch
  • salt
  • root
  • python-twisted
  • python-webtest
  • python-whoosh
  • python-pygame-sdl2
  • python-wslib
  • python-oauth2client
  • python-flup
  • mysql-workbench
  • python-wheezy-template
  • python-oscrypto
  • python-pyro
  • python-paste
  • python-openid
  • python-owslib
  • python-mimeparse
  • python-iminuit
  • python-formencode
  • python-genshi
  • python-falcon
  • python-asn1crypto
  • matrix-synapse
  • python-requests-ftp
  • python-htmlin
  • python-formencode
  • hotdoc
  • xonsh
  • boost
  • deluge
  • buildbot
  • python-cherrypy
  • pymol
electrum/src/Electrum-4.5.4/packages/pip/_vendor/distlib/compat.py
474:    from cgi import escape

bluefish/src/bluefish-2.2.15/data/bflib/bflib_python_2.3.xml
22797:Begin by writing import cgi. Do not use from cgi import

ninja/src/ninja-1.12.0/src/browse.py
38:    from cgi import escape

nuitka/src/Nuitka-2.1.5/nuitka/build/inline_copy/tqdm/tqdm/notebook.py
69:        from cgi import escape

python-boltons/src/boltons/boltons/tableutils.py
58:    from cgi import escape as html_escape
67:    from cgi import escape as html_escape

pycharm-community-edition/src/intellij-community/python/helpers/virtualenv-20.24.5.pyz: binary file matches (found "\0" byte around offset 5)

pycharm-community-edition/src/intellij-community/python/helpers/virtualenv-20.13.0.pyz: binary file matches (found "\0" byte around offset 5)

pycharm-community-edition/src/intellij-community/python/helpers/typeshed/stubs/WebOb/webob/request.pyi
13:from cgi import FieldStorage

pycharm-community-edition/src/intellij-community/python/helpers/typeshed/stubs/WebOb/webob/multidict.pyi
3:from cgi import FieldStorage

python-cherrypy/src/cherrypy-18.9.0/cherrypy/lib/httputil.py
15:from cgi import parse_header

python-boto/src/boto-2.49.0.20190327/boto/ecs/item.py
28:    from cgi import escape as html_escape

python-cheetah3/src/python-cheetah3/Cheetah/Tests/Regressions.py
2:    from cgi import escape as html_escape

python-boto/boto-python-3.8.patch
14:+    from cgi import escape as html_escape

python-distlib/src/python-distlib/distlib/compat.py
480:    from cgi import escape

python-future/src/future-1.0.0/docs/compatible_idioms.rst
1246:    from cgi import escape

python-future/src/future-1.0.0/docs/notebooks/Writing Python 2-3 compatible code.ipynb
2767:    "from cgi import escape\n",

python-future/src/future-1.0.0/docs/build/html/_sources/compatible_idioms.rst.txt
1246:    from cgi import escape

python-genshi/src/genshi-0.7.7/examples/bench/basic.py
8:from cgi import escape

python-gevent/src/gevent-24.2.1/examples/webproxy.py
20:    from cgi import escape

python-htmlmin/src/htmlmin-220b1d16442eb4b6fafed338ee3b61f698a01e63/htmlmin/escape.py
33:  from cgi import escape

python-lxml/src/lxml-lxml-5.1.0/src/lxml/html/diff.py
14:    from cgi import escape as html_escape

python-lxml/src/lxml-lxml-5.1.0/src/lxml/doctestcompare.py
45:    from cgi import escape as html_escape

python-lxml/src/lxml-5.1.0/src/lxml/html/diff.py
14:    from cgi import escape as html_escape

python-lxml/src/lxml-5.1.0/src/lxml/doctestcompare.py
45:    from cgi import escape as html_escape

python-markdown2/src/python-markdown2-2.4.12/perf/recipes.pprint
97:               {'comment': u'I am completely new to python,\n\nI want to test if python is working on my hosting account. I am told it is!\n\nI have copied the text at the bottom of my post, i have then pasted it to notepad, saved it as ptest.cgi and secondly ptest.txt\n\nuploaded it to my cgi-bin, inside a folder called python, chomod 755\nthen go to my page:  http://yourfeet.co.uk/cgi-bin/python/ptest.cgi\n\nor http://yourfeet.co.uk/cgi-bin/python/ptest.txt\n\n\nboth give errors in log as :  Premature end of script headers\n\nWhat am i missing out please\n.\n.\n.\n\n\n\n\n#!/usr/local/bin/python\nprint "Content-type: text/html"\nprint\nprint "<pre>"\nimport os, sys\nfrom cgi import escape\nprint "Python %s" % sys.version\nkeys = os.environ.keys()\nkeys.sort()\nfor k in keys:\n    print "%s\\t%s" % (escape(k), escape(os.environ[k]))\nprint "</pre>" ',

python-nltk/src/nltk-3.8.1/nltk/tree/prettyprinter.py
25:    from cgi import escape

python-numpy/src/numpy-1.26.4/tools/npy_tempita/__init__.py
44:    from cgi import escape as html_escape

python-pipenv/src/pipenv-2023.12.1/pipenv/patched/pip/_vendor/distlib/compat.py
474:    from cgi import escape

python-odfpy/src/odfpy-release-1.4.2/contrib/odf2epub/odf2epub
25:from cgi import escape

python-pip/src/pip-24.0/src/pip/_vendor/distlib/compat.py
480:    from cgi import escape

python-odfpy/src/odfpy-release-1.4.2/contrib/html2odt/shtml2odt.py
25:from cgi import escape,parse_header

python-odfpy/src/odfpy-release-1.4.2/contrib/html2odt/html2odt.py
25:from cgi import escape,parse_header

python-pystache/src/pystache-0.6.5/pystache/defaults.py
15:    from cgi import escape

python-repoze.profile/src/repoze.profile-2.3/repoze/profile/compat.py
41:        from cgi import parse_qs

python-sentry_sdk/src/sentry-python-1.45.0/sentry_sdk/utils.py
27:    from cgi import parse_qs  # type: ignore

supervisor/src/supervisor-4.2.5/supervisor/compat.py
141:    from cgi import escape

python-testrepository/src/testrepository-0.0.21/lib/python3.11/site-packages/pip/_vendor/distlib/compat.py
480:    from cgi import escape

python-wheezy-template/src/wheezy.template-3.2.2/demos/bigtable/bigtable.py
432:#from cgi import escape
[jelle@natrium][/mnt/arch/python-packaging]%rg -uuu "unittest.findTestCases"   -g '*.py' .
./cython0/src/cython-0.29.37.1/runtests.py
1535:                    suite.addTest(unittest.findTestCases(sys.modules[cls]))

./cython/src/cython/runtests.py
1809:                    suite.addTest(unittest.findTestCases(sys.modules[cls]))

./cython/src/cython-3.0.10/runtests.py
1809:                    suite.addTest(unittest.findTestCases(sys.modules[cls]))

./python/src/Python-3.12.3/Lib/unittest/loader.py
490:        "unittest.findTestCases() is deprecated and will be removed in Python 3.13. "

./python/src/Python-3.12.3/Lib/test/test_unittest/test_loader.py
1526:            suite = unittest.findTestCases(m,

./python/src/Python-3.12.2/Lib/unittest/loader.py
490:        "unittest.findTestCases() is deprecated and will be removed in Python 3.13. "

./python/src/Python-3.12.2/Lib/test/test_unittest/test_loader.py
1526:            suite = unittest.findTestCases(m,

./supervisor/src/supervisor-4.2.5/supervisor/tests/test_web.py
182:    return unittest.findTestCases(sys.modules[__name__])

./supervisor/src/supervisor-4.2.5/supervisor/tests/test_templating.py
1790:    return unittest.findTestCases(sys.modules[__name__])

./supervisor/src/supervisor-4.2.5/supervisor/tests/test_supervisord.py
839:    return unittest.findTestCases(sys.modules[__name__])

./supervisor/src/supervisor-4.2.5/supervisor/tests/test_supervisorctl.py
2072:    return unittest.findTestCases(sys.modules[__name__])

./supervisor/src/supervisor-4.2.5/supervisor/tests/test_states.py
56:    return unittest.findTestCases(sys.modules[__name__])

./supervisor/src/supervisor-4.2.5/supervisor/tests/test_socket_manager.py
253:    return unittest.findTestCases(sys.modules[__name__])

./supervisor/src/supervisor-4.2.5/supervisor/tests/test_rpcinterfaces.py
2401:    return unittest.findTestCases(sys.modules[__name__])

./supervisor/src/supervisor-4.2.5/supervisor/tests/test_poller.py
443:    return unittest.findTestCases(sys.modules[__name__])

./supervisor/src/supervisor-4.2.5/supervisor/tests/test_options.py
3809:    return unittest.findTestCases(sys.modules[__name__])

./supervisor/src/supervisor-4.2.5/supervisor/tests/test_loggers.py
604:    return unittest.findTestCases(sys.modules[__name__])

./supervisor/src/supervisor-4.2.5/supervisor/tests/test_http.py
689:    return unittest.findTestCases(sys.modules[__name__])

./supervisor/src/supervisor-4.2.5/supervisor/tests/test_events.py
513:    return unittest.findTestCases(sys.modules[__name__])

./supervisor/src/supervisor-4.2.5/supervisor/tests/test_end_to_end.py
424:    return unittest.findTestCases(sys.modules[__name__])

./supervisor/src/supervisor-4.2.5/supervisor/tests/test_dispatchers.py
1232:    return unittest.findTestCases(sys.modules[__name__])

./supervisor/src/supervisor-4.2.5/supervisor/tests/test_confecho.py
18:    return unittest.findTestCases(sys.modules[__name__])

./supervisor/src/supervisor-4.2.5/supervisor/tests/test_childutils.py
138:    return unittest.findTestCases(sys.modules[__name__])

./python-pylint/src/pylint-3.1.0/pylint/checkers/stdlib.py
262:            "unittest.findTestCases",

./python-pyscard/src/pyscard-2.0.8/smartcard/test/scard/testsuite_scard.py
47:        testsuite_scard.addTest(unittest.findTestCases(module))

./python-pyscard/src/pyscard-2.0.8/smartcard/test/frameworkpcsc/testsuite_frameworkpcsc.py
40:        testsuite_framework.addTest(unittest.findTestCases(module))

./python-pyscard/src/pyscard-2.0.8/smartcard/test/framework/testsuite_framework.py
55:        testsuite_framework.addTest(unittest.findTestCases(module))

./python-pyserial/src/pyserial-3.5/test/run_all_tests.py
40:        testsuite = unittest.findTestCases(module)

./python-pyscard/src/pyscard-2.0.8/smartcard/test/framework/testcase_CardConnection.py
246:    suite1 = unittest.makeSuite(testcase_CardConnection)

./python-pyscard/src/pyscard-2.0.8/smartcard/test/framework/testcase_Card.py
119:    suite1 = unittest.makeSuite(testcase_CardConnection)

./python-pyscard/src/pyscard-2.0.8/smartcard/test/framework/testcase_CAtr.py
119:    suite1 = unittest.makeSuite(testcase_CAtr)

./python-pyscard/src/pyscard-2.0.8/smartcard/test/framework/testcase_ATR.py
67:    suite1 = unittest.makeSuite(testcase_ATR)

./python-wstools/src/wstools/tests/test_wsdl.py
38:        suite.addTest(unittest.makeSuite(WSDLToolsTestCase, 'test_'))
  • yt-dlp
  • mitmproxy
  • ocrfeeder
  • polymake
  • python-future
  • python-kivy
  • python-mediafile
  • python-pgpy
  • python-tweepy
  • ranger
[jelle@natrium][/mnt/arch/python-packaging]%rg -uuu "import imghdr"   -g '*.py' .
./ocrfeeder/src/ocrfeeder/src/ocrfeeder/util/graphics.py
25:import imghdr

./polymake/src/polymake-4.11/resources/jupyter-polymake/jupyter_kernel_polymake/kernel.py
8:import imghdr

./python-future/src/future-1.0.0/src/future/backports/email/mime/image.py
12:import imghdr

./python-kivy/src/Kivy-2.2.1/kivy/core/image/__init__.py
65:import imghdr

./python-mediafile/src/mediafile/mediafile.py
52:import imghdr

./python-pgpy/src/python-pgpy/pgpy/constants.py
5:import imghdr

./python-tweepy/src/tweepy-4.14.0/tweepy/api.py
7:import imghdr
  • bandit
  • mercurial
  • pychess
  • python-boto
  • libsvm
  • python-curio
  • python-pyocd
  • routersploit
[jelle@natrium][/mnt/arch/python-packaging]%rg -uuu "import telnetlib"   -g '*.py' .
./bandit/src/bandit-1.7.7/tests/functional/test_functional.py
240:        """Test for `import telnetlib` and Telnet.* calls."""

./bandit/src/bandit-1.7.7/examples/telnetlib.py
1:import telnetlib

./jython/src/Lib/test/test_telnetlib.py
2:import telnetlib

./libsvm/src/libsvm-332/tools/grid.py
317:        import telnetlib

./mercurial/src/mercurial-6.7.2/tests/test-demandimport.py
165:import telnetlib
194:    import telnetlib

./peda/src/peda-1.2/lib/skeleton.py
180:import telnetlib

./pychess/src/pychess-1.0.5/lib/pychess/ic/TimeSeal.py
3:import telnetlib

./pychess/src/pychess-1.0.4/lib/pychess/ic/TimeSeal.py
3:import telnetlib

./python-boto/src/boto-9e1cd3bd76e738d80630f1bd9160fd87c8eab865/tests/integration/ec2/test_connection.py
30:import telnetlib

./python-boto/src/boto-2.49.0.20190327/tests/integration/ec2/test_connection.py
30:import telnetlib

./python-curio/src/curio/curio/monitor.py
58:import telnetlib

./routersploit/src/routersploit-3.4.2/routersploit/core/telnet/telnet_client.py
1:import telnetlib

./routersploit/src/routersploit-3.4.2/routersploit/core/exploit/shell.py
2:import telnetlib

./python-pudb/src/pudb-2022.1.3/pudb/remote.py
142:            import telnetlib as tn

./python-pylint/src/pylint-3.1.0/tests/functional/a/access/access_attr_before_def_false_positive.py
9:import telnetlib

./python-pyocd/src/pyOCD-0.36.0/test/unit/test_semihosting.py
23:# import telnetlib

pipes

./canto-curses/src/canto-curses-0.9.9/canto_curses/command.py
17:import pipes

./hamster-time-tracker/src/hamster-3.0.3/waflib/Utils.py
587:    import pipes

./hamster-time-tracker/src/hamster-3.0.3/waflib/extras/genpybind.py
2:import pipes

./dnf/src/dnf-4.19.0/dnf/pycomp.py
84:    import pipes

./displaycal/src/DisplayCAL-3.9.12/DisplayCAL/worker_base.py
8:import pipes

./displaycal/src/DisplayCAL-3.9.12/DisplayCAL/worker.py
15:import pipes

./buildbot/src/buildbot/worker/buildbot_worker/runprocess.py
91:    import pipes  # pylint: disable=import-outside-toplevel

./clang/src/clang-17.0.6.src/utils/creduce-clang-crash.py
18:import pipes

./jupyter-nbclassic/src/nbclassic-1.0.0/setupbase.py
15:import pipes

./ldb/src/ldb-2.9.0/third_party/waf/waflib/Utils.py
587:    import pipes

./ldb/src/ldb-2.9.0/third_party/waf/waflib/extras/genpybind.py
2:import pipes

./kupfer/src/kupfer-326/waflib/Utils.py
587:    import pipes

./kupfer/src/kupfer-325/waflib/Utils.py
587:    import pipes

./kicad/src/kicad/thirdparty/sentry-native/external/crashpad/build/run_tests.py
19:import pipes

./waf/src/waf-2.0.27/waflib/Utils.py
587:    import pipes

./waf/src/waf-2.0.27/waflib/extras/genpybind.py
2:import pipes

./jython/src/Lib/test/test_pipes.py
1:import pipes

./virt-manager/src/virt-manager-4.1.0/virtManager/object/domain.py
1309:        import pipes

./tevent/src/tevent-0.16.1/third_party/waf/waflib/Utils.py
587:    import pipes

./tevent/src/tevent-0.16.1/third_party/waf/waflib/extras/genpybind.py
2:import pipes

./mysql-workbench/src/mysql-workbench-community-8.0.36-src/plugins/wb.admin/backend/wb_server_management.py
30:import pipes

./mercurial/src/mercurial-6.7.2/tests/test-verify-repo-operations.py
39:import pipes

./tensorboard/src/embedded_tools/tools/objc/j2objc_dead_code_pruner.py
32:import pipes  # swap to shlex once on Python 3

./tensorboard/src/tensorboard-2.15.1/tensorboard/manager_e2e_test.py
23:import pipes

./meld/src/meld/meld/melddoc.py
20:import pipes

./tensorboard/src/tensorboard-2.15.1/tensorboard/tools/diagnose_tensorboard.py
32:import pipes

./tdb/src/tdb-1.4.10/third_party/waf/waflib/Utils.py
587:    import pipes

./tdb/src/tdb-1.4.10/third_party/waf/waflib/extras/genpybind.py
2:import pipes

./talloc/src/talloc-2.4.2/third_party/waf/waflib/Utils.py
587:    import pipes

./talloc/src/talloc-2.4.2/third_party/waf/waflib/extras/genpybind.py
2:import pipes

./samba/src/samba-4.20.0/third_party/waf/waflib/Utils.py
587:    import pipes

./samba/src/samba-4.20.0/third_party/waf/waflib/extras/genpybind.py
2:import pipes

./python-dbus-deviation/src/dbus-deviation-0.6.1/dbusdeviation/utilities/vcs_helper.py
37:import pipes

./python-fire/src/fire-0.6.0/fire/trace.py
32:import pipes

./python-fire/src/fire-0.6.0/fire/core.py
59:import pipes

./python-humanfriendly/src/python-humanfriendly-10.0/humanfriendly/testing.py
28:import pipes

./python-humanfriendly/src/python-humanfriendly-10.0/humanfriendly/cli.py
82:import pipes

./python-iminuit/src/python-iminuit-root/interpreter/llvm-project/clang/utils/creduce-clang-crash.py
17:import pipes

./sagemath/src/sage-10.3/build/sage_bootstrap/flock.py
15:import pipes

./python-iminuit/src/python-iminuit/extern/root/interpreter/llvm-project/clang/utils/creduce-clang-crash.py
17:import pipes

./root/src/root-6.30.04/interpreter/llvm-project/clang/utils/creduce-clang-crash.py
17:import pipes

./python-nodeenv/src/nodeenv-1.8.0/nodeenv.py
26:import pipes

./python-nodeenv/src/nodeenv-1.8.0/tests/nodeenv_test.py
5:import pipes

./reprotest/src/reprotest/reprotest/lib/adt_testbed.py
27:import pipes

./reprotest/src/reprotest/reprotest/lib/VirtSubproc.py
34:import pipes

./python-tensorboard_plugin_wit/src/embedded_tools/tools/objc/j2objc_dead_code_pruner.py
32:import pipes  # swap to shlex once on Python 3

cgitb

[jelle@natrium][/mnt/arch/python-packaging]%rg -uuu "import cgitb"   -g '*.py' .
./krita/src/krita-5.2.2/plugins/extensions/pykrita/plugin/krita/excepthook.py
14:import cgitb

./kajongg/src/kajongg-24.02.2/src/mainwindow.py
16:import cgitb

./playitslowly/src/playitslowly-1.5.1/playitslowly/myGtk.py
380:        import cgitb

./python/src/Python-3.12.3/Lib/cgitb.py
5:    import cgitb; cgitb.enable()

./python/src/Python-3.12.3/Lib/test/test_cgitb.py
44:                  ('import cgitb; cgitb.enable(logdir=%s); '
60:                  ('import cgitb; cgitb.enable(format="text", logdir=%s); '

./python/src/Python-3.12.2/Lib/cgitb.py
5:    import cgitb; cgitb.enable()

./python/src/Python-3.12.2/Lib/test/test_cgitb.py
44:                  ('import cgitb; cgitb.enable(logdir=%s); '
60:                  ('import cgitb; cgitb.enable(format="text", logdir=%s); '

./virtualbox/src/VirtualBox-7.0.16/src/VBox/ValidationKit/testmanager/webui/wuibase.py
951:        import cgitb;

./virtualbox/src/VirtualBox-7.0.16/src/VBox/ValidationKit/testmanager/webui/wuiadmin.py
43:import cgitb;

./virtualbox/src/VirtualBox-7.0.16/src/VBox/ValidationKit/testmanager/core/webservergluecgi.py
43:import cgitb;

./virtualbox/src/VirtualBox-7.0.16/src/VBox/ValidationKit/testmanager/core/webservergluebase.py
43:import cgitb

./python-flup/src/flup-1.0.3/flup/server/ajp_base.py
978:            import cgitb

./python-flup/src/flup-1.0.3/flup/server/scgi_base.py
570:            import cgitb

./python-flup/src/flup-1.0.3/flup/server/fcgi_base.py
1235:            import cgitb

./python-openid/src/python3-openid-3.2.0/examples/server.py
12:import cgitb

./python-openid/src/python3-openid-3.2.0/examples/consumer.py
14:import cgitb

./python-paste/src/Paste-3.5.3/paste/cgitb_catcher.py
12:import cgitb

./python-pygame-sdl2/src/pygame_sdl2/test/util/build_page/libs/pywebsite/__init__.py
7:import cgitb

./python-pygame-sdl2/src/pygame_sdl2/test/util/build_page/libs/build_client/update.py
9:import cgitb

./scribus/src/scribus-1.6.1/scribus/plugins/scripter/python/excepthook.py
10:import cgitb

ossaudiodev

10:import cgitb
[jelle@natrium][/mnt/arch/python-packaging]%rg -uuu "import ossaudiodev"   -g '*.py' .
./pysolfc/src/PySolFC-2.21.0/pysollib/pysolaudio.py
380:        # import ossaudiodev
404:        import ossaudiodev
415:        import ossaudiodev
435:        import ossaudiodev
463:        import ossaudiodev

./python-nltk/src/nltk-3.8.1/nltk/corpus/reader/timit.py
436:            import ossaudiodev
if sys.version_info >= (3, 10):
	import importlib.metadata as importlib_metadata
else
	import importlib_metadata

Parsing metadata

Parsing METADATA from Python package

import sys

from packaging.metadata import parse_email, Metadata

raw, unparsed = parse_email(metadata)
parsed = Metadata.from_raw(raw)

pyversion = f"{sys.version_info.major}.{sys.version_info.minor}"
environment = {'python_version': pyversion}
deps = []
for dep in parsed.requires_dist:
    if dep.marker is None:
         deps.append(dep.name)
	 continue
    if 'python_version' in str(dep.marker) and dep.marker.evaluate(environment)
         deps.append(dep.name)
    # do something with extra, by filling in the "extra" env

But we also need to detect:

https://github.com/abravalheri/validate-pyproject/blob/5ea862ffb5a31f4611813f223a1f1c0977661196/src/validate_pyproject/remote.py#L14