Migrating a setup.py Script to a pyproject.toml configuration

Greetings,

I’m in the process of migrating the fenrir screenreader to use the newer pyproject.toml style of package configuration and have hit a bit of a snag.

In the base directory, we have folders the likes of conf, tools, docs, and so on. I was trying to figure out how to tell the build backend to put the things in conf into /etc when the user goes to install the package from their package manager, tools in /usr/share/fenrirscreenreader/tools, locale in /usr/share/locale and so on. So far, I’ve come up a bit empty; I’ve spent a few hours searching and so far the conclusion seems to be to have the packaging script install those by itself. Is this accurate or have I missed something? If not, where is the specification for mapping source paths to destinations? The package data in setuptools didn’t quite look like what I am after, or I didn’t see an example that fit the bill for what I’m trying to do. Thanks in advance for the guidance.

Note that setup.py is not deprecated[1], and I think this is a valid reason to keep it around.

You can migrate to using pyproject.toml file for your metadata and keep these install steps in the script.


  1. unfortunate URL, there ↩︎

I had done that, but when uv goes to build the wheel, the end result is something like this tree.

the Output of tree

pkg
└── fenrir-git
└── usr
├── bin
└── lib
├── python3.13
│ └── site-packages
│ ├── etc
│ │ └── fenrirscreenreader
│ │ ├── keyboard
│ │ └── punctuation
│ ├── fenrirscreenreader
│ │ ├── commands
│ │ │ ├── commands
│ │ │ │ └── pycache
│ │ │ ├── help
│ │ │ │ └── pycache
│ │ │ ├── onByteInput
│ │ │ │ └── pycache
│ │ │ ├── onCursorChange
│ │ │ │ ├── orig_sorting
│ │ │ │ │ └── pycache
│ │ │ │ ├── pycache
│ │ │ │ └── resort
│ │ │ │ └── pycache
│ │ │ ├── onHeartBeat
│ │ │ │ ├── deactive
│ │ │ │ │ └── pycache
│ │ │ │ └── pycache
│ │ │ ├── onKeyInput
│ │ │ │ └── pycache
│ │ │ ├── onPlugInputDevice
│ │ │ │ └── pycache
│ │ │ ├── onScreenChanged
│ │ │ │ └── pycache
│ │ │ ├── onScreenUpdate
│ │ │ │ ├── pycache
│ │ │ │ └── rework
│ │ │ │ └── pycache
│ │ │ ├── onSwitchApplicationProfile
│ │ │ │ ├── inactive
│ │ │ │ │ └── pycache
│ │ │ │ └── pycache
│ │ │ ├── pycache
│ │ │ ├── quickMenu
│ │ │ │ └── pycache
│ │ │ ├── sayAll
│ │ │ │ └── pycache
│ │ │ ├── vmenu-navigation
│ │ │ │ └── pycache
│ │ │ └── vmenu-profiles
│ │ │ ├── BYTE
│ │ │ │ └── pycache
│ │ │ ├── KEY
│ │ │ │ ├── mc
│ │ │ │ │ ├── file
│ │ │ │ │ │ └── pycache
│ │ │ │ │ ├── pycache
│ │ │ │ │ └── search
│ │ │ │ │ └── pycache
│ │ │ │ ├── mutt
│ │ │ │ │ ├── file
│ │ │ │ │ │ └── pycache
│ │ │ │ │ ├── pycache
│ │ │ │ │ └── search
│ │ │ │ │ └── pycache
│ │ │ │ ├── nano
│ │ │ │ │ ├── file
│ │ │ │ │ │ └── pycache
│ │ │ │ │ ├── Help
│ │ │ │ │ │ └── pycache
│ │ │ │ │ ├── pycache
│ │ │ │ │ └── search
│ │ │ │ │ └── pycache
│ │ │ │ ├── pycache
│ │ │ │ └── vim
│ │ │ │ ├── file
│ │ │ │ │ └── pycache
│ │ │ │ ├── pycache
│ │ │ │ └── search
│ │ │ │ └── pycache
│ │ │ └── pycache
│ │ ├── core
│ │ │ └── pycache
│ │ ├── inputDriver
│ │ │ └── pycache
│ │ ├── pycache
│ │ ├── remoteDriver
│ │ │ └── pycache
│ │ ├── screenDriver
│ │ │ └── pycache
│ │ ├── soundDriver
│ │ │ └── pycache
│ │ ├── speechDriver
│ │ │ └── pycache
│ │ └── utils
│ │ └── pycache
│ ├── fenrir_screenreader-2025.1.28.dist-info
│ ├── pycache
│ └── usr
│ └── share
│ ├── fenrirscreenreader
│ │ ├── scripts
│ │ └── tools
│ │ └── pycache
│ ├── locale
│ │ ├── de
│ │ │ └── LC_MESSAGES
│ │ ├── es
│ │ │ └── LC_MESSAGES
│ │ ├── pl
│ │ │ └── LC_MESSAGES
│ │ ├── pt
│ │ │ └── LC_MESSAGES
│ │ └── ru
│ │ └── LC_MESSAGES
│ ├── man
│ │ └── man1
│ └── sounds
│ └── fenrirscreenreader
│ ├── default
│ └── template
└── systemd
└── system

