Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Script directory not included in sys.path when a ._pth is in use

Tags:

python

pth

I am attempting to solve a weird issue related to importing modules in a Python script I have written. The file that implements the module is in the same directory as the main Python script.

The Python script works perfectly when I use ActivePython. However, when I use the Embedded Distribution I get the following error.

ModuleNotFoundError: No module named 'pyWhich'

I have traced the difference in behavior to the way the sys.path veritable is set in the Embedded Distribution.

In ActivePython, the environment in which my script works, the first entry in sys.path is the directory containing the script. In the Embedded Distribution, there is no entry for the directory containing the script.

The Embedded Distribution uses a _pth file to set the sys.path. I am using the default ._pth file, which I have included below for your convenience.

python36.zip
.

# Uncomment to run site.main() automatically
#import site

My question is, what magical incantation do I need to add to my _pth file to tell Python to please put the directory containing any script I run in sys.path so my scripts will work with the Embedded Distribution. The documentation on path configuration files does not seem to contain this information.

like image 638
Ben Key Avatar asked Apr 25 '18 13:04

Ben Key


1 Answers

I am still hoping for a magical incantation I can add to my _pth file that says "please put the directory containing any script I run in sys.path" so I do not have to modify all my scripts. However, it is possible that no such magical incantation exists.

I have found that the following magical incantation, when added to a Python script, achieves the desired results. And, unlike other solutions you may find out there in the wild, this one will work in the context of cx_Freeze and IDLE and in any other context in which the simple file based solutions will not work.

import inspect
import os
import sys

# Add script directory to sys.path.
# This is complicated due to the fact that __file__ is not always defined.

def GetScriptFile():
    """Obtains the full path and file name of the Python script."""
    if hasattr(GetScriptFile, "file"):
        return GetScriptFile.file
    ret = ""
    try:
        # The easy way. Just use __file__.
        # Unfortunately, __file__ is not available when cx_freeze is used or in IDLE.
        ret = os.path.realpath(__file__)
    except NameError:
        # The hard way.
        if len(sys.argv) > 0 and len(sys.argv[0]) > 0 and os.path.isabs(sys.argv[0]):
            ret = os.path.realpath(sys.argv[0])
        else:
            ret = os.path.realpath(inspect.getfile(GetScriptFile))
            if not os.path.exists(ret):
                # If cx_freeze is used the value of the ret variable at this point is in
                # the following format: {PathToExeFile}\{NameOfPythonSourceFile}. This
                # makes it necessary to strip off the file name to get the correct path.
                ret = os.path.dirname(ret)
    GetScriptFile.file = ret
    return GetScriptFile.file

def GetScriptDirectory():
    """Obtains the path to the directory containing the script."""
    if hasattr(GetScriptDirectory, "dir"):
        return GetScriptDirectory.dir
    module_path = GetScriptFile()
    GetScriptDirectory.dir = os.path.dirname(module_path)
    return GetScriptDirectory.dir

sys.path.insert(0, GetScriptDirectory())

By the way, if you wish to see this in action, I have implement it my my Python Which project.

like image 50
Ben Key Avatar answered Sep 28 '22 04:09

Ben Key