Suppose I provide a module in the command line and want to import it using the "imp" module:
$ foo.py mod.a.b.c
What is the proper way of doing this?
Split the "mod.a.b.c" and add each path? The behaviour of "imp" does not seem to be parallel to "import".
Given a module path as a string (modulename), you can import it with
module = __import__(modulename,fromlist='.')
Note that __import__('mod.a.b.c') returns the package mod, while __import__('mod.a.b.c',fromlist='.') returns the module mod.a.b.c.
Related
I am using django and I have a file named models.admin.py and I want to do the following idea in models.py:
from "models.admin" import *
however, I get a syntax error for having double quotes. But if I just do
from models.admin import *
then I get "ImportError: No module named admin"
Is there any way to import from a python file that has a period in its name?
Actually, you can import a module with an invalid name. But you'll need to use imp for that, e.g. assuming file is named models.admin.py, you could do
import imp
with open('models.admin.py', 'rb') as fp:
models_admin = imp.load_module(
'models_admin', fp, 'models.admin.py',
('.py', 'rb', imp.PY_SOURCE)
)
But read the docs on imp.find_module and imp.load_module before you start using it.
If you really want to, you can import a module with an unusual filename (e.g., a filename containing a '.' before the '.py') using the imp module:
>>> import imp
>>> a_b = imp.load_source('a.b', 'a.b.py')
>>> a_b.x
"I was defined in a.b.py!"
However, that's generally a bad idea. It's more likely that you're trying to use packages, in which case you should create a directory named "a", containing a file named "b.py"; and then "import a.b" will load a/b.py.
The file is called models/admin.py. (Source)
That is, it should be called admin.py in a directory called models.
Then you can import using from models.admin import *, assuming that it is in your Python path.
Like below
Assume dir structure is like this:
C:.
│ script.py
│
└───Parent
└───Child
├───1.1
│ main.py
│
└───1.2
**assume you want to import main.py in script.py **
your main.py looks like below
def my_function():
print("Hello from a function")
your script.py looks like below
from os import path
import importlib
from os.path import dirname
import sys
import importlib.util
def getPath():
# your logic to get to the path
return path.join(dirname(__file__),'Parent','Child','1.1','main.py')
file_path = getPath()
module_name = 'main'
spec = importlib.util.spec_from_file_location(module_name, file_path)
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
#call functions like this
module.my_function()
Check out this gist
No, you can't import a python file as a module if its name contains a period (or a question mark, or exclamation mark, etc). A python module's name (not including the .py) must be a valid python name (ie can be used as a variable name).
In my case, I am using grafanalib, and the filename has to be xx.dashboard.py based on the doc. However, I do want to import this file to simplify the uploading step.
I got warning when I use import imp:
the imp module is deprecated in favour of importlib and slated for removal in Python 3.12; see the module's documentation for alternative uses
Here is the simple demo using importlib and pathlib:
foo.bar.py and main.py are in the same foler.
# foo.bar.py
num = 42
# main.py
import importlib.machinery
import pathlib
module = importlib.machinery.SourceFileLoader(
"foo_bar",
pathlib.Path(__file__).parent.joinpath("foo.bar.py").resolve().as_posix(),
).load_module()
print(module.num) # 42
You are not referencing files in the import statement, you are referencing modules and packages.
Please read the docs, they are very clear on that matter.
Anyway, since you are using django, the usual approach won't work. If you want to keep models in separate files, rather than in models.py, you have to take extra steps, outlined, for example, here.
Edit:
Well, I don't really know what the questioneer means when he mentions admin and whether or not it is related to the admin interface of django. My points still stand.
In python 2 I can create a module like this:
parent
->module
->__init__.py (init calls 'from file import ClassName')
file.py
->class ClassName(obj)
And this works. In python 3 I can do the same thing from the command interpreter and it works (edit: This worked because I was in the same directory running the interpreter). However if I create __ init __.py and do the same thing like this:
"""__init__.py"""
from file import ClassName
"""file.py"""
class ClassName(object): ...etc etc
I get ImportError: cannot import name 'ClassName', it doesn't see 'file' at all. It will do this as soon as I import the module even though I can import everything by referencing it directly (which I don't want to do as it's completely inconsistent with the rest of our codebase). What gives?
In python 3 all imports are absolute unless a relative path is given to perform the import from. You will either need to use an absolute or relative import.
Absolute import:
from parent.file import ClassName
Relative import:
from . file import ClassName
# look for the module file in same directory as the current module
Try import it this way:
from .file import ClassName
See here more info on "Guido's decision" on imports in python 3 and complete example on how to import in python 3.
I'm trying to import a class from a module named my_classes.py. Problem is, it's located within a directory called #file_directory.
So the structure is, I have main.py at the top of the project directory, and also a directory called lib at the same level. Within 'lib' there is subdirectory named '#file_directory' and within it a module 'my_classes' as shown below.
-> main.py
-> /lib
-> lib_other_files.py
-> /#file_directory
-> my_classes.py
What I can usually do is
from lib.#file_directory.myclasses import cust_class
But because the # symbol is a wrapper symbol, it prevents me from importing files from '#file_directory'. The simple soultion is of course, just change the directory name but I want to keep the file name/don't have the rights to change it in the project. Is there a way to use like a escpae character to import module from a directory with special characters?
Another possibility: use the __import__() built-in function. This is essentially removing the overhead of the normal import command, but it allows you more flexibility in package-naming because it just takes a string as an argument - and that string can escape the otherwise-invalid characters.
So, this code should work:
_temp = __import__("lib.#file_directory.myclasses", globals(), locals(), ['cust_class'], 0)
cust_class = _temp.cust_class
Edit: The python standard library recommends using importlib instead. The same code would look like this in that:
import importlib
cust_class = importlib.import_module("lib.#file_directory.myclasses", "cust_class")
You can not import modules with characters like the '#' symbol... however, using execfile may be an appropriate workaround for you.
Tested with Python 2.7.5
my_classes.py example code:
def printMe():
print "foo from my_classes"
main.py example code:
execfile("./lib/#file_directory/my_classes.py")
printMe()
Executing main.py prints out:
>>python main.py
foo from my_classes
Whats happening is main.py will run the my_classes.py file and now you can directly reference functions or any relevant code from my_classes.py.
Python 3.X Equivalent
I dont have python 3 installed but they did remove execfile.. the alternative for execfile would be:
exec(open("./lib/#file_directory/my_classes.py").read())
Hope this helps you accomplish your needs.
Assuming my directory structure is:
C:\Scripts\myscript.py
C:\Scripts\customjson\json.py
The myscript.py python script has at the top:
sys.path.append(os.path.join(os.path.dirname(sys.argv[0]), 'customjson'))
import json
The thing is, I have a "customjson" folder that contains a json.py that I want to use instead of the default json package that Python 2.7 comes with. How do I make it so that the script uses "customjson" instead of the standard json?
Try to insert your customjson directory first in sys.path:
sys.path.insert(0, os.path.join(os.path.dirname(sys.argv[0]), 'customjson'))
import json
You could use something like this:
import sys
_orig_path = sys.path
sys.path = ["C:\Scripts\customjson"]
import json
sys.path = _orig_path
But, of course, that code wouldn't be portable. To make it portable, you could use:
import sys, os
_orig_path = sys.path
sys.path = [
os.path.abspath(os.path.join(os.path.dirname(__file__), "customjson")),
]
import json
sys.path = _orig_path
Or, you could rename json.py to, for example, json2.py. And then import it:
import json2
or, if you absolutely need it to be named json:
import json2 as json
..yeah, the second one looks better, doesn't it?
I say: Make your customjson folder a package.
It's easy:
Create a file named __init__.py in your customjson folder. The file can be empty if you don't want anything special defined at the package level.
Change your import statement to refer to the module within the package (i.e. import customjson.json).
Change your references to the module to use the full path (customjson.json.whatever), or instead further change your import statement to include as as clause (import customjson.json as json). If you're using from ... import ... syntax, this is unnecessary. While using an as clause may be easier than rewriting your accesses, it may confusing any other programmer who reads your code and expects it to be using the standard json module.
Given the folder layout you describe in the question, you won't need to mess around with the module search path at all if you go this route, since the running script's current folder is always included in the path and that's where the customjson package is located.
I haven't come across this problem yet, but I'm curious about how to import a module that has the same name as a sub-package. For instance, a possible module-structure could look like this:
mymodule\
__init__.py
string.py
Now, what if I need the mymodule.string subpackage and the string module that is delivered with every Python distribution from a package that is within the same directory, such as __init__.py? The following lines of code all import the subpackage.
from . import string
import mymodule.string as string
import string
In Python 2.5 or 2.6, you can use:
>>> from __future__ import absolute_import
Which tells Python that all imports that aren't explicitly relative should be treated as absolute. I.e., after using this declaration, you can access both the builtin string module and your own string module using:
>>> import string as the_builtin_string_module
>>> from . import string as my_package_string_module
I believe that this becomes the default in Python 2.7 (and Python 3.0).
For more info, see: http://www.python.org/dev/peps/pep-0328/#rationale-for-absolute-imports
You don't have to import it as a top level import.
Just import mymodule.string, foo = mymodule.string.baz(), etc.
If you really want to use the subpackage as string, you can import it as string, but first do something like import string as builtinstring