import and package confusion

D

Dale Amon

I am going around in circles right now and have to
admit I do not understand what is going on with
import of hierarchical packages/modules. Perhaps someone
can get me on the road again. Here is a subset of what I
am trying to accomplish:

The package directory set up:

VLMLegacy/
__init__.py
Reader.py
Conditions.py
VLM4997/
__init__.py
Conditions.py
WINGTL/
__init__.py
Conditions.py

The inheritance:

object
Reader
Conditions
VLM4997.Conditions
WINGTL.Conditions


Now how do I use import or from to be able to
use these modules? The following is not 'real'
code and is only intended to give some idea of
what I am trying to accomplish:

import sys
sys.path.extend (['../lib', '../bin'])

import VLMLegacy.VLM4997.Conditions
import VLMLegacy.WINGTL.Conditions

b = VLM4997.Conditions(2)
b.test()

c = WINGTL.Conditions(2)
c.test()

And of course note that both of those must inherit
VLMLegacy.Conditions().


-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (GNU/Linux)

iD8DBQFJ+JPhZHES7UL0zXERAhvoAJ4vFinsMeupaQMRx/YiNoWyHzvt+ACbB2rv
DkwvXk9s2XZMMb2ESZ8uJvc=
=m8Jw
-----END PGP SIGNATURE-----
 
D

Dale Amon

I am trying to get to the heart of what it is I am
missing. Is it the case that if you have a module C in a
package A:

A.C

that there is no way to load it such that you can use:

x = A.C()

in your code? This is just a simpler case of what I'm
trying to do now, which has a module C in a sub-package
to be imported:

A.B.C

ie with files:
mydir/A/B/C.py
mydir/mymain.py

and executed in mymain.py as:

x = A.B.C()

I may still chose to do it the way you suggested, but I
would still like to understand why this does not work.


-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (GNU/Linux)

iD8DBQFJ+Kw1ZHES7UL0zXERAm0JAJ9Voi9IFaJpAW54hbvzLMe+EIUQgQCeK7b6
PGA7KRX2NuKp/oClmXJCpEI=
=58Pz
-----END PGP SIGNATURE-----
 
S

Scott David Daniels

Dale said:
I am trying to get to the heart of what it is I am
missing. Is it the case that if you have a module C in a
package A:
A.C
that there is no way to load it such that you can use:
x = A.C()
in your code?
OK, here's a simple question. What do you expect from:
import sys
sys()
sys is a module, and as such, it is not callable.
Just because you put a class inside a module, does not mean
that class magically does something by virtue of having the
same name as the module.

A module is a namespace to hold classes, functions, etc....
A package is a namespace to hold modules (possibly more).

I don't understand why you don't use files like:

VLMLegacy/
__init__.py
Reader.py
VLM4997.py
WINGTL.py
But, presuming some kind of rationale,
put the code you want in
VLMLegacy/VLM4997/__init__.py

--Scott David Daniels
(e-mail address removed)


--Scott David Daniels
(e-mail address removed)
 
D

Dale Amon

OK, here's a simple question. What do you expect from:
import sys
sys()
sys is a module, and as such, it is not callable.
Just because you put a class inside a module, does not mean
that class magically does something by virtue of having the
same name as the module.

A module is a namespace to hold classes, functions, etc....
A package is a namespace to hold modules (possibly more).

I don't understand why you don't use files like:

VLMLegacy/
__init__.py
Reader.py
VLM4997.py
WINGTL.py

Well, it is far more complex than that: I just cut it down to
the most minimal case I could.
But, presuming some kind of rationale,
put the code you want in VLMLegacy/VLM4997/__init__.py

That doesn't really do it. Perhaps I should try to describe
the situation better.

There are n different similar systems, each with multiple classes.
They could either be implimented as a class at the first level:

VLMLegacy
Condition.py
Plan.py
|
|
etc

but in that case each class will be filled with conditionals
that try to do the correct thing depending on which system's
data they are reading. That approach has already gotten *insane*
and I need to objectify things: put all the common code into
abstract superclasses, and then create a subclass for each
different system (of which there will be an unknown number added
over time), ie:

