"Global name not defined" error - python

There are several posts around this error I have already read, but I still don't get what I am doing wrong.
I put it into a minimal example:
Imagine I have a Doc.py, and the package Tools which includes Tool1.py and Tool2.py.
Doc.py:
from Tools import *
import sys
def __main__():
TOOL_REPORT("Tool1","Test")
def TOOL_REPORT(tool, path):
if(tool == 'Tool1'):
Tool1.REPORT(path)
elif(tool == 'Tool2'):
Tool2.REPORT(path)
else:
sys.stderr.write("This tool is not yet included in Doc. Please check TOOLS for more information.")
if __name__=="__main__": __main__()
Tool1.py:
def REPORT(path):
print("Tool1 "+path)
Tool2.py:
def REPORT(path):
print("Tool2 "+path)
If I run this, I always end up with this error:
File "Doc.py", line 15, in TOOL_REPORT
Tool1.REPORT(path)
NameError: global name 'Tool1' is not defined
I'd appreciate any hint to what is going wrong!

Your Tool1 and Tool2 submodules are not visible until explicitly imported somewhere.
You can import them in the Tools/__init__.py package file:
import Tool1, Tool2
at which point they become available for import from Tools.
Another option is to import the modules from your own code:
import Tools.Tool1, Tools.Tool2
from Tools import *
Only when explicitly imported are submodules also set as attributes of the package.

Python will treat any folder as a module when there is __init__.py file present in it. Otherwise it will just be another folder for python and not a module from which it can import things. So just add init.py file in your Tool folder (so it will become module in pythonic terms) and then you can import that module in other python scripts.
One more things for better practice instead of using
from Tools import *
Always provide the file name of library specifically which you want to import like in your case you should use it like this
from Tools import Tool1, Tool2
This will enhance the code readbility for others and for you too.

Related

ImportError attempted relative import with no known parent

Based on some answers I try to be more specific.
I want to import the print and the models AND code in my main.py
I know the question gets asked a lot, but still I could not figure out whats wrong with my code!
I have a project directory like this
-project
--__init__py
--main.py
--print.py
--requests
--__init__.py
--models.py
--code.py
i want to import from print.py and * from requests
Therefore I tried to add these lines in main.py
from . import print
#or
import print
#for requests I tried
import os.path
import sys
sys.path.append('./requests')
from requests import *
all of those lines cause the same ImportError attempted relative import with no known parent ,
using Python 39
anyone an idea where the problem is?
I am very confused that this seems not to work, was it possible in older versions?
You should definitely not be doing anything with sys.path. If you are using a correct Python package structure, the import system should handle everything like this.
From the directory structure you described, project would be the name of your package. So when using your package in some external code you would do
import package
or to use a submodule/subpackage
import project.print
import project.requests
and so on.
For modules inside the package you can use relative imports. When you write
i want to import from print.py and * from requests Therefore I tried
it's not clear from where you want to import them, because this is important for relative imports.
For example, in project/main.py to import the print module you could use:
from . import print
But if it's from project/requests/code.py you would use
from .. import print
As an aside, "print" is probably not a good name for a module, since if you import the print module it will shadow the print() built-in function.
Your main file should be outside the 'project'-directory to use that as a package.
Then, from your main file, you can import using from project.print import ....
Within the project-package, relative imports are possible.

How can I import a python module whose name is a uid?

For some reason, I had to change a module name from A.py to 0880ceae-8a46-11eb-bcf6-38f9d349be8e.py. 0880ceae-8a46-11eb-bcf6-38f9d349be8e.py is a uid generated by uuid.uuid1().
After my change, I try to import a class B from the py file by the following two ways, both do not work out.
First solution is to import directly
from 0880ceae-8a46-11eb-bcf6-38f9d349be8e import B
It has an error SyntaxError: invalid token
Second solution is to define a variable before import
uid = '0880ceae-8a46-11eb-bcf6-38f9d349be8e'
from uid import Model_API
And it has en error ModuleNotFoundError: No module named 'uid'
Anyone has a good idea? Thanks.
Here is possible solution to your problem tested using python3:
# Modern approach
import importlib
module = importlib.import_module(".", "0880ceae-8a46-11eb-bcf6-38f9d349be8e")
module.hello()
# Deprecated way
module = __import__("0880ceae-8a46-11eb-bcf6-38f9d349be8e")
module.hello()
Both of the above methods are tested and works.
Here are the rules to keep in mind:
Check your filename should end with .py extension, .py.py will cause ModuleNotFoundError.
Make sure to not include .py extension while using in importlib module.

Import all modules from folder, execute function from all of them with known name

