MrMino / wheelfile

🔪🧀 API for creating and inspecting Python .whl files (wheels)
MIT License
29 stars 5 forks source link

Using this package to patch a wheel file #9

Closed mboisson closed 3 years ago

mboisson commented 3 years ago

Hi, We have a use case (https://github.com/ComputeCanada/software-stack/issues/80) to patch a wheel file to update the Version of a wheel to include a local version tag.

I could not figure out how to do this with your package. I need to: 1) read an existing wheel 2) update the metadata info to change the version 3) rewrite a new wheel under a new name

Any guidance on how to do that would be appreciated.

For now, we have https://github.com/ComputeCanada/wheels_builder/pull/29 but this does not handle the RECORD file

MrMino commented 3 years ago

Hi!

This is one of the features I would really like to implement, but it isn't yet there, at least not in any "supported" manner. Simply put, Python's zipfile, which handles PKZIP for wheelfile, doesn't really allow arbitrary modifications to an existing archive. From what I understand, one has to rebuild the archive in memory to do that.

I was going to add a mode='a' switch so that this is handled internally by WheelFile, and afterwards you'd be able to just wf.version = new_version, but it will take a lot head scratching to do it properly. I don't think I will be able to make it happen in any timeframe that could be helpful to your case.

What I can offer instead, is this snippet. It generates a new version of a wheel based on an already existing one. It might not be better than your current approach, but that is the best I can muster with current version.

I tested it on the latest Django wheel, and it seems to work properly, modulo the fact that wheel unpack will not work because of normalization issues (see #10) - WheelFile does it as described by the spec, but the rest of the ecosystem - not necessarily.

Please test it extensively before committing anything to your indexes :).

Also, before using this I would advise you to wait until next Monday. This weekend I'm going to make a release that fixes few bugs, including one nasty oversight of mine wrt. RECORD files spec. The wheels do work right now, but there is a minute chance that after a repacked, misformatted wheel may nuke site-packages on removal / update :grin:. See pypa/pip#10118 or #11.

I will update the gist accordingly afterwards.

Please beware that this implementation is in very early stage of development. There may be minute mistakes and oversights that can result in a wheel that, while installable, might not be 100% up to spec.

MrMino commented 3 years ago

@mboisson wheelfile==0.0.7 is out, I updated the gist accordingly.

I also decided that this usecase will become a separate WheelFile method, so if you're willing to wait ~a week, this snippet will become:

foo1 = WheelFile(...)
foo2 = WheelFile.clone(foo1, version=foo1.version + 'computecanada')

(Actual method signature TBD.)

mboisson commented 3 years ago

@mboisson wheelfile==0.0.7 is out, I updated the gist accordingly.

I also decided that this usecase will become a separate WheelFile method, so if you're willing to wait ~a week, this snippet will become:

foo1 = WheelFile(...)
foo2 = WheelFile.clone(foo1, version=foo1.version + 'computecanada')

(Actual method signature TBD.)

That would be nice! Thanks!

MrMino commented 3 years ago

@mboisson

Sorry this took longer than I said it would, it turned out that this would be a bit more hairy if implemented with the same API style as the rest of the library.

For your usecase, you can use it as follows:

with WheelFile(path_to_wheel) as wf:                                        
    WheelFile.from_wheelfile(wf, version=str(wf.version) + '+computecanada')

I tested it on django and it seems to work as intended.

A working version is now on master. It requires implementing one more check (it should raise ValueError when the new WheelFile would result in overwriting the old one), but for your usage it should suffice.

I released it as 0.0.8.dev0. Feel free to use it:

pip install wheelfile==0.0.8.dev0

Please test extensively before bulk changing files. All bug reports greatly appreciated.

MrMino commented 3 years ago

v0.0.8 released.

pip install wheelfile==0.0.8

See from_wheelfile docs.

mboisson commented 3 years ago

Hi @MrMino, I just tested. It seems to work very well!

Thank you!