VLMLegacy/
Conditions.py Abstract classes
Plan.py
|
|
etc
TYPE1/ Subclasses of above specific to Type 1
Conditions.py
Plan.py
|
|
etc
TYPE2/ Subclasses for Type 2
Conditions.py
Plan.py
|
|
etc

|
TYPEn/ Subclasses for Type n
Conditions.py
Plan.py
|
|
etc

Every VLMLegacy.TYPEn.Conditions (or other class) has exactly
the same set of methods; each of those methods inherits much
of its basic behavior from VLMLegacy.Conditions.

If I make every subclass a unique name, things will
rapidly get out of hand, especially when I start
adding TYPEn+1,2... etc.

So yes, the approach isn't arbitrary, it is a solution
to real design problems which even the above does not
fully do justice to.

What I would really like to do when executing is more
like:

type = "VLM4997"
type.Header(args)
type.Plan(args)
type.Conditions(args)

Where the type might change from execution to execution
or even on different iterations.


-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (GNU/Linux)

iD8DBQFJ+Lm7ZHES7UL0zXERAvBxAJ9nOV0fTpf24zZLgMw55g41bz9IpgCeJNBJ
Lc7dLMLIdlQptIIGJsNnUqs=
=rYLy
-----END PGP SIGNATURE-----
 
D

Dale Amon

type = "VLM4997"
type.Header(args)
type.Plan(args)
type.Conditions(args)
Where the type might change from execution to execution
or even on different iterations.

Actually let me make that reflect more accurately what
is going on:

obj = Deck(rdr)
obj.header = type.Header(rdr)
obj.plan[0] = type.Plan(rdr)
obj.plan[1] = type.Plan(rdr)
obj.cond = type.Conditions(rdr)

obj.cond.calcsomething(args)

and so forth through many pages of code...





-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (GNU/Linux)

iD8DBQFJ+Ls0ZHES7UL0zXERAp8OAJ0QDjGH1h1oWLhU++irhOBbNV4JTACeK13B
OC8LycxNqDXHL7X98kYTCq4=
=ZjXw
-----END PGP SIGNATURE-----
 
S

Scott David Daniels

You did not answer the question above, and I think the answer is the root
of your misunderstanding. A class and a module are _not_the_same_thing_.
sys is not a package, it is a module.Unlike Java, we are free to have several things in a module:

several classes, several functions, several constants....

There are n different similar systems, each with multiple classes.
They could either be implimented as a class at the first level:

VLMLegacy
Condition.py
Plan.py
|
|
etc

but in that case each class will be filled with conditionals
that try to do the correct thing depending on which system's
data they are reading. That approach has already gotten *insane*
and I need to objectify things: put all the common code into
abstract superclasses, and then create a subclass for each
different system (of which there will be an unknown number added
over time), ie:

VLMLegacy/
Conditions.py Abstract classes
Plan.py
|
|
etc
TYPE1/ Subclasses of above specific to Type 1
Conditions.py
Plan.py
|
|
etc
TYPE2/ Subclasses for Type 2
Conditions.py
Plan.py
|
|
etc

|
TYPEn/ Subclasses for Type n
Conditions.py
Plan.py
|
|
etc

Every VLMLegacy.TYPEn.Conditions (or other class) has exactly...
But VLMLegacy.TYPEn.Conditions is a _module_, not a _class_.
I suggest VLM4497.py look a bit like the following:
from VLMLegacy import abstract_classes
class Condition(abstract_classes.BaseCondition):
...
class Plan(abstract_classes.BasePlan):
...
Header = abstract_classes.BaseHeader # Note we needed no customization
...
the same set of methods; each of those methods inherits much
of its basic behavior from VLMLegacy.Conditions.

If I make every subclass a unique name, things will
rapidly get out of hand, especially when I start
adding TYPEn+1,2... etc.

So yes, the approach isn't arbitrary, it is a solution
to real design problems which even the above does not
fully do justice to.

What I would really like to do when executing is more
like:

