New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support building pure Python wheels #1021
Comments
But to build native wheels you need to spin up 3 different operating systems. For pure wheel, you need only one OS. short inspection of setup.py will inform if there is any compiled code. Or simply run a local build of the wheel and check the output file. Building a pure wheel from a non-pure python package is an error that happens (misconfiguration) and pointing a user that you produce pure wheel is part of error reporting. And If you got such an error you could simply switch to call of |
that's easy for one, hard for 100, impossible for a 1000. |
Add a new --pure-wheel command line option to also build pure Python wheel. If not selected, build will fail with a wheel that does not contain platform-specific code once built. Also add a new CIBW_PURE_WHEEL environment variable for this option. Reference: pypa#1021 Signed-off-by: Philippe Ombredanne <pombredanne@nexb.com>
I pushed a minimal implementation with a test. It works with a new --pure-wheel option and keeps on trucking rather than failing in this case. See #1022 |
Writle simple shell script which will call And if You have such script then you could even process 10 000 packages
To use such flag you need first determine if package is pure python. What is advantage of using cibuildwheel? |
@Czaki I appreciate the feedback and I know how to drive this alright ... See https://github.com/nexB/skeleton/tree/main/etc/scripts if you are interested
Not at all. cibuildwheel today ALWAYS build a wheel, pure or not. And then raise an Exception if the wheel was pure. At scale you cannot know if a wheel will be pure unless you build it first as a given build context could lead to build a plain wheel for some package that have optional native speedup extensions. Now, are suggesting something like:
What I want is something simpler: build it with cibuildwheel, and get the results out, pure or not. No need to guess. |
Add a new --pure-wheel command line option to also build pure Python wheel. If not selected, build will fail with a wheel that does not contain platform-specific code once built. Also add a new CIBW_PURE_WHEEL environment variable for this option. Reference: pypa#1021 Signed-off-by: Philippe Ombredanne <pombredanne@nexb.com>
But one of the common errors of packages that have optional native dependency is to build the pure wheel, instead of the native one. So there is a need to raise such an exception. So cibuildwheel cannot produce pure wheel by default, to not force package maintainers for inspecting the list of produced wheels on every release (which will consume much more time than setup). Additionally to build a pure wheel one need only one runner, not three. These are two arguments why building pure wheels need a different workflow than building a native one. So what is the argument for doing it using |
and this is not changed in the PR. The pure wheel is kept IFF it exists and the --pure-wheel option was created.
As I said, the stock cibuildwheel already build pure wheels across all the runners anyway. It just discards them and fail if they were created. My addition keeps them optionally.
Again, cibuildwheel already builds plain wheels. So your argument does not hold IMHO. |
As I said above, I want to avoid having too many moving parts and I having to guess if a wheel is pure or not. |
I don't fully understand the use-case for this yet. You'd like an automated way to build wheels for 100-1000 sdists? This kinda makes sense, except that, as @Czaki says:
So what would be the strategy here? Build on linux and if a platform wheel pops out, build on macos and windows as well? Or build on all three and arbitrarily pick one? Cards on the table: I am still slightly biased against adding this feature, simply because build exists, which is a simpler tool which already does this. I suppose that it doesn't test the wheels against multiple versions of python, so there is some rationale for cibuildwheel. But we have to balance these user needs against the priorities of clarity of direction of the project, and maintenance/support burden. I also note that this has been discussed before: #255, #862. |
I maintain Python tools like https://github.com/nexB/scancode-toolkit that depend on quite a wheel packages with a mix of pure and native code. I support linux windows and macos and provide self-contained installable archives that contain all the prebuilt binaries. This way the tool can be installed on Windows or macOS even if there are no build tools or toolchain on hand. If I would get all these prebuilt upstream on PyPI, I would not need many of this!
You are already buidling the plain wheels... rather I mean cibuildwheel already builds the plain wheels and then after than if it sees this is a plain/pure wheel it fails the whole build. I am for now just adding a simple option to not fail the build and still provide the pure wheel that was built. This will three time the wheel, so I will surely discard one and this could surely be streamlined... but I am not sure you can have a matrix job alert other in flight job not to build some wheel because it was a pure wheel that built in another matrix job ;) Which one of the three I would pick does not matter much as they should be binary identical (or rather likely will be when we get reproducible built wheels)... at least the content and the same is the same.
Testing is part of the appeal and also just taking advantage that the pure was built and will be always built in all cases. With all that said, if you do not want it that's OK: I will maintain my fork alright... but I think this is a disservice to cibuildwheels users to always fail on pure wheels and in earnest I would rather apply my energy to the greater good and helping furthering this tools than maintains my own more complicated loop. |
@zanecodes FYI since this is related to #862 |
So you ask fo option to remove cibuildwheel/cibuildwheel/linux.py Lines 196 to 208 in b52698d
|
I don't think this is reasonable or going to work for you. It's quite rare that a binary wheel will actually build without any dependencies. You have no idea of how to test an arbitrary wheel, so you might not even know if it wasn't going to work. If someone is very careful and has no binary dependencies, then the default absolutely-no-cibuildwheel-configuration might work; I'm pretty sure cibuildwheel is designed to be configured. You have to tell it how to test your package. You have to tell it how to prepare for binary builds. There have been thoughts about standardizing this (see #564), and cibuildwheel now has toml config that could be picked up, but again, anyone with this would also be providing wheels. For pure wheels, we provide
So you are building infrastructure to build a 1000 wheels at a time, but can't be bothered to put a tiny bit of logic in to save at least 3x and probably 12x of your time most of the time by using |
That's probably not what @joerick was referring to and that I was thinking about: cibuildwheel does a simple installation test of each built wheel in the OS/arch/Python context of the build to ensure this can install correctly. That's not in tox and nox job specs to do this IMHO, this is more a simple smoke test check at the tail end of teh build. |
@Czaki re:
this could work out too... great idea. |
No it does not. It does nothing at all by default. You can configure it to run your tests, and if you put in
Nox doesn't have specs. You can do a parametrized Python job and install from your wheel in it. It's about 3 lines. Tox probably can do it too, but I tend to avoid tox, at least until tox 4 is out. Parametrizing across OS's is done by your CI, not ?ox. Archs are a tiny bit harder, but you are likely paramatrizing across those too - and we added support for pipx in manylinux, so any manylinux arch can run I believe all the tools you need are available separately, and there's no need to try to force cibuildwheel to do something it's not designed to do. |
@henryiii re:
At least for the code I help maintain like pyahocorasick or intbitset, these are self contained, so would be bitarray, these being some of the native dependencies that come to mind. I reckon that building larger machinery is involved alright, but that's not my target.
I already have code for this alright: https://github.com/nexB/skeleton/blob/b1dabd894c469174b0fee950043f7d29fac6027f/etc/scripts/utils_thirdparty.py#L2829
That's not been my experience and in practice even if I may no know how to run the test suites of these third-party packages, I have extensive test suites in my packages that make this a lesser issue |
now, if you guys think this is not a feature for here, I am fine to close this, I will do it elsewhere, no hard feelings! |
I think we should assign a custom error code to pure-wheel "failures", then I think it would still solve your case (except maybe for smoke-check tests, but those are easy to run manually, say with nox). |
This is a good idea. Then you could fall back to PyPA-build when the wheel is pure. |
Technically, the wheel is already built - we are checking the wheel tags via the name, so you could just use that. (Though it should be pretty fast, regardless, so rebuilding wouldn't be expensive) |
We should make a table in the docs and have a few return codes, ideally. This one could come with a note that the built wheel will be available in the output folder if it is returned. |
Add a new --pure-wheel command line option to also build pure Python wheel. If not selected, build will fail with a wheel that does not contain platform-specific code once built. Also add a new CIBW_PURE_WHEEL environment variable for this option. Reference: pypa#1021 Signed-off-by: Philippe Ombredanne <pombredanne@nexb.com>
@henryiii FWIW, |
@henryiii I think I finally understood ... did you mean to have a specific numeric error code returned by the command line? |
Having a tidy up. Closing this as a non-goal of cibuildwheel. |
My personal experience: my module current lacks the support for Cpython 3.11. So for this Cpython version it produces a pure python wheel. Some of the projects that uses my module use Personally, I put |
But why people are building wheel on it's own instead using your wheel? |
You can specify in your [tool.cibuildwheel]
skip=["cp311-*", "pp*"] Then anyone will get this without setting environment variables. Though cibuildwheel is not replacement for nox/tox, or some other general tool for building and testing. It's a tool to make wheels for upload to PyPI. This should only be done once, not by "projects using modules"? Also, make sure you are uploading a pure Python wheel too; installers pick the specific one from PyPI first, but fall back on the pure one if one is not available (will help other platforms, too, no one should be building SDists in that case unless they ask for them). |
For the C extension, I don't really know X-D
Thank you, I'll try it.
Well, but so why
I used to do it, but people asked me to remove pure python wheels. This is because they use a not supported arch. So I preferred to remove the pure python package and let the sdist to generate the pure python package. |
PS: about this I opened an issue on pip: |
to validate if the wheels were build properly.
then maybe upload |
You can use |
I should also point out you have to opt-into the testing (with Having pip try to build the SDist and then fall back to a pure Python wheel sounds like a bad idea. I think it's better to provide a pure Python implementation and then users who really need the performance can use pip's build from source flag. The cost to try to build the SDist will be high and likely produce a lot of output. If you cover a large fraction of users with the binaries, they should mostly be happy. Some users want reproducible environments and don't want to be building SDists, which is not reproducible. The recent failed PEP on locking environments didn't even allow SDist builds, for example. |
I tested it and it works, but only if
I get this error and Gugol does not help me:
Not sure to had understood. Do you mean I have to add the tests by default? IMHO it should the user that have to decide to run the tests or not, since they are also a bit slow (they tests against segfaults and memory leaks too).
Well, PEP 665 was rejected because the lack of sdist support indeed :) |
I'm not sure if it is connected, but you need to provide the path to |
Ahh, sorry, pipx has a bug with wheel. It filters |
@henryiii Thank you, it worked:
But does it only rename the wheel? |
It changes the wheel metadata to reflect the new tags too. |
My reading of this thread is that there intended to be a specific exit code for |
As a follow up to #1007 I would like to also allow building a pure wheel.
Why? When I build arbitrary wheels, I cannot know ahead of time if a wheel will be pure Python or native. And if I build many wheels including sdist tarballs as in #597 (comment) there is no way I can know ahead of time if a built wheel will be pure python or not.
The text was updated successfully, but these errors were encountered: