Skip to content

Use get_ext_fullpath instead of get_outputs in ffiplatform._build - #273

Open
afonsojanu wants to merge 2 commits into
python-cffi:mainfrom
afonsojanu:fix/ffiplatform-multiple-build-ext-outputs
Open

Use get_ext_fullpath instead of get_outputs in ffiplatform._build#273
afonsojanu wants to merge 2 commits into
python-cffi:mainfrom
afonsojanu:fix/ffiplatform-multiple-build-ext-outputs

Conversation

@afonsojanu

Copy link
Copy Markdown

Closes #246. Related to #229, which hit the same underlying crash.

_build() compiles a single extension and then unpacks its output with [soname] = cmd_obj.get_outputs(). That works as long as build_ext reports exactly one output, but get_outputs() reflects everything the command built, not just the extension we asked for. #246 shows a project with another native extension already registered ending up with two entries there, so the unpacking raises a bare ValueError: too many values to unpack instead of anything actionable. #229 is a beginner hitting the identical crash with no clue what went wrong, which is basically the same request: give a real answer instead of an opaque unpack failure.

build_ext.get_ext_fullpath(name) is the standard way to ask for the output path of one specific extension, so swapping to that sidesteps the whole problem: we get back exactly the file for the extension we passed in, regardless of what else get_outputs() would have reported.

Added a regression test in testing/cffi0/test_platform.py that monkeypatches build_ext.get_outputs to return an extra, nonexistent path (simulating the multi-extension situation from #246) and checks that ffi.verify() still compiles and loads correctly. Confirmed it reproduces the exact reported ValueError: too many values to unpack (expected 1) against the unpatched _build(), and passes with the fix. Ran the full testing/cffi0/test_platform.py, test_zdistutils.py, test_verify.py and test_verify2.py suites locally, all green.

get_outputs() returns every output the build_ext command produced, not
just the one we asked it to build. When the Distribution/build_ext
state ends up carrying more than one extension (as reported in python-cffi#246,
where the caller's own project already has other native extensions
registered), the unconditional [soname] = cmd_obj.get_outputs()
unpacking crashes with a bare ValueError instead of naming the
extension we actually wanted.

get_ext_fullpath(ext.name) asks build_ext directly for the path of the
specific extension we passed in, so it no longer depends on exactly
one output existing. This also gives a clearer failure mode for python-cffi#229,
where a beginner hit the same unpacking crash with no way to tell what
went wrong.

@mattip mattip left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One small nit. LGTM, if CI passes.

Comment thread testing/cffi0/test_platform.py Outdated
# force a fresh module name/compile every run, so the monkeypatched
# get_outputs() above is actually exercised instead of reusing a
# previously-built module cached under the same checksum-derived name
tag = binascii.hexlify(os.urandom(8)).decode()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems simpler and does not require importing binascii.

Suggested change
tag = binascii.hexlify(os.urandom(8)).decode()
tag = os.urandom(8).hex()

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call, pushed that.

Simpler, and drops the now-unneeded binascii import.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

2 participants