type = "VLM4997"
type.Header(args)
type.Plan(args)
type.Conditions(args)

Where the type might change from execution to execution
or even on different iterations.
Well, "VLM4997" is a _string_, and it has no attributes (nor methods)
named "Header", "Plan", or "Conditions." And "type" is a perfectly awful
name for a variable, since it hides the builtin named type. You seem to
confuse names, files, and classes defined in files (at least in your
writing).

--Scott David Daniels
(e-mail address removed)
 
D

Dale Amon

You did not answer the question above, and I think the answer is the root
of your misunderstanding. A class and a module are _not_the_same_thing_.
sys is not a package, it is a module.
Unlike Java, we are free to have several things in a module:
several classes, several functions, several constants....

These modules would grow to be hundreds of pages long and a
difficult to deal with to debug a problem related to one obscure
system without looking at (or potentially screwing up) any of the
others. I prefer one class per module.

This gets more into philosophy, but I figure any function or method
that does not fit on one page is too big; and any source file that
is more than 20 pages long should be broken in half. I like my modules
in the 5-10 page size range, including the embedded Unix ManPages and
the cvs history. But that's just my house style.
Well, "VLM4997" is a _string_, and it has no attributes (nor methods)
named "Header", "Plan", or "Conditions." And "type" is a perfectly awful
name for a variable, since it hides the builtin named type. You seem to
confuse names, files, and classes defined in files (at least in your
writing).

Actually I'm not. I am simply trying to use a pseudo code
to explain roughly what is going on. There will be a string
that selects what the set of classes are to be used on any
given iteration and it will be used to generate the name
of the class and/or name of the module where it is to be found.
I'm an old ObjC hacker. I often put the class or method in a
variable and do the bindings at runtime. I am already doing some
of that sort of thing in this system with the method names and
it works nicely.

The point I take away from this is that packages and
modules have dotted names, but Classes do not and there
is no way to do exactly what I wanted to do.

The dot syntax would have been quite nice (I quite like the
"::" syntax in Perl) and would have made the code much
clearer. The way you suggested with a 'typename_classname'
generated using a from/import statement will just have to
suffice.





-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (GNU/Linux)

iD8DBQFJ+NVPZHES7UL0zXERAlEhAJsEgqyFWEeRSyMq43fjW6DWJUrz0ACfY1Tf
He6F8qwFR/YsTioC4V9nBT4=
=RH2i
-----END PGP SIGNATURE-----
 
D

Dale Amon

Well, I've managed to get close to what I want,
and just so you can see:

#!/usr/bin/python

import sys
sys.path.extend (['../lib', '../bin'])

from VLMLegacy.CardReader import CardReader
rdr = CardReader ("../example/B767.dat","PRINTABLE")

iotypes = ["WINGTL","VLMPC","VLM4997"]
for iotype in iotypes:
packagename = "VLMLegacy." + iotype + ".Conditions"
classname = iotype + "_Conditions"
code = "from %s import Conditions as %s" \
% (packagename, classname)
x = compile (code,"foo","exec")
exec x
cls = globals()[classname]
a = cls(rdr,2)
a.test()


-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (GNU/Linux)

iD8DBQFJ+O6qZHES7UL0zXERAiXnAJsGHIlD0KUKUoBHWmrsC4CNpNMNjgCdHZ0+
VSyLRAiyzzGbakQvAqS3cnY=
=5Dsm
-----END PGP SIGNATURE-----
 
D

Dale Amon

Nope. You have not been clear with what you want, and part
of the lack of clarity is your imprecision about names.

If you insist on having a class per module, you will
always have redundant-looking class names somewhere.
You will help yourself out a lot by not sharing the class
name and the base class name (not the least in error
messages), but it is possible to have them the same.

That in particular may happen. This has all been a matter
of running tests to see how close I could get to the
desired concept using Python. With some working test code
I have now, the answer is 'close enough'.

Your assistance has been useful, regardless of whether
it sounded that way or not ;-)


-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (GNU/Linux)

