Kung Fu Kung Fu

Fujian White Crane Kung Fu

Zope Zope

What I have and am doing with Zope

Photos Photos

Photoalbum, both old and new.

Receptsamlingen Receptsamlingen

In Swedish only. About my "Collection of Recipes" website.

Contact me Contact me

My contact details and how to contact me.

  Mobile version of this page Mobile version of this page


 

Python package path when executed elsewhere

executed path, package_home, execution, dirname, filename, globals, foobar, package path, sys.path

14th of December 2004

I stumbled across a problem today with running a python package from a different directory than where the python files are. The package looked like this (in principle):

 /home/someone/mypackage/
    __init__.py
    template.html
    foobar.py

The foobar.py script contains this code:

 def foo():
    tmpl = open('template.html').read()
    return tmpl.replace('X','Y')

That's fine and works when you run the file directly. The problem comes when you run the foobar.py script from somewhere completely different (e.g. /home/mrbloggs/otherpackage/). The solution to this comes from Zope's package_home.

The problem is that if your script does the following:

 import sys
 sys.path.insert(0, '/home/someone/mypackage')
 import foobar
 foobar.foo()

Then the file template.html can not be found. That's because upon executing the importing script it holds a different execution path.

So what I did was that I added the following code which I pinched from Zope's package_home:

 def package_home(gdict):
    filename = gdict["__file__"]
    return os.path.dirname(filename)

 def foo():
    tmpl = open(os.path.join(package_home(globals()), 'template.html')).read()
    return tmpl.replace('X','Y')

Good to know for the future!


Comment

adam smith - 16th June 2006  [«« Reply to this]
Thanks for this post--I have been perplexed by this same issue. I did the following to make it a little more convenient to call:

I put this code into a package_home.py module:

---
import os

def get_package_home(context):
return os.path.dirname(context["__file__"])

def get_execution_path(context, filename):
return os.path.join(get_package_home(context), filename)
---

Then in my code, I just need to import it and call it like this:

---
from package_home import get_execution_path
get_execution_path(globals(), 'template.html')
---

(It doesn't look like indentation is preserved in these posts.)

Python is not my primary language, so I am not sure if this is possible, but I wonder if we can't get rid of the repetitive globals() in the call by having the get_execution_path method somehow (through introspection) get this information for the calling object.

Also, is there a way to include these methods in an upper level package's __init__.py file so they can be available to all the code in an application without having to explicitly import it into every module we want to use it in?
adam smith - 14th July 2006   [«« Reply to this]
OK, I finally returned to this, and here is the latest version using introspection to make finding the package home as convenient as possible:

# IN package_home.py
import os, sys, inspect

def _package_home(filename):
return os.path.dirname(filename)

def package_home(context):
""" this preserves the functionality of the original package_home function
within this new approach"""
return _package_home(context["__file__"])

def execution_path(filename):
return os.path.join(_package_home(inspect.getfile(sys._getframe(1))), filename)

def execution_path2(filename):
"""alternately, you can just use this method to hide a lot of complexity
without needing any of the other functions above"""
return os.path.join(os.path.dirname(inspect.getfile(sys._getframe(1))), filename)

#USAGE
from package_home import execution_path
execution_path('template.html')

Again, sorry that I don't know how to preserve indentation in these posts.

The sys._getframe(1) call examines the call stack and retrieves information about the calling function, so no matter how it is executed, it should work.
 
Name:
Email:
hide my email address.

Your email address will be encoded to prevent email-extraction spiders from reading it so you won't get spammed if you decide to show your email address.