I have a file called dns_poison.py that needs to call a package called netscanner. When i try and load the icmpscan module from dns_poison.py I get this message:
ModuleNotFoundError: No module named 'icmpscan'
I've done a sys.path and can confirm that the correct path is in place. The files are located at D:\PythonProjects\Networking\tools and D:\PythonProjects appears when I do a sys.path.
Here is my directory structure:
dns_poison.py
netscanner/
__init__.py
icmpscan.py
Code snippets for the files are as follows:
dns_poison.py
import netscanner
netscanner\__init__.py
from icmpscan import ICMPScan
netscanner\icmpscan.py
class ICMPScan:
def __init__(self, target, count=2, timeout=1):
self.target = target
self.count = count
self.timeout = timeout
self.active_hosts = []
# further code below here....
I don't understand why it cannot find the module, as I've used this exact same method on other python projects without any problems. Any help would be much appreciated.
When you run python dns_poison.py, the importer checks the module path then the local directory and eventually finds your netscanner package that has the following available:
netscanner
netscanner.icmpscan
netscanner.icmpscan.ICMPScan
Now I ask you, where is just icmpscan? The importer cannot find because well, it doesnt exist. The PYTHONPATH exists at wherever dns_poison.py resides, and doesn't append itself to include the absolute path of any imported modules because that simply not how it works. So netscanner can be found because its at the same level as dns_poison.py, but the importer has no clue where icmpscan.py exists because you havent told it. So you have two options to alter your __init__.py:
from .icmpscan import ICMPScan which works with Python 3.x
from netscanner.icmpscan import ICMPScan which works with both Python 2.x/3.x
Couple of references for you:
Python Import System
Python Modules recommend you ref section 6.4.2 Intra-package References
The most simple way to think about this is imports should be handled relative to the program entry-point file. Personally I find this the most simple and fool-proof way of handling import paths.
In your example, I would have:
from netscanner.icmpscan import ICMPScan
In the main file, rather than add it to init.py.
Related
I'm using Python 3.95, and have two files:
shapes.py, which defines class Circle, class Square, and class Triangle
textures.py, which defines class Smooth and class Rough
I'd like to be able to do something like:
from .shapes import *
but I get error ImportError: attempted relative import with no known parent package.
All files are stored in the same folder, and I'm trying to execute Python from that folder, on Python files stored in that folder.
There are numerous posts on SO describing this error, and I've tried their solutions, but to no avail. It seems like some of this depends on Python 2 vs 3, some depends on which folder you're executing from, some depends on packages and modules (which I do not entirely understand).
Some things I've tried which have not worked:
Creating an __init__.py file
Using from shapes import * instead of from .shapes import *
Using from .shapes import Circle
Adding these lines:
import sys
import os
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
sys.path.append(os.path.dirname(SCRIPT_DIR))
This is likely a basic mistake: I'm not trying to build a module or package for distribution, I simply want to put different classes into different files, instead of all my classes in one giant file. How can I do so?
The current directory is only prepended to sys.path automatically if the script is the python file (not if the script is the first argument to python like python app.py).
I think that you can either:
add #! /usr/bin/env python at the start of the main file and make it executable with chmod +x main.py
append the right directoy to sys.path, as it seems to me that you are trying to append the parent dir. SCRIPT_DIR in your last attempt is already the current directory and you don't need to call dirname on it again.
There's no need for a relative import if your main script needs to use a module in the same folder. If you have a main.py and a shapes.py (containing for example a function fun1()), just use any of these:
import shapes
shapes.fun1()
from shapes import fun1
fun1()
from shapes import *
fun1()
Note that the latter is not preferable, since it's not at all clear what you're importing and if shapes.py is later changed to include something that shadows something from an earlier import, it may break your code in surprising ways. Surprise is bad.
If you're writing a package called shapes, create a folder called shapes, put an __init__.py in it, and a Python file which could be called shapes.py or anything you want, as you'll be importing what's relevant from the __init__.py.
Then shapes/__init__.py could be something like:
from .shapes import *
Here, using the * makes a bit more sense, although I'd still favour from .shapes import fun1. The . is not needed, but here it makes sense, because it is relative to another file that's also in the package.
And shapes/shapes.py might be something like:
from .other_mod import fun2
def fun1():
fun2()
Here, the . makes sense if shapes.py and other_mod.py are always going to be sitting next to each other in the package, but perhaps move around within the internal structure. Or perhaps you want to use the explicit . to avoid conflicts with other names.
If other_mod.py is something like:
def fun2():
print('hello')
You could write a main.py in the same folder where the shapes folder sits and the code with shapes imports above would work.
Can you try create new folder and add [shapes.py,textures.py,init.py] files into shapes folder
backend/
|
|------folder_shapes/shapes.py
|------folder_shapes/textures.py
|------folder_shapes/__init__.py
|------your_script.py
|
Then try import from your_script.py
In a project, I want to dynamically import the right module based on a version-number.
For this I'm using importlib, and works find as long as the package is part of the source.
AdminApi = import_module(f"{self.version}", "AdminApi").AdminApi
The folder-structure looks like:
Admin-Package /
- __init__.py # Contains dynamic class loader
- admin64/
- __init__.py # contains AdminApi v6.4
- ...
- admin65/...
- __init__.py # contains AdminApi v6.5
- ...
However, now I find myself needing to decouple the code into its own package to re-use in another project. So I've packaged this part of the source. This however seems to cause path-related issues. This seems to mean that importlib cannot help me.
So far, thanks to: https://stackoverflow.com/a/54138717/5731101
I've come to this point:
import importlib
from pathlib import Path
path = Path(__file__).resolve().parent
script_path = os.path.join(path, version, '__init__.py')
spec = importlib.util.spec_from_file_location(f"AdminApi", script_path)
AdminApi = importlib.util.module_from_spec(spec)
spec.loader.exec_module(AdminApi)
Unfortunately the spec.loader.excec_module fails with error: ModuleNotFoundError: No module named 'AdminApi' Even thought the class is clearly available in the file supplied via the path.
I would be grateful if anyone can help me out on this.
I decided to try another tool in the toolbox of importlib Based on this answer: https://stackoverflow.com/a/67692/5731101
from importlib.machinery import SourceFileLoader
foo = SourceFileLoader("AdminAPI", "/path/to/file.py").load_module()
foo.AdminAPI()
This approach had no problems detecting the class and simply imported everything correctly.
I have a Python module which uses some resources in a subdirectory of the module directory. After searching around on stack overflow and finding related answers, I managed to direct the module to the resources by using something like
import os
os.path.join(os.path.dirname(__file__), 'fonts/myfont.ttf')
This works fine when I call the module from elsewhere, but it breaks when I call the module after changing the current working directory. The problem is that the contents of __file__ are a relative path, which doesn't take into account the fact that I changed the directory:
>>> mymodule.__file__
'mymodule/__init__.pyc'
>>> os.chdir('..')
>>> mymodule.__file__
'mymodule/__init__.pyc'
How can I encode the absolute path in __file__, or barring that, how can I access my resources in the module no matter what the current working directory is? Thanks!
Store the absolute path to the module directory at the very beginning of the module:
package_directory = os.path.dirname(os.path.abspath(__file__))
Afterwards, load your resources based on this package_directory:
font_file = os.path.join(package_directory, 'fonts', 'myfont.ttf')
And after all, do not modify of process-wide resources like the current working directory. There is never a real need to change the working directory in a well-written program, consequently avoid os.chdir().
Building on lunaryorn's answer, I keep a function at the top of my modules in which I have to build multiple paths. This saves me repeated typing of joins.
def package_path(*paths, package_directory=os.path.dirname(os.path.abspath(__file__))):
return os.path.join(package_directory, *paths)
To build the path, call it like this:
font_file = package_path('fonts', 'myfont.ttf')
Or if you just need the package directory:
package_directory = package_path()
A little bit of an explanation of my situation before my question.
I created a module called foo. foo's location in the file system is
/runtime/foo
and the script "test.py" which imports foo by using sys.path.append() is located in.
/runtime/bar/test.py
Foo's structure is as follows
foo
mtr.txt
__init__.py
datasources.py
I would like a class within datasources.py to open the file mtr.txt. However, I am not able to do this without explicting giving a path within datasources. In this case it would be
/runtime/foo/mtr.txt
My code will work if I do give it this path, but this is something that should be doable, but I can't find the answer.
I have tried the following commands within a class in datasources.py.
open("mtr.txt")
open("./mtr.txt")
and a few other things using the os.path.dirname()
Is there a way to open the file 'mtr.txt' without giving its full path within datasources.py?
Thanks
Use pkg_resources
import pkg_resources
data = pkg_resources.resource_string(__name__, "mtr.txt")
There are more methods provided by this package, check the docs for Resource Manager API.
i need to call a function from from one python class to another which are at different directories.
I'm using Eclipse and PyDev for developing scripts.
sample.py
class Employee:
def meth1(self,arg):
self.arg=arg
print(arg)
ob=Employee()
ob.meth1("world")
main.py
class main:
def meth(self,arg):
self.arg=arg
print(arg)
obj1=main()
obj1.meth("hello")
I need to access meth1 in main.py
updated code
main.py
from samp.sample import Employee
class main:
def meth(self,arg):
self.arg=arg
print(arg)
obj1=main()
obj1.meth("hello")
After executing main.py it is printing "world" automatically without calling it.
my requirement is i need to call meth1 from main.py explicitly
please find my folder below
import is the concept you need here. main.py will need to import sample and then access symbols defined in that module such as sample.Employee
To ensure that sample.py can be found at import time, the path to its parent directory can be appended to sys.path (to get access to that, of course, you will first need to import sys). To manipulate paths (for example, to turn a relative path like '../samp' into an absolute path, you might want to import os as well and take a look at the standard library functions the sub-module os.path has to offer.
You will have to import the sample.py file as a module to your main.py file. Since the files are in different directories, you will need to use the __init__.py
From the documentation:
The __init__.py files are required to make Python treat the directories as containing packages; this is done to prevent directories with a common name, such as string, from unintentionally hiding valid modules that occur later on the module search path. In the simplest case, __init__.py can just be an empty file, but it can also execute initialization code for the package or set the __all__ variable, described later.
Here is a related stack overflow question which explains the solution in more detail.
It's generally not a good idea to alter the sys.path variable. This can make scripts non-portable. Better is to just place your extra modules in the user site directory. You can find out what that is with the following script.
import os
import sys
import site
print(os.path.join(site.USER_BASE, "lib", "python{}.{}".format(*sys.version_info[0:2]), "site-packages"))
Place your modules there. Then you can just import as any other module.
import sample
emp = sample.Employee()
Later you can package it using distutils or setuptools and the imports will still work the same.