How to import Python code from a source file? - python

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.

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.

Access files relative to imported python module

Preliminary:
I have Anaconda 3 on Windows 10, and a folder, folder_default, that I have put on the Python path. I'm not actually sure whether that's the right terminology, so to be clear: regardless to where my Python script is, if I have a line of code that says import myFile, that line of code will succeed if myFile.py is in folder_default.
My issue:
In folder_default, I have:
A subfolder called useful_files which contains a text file called useful_file_1.txt.
A python script called my_misc.py.
my_misc.py has a line similar to: np.loadtxt('useful_files/useful_file_1.txt'). This line does not work if I use import my_script in a python file in a location other than folder_default, since useful_files/useful_file_1.txt is not the folder path relative to the python file that imports my_misc.py. I don't want to start using global file paths if I can avoid it.
How can I access files using file paths relative to the imported python module, rather than relative to the python script that imports that module?
Please let me know if the question is unclear - I tried to write a fake, minimal version of the setup that's actually on my computer in the hopes that that would simplify things, but I can change it if that actually makes things more confusing.
Thanks.
You can get the path to current module using the getfile method of inspect module as inspect.getfile(inspect.currentframe()).
For example:
# File : my_misc.py
import os, inspect
module_dir_path = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))) # get path to the directory of current module
useful_file_path = os.path.join(module_dir_path,'useful_files','useful_file_1.txt')
# path stored in useful_file_path. do whatever you want!
np.loadtxt(useful_file_path)

Making a directory for a file

I was making a exercise generator algorithm for my friend, but I stumbled across a problem. It is a python program, and I wanted to generate a folder in a directory that was above the program's location (like, the python file is in 'C:\Documents\foo' and the folder should be created in 'C:\Documents') so that it could then store the file the program created. Is there a way to do this or should I try something else?
Use the path argument of the os.mkdir() function.
Getting the current script directory is not a built-in feature, but there are multiple hacks suggested here.
Once you get the current script directory, you can build a path based off of that.
Not super familiar with Python in a Windows environment, but this should be easily do-able. Here is a similar question that might be worth looking at: How to check if a directory exists and create it if necessary?
Looks like the pathlib module might do what you are looking for.
from pathlib import Path
path = Path("/my/directory/filename.txt")
try:
if not path.parent.exists():
path.parent.mkdir(parents=True)
except OSError:
# handle error; you can also catch specific errors like
# FileExistsError and so on.
Appears to work on Win 7 with Python 2.7.8 as described:
import os.path
createDir = '\\'.join((os.path.abspath(os.path.join(os.getcwd(), os.pardir)), 'Foo'))
if not os.path.exists(createDir):
os.makedirs(createDir)

mixing multiple python module path's

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.

Python: Importing an "import file"

I am importing a lot of different scripts, so at the top of my file it gets cluttered with import statements, i.e.:
from somewhere.fileA import ...
from somewhere.fileB import ...
from somewhere.fileC import ...
...
Is there a way to move all of these somewhere else and then all I have to do is import that file instead so it's just one clean import?
I strongly advise against what you want to do. You are doing the global include file mistake again. Although only one module is importing all your modules (as opposed to all modules importing the global one), the remaining point is that if there's a valid reason for all those modules to be collected under a common name, fine. If there's no reason, then they should be kept as separate includes. The reason is documentation. If I open your file, and see only one import, I don't get any information about what is imported and where it comes from. If on the other hand, I have the list of imports, I know at a glance what is needed and what not.
Also, there's another important error I assume you are doing. When you say
from somewhere.fileA import ...
from somewhere.fileB import ...
from somewhere.fileC import ...
I assume you are importing, for example, a class, like this
from somewhere.fileA import MyClass
this is wrong. This alternative solution is much better
from somewhere import fileA
<later>
a=fileA.MyClass()
Why? two reasons: first, namespacing. If you have two modules having a class named MyClass, you would have a clash. Second, documentation. Suppose you use the first option, and I find in your code the following line
a=MyClass()
now I have no idea where this MyClass comes from, and I will have to grep around all your files in order to find it. Having it qualified with the module name allows me to immediately understand where it comes from, and immediately find, via a /search, where stuff coming from the fileA module is used in your program.
Final note: when you say "fileA" you are doing a mistake. There are modules (or packages), not files. Modules map to files, and packages map to directories, but they may also map to egg files, and you may even create a module having no file at all. This is naming of concepts, and it's a lateral issue.
Of course there is; just create a file called myimports.py in the same directory where your main file is and put your imports there. Then you can simply use from myimports import * in your main script.

Categories

Resources