Get Path to Python File Before Installation

Question:

I have a project that includes c++ binaries and python scripts, it’s setup such that it should be installed using setuptools. One of the python files is intended to be both used as a script "
python3 script_name.py params
and for it’s primary function to be used in other python projects from script_name import function.
The primary function calls a binary which is in a known relative location before the installation (the user is expected to call pip install project_folder). So in order to call the binary I want to get this files location (pre installation)

To get this I used something like

Path(__file__).resolve().parent

however, since the installation moves the file to another folder like ~/.local/... this doesn’t work when imported after the installation.

Is there a way to get the original file path, or to make the installation save that path somewhere?

EDIT:
After @sinoroc ‘s suggestion I tried including the binary as a resource by putting an __init__.py in the build folder and putting

from importlib.resources import files
import build

binary = files(build).joinpath("binary")

in the main init. After that package.binary still gives me a path to my .local/lib and binary.is_file() still returns False

from importlib_resources import files

GenerateHistograms = files("build").joinpath("GenerateHistograms")

gave the same result

Asked By: Chalky

||

Answers:

Since you are installing your package, you also need to include your C++ binary in the installation. You cannot have a mixed setup. I suggest something like this.

In your setup.py:

from setuptools import setup, find_packages

setup(
    name="mypkg",
    packages=find_packages(exclude=["tests"]),
    package_data={
        "mypkg": [
            "binary",  # relative path to your package directory
        ]
    },
    include_package_data=True,
)

Then in your module use pkg_resources:

from pathlib import Path

from pkg_resources import resource_filename

# "binary" is whatever relative path you put in package_data
path_to_binary = Path(resource_filename("mypkg", "binary"))

pkg_resources should be pulled in by setuptools.

EDIT: the recipe above might be a bit out of date; as @sinoroc suggests, using importlib.resources instead of pkg_resources is probably the modern equivalent.

Answered By: suvayu

So I managed to solve it in with @sinroc ‘s approach in the end

In setup.py

package_data={'package':['build/*']}
include_package_data=True

and in the primary __init.py__:

from importlib.resources import files
binary = files("package.build").joinpath("binary")

So I could then from package import binary to get the path

EDIT: Looks like someone also pointed the error in my ways out before I finished ^^

Answered By: Chalky