mixing multiple python module path's - python

I have ran into strange problem, which I cannot find an answer.
I want to use file which may be located in different modules, with same path names (folders contain empty init.py files as well):
road1/pato/
road2/pato/modtest.py
where modtest contains simply a=1
Simple script for testing, test.py , contains:
import pato.modtest
print(pato.modtest.a)
and running
PYTHONPATH=road2/ python test.py
runs fine as expected. What is confusing, is that
PYTHONPATH=road1/:road2/ python test.py
gives an error
ImportError: No module named 'pato.modtest'
All the documentation I have read states that PYTHONPATH may contain multiple path-s and it should be just fine, running program is just looking through them in order. In this case, however, adding empty path in the front of path seem to prevent reading from later path's. If this is expected behaviour, fine, I'd appreciate links to good docs about it.

You have a namespace clash.
According to your PYTHONOPATH, when you import "pato.modtest" Python first looks if "pato" or "pato.modtest" are present in the current namespace.
As they are not present it then goes to sys.path and tries the first path which in your case is "road1/".
It finds the module "pato" there and then looks for object "modtest", not having found, it looks for a module road1/pato/modtest, not having found, it gives up.

Related

Nested function causing troubles

I've got a Python script.
I've had several functions in this script which I decided to move to a 'package' folder beside the main script.
In this folder, I created a *.py file where I put all my functions.
I've placed an empty init.py near this file within the 'package' folder.
When starting the code of my main script with:
from package_folder.my_functions import *
the script works well when calling every functions from that file.
But when trying to import it directly:
import package_folder.my_functions
it doesn't seems to work as well as with the above technique.
The cause seems to be the fact that in the file wellmy_functions.py, I have a function that needs an other one, declared previously in that file.
I had this obscure error on that function that needs an other one:
TypeError: 'NoneType' object is not callable
Is this permissible and if not, how to manage this case?
It's generally not a good idea to use from module import *. Wildcard importing leads to namespace pollution; you imported more names than you need and if you accidentally refer to an imported name you may not get the NameError you wanted.
Also, if a future version of the library added additional names, you could end up masking other names, leading to strange bugs still:
Example
from my_mod1 import func1
from my_mod2 import *
If you upgrade my_mod2 and it now includes a my_mod2.func1 it'll replace the my_mod1.func1 import in the 1st line.

Python 2.7 strange import warning