iD4DBQFJ+PAUZHES7UL0zXERAkckAJ4gTKwKN86za+zeQQ7Ch6E04zLopwCWITAB
8VlxGQICOzJOcpHE1NcLBA==
=vh31
-----END PGP SIGNATURE-----
 
D

Dave Angel

Dale said:
The point I take away from this is that packages and
modules have dotted names, but Classes do not and there
is no way to do exactly what I wanted to do.

The dot syntax would have been quite nice (I quite like the
"::" syntax in Perl) and would have made the code much
clearer. The way you suggested with a 'typename_classname'
generated using a from/import statement will just have to
suffice.
You clearly still don't understand. The dot syntax works very
predictably, and quite flexibly. The problem was that by using the same
name for module and class, you didn't realize you needed to include both.

If a particular module is called mymodule, and you want to use a class
within it called myclass, you can do it readily with:

import mymodule
obj = mymodule.myclass(arg1, arg2)

If you have the same class name in more than one module, you can make
either one simply by doing:

obj = mymodule1.myclass(arg1, arg2)
obj = .mymlodule2.myclass(arg1, arg2)

And in particular if you simply do the following, you can choose between
those modules:

if test:
mod = mymodule1
else:
mod = mymodule2
obj = mod.myclass(arg1, arg2)

Now the same logic would work if you added packages to the mix, and if
you happened to call the class the same thing as the module. But it
would be very confusing in a message like this, so I choose not to.

The compiler doesn't care if the names are the same, but when you get
scoping wrong, the error messages will be confusing.

Please don't sink to exec or eval to solve what is really a
straightforward problem.
 
D

Dale Amon

The dot syntax works very
predictably, and quite flexibly. The problem was that by using the same
name for module and class, you didn't realize you needed to include both.

It is one of the hazards of working in many very different
languages. But I see where that confusion lies and that is
a useful thing to know.
And in particular if you simply do the following, you can choose between
those modules:

if test:
mod = mymodule1
else:
mod = mymodule2
obj = mod.myclass(arg1, arg2)

Not really applicable to the case I have. There can be lots of
different ones and the input selection comes from a command line
string so...
Please don't sink to exec or eval to solve what is really a
straightforward problem.

I do not really see any other way to do what I want. If
there is a way to get rid of the exec in the sample code
I have used, I would love to know... but I can't see how
to import something where part of the name comes from user
command line input without interpreting the code via exec.
[See the test module I posted.] I'm dealing with something
like this:

myprogram --type WINGTL file.dat

the set of types will have new members added as they are
discovered and I intend to minimize code changes to doing
nothing but create a subpackage directory with the new
modules, drop it in place. New functionality with no
mods to the existing code...




-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (GNU/Linux)

iD8DBQFJ+RaqZHES7UL0zXERArqLAJ9a0RNk7m6d9n/8TEMJo+gX7g4wvQCcDz6h
PSp7ljOstxibrPK609li8tE=
=6MmF
-----END PGP SIGNATURE-----
 
A

alex23

I do not really see any other way to do what I want. If
there is a way to get rid of the exec in the sample code
I have used, I would love to know... but I can't see how
to import something where part of the name comes from user
command line input without interpreting the code via exec.

Are you familiar with __import__?

iotypes = ["WINGTL","VLMPC","VLM4997"]
for iotype in iotypes:
packagename = "VLMLegacy." + iotype + ".Conditions"
classname = iotype + "_Conditions"
module = __import__(packagename)
cls = getattr(module, classname)
# etc

Much cleaner :) And far more secure: any time you think "user input"
AND "exec", you're probably going in the wrong direction...
 
A

Arnaud Delobelle

Dale Amon said:
I do not really see any other way to do what I want. If
there is a way to get rid of the exec in the sample code
I have used, I would love to know... but I can't see how
to import something where part of the name comes from user
command line input without interpreting the code via exec.

__import__
 
J

Jeroen Ruigrok van der Werven

-On [20090430 02:21] said:
import sys
sys.path.extend (['../lib', '../bin'])

from VLMLegacy.CardReader import CardReader
rdr = CardReader ("../example/B767.dat","PRINTABLE")