Well, I have pretty hard task and I'm completely stucked, like in any direction.
What program should do:
Import all modules (names are random) from folder
MainScript.py
modules/
mod1.py
mod2.py
mod3.py
...
Execute specific (known name, and everywhere it's same) function.
mod1.main()
mod2.main()
mod3.main()
...
As I understand it, I should list all files in folder , then make list with them and for each [x] in list import module and execute script. I've found that modules[0].main() works only if modules[0] no string, so, it should be modules[0]=main not modules[0]='main'. So and there I need somehow deal with it... but for import I don't know...
I've already googled about it, only found https://stackoverflow.com/a/1057534/10289135
And I guess it will not work for me (I also don't understand how it works and script didn't work for me)
Any ideas?
You can use the following syntax:
from filename(remove the .py) import *
This is a wild card import it imports every thing from a module literally everything .By doing this you dont need to do the work like 'filename.blabla' ,but simply you can do 'blabla'.
import os
import sys
import importlib
modules = []
for i in os.listdir("C:\\Windows\\path\\to\\your\\modules\\"):
mod = i
modules.append(mod)
sys.path.append("C:\\Windows\\path\\to\\your\\modules\\")
for i in modules:
i = i[:i.find(".")]
module = importlib.import_module(f"{i}")
module.main()

python importing file on virtual environment

I am writing a web app using python3, venv and c9.io PAAS. I have the following structure of my code:
batch_runner.py
logic/
__init__.py
parsers/
__init__.py
time_parser.py
abstract_parser.py
here batch_runner imports abstract_parser, which, in it turn, import from time_parser. everything was installed and runs with venv activated.
To be specific, batch_runner.py contains:
from logic.parsers import abstract
from sys import argv
url = argv[1]
a = abstract(url)
logic/__init__.py is empty. logic/parsers/__init__.py contains:
from abstract_parser import abstract
from time_parser import _timeInfo
If I go to logic and run python abstract_parser.py directly, everything works as expected. However, if I go one level up, and run python batch_runner.py, it is able to import abstract_parser, but it can't find time_parser which is called from abstract_parser, throwing ImportError: No module named 'abstract'
Change this:
from abstract_parser import abstract
To
from logic.parsers.abstract_parser import abstract
Do read about importing from the python documentation on modules.
In this case, one possible solution is to use relative imports inside your package:
That is, in logic/parsers/__init__.py, use:
from .abstract_parser import abstract
from .time_parser import _timeInfo
and in abstract_parser.py:
from .time_parser import _timeInfo
This should let parsers/__init__.py find the abstract_parser module and the time_parser module.
The python import system has a surprising number of traps that you can fall into. This blog post by Nick Coghlan describes many of them, and I personally consider it a must-read if you're planning to develop a package.

Python - Importing a global/site-packages module rather than the file of the same name in the local directory

I'm using python and virtualenv/pip. I have a module installed via pip called test_utils (it's django-test-utils). Inside one of my django apps, I want to import that module. However I also have another file test_utils.py in the same directory. If I go import test_utils, then it will import this local file.
Is it possible to make python use a non-local / non-relative / global import? I suppose I can just rename my test_utils.py, but I'm curious.
You can switch the search order by changing sys.path:
del sys.path[0]
sys.path.append('')
This puts the current directory after the system search path, so local files won't shadow standard modules.
My problem was even more elaborate:
importing a global/site-packages module from a file with the same name
Working on aero the pm recycler I wanted access to the pip api, in particular pip.commands.search.SearchCommand from my adapter class Pip in source file pip.py.
In this case trying to modify sys.path is useless, I even went as far as wiping sys.path completely and adding the folder .../site-packages/pip...egg/ as the only item in sys.path and no luck.
I would still get:
print pip.__package__
# 'aero.adapters'
I found two options that did eventually work for me, they should work equally well for you:
using __builtin__.__import__() the built-in function
global_pip = __import__('pip.commands.search', {}, {}, ['SearchCommand'], -1)
SearchCommand = global_pip.SearchCommand
Reading the documentation though, suggests using the following method instead.
using importlib.import_module() the __import__ conv wrapper.
The documentation explains that import_module() is a minor subset of functionality from Python 3.1 to help ease transitioning from 2.7 to 3.1
from importlib import import_module
SearchCommand = import_module('pip.commands.search').SearchCommand
Both options get the job done while import_module() definitely feels more Pythonic if you ask me, would you agree?
nJoy!
I was able to force python to import the global one with
from __future__ import absolute_import
at the beginning of the file (this is the default in python 3.0)
You could reset your sys.path:
import sys
first = sys.path[0]
sys.path = sys.path[1:]
import test_utils
sys.path = first + sys.path
The first entry of sys.path is "always" (as in "per default": See python docs) the current directory, so if you remove it you will do a global import.
Since my test_utils was in a django project, I was able to go from ..test_utils import ... to import the global one.
Though, in first place, I would always consider keeping the name of local file not matching with any global module name, an easy workaround, without modifying 'sys.path' can be to include global module in some other file and then import this global module from that file.
Remember, this file must be in some other folder then in the folder where file with name matching with global module is.
For example.
./project/root/workarounds/global_imports.py
import test_utils as tutil
and then in
./project/root/mycode/test_utils.py
from project.root.workarounds.global_imports import tutil
# tutil is global test_utils
# you can also do
from project.root.workarounds.global_imports import test_utils

Categories

Resources