I have a weird error re: imports in Python 2.7 when one script calls a different script which calls a different script - testbench.py imports user.py imports hardware.py
testbench.py runs a hardware testbench
user.py takes user input (Specifically, the serial number of the hardware to test)
hardware.py has some information about valid #SNs (In the integer highestSerial)
user.py uses the hardware.highestSerial variable
In both cases, the workflow is like this:
>>>python
>>>import user
>>>help(user)
>>>exit()
>>>python testbench.py
CASE 1
\\testbench.py
\\user.py
\\hardware.py
\\__init__.py
\\hardware\\__init__.py
\\hardware\\hardwareList.txt
Output 1
No warnings from help(user)
Calling the script outputs: AttributeError: 'module' object has no attribute 'highestSerial'
CASE 2
\\testbench.py
\\user.py
\\hardware.py
\\__init__.py
\\hardware\\hardwareList.txt
Output 2
help(user) outputs: __warningregistry__ = {(Not importing directory 'hardware': missing _...
calling the script works fine
Difference between cases
In the first case, there is a hardware folder with__init__.py in it - there are no warnings, but the code breaks (Because the attribute I'm looking for isn't in the folder)
In the second case, there is no hardware folder so I get a Not importing directory warning but the code works fine.
Now obviously I could just rename some things but do any of you know what is going on behind the scenes?
EDIT And things go completely crazy when I put hardware.py inside \hardware\ but we'll forget that scenario temporarily
EDIT 2 My thinking has been that I want to make a hardware.py script to access all the things in the \hardware\ folder - serial number list, hardware types etc., none of which is in python but rather in .txt files, .csv files etc. Is that an entirely mistaken way to do things?
You have both a hardware package and a hardware module. Don't. Rename one or the other; Python has to inspect the hardware directory too.
In case 1, the hardware/__init__.py package is being imported before the hardware.py module is found, and it appears you left the __init__.py file empty, so trying to access highestSerial raises an attribute error.
In case 2, the hardware directory is inspected for a __init__.py file first, raising a warning to let you know that that file is missing; this is to prevent a common error made by beginnning Python developers that forget to create that file.
Python then does find hardware.py and imports that instead.
You should not use directory names that match module names. Just rename hardware.py (and adjust your imports) or rename the directory.

How to import Python code from a source file?

I was hesitant about asking this because I've seen similar questions with overly complicated answers. The question I actually want answered to was closed on account of being "vague" and "not a real question", so I will be as specific as possible.
I have an object called "line" in a file called "line.py". I want to create another object that inherits from "line" called "line_segment" and put it in a file called "line_segment.py" in the same directory.
path_finding_lib/
line.py
line_segment.py
a_star.py
The problem is I can't seem to find a way to use the code in "line.py" from inside "line_segment.py" without appending strings to the system PATH variable and stuff like that.
Isn't there a way to import code from a file path or something like that? If not, why not?
While you could append to the python path for a particular file using:
import sys
sys.path.append('pathtoModule')
If they are in the same folder, (not a module, as you lack an init.py), you can simply import from the line module by doing:
from line import Line
class LineSegment(line):
Naming convention supplies underscores and lowercases for modules, Capitalized for Classes:
http://www.python.org/dev/peps/pep-0008/
It is nonstandard and will likely lead to trouble if you dynamically append to the python path in your project, as it will cause errors in object comparison.
If you have an object declared as follows:
path_finding_lib/
line.py
line_segment.py
a_star.py
somemodule/
afile.py
If your line module imports and instantiates an object from afile using the path somemodule.afile.SomeObject
It is not the same class as instantiating an object from within afile:
afile.SomeObject.
If afile returns an instance of afile.SomeObject and the object is compared for equality to an instance of somemodule.afile.SomeObject, they will be found to be not equivalent.
i.e.
somemodule.afile.SomeObject == afile.SomeObject
==> False
The easiest way to use python code in other files is to use import statement.
Say when you do
import xyz
Python will attempt to find the file xyz.py. It looks into
The site-packages folder (which is the folder in your python installation directory which contains pre-installed modules like say django etc)
Locations mentioned in PYTHONPATH environment variable (or sys.path in python)
Your current directory
In your case, your program should have the following line
from line import line
Where first line is your line.py file and second line is your class
Wherever you want to use line object for inheritance just use
class newline(line):
The catch is how you run the program. If you run it from within path_finding_lib (i.e. when your working directory is path_finding_lib and you do
python line_segment.py
, it should work (You can optionally also make a blank file init.py in the same folder).
If you run it from say your home directory
~$ python /path_to/path_finding_lib line_segment.py
It will NOT work. This is because python will search site-packages, PYTHONPATH and your current directory and not find line.py. To be able to run it from everywhere, before you run it add location of line.py to the PYTHONPATH
$export PYTHONPATH=/path_to/path_finding_lib
Then you should be able to run it
NOTE: I have assumed you have a linux ystem. For Windows unfortunately I do not know the procedure of modifying PYTHONPATH
Since they're in the same directory, create an empty file named __init__.py. This lets Python treat the directory you're working from as a package, and you'll be able to pull objects and methods from these other files.

How to get the current running module path/name

I've searched and this seems to be a simple question without a simple answer.
I have the file a/b/c.py which would be called with python -m a.b.c. I would like to obtain the value a.b.c in the module level.
USAGE = u'''\
Usage:
python -m %s -h
''' % (what_do_i_put_here,)
So when I receive the -h option, I display the USAGE without the need to actually write down the actual value in each and every script.
Do I really need to go through inspect to get the desired value?
Thanks.
EDIT: As said, there are answers (I've searched), but not simple answers. Either use inspect, use of traceback, or manipulate __file__ and __package__ and do some substring to get the answer. But nothing as simple as if I had a class in the module, I could just use myClass.__module__ and I would get the answer I want. The use of __name__ is (unfortunately) useless as it's always "__main__".
Also, this is in python 2.6 and I cannot use any other versions.
This works for me:
__loader__.fullname
Also if I do python -m b.c from a\ I get 'b.c' as expected.
Not entirely sure what the __loader__ attribute is so let me know if this is no good.
edit: It comes from PEP 302: http://www.python.org/dev/peps/pep-0302/
Interesting snippets from the link:
The load_module() method has a few responsibilities that it must
fulfill before it runs any code:
...
It should add an __loader__ attribute to the module, set to the
loader object. This is mostly for introspection, but can be used
for importer-specific extras, for example getting data associated
with an importer.
So it looks like it should work fine in all cases.
I think you're actually looking for the __name__ special variable. From the Python documentation:
Within a module, the module’s name (as a string) is available as the value of the global variable __name__.
If you run a file directly, this name will __main__. However, if you're in a module (as in the case where you're using the -m flag, or any other import), it will be the complete name of the module.
When run with -m, sys.path[0] contains the full path to the module. You could use that to build the name.
source: http://docs.python.org/using/cmdline.html#command-line
Another option may be the __package__ built in variable which is available within modules.
Number of options are there to get the path/name of the current module.
First be familiar with the use of __file__ in Python, Click here to see the usage.
It holds the name of currently loaded module.
Check/Try the following code, it will work on both Python2 & Python3.
» module_names.py
import os
print (__file__)
print (os.path.abspath(__file__))
print (os.path.realpath(__file__))
Output on MAC OS X:
MacBook-Pro-2:practice admin$ python module_names.py
module_names.py
/Users/admin/projects/Python/python-the-snake/practice/module_names.py
/Users/admin/projects/Python/python-the-snake/practice/module_names.py
So here we got the name of current module name and its absolute path.
The only way is to do path manipulation with os.getcwd(), os.path, file and whatnot, as you mentioned.
Actually, it could be a good patch to implement for optparse / argparse (which currently replace "%prog" in the usage string with os.path.basename(sys.argv[0]) -- you are using optparse, right? -- ), i.e. another special string like %module.
Why does nobody mentioned the .__module__?
When doing a self.__module__ you will get the module path.
You can also do this outside of the class:
Class A:
self.__module__ # gets module.filename
def get_module():
A.__module__ # also gets module.filename
One liner But OS dependent
it does not work in interpreter! since file is meaningless there in the interpreter and is not defined.
does not require os module to be imported.
modulename=__file__.split("\\")[-1].split('.')[0]
Explanation:
X:\apple\pythonabc.py | will output pythonabc.py
select the last element after splitting with slashes, then select the first element by splitting it with dot '.'. because first step gives module.py, second step gives 'module' only. __file__ is a unique variable and returns the filepath of current module.
Comment any flaws or has any other pitfalls.
you should hardcode a.b.c in your help, if you distribute the package as such then that's the way to call it regardless of where a is located in the filesystem, as long as it's on the PYTHONPATH it'll be imported.

Dynamically importing modules in Python3.0?

I want to dynamically import a list of modules. I'm having a problem doing this. Python always yells out an ImportError and tells me my module doesn't exist.
First I get the list of module filenames and chop off the ".py" suffixes, like so:
viable_plugins = filter(is_plugin, os.listdir(plugin_dir))
viable_plugins = map(lambda name: name[:-3], viable_plugins)
Then I os.chdir to the plugins directory and map __import__ the entire thing, like so:
active_plugins = map(__import__, viable_plugins)
However, when I turn active_plugins into a list and try to access the modules within, Python will throw out an error, saying it cannot import the modules since they don't appear to be there.
What am I doing wrong?
Edit: By simply using the interactive interpreter, doing os.chdir and __import__(modulefilename) produces exactly what I need. Why isn't the above approach working, then? Am I doing something wrong with Python's more functional parts?
It says it can't do it, because even though you're changing your directory to where the modules are, that directory isn't on your import path.
What you need to do, instead of changing to the directory where the modules are located, is to insert that directory into sys.path.
import sys
sys.path.insert(0, directory_of_modules)
# do imports here.

Categories

Resources