from os import listdir
modo= [name.split(".py")[0] for name in listdir("scripts") if name.endswith(".py")]
modules = {}
for modu in modo:
modules[modu] = __import__(modu)
test_samp.function("test")
Hello!
If, say "test_samp.py" exists in the scripts directory, why does
this not allow me to run test_samp.function("test")?
It returns:
Unhandled exception in thread started by <function function at 0x8e39204>
Traceback (most recent call last):
File "test_this.py", line 6, in function
test_samp.function("test")
NameError: global name 'test_samp' is not defined
You have two problems in your code:
__import__ doesn't import into global namespace, it returns a module
you're trying to import test_samp while it's scripts.test_samp
What you actually want is:
scripts = __import__("scripts", fromlist=modo)
scripts.test_samp.function("test")
Above __import__ returns scripts package with all the sub-modules loaded. Don't forget to make scripts directory a package by creating __init__.py in it.
See also: Why does Python's __import__ require fromlist?
Your are not defining test_samp you are defining modules['test_samp']. Plus if it's in scripts you need to import scripts.test_samp
in yor case use a package.Add an empty (or not) __init__.py (with 2 underscores). and use import scripts. Access your function with scripts.test_samp.function("test"). And you could use reload(scripts) to reload all of the package.
You can run it using this:
modules["test_samp"].function("test")
Related
I have split a project that i write from 1 file to several files
The thing is, that i have around 50 classes that I created and are called from the main file, I don't want to rewrite all those class references and add the module name before each class.
I tried to make all those classes accessible through 1 package (Tokens)
So I have
Main.py
Tokens /
__init__.py
Gen.py
BuilltIns.py
The Idea was to populate the package namespace with all the classes, and then import the package inside Main.py
__init__.py:
from Gen import *
from BuilltIns import *
Main.py:
from Tokens import *
When I ran __init__ it works perfectly, and dir() reveals that all class names are imported to package namepace.
However, when i run Main.py, I get the error message:
Traceback (most recent call last):
File "../Main.py", line 1, in <module>
from Tokens import *
File "..\Tokens\__init__.py", line 1, in <module>
from Gen import *
ModuleNotFoundError: No module named 'Gen'
How should I extract the 60+ classes from Main.py to other modules without rewriting all the calls for those classes?
You should use from Tokens.Gen import ... since Tokens is the package where the Gen module resides. The import path should be relative to the main script, unless you've modified the sys.path to specify additional directories to be searched during imports.
Alternatively, in Tokens/__init__.py you can do from .Gen import * (note the . before Gen). This denotes a relative import. What happens when you run the main script is that the current working directory is added to the paths to be searched during imports, so when from Gen import ... is encountered only the default locations are searched (which doesn't include the Tokens directory). By using a relative import you tell Python where it can find that module relative to the current one.
Note that you can define your classes in __all__ in order to constrain what will be imported during from ... import *. This way you don't leak other names in your main script's namespace.
Say I am using Python 3 (and hence absolute imports) and my directory structure looks like this:
> package:
> sub_directory
__init__.py
sub_dir_file.py
sub_dir_file2.py
__init__.py
main_dir_file.py
In the file sub_dir_file.py I wish to import a function from sub_dir_file2.py. The catch is, I want to be able to run sub_dir_file.py with __name__ == '__main__', as well as import it in main_dir_file.py. Hence, if in sub_dir_file.py I use a relative import:
from .sub_dir_file2 import some_function
the module executes perfectly fine when run from main_dir_file.py, but throws an error when executed directly (as the relative import cannot be executed when __name__ == '__main__'. If I however use a normal absolute import, sub_dir_file.py will execute as a main, but cannot be imported from main_dir_file.py.
What would be the most elegant way of solving this problem? One obvious solution seems to be:
if __name__ == '__main__':
from sub_dir_file2 import some_function
else:
from .sub_dir_file2 import some_function
However, it doesn't seem very pythonic.
You should use the relative import syntax from .sub_dir_file2 import some_function or eventually the absolute syntax from package.sub_directory.sub_dir_file2 import some_function.
Then, in order to call one of the package sub module, it is simpler to use the -m option of the python interpreter to execute its content as the __main__ module.
Search sys.path for the named module and execute its contents as the
main module.
Since the argument is a module name, you must not give a file
extension (.py). The module name should be a valid absolute Python
module name, but the implementation may not always enforce this (e.g.
it may allow you to use a name that includes a hyphen).
For example:
> python -m package.main_dir_file
> python -m package.sub_directory.sub_dir_file
I would suggest using a main() function invoked if name is __main__. It's a good habit anyway, as far as I'm aware.
That way you can just call the imported module's main() yourself. It has other benefits, too, like allowing you to test or re-invoke the module without necessarily executing the file every time.
I have 2 python scripts.
satellite_utils.py
apply_errata.py
The script that I run is :
python3.4 apply_errata.py
apply_errata.py calls functions defined in satellite_utils.py.
Now I am using the module logging to log my messages. I want to import this only once rather than having to declare this in every script.
If i define logging in apply_errata.py and a reference is made to it in satellite_utils.py, I get :
Traceback (most recent call last):
File "apply_errata.py", line 20, in <module>
satellite_utils.applyErrata(args.release, args.all, args.rollback)
File "/root/config-3.1.21/automated-os-patching/satellite_utils.py", line 34, in applyErrata
applyErrataOnSystem(system, release, automaticRollback, [erratum])
File "/root/config-3.1.21/automated-os-patching/satellite_utils.py", line 39, in applyErrataOnSystem
logging.warning('is when this event was logged.')
NameError: name 'logging' is not defined
Any way I can avoid an import statement in everyfile ?
You can use the logging instance in the satellite_utils like this:
# in apply_errata.py
import satellite_utils
satellite_utils.logger.info('hello there')
or
# in apply_errata.py
from satellite_utils import logger
logger.info('hi there')
This works because any name defined in a Python file is attached to the global scope of that file (in Python files are modules, so file == module), and is accessible to anyone.
It's import to point out that this is, shall we say, not the canonical and preferred way to do things. You're a grown-up, you can decide for yourself.
Why it's not bad to import modules multiple times: they get cached by Python in the sys.modules dict, so next time when you import you'll just get that cached copy. Python docs on sys.modules
You can do it by importing the necessary libraries in a script and then import everything in that script into another script using wildchar. By doing this you are not importing all of them again instead you are referencing them and they can be used in the second script as if you were using them in the friest script.
For example:
1. Script1.py
import logging
import something
.....
...
log_i=logging.info
log_d=logging.debug
Script2.py
from Script1 import * #import all in Script1
log_i("this is info log")
log_d("this is debug log")#use the imported data
Here logging is imported in Script1 and I'm importing all from Script1 to Script2 which means all the libraries,variables,function definitions used in Script1 is accessible and modifiable from Script2. Hence I'm using logging directly without any declaration/assignment in Script2.
As per #anugrah's comment you can use __init__.py to initialise the modules in a directory so that they can be imported and used like the above method. So if you choose this method then it will be like
abc/__init__.py
abc/modules.py
import logging,os,sys
log_i=logging.info
log_d=logging.debug
Script1.py
from abc.modules import log_* #now I'm importing only log_i,log_d
log_i("this is info log")
log_d("this is debug log")
I am trying to do a python script that it is divided in multiple files, so I can maintain it more easily instead of making a very-long single file script.
Here is the directory structure:
wmlxgettext.py
<pywmlx>
|- __init__.py
|- (some other .py files)
|- <state>
|- __init__.py
|- state.py
|- machine.py
|- lua_idle.py
if I reach the main directory of my project (where the wmlxgettext.py script is stored) and if I try to "import pywmlx" I have an import error (Attribute Error: 'module' object has no attribute 'state')
Here is the complete error message:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/user/programmi/my/python/wmlxgettext/true/pywmlx/__init__.py", line 9, in <module>
import pywmlx.state as statemachine
File "/home/user/programmi/my/python/wmlxgettext/true/pywmlx/state/__init__.py", line 1, in <module>
from pywmlx.state.machine import setup
File "/home/user/programmi/my/python/wmlxgettext/true/pywmlx/state/machine.py", line 2, in <module>
from pywmlx.state.lua_idle import setup_luastates
File "/home/user/programmi/my/python/wmlxgettext/true/pywmlx/state/lua_idle.py", line 3, in <module>
import pywmlx.state.machine as statemachine
AttributeError: 'module' object has no attribute 'state'
Since I am in the "project main directory" pywmlx should be on PYTHONPATH (infact I have no troubles when I tried to import pywmlx/something.py)
I'm not able to figure where is my error and how to solve this problem.
Here is the pywmlx/__init__.py source:
# all following imports works well:
from pywmlx.wmlerr import ansi_setEnabled
from pywmlx.wmlerr import wmlerr
from pywmlx.wmlerr import wmlwarn
from pywmlx.postring import PoCommentedString
from pywmlx.postring import WmlNodeSentence
from pywmlx.postring import WmlNode
# this is the import that does not work:
import pywmlx.state as statemachine
Here is the pywmlx/state/__init__.py source:
from pywmlx.state.machine import setup
from pywmlx.state.machine import run
But I think that the real problem is somewhat hidden in the "imports" used by one (or all) python modules stored in pywmlx/state directory.
Here is the pywmlx/state/machine.py source:
# State is a "virtual" class
from pywmlx.state.state import State
from pywmlx.state.lua_idle import setup_luastates
import pywmlx.nodemanip as nodemanip
def addstate(self, name, value):
# code is not important for this question
pass
def setup():
setup_luastates()
def run(self, *, filebuf, fileref, fileno, startstate, waitwml=True):
# to do
pass
Finally here is the pywmlx/state/lua_idle.py source:
import re
import pywmlx.state.machine as statemachine
# State is a "virtual" class
from pywmlx.state.state import State
# every state is a subclass of State
# all proprieties were defined originally on the base State class:
# self.regex and self.iffail were "None"
# the body of "run" function was only "pass"
class LuaIdleState (State):
def __init__(self):
self.regex = re.compile(r'--.*?\s*#textdomain\s+(\S+)', re.I)
self.iffail = 'lua_checkpo'
def run(xline, match):
statemachine._currentdomain = match.group(1)
xline = None
return (xline, 'lua_idle')
def setup_luastates():
statemachine.addstate('lua_idle', LuaIdleState)
Sorry if I posted so much code and so many files... but I fear that the files, in directory, hides more than a single import problem, so I published them all, hoping that I could explain the problem avoiding confusion.
I think that I miss something about how import works in python, so I hope this question can be useful also to other programmers, becouse I think I am not the only one who found the official documentation very difficult to understand when explaining import.
Searches Done:
Not Useful: I am already explicitly using import x.y.z all times I need to import something
Not Useful: Even if the question asks about import errors, it seems not useful for the same reason as (1)
Not Useful: As far as I know, pywmlx should be located into PYTHONPATH since "current working directory" on my tests is the directory that contains the main python script and pywmlx directory. Correct me if I am wrong
Python does several things when importing packages:
Create an object in sys.modules for the package, with the name as key: 'pywmlx', 'pywmlx.state', 'pywmlx.state.machine', etc.
Run the bytecode loaded for that module; this may create more modules.
Once a module is fully loaded and it is located inside another package, set the module as an attribute of the parent module object. Thus the sys.modules['pywmlx.state'] module is set as the state attribute on the sys.modules['pywmlx'] module object.
That last step hasn't taken place yet in your example, but the following line only works when it has been set:
import pywmlx.state.machine as statemachine
because this looks up both state and machine as attributes first. Use this syntax instead:
from pywmlx.state import machine as statemachine
Alternatively, just use
import pywmlx.state.machine
and replace statemachine. everywhere else with pywmlx.state.machine.. This works because all that is added to your namespace is a reference to the sys.modules['pywmlx'] module object and the attribute references won't need to be resolved until you use that reference in the functions and methods.
You are having a circular import in your framework. Circular imports do not work well with aliases. When importing a module with an alias and then, during the circular import, importing it again without an alias, python complains. The solution is to not use aliases (the "import module as" syntax) but always use the full "import module" statement.
im facing typical NameError (without any additional message) on command "cd" while importing other file.
E.g. executor.py
import sys
from java.lang import System
import ds_update
x = ds_update.DataSource()
x.someAction()
And ds_update.py
import sys
from java.lang import System
import sys
from java.lang import System
class DataSource:
def someAction(self):
try:
cd('/')
...
Got error: (if those commands are in one file, there is no problem with cd)
Problem invoking WLST - Traceback (innermost last):
File "...\executor.py", line 17, in ?
File "...\ds_update.py", line 11, in updateDS
NameError: cd
Thank you:-)
You're trying to use a function that isn't defined, namely cd(), according to your comments, it is something provided by WLST. I never used Jython nor WLST, but you have to find a way to import these methods in your script to be able to use them.
there are a few imports needed, namely at least:
import wl
the way to generate the wl module is described by Oracle here http://docs.oracle.com/cd/E15051_01/wls/docs103/config_scripting/using_WLST.html#wp1094333
then you should prefix with "wl." all your "cd" and other WLST built-in commands.
you will find more here
http://www.javamonamour.org/2013/08/wlst-nameerror-cd.html
Even though it is old, I want to add this:
WLST uses a type of namespace. because of this, functions pertaining to wlst don't work if you put the to-be-imported-files not in /wlserver_10.3/common/wlst