124 directories

Am I doing something wrong when doing the build step?

Current PKGBUILD

Maintainer: Storm Dragon storm_dragon@linux-a11y.org

Contributor: Chrys chrys@linux-a11y.org

_gitname=‘fenrir’
pkgname=“{_gitname}-git" pkgver=r3308.78797390 pkgrel=1 epoch=1 pkgdesc='A user space console screen reader written in python3' arch=('any') url="https://git.stormux.org/storm/fenrir" license=('LGPL') depends=('espeak-ng' 'python' 'python-pyudev' 'python-daemonize' 'python-evdev' 'python-dbus' 'python-pyte') optdepends=('brltty: For Braille support' 'gstreamer: for soundicons via gstreamer' 'socat: Control running Fenrir screenreader' 'sox: The default sound driver' 'python-pythondialog: For TUI configuration tool' 'python-pyttsx: TTS support' 'python-pyenchant: for spell check functionality' 'xclip: for copy to X session clipboard' 'speech-dispatcher: TTS support') makedepends=('git' 'python-setuptools' 'uv') provides=('fenrir') conflicts=('fenrir') backup=('etc/fenrirscreenreader/settings/settings.conf') source=("git+https://git.stormux.org/storm/{_gitname}.git”
‘fenrirscreenreader.service’)
sha512sums=(‘SKIP’
‘e5e690bd9084d20a3c96ed391989e1db5211ef65b36a18ca6a49f8e16b40771a8a35151388df69d3cc64459d075ecb5fd0c415e11dfb43bc6ed2927612262168’)

prepare()
{
cd “srcdir/_gitname”
git checkout testing
}

pkgver()
{
cd “srcdir/_gitname”
printf “r%s.%s” “(git rev-list --count HEAD)" "(git rev-parse --short HEAD)”
}

build() {
cd “srcdir/_gitname”
uv build --wheel -no-isolation
}

package() {
install -d “$pkgdir/usr/lib/systemd/system/”
install -Dm644 fenrirscreenreader.service “$pkgdir/usr/lib/systemd/system/fenrirscreenreader.service”
cd “srcdir/_gitname”
python -m installer --destdir=“$pkgdir” dist/*.whl
}

vim: set ts=2 sw=2 et:

What package manager? Do you mean something like pip?

With tools like pip, and the PyPA ecosystem in general this is not possible. It used to be possible to do this (and maybe it kind of still is possible if you try hard enough), but it was a bad thing – for some relatively subjective definition of “bad” – and modern packaging tools do not allow it as far as I can remember.

One reason is that such a mechanism is not cross-platform (what is /etc on Windows?). Modern Python packaging ecosystem (at least PyPA) does not want to allow this behavior any longer and this behavior was never standardized into a specification.

What you want to achieve is very much dependent on the operating system, and as such should be handled by the packaging ecosystem of the operating system. For example on Debian, Ubuntu, and all their derivatives it should be handled by the apt package manager via .deb files (instead of pip and sdists or wheels files).

More concretely, what you were using was probably data_files in setup.py. As far as I can tell this data_files feature is deprecated in setuptools. I do not think any of the other modern Python packaging tools has any explicit support for this. It might still work somehow, though, but I doubt it.

That checks out with what I’ve been seing in the pacman output and the research I had done.