iotypes = ["WINGTL","VLMPC","VLM4997"]
for iotype in iotypes:
packagename = "VLMLegacy." + iotype + ".Conditions"
classname = iotype + "_Conditions"
code = "from %s import Conditions as %s" \
% (packagename, classname)
x = compile (code,"foo","exec")
exec x
cls = globals()[classname]
a = cls(rdr,2)
a.test()

Although I can applaud your creativity, this really is very hackish for
Python and definitely has a bad 'smell'.

Like you I work with many different languages, but I am not going to force
the natural flow of Python into something resembling Java or whatever
other language.

Simply doing:

Right now your code boils down to:

from VLMLegacy.VLM4997.Conditions import Conditions as VLM4997_Conditions
from VLMLegacy.VLMPC.Conditions import Conditions as VLMPC_Conditions
from VLMLegacy.WINGTL.Conditions import Conditions as WINGTL_Conditions

And while you are, of course, allowed to do so, it's not the way you would
want to approach it in Python.

For each subpackage/module you could add an import and __all__ to
__init__.py to expose Conditions and then shorten it all to:

import VLMLegacy.VLM4997 as VLM4997
import VLMLegacy.VLMPC as VLMPC
import VLMLegacy.WINGTL as WINGTL

So that you can do:

a = VLM4997.Conditions(rdr, 2)
a.test()
 
D

Dave Angel

Dale said:
The dot syntax works very
predictably, and quite flexibly. The problem was that by using the same
name for module and class, you didn't realize you needed to include both.

It is one of the hazards of working in many very different
languages. But I see where that confusion lies and that is
a useful thing to know.

And in particular if you simply do the following, you can choose between
those modules:

if test:
mod = mymodule1
else:
mod = mymodule2
obj = mod.myclass(arg1, arg2)

Not really applicable to the case I have. There can be lots of
different ones and the input selection comes from a command line
string so...

Please don't sink to exec or eval to solve what is really a
straightforward problem.

I do not really see any other way to do what I want. If
there is a way to get rid of the exec in the sample code
I have used, I would love to know... but I can't see how
to import something where part of the name comes from user
command line input without interpreting the code via exec.
[See the test module I posted.] I'm dealing with something
like this:

myprogram --type WINGTL file.dat

the set of types will have new members added as they are
discovered and I intend to minimize code changes to doing
nothing but create a subpackage directory with the new
modules, drop it in place. New functionality with no
mods to the existing code...
As Scott David Daniels says, you have two built-in choices, depending on
Python version. If you can use __import__(), then realize that
mod = __import__("WINGTL")

will do an import, using a string as the import name. I don' t have the
experience to know how it deals with packages, but I believe I've heard
it does it the same as well.


One more possibility, if you're only trying to get a single package
hierarchy at a time, it might be possible to arrange them in such a way
that the sys.path search order gets you the package you want. Rather
than the top level being a package, it'd be an ordinary directory, and
you'd add it to the sys.path variable so that when you import a
subpackage (which would now really just be a package), you'd get the
right one.

DaveA
 
G

Gabriel Genellina

I do not really see any other way to do what I want. If
there is a way to get rid of the exec in the sample code
I have used, I would love to know... but I can't see how
to import something where part of the name comes from user
command line input without interpreting the code via exec.

Are you familiar with __import__?

iotypes = ["WINGTL","VLMPC","VLM4997"]
for iotype in iotypes:
packagename = "VLMLegacy." + iotype + ".Conditions"
classname = iotype + "_Conditions"
module = __import__(packagename)
cls = getattr(module, classname)
# etc

(doesn't work as written, because __import__ returns the top package when
given a dotted name)
Replace the last three lines with:

__import__(packagename)
module = sys.modules[packagename]
cls = getattr(module, "Conditions")
 
D

Dale Amon

import sys
sys.path.extend (['../lib', '../bin'])

from VLMLegacy.CardReader import CardReader
rdr = CardReader ("../example/B767.dat","PRINTABLE")

