DumTux
DumTux

Reputation: 726

How to get the current path of compiled binary from Python using Nuitka?

Nuitka is good at compiling Python to excutable binary. But the compiled binary finds other resource files from original absolute path. Thus, for moving to another computer requires to make the directory tree same as the original one.

For example, if I compile a project like this:

/home/me/myproj/
╠═ myprog.py
╚═ resource
   ╚═ foo.data

I should put the resulting binary and resource to the same location of another computer. How to solve this problem?

My simpler spike is:

# /home/me/myproj/spike.py
import os
print(os.path.dirname(__file__))

And after compiling it, moving to any other location, I always got the result of /home/me/myproj.

I need a result like /another/path if I move compiled myproj.bin to /another/path.

Upvotes: 3

Views: 3543

Answers (4)

Carl Cheung
Carl Cheung

Reputation: 558

For those who using nuitka with onefile mode, just use sys.executable

It will return something like /tmp/onefile_xxxxxxxx/python3, and then you can os.path.dirname it to get its parent dir

Upvotes: 0

Dimas Lanjaka
Dimas Lanjaka

Reputation: 294

here my working get relative path relative from nuitka frozen exe or the cwd when running single python file (python filename.py).

import os
import sys
import re
from typing import Union

# Determine if application is a script file or frozen exe
if getattr(sys, 'frozen', False):
    __CWD__ = os.path.dirname(os.path.realpath(sys.executable))
elif __file__:
    __CWD__ = os.getcwd()

def is_nuitka() -> bool:
    """
    Check if the script is compiled with Nuitka.
    """
    is_nuitka = "__compiled__" in globals()
    is_nuitka2 = "NUITKA_ONEFILE_PARENT" in os.environ
    return is_nuitka or is_nuitka2

def get_nuitka_file(filePath: str) -> str:
    """
    Get the path for a file within a Nuitka compiled application.

    Args:
        filePath (str): The file path.

    Returns:
        str: The absolute file path.
    """
    filePath = os.path.normpath(filePath)
    is_nuitka_standalone = "__compiled__" in globals()
    is_nuitka_onefile = "NUITKA_ONEFILE_PARENT" in os.environ
    if is_nuitka_onefile:
        temp_appd = os.path.join(os.getenv('localappdata'), 'Temp')
        resdict = {}
        for item in os.listdir(temp_appd):
            if len(re.findall('''onefile_\d+_\d+''', item)) > 0:
                resdict[re.findall('''onefile_\d+_(\d+)''', item)[0]] = item
        respth = resdict[max(list(resdict.keys()))]
        return os.path.join(os.getenv('localappdata'), 'Temp', respth, filePath)
    if is_nuitka_standalone:
        return os.path.join(__CWD__, filePath)
    return os.path.normpath(os.path.join(__CWD__, filePath))

def get_relative_path(*args: Union[str, bytes]) -> str:
    """
    Get the relative path from the current working directory (CWD).

    Args:
        *args (Union[str, bytes]): Variable number of path components.

    Returns:
        str: The normalized relative path.
    """
    join_path = str(os.path.join(*args))
    result = os.path.normpath(str(os.path.join(__CWD__, join_path)))
    if is_nuitka():
        result = os.path.normpath(str(os.path.join(os.path.dirname(sys.argv[0]), join_path)))
        debug_log(os.path.dirname(sys.argv[0]), os.path.join(*args))
    return result

Upvotes: 0

SnakeСharming
SnakeСharming

Reputation: 71

Try using sys.argv[0] with os.path.abspath instead of __file__ .

For example:

abs_pth = os.path.abspath(sys.argv[0])
your_dir = os.path.dirname(abs_pth)

for val in abs_pth,your_dir:
    print(val)

This will help you get the current path to the executable binary file, as well as work with directories located in the same folder.

https://nuitka.net/doc/user-manual.html#onefile-finding-files

There is a difference between sys.argv[0] and __file__ of the main module for onefile more, that is caused by using a bootstrap to a temporary location. The first one will be the original executable path, where as the second one will be the temporary or permanent path the bootstrap executable unpacks to. Data files will be in the later location, your original environment files will be in the former location.

# This will find a file near your onefile.exe
open(os.path.join(os.path.dirname(sys.argv[0]), "user-provided-file.txt"))
# This will find a file inside your onefile.exe
open(os.path.join(os.path.dirname(__file__), "user-provided-file.txt"))

Upvotes: 7

workmail20
workmail20

Reputation: 11

Another good function to resolve __file__ problem, it is to use --standalone flag, which create one main ".bin" file + other ".so" dependencies in one folder.

python -m nuitka --standalone program.py

https://nuitka.net/doc/user-manual.html#use-case-4-program-distribution

Upvotes: 1

Related Questions