How to deal with binary extensions (.pyd files) and binary scripts (.exe files)?

Hi,

I’ve made a binary Python extension using C++ with the help of PyBind11.
This extension come with a “binary script” which is a regular executable file.

Now I’m struggling with the creation of a wheel file to distribute it.

Using pyproject.toml and setuptools backend, I’m able to create wheel file to install a regular Python package (made of .py files) with regular script files (using entry points in .py files)

But how to deal with my .pyd file which contains my whole extension package ?

I’ve try several things, the best I could achieve is a wheel file which install my package as
python-install-dir/Lib/site-packages/mypackage/mypackage.pyd

But with that, my package members are accessible from a Python script using “mypackage.mypackage.mymember” syntax

If I manually install my pyd file as “python-install-dir/Lib/site-packages/mypackage.pyd” file (without the “mypackage” subdirectory), it works as expected : I can access my package members with the “mypackage.mymember” syntax

How to configure my pyproject.toml file to achieve this ?
Or is there anything I’ve missed in my .pyd file ?
Maybe should I switch to another build backend ?

My extension also comes with a binary tool (“mytool.exe” file).
How can I include it in my wheel file so it ends up in the “python-install-dir/Scripts” directory ?

Put the .pyd in mypackage/_mypackage.pyd, and add a file mypackage/__init__.py which contains:

from _mypackage import *

That’s how this is usually done.

I’ve tried this, but this made a “myfunction” member accessible via mypackage._mypackage.myfunction instead of mypackage.myfunction

In the sources of my PYD file, I declare a “mypackage” module and add “myfunction” to it.
Maybe there is something wrong here to make it work?

from .. import * doesn’t remove anything from _mypackage, so it’s not surprising that mymember is still there. That’s as it should be.

mypackage should have a copy as well, because that’s what the import does: copy the reference. Are you sure __init__.py is present after an install, and you didn’t spell the filename in any way differently?

You could try this:

import mypackage
print(mypackage.__file__)

This should print ...\Lib\site-packages\mypackage\__init__.py.

I finally made it work.

I had a bunch of typo due to some misleading names : it’s an old code and there is a lot of “mypackage/mypackage/mypackage.py” files containing a “mypackage” class…

But I switched to another solution. I’ve renamed my “mypackage/mypackage.pyd” file to “mypackage/init.pyd”.

By doing this, the member names are correct without any import, and more important in my case, the call to type(something) return the “mypackage/myclass” string.

This important for me because a part of this old code make use of this string to identify python types from C++, and it was broken by the use of a init.py file with import directives.

Anyway, thanks for your help.