Maybe define a “freethreading” extra? (although that would only handle cases of adding minimum version constraints - it can’t turn off any of the default dependency constraints)
Would it make sense to have a single threaded free-threaded classifier? For many projects that wrap a C-API, they will not be able to run in threads. Ideally they should take a lock while they are being accessed so Python can do other things if needed. Putting Programming Language :: Python :: Free Threading :: Resilient feels a bit odd for a package that runs only in one thread. Maybe there could be one more classifier, Programming Language :: Python :: Free Threading :: Single Thread, that indicates that a package does support the free-threaded build, but is a single threaded package.
The free-threaded build does not mean multithreaded, it is simply a different build of Python without the GIL. It’s perfectly valid to support the free-threaded build with a single threaded package.
I’d also say it’s valid to have a free-threaded wheel that takes the GIL. That still means you can use the package with free-threaded Python; if you don’t provide a wheel, you can’t use the package at all. Again, free-threaded doesn’t mean multithreaded; it’s just a different build. If your package is an IO package, for example, people still need to be able to get the IO in the free-threaded build; maybe they don’t care about multithreaded IO but want to do something else multithreaded later with the data. Etc. Though I’d say in this case you could probably just not provide the classifier and just provide the wheels, or use the Unstable classifier - long term, a lock for just your package is better than holding the “GIL”.
not really sure about this, I don’t think I follow your reasoning.
you mean the classifier would be used by packages that are single-threaded in the sense that they don’t allow concurrency at all?
would that include packages that can be used concurrently by multiple threads but need to have mutual exclusion among the threads (e.g. via some internal locking)?
if this is the case, I don’t think “single-threaded” is the right wording.
if that was a package of mine, I’d pick “resilient” instead.
there’s no reason to expect full parallelization, in general.
I think the classifiers are more interesting in terms of stability against the free-threaded build, rather than performance.
you mean the classifier would be used by packages that are single-threaded in the sense that they don’t allow concurrency at all?
Yes, there are a lot of packages that wrap C APIs, and those might not ever support multithreading, but these packages should still provide free-threaded builds, because otherwise you can’t use them at all from a free-threaded Python build. I’m thinking such a package would balk at adding a Free Threading :: ... classifier to show they support Free Threading, when in fact they only support a single thread in Free Threading builds. Having a dedicated classifier to indicate that they support the Free Threaded Python but can’t run in parallel might help some packages adopt the classifiers. Such a package doesn’t really need levels of support (once the locking is in place, it’s just regular single threaded code). And users can still do other things in other threads, so it’s still useful, too.
This could also be called Programming Language :: Python :: Free Threading :: Thread-safe, perhaps.
My worry is that an additional classifier may create more confusion than clarity, and I would stick with the numbered ones in your list above.
As an anecdotal reference: I’ve been working on porting python-zstandard to free-threading recently.
The package wraps zstd C-APIs and it has limitations on what multithreaded usage is allowed: API Usage — python-zstandard 0.22.0-pre documentation.
Essentially, if you use the same de/compressor context object from multiple threads you get a segfault, and this was also the case with the GIL in place.
We opted for not fixing the segmentation fault, but that doesn’t undermine the package stability when using it as documented in either build.
In fact, it is quite stable.
EDIT: I should add that it is also possible to use internal thread-based parallelization.
My point here is that while stability against free-threading builds can be broadly understood, the meaning of single-threaded-ness and thread-safety can be cumbersome to classify.
Thank you again for your PR, I think it should move forward
I think more likely is that a package wrapping a C API does support freethreading but there maybe be conditions on how to use the API safely. In other words “supports multithreading” does not necessarily mean “idiot-proof, won’t crash” but rather “use as documented”.