iotypes = ["WINGTL","VLMPC","VLM4997"]
for iotype in iotypes:
packagename = "VLMLegacy." + iotype + ".Conditions"
classname = iotype + "_Conditions"
code = "from %s import Conditions as %s" \
% (packagename, classname)
x = compile (code,"foo","exec")
exec x
cls = globals()[classname]
a = cls(rdr,2)
a.test()

Right now your code boils down to:

from VLMLegacy.VLM4997.Conditions import Conditions as VLM4997_Conditions
from VLMLegacy.VLMPC.Conditions import Conditions as VLMPC_Conditions
from VLMLegacy.WINGTL.Conditions import Conditions as WINGTL_Conditions

And while you are, of course, allowed to do so, it's not the way you would
want to approach it in Python.

For each subpackage/module you could add an import and __all__ to
__init__.py to expose Conditions and then shorten it all to:

import VLMLegacy.VLM4997 as VLM4997
import VLMLegacy.VLMPC as VLMPC
import VLMLegacy.WINGTL as WINGTL

So that you can do:

a = VLM4997.Conditions(rdr, 2)
a.test()

If my proof of concept test code were actually all there was
you would be correct. But what I wish to accomplish is that
a string supplied from the command line does a run time load
of code that is not even explicitely mentioned in the main
body of the system.

myprogram --type NEWTYPE old.dat

Where NEWTYPE did not exist when the above code was written and
distributed. Think of the following scenario.

* Customer tells me, we have old data decks which are not
quite in any of the supported formats.

* I supply a new subpackage NEWTYPE with the varient code.

* They copy it into the package directory, VLMLegacy/NEWTYPE.

* They type the name of that package as a command line arg as
above.

* The code I wrote takes their string and dynamically binds
and uses the new code without changing anything else in
the code base.

Now I agree it is hackish. I don't really want to eval,
I just want to import a module whose name is contained
in a variable. I'm not unhappy with the second part where
I use globals()[thestring] to get from a string to a
class object; I am indeed bothered that I have to eval
to do the import as I have been unable so far to find
a way to make it work dynamically. I'd be perfectly happy
if something like this worked:

from VLMLegacy.CardReader import *
opts, args = p.parse_args()
iotype = opts.type
targetname = "Deck"
packagename = "VLMLegacy." + iotype + "." targetname
classname = iotype + "_" + targetname

# I only wish something like this worked...
from packagename import targetname as classname

cls = globals()[classname]

file = args[0]
rdr = CardReader(file,opts.punchtype)
a = cls(rdr,2)
a.read()

<do minutes or hours of calculations>

but it doesn't. Oh, and it gets worse later. The data I'm
reading is potentially straight off ancient Fortran decks
with no spaces between numbers. ;-)

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (GNU/Linux)

iD8DBQFJ+bBFZHES7UL0zXERAv3aAJ9xt/FoG1/mQZcAHboxdm0cUmgXfQCbBOtb
11PHbvtqTtl8jOoVTn6lq6w=
=hbqM
-----END PGP SIGNATURE-----
 
D

Dale Amon

As Scott David Daniels says, you have two built-in choices, depending on
Python version. If you can use __import__(), then realize that
mod = __import__("WINGTL")

will do an import, using a string as the import name. I don' t have the
experience to know how it deals with packages, but I believe I've heard
it does it the same as well.
One more possibility, if you're only trying to get a single package
hierarchy at a time, it might be possible to arrange them in such a way
that the sys.path search order gets you the package you want. Rather
than the top level being a package, it'd be an ordinary directory, and
you'd add it to the sys.path variable so that when you import a
subpackage (which would now really just be a package), you'd get the
right one.

That would be too unpredictable. But I find the first option
very interesting. I was looking at the __import__ in the Python
book and thought it *might* be able to do it, but I was not sure
if it was a solution or an enticing event horizon.

I'm using 2.5 btw.




-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (GNU/Linux)

iD8DBQFJ+bEdZHES7UL0zXERAhs7AJwPbFeD3XM9oYLk8+uuHmGk1oOGCgCdFL9r
DtjkMI1GJ79W9Gpyyf5uMP0=
=VyXe
-----END PGP SIGNATURE-----
 
