opening a file using a relative path from a subclass in a package

  • Thread starter spike grobstein
  • Start date
S

spike grobstein

So, I've got this project I'm working on where the app defines various
classes that are subclassed by module packages that act like plugins...

I'd like the packages to define a file path for supporting files
(graphics, etc) that are stored inside the package. The problem is that
the superclass's definition (stored elsewhere) has all of the code for
actually opening the files, so when I use the
os.path.dirname(os.path.abspath(__file__)) trick, it's finding the
superclass, not the package's path.

is this possible? or do I have to add code to each subclassing package
to calculate the absolute path of it and pass that as a variable?

I'd rather not have to repeat myself for each package that I make, and
I've got a feeling that I'm missing something really obvious.

thanks in advance!


....spike
 
H

Heiko Wundram

spike said:
I'd like the packages to define a file path for supporting files
(graphics, etc) that are stored inside the package. The problem is that
the superclass's definition (stored elsewhere) has all of the code for
actually opening the files, so when I use the
os.path.dirname(os.path.abspath(__file__)) trick, it's finding the
superclass, not the package's path.

Try:

import sys

os.path.dirname(os.path.abspath(sys.modules[self.__class__.__module__].__file__))

if you have an instance object (self) at hand, otherwise

os.path.dirname(os.path.abspath(sys.modules[selfcls.__module__].__file__))

if you have a class object (selfcls) at hand.

Thing being why your approach doesn't work is that __file__ references a
global which is always resolved in the namespace the function is defined
in, so the source file it's defined in. You can get at the module object
(the global namespace) of a class object by using the sys.modules trick.

Be aware that this is pretty... non-standard stuff, to say it mildly... ;-)

HTH!

--- Heiko.
 
S

spike grobstein

oh, wow. that works!!!

thanks for the help!

so, since python supports module packages like it does, you'd think
that it would have ways of making add-on or extension modules to be
more self contained.

Thanks, again!
 
H

Heiko Wundram

spike said:
so, since python supports module packages like it does, you'd think
that it would have ways of making add-on or extension modules to be
more self contained.

Errm... You're not quite understanding what the problem is about. A class is
just an object. A class object may appear in many modules (namespaces),
even in non-module namespaces (function namespaces). It's part of the
debugging system that a class is bound to a module (by the __module__
member of the class object), which helps in finding the source for a class
if you're the debugger.

The method I wrote to you won't work if you import the class from some file
and want to get the file where the class is imported, not where it's
defined. So, the following won't do what you think:

a.py
====

import c

class x:
__metaclass__ = c.superclass
pass

b.py
====

from a import x

c.py
====

class superclass(type):
def __init__(cls,name,bases,dct):
print cls.__module__

d.py
====

import b

python d.py

will print
"a"

and not
"b"

what you might have expected.

So, actually this is quite fragile stuff, and is something that's better
left alone if you care for portable code. Why do you desperately need
access to the source file of the extension class? Isn't it enough that you
import the extension class and rely on the fact that its module object has
a member which is a class object which defines a certain interface? Can't
you use the class name if you need a unique identifier for the class in
your system? (self.__class__.__name__)

Think about it...

--- Heiko.
 
S

spike grobstein

I understand why it wasn't working and it makes sense based on the
structure of namespaces that python defines, however, I'm just
surprised that there isn't some kind of built-in facility for dealing
with these types of things.

Module packages are a spectacular idea, it is just kinda easy to get
confused when you start spaghettifying your imports with multiple
directories and whatnot.

My whole reason for wanting to do this is that I've written a program
that contains a framework for extending the application. It's got a
plugin-like module package framework that allows endusers to add new
functionality, and I'd like it to not only be as trivial as possible to
create new plugins (by simply plugging in values to a new subclass),
but to also repeat as little code as possible (the DRY principal; don't
repeat yourself)

I toyed with the idea of using generic filenames (icon.png,
description.rtf, etc), but ultimately decided against it when I thought
about things I'd want to implement in the future.
 
F

Fredrik Lundh

"spike grobstein" write:
I understand why it wasn't working and it makes sense based on the
structure of namespaces that python defines, however, I'm just
surprised that there isn't some kind of built-in facility for dealing
with these types of things.

Module packages are a spectacular idea, it is just kinda easy to get
confused when you start spaghettifying your imports with multiple
directories and whatnot.

My whole reason for wanting to do this is that I've written a program
that contains a framework for extending the application. It's got a
plugin-like module package framework that allows endusers to add new
functionality, and I'd like it to not only be as trivial as possible to
create new plugins (by simply plugging in values to a new subclass),
but to also repeat as little code as possible (the DRY principal; don't
repeat yourself)

I toyed with the idea of using generic filenames (icon.png,
description.rtf, etc), but ultimately decided against it when I thought
about things I'd want to implement in the future.

why not just add an attribute to each subclass which tells the baseclass
where to look for the files ? if you let the attribute be either a directory
or a file in the directory, you can do

class MySubClass(somemodule.SuperClass):
location = __file__
...

in most subclasses, but you can also do fancier stuff, like:

class MyOtherSubClass(somemodule.SuperClass):
for p in ".", __file__, "/usr/local/mysystem/config/root":
if os.path.isfile(os.path.join(p, "config.xml")):
self.location = p # found it!
break

the superclass would then simply use self.location to locate stuff:

class SuperClass(...):

location = "."

def find_resources(self):
# location can be either a directory or a file in the
# config directory
location = self.location
if os.path.isfile(location): # use the directory this file is in
location = os.path.dirname(self.location)
data = ConfigLoader(os.path.join(location, "config.xml"))
...

</F>
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,981
Messages
2,570,188
Members
46,732
Latest member
ArronPalin

Latest Threads

Top