D

Dale Amon

Are you familiar with __import__?

iotypes = ["WINGTL","VLMPC","VLM4997"]
for iotype in iotypes:
packagename = "VLMLegacy." + iotype + ".Conditions"
classname = iotype + "_Conditions"
module = __import__(packagename)
cls = getattr(module, classname)
# etc

(doesn't work as written, because __import__ returns the top package when
given a dotted name)
Replace the last three lines with:

__import__(packagename)
module = sys.modules[packagename]
cls = getattr(module, "Conditions")

Thanks. That works marvelously. I just knew there
had to be a better way.



-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (GNU/Linux)

iD8DBQFJ+bNZZHES7UL0zXERAqG6AJ9apWZ67No797XSVrXi8AfOgqgVwACfdFgc
qvusiLAXEGWWznBneViJhlc=
=IYPu
-----END PGP SIGNATURE-----
 
M

MRAB

Dale said:
import sys
sys.path.extend (['../lib', '../bin'])

from VLMLegacy.CardReader import CardReader
rdr = CardReader ("../example/B767.dat","PRINTABLE")

iotypes = ["WINGTL","VLMPC","VLM4997"]
for iotype in iotypes:
packagename = "VLMLegacy." + iotype + ".Conditions"
classname = iotype + "_Conditions"
code = "from %s import Conditions as %s" \
% (packagename, classname)
x = compile (code,"foo","exec")
exec x
cls = globals()[classname]
a = cls(rdr,2)
a.test()
Right now your code boils down to:

from VLMLegacy.VLM4997.Conditions import Conditions as VLM4997_Conditions
from VLMLegacy.VLMPC.Conditions import Conditions as VLMPC_Conditions
from VLMLegacy.WINGTL.Conditions import Conditions as WINGTL_Conditions

And while you are, of course, allowed to do so, it's not the way you would
want to approach it in Python.

For each subpackage/module you could add an import and __all__ to
__init__.py to expose Conditions and then shorten it all to:

import VLMLegacy.VLM4997 as VLM4997
import VLMLegacy.VLMPC as VLMPC
import VLMLegacy.WINGTL as WINGTL

So that you can do:

a = VLM4997.Conditions(rdr, 2)
a.test()

If my proof of concept test code were actually all there was
you would be correct. But what I wish to accomplish is that
a string supplied from the command line does a run time load
of code that is not even explicitely mentioned in the main
body of the system.

myprogram --type NEWTYPE old.dat

Where NEWTYPE did not exist when the above code was written and
distributed. Think of the following scenario.

* Customer tells me, we have old data decks which are not
quite in any of the supported formats.

* I supply a new subpackage NEWTYPE with the varient code.

* They copy it into the package directory, VLMLegacy/NEWTYPE.

* They type the name of that package as a command line arg as
above.

* The code I wrote takes their string and dynamically binds
and uses the new code without changing anything else in
the code base.

Now I agree it is hackish. I don't really want to eval,
I just want to import a module whose name is contained
in a variable. I'm not unhappy with the second part where
I use globals()[thestring] to get from a string to a
class object; I am indeed bothered that I have to eval
to do the import as I have been unable so far to find
a way to make it work dynamically. I'd be perfectly happy
if something like this worked:

from VLMLegacy.CardReader import *
opts, args = p.parse_args()
iotype = opts.type
targetname = "Deck"
packagename = "VLMLegacy." + iotype + "." targetname
classname = iotype + "_" + targetname

# I only wish something like this worked...
from packagename import targetname as classname
Try:

cls = getattr(__import__(packagename), targetname)
cls = globals()[classname]

file = args[0]
rdr = CardReader(file,opts.punchtype)
a = cls(rdr,2)
a.read()

<do minutes or hours of calculations>

but it doesn't. Oh, and it gets worse later. The data I'm
reading is potentially straight off ancient Fortran decks
with no spaces between numbers. ;-)
 

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

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,537
Members
45,020
Latest member
GenesisGai

Latest Threads

Top