Python: Visibility of module-level variable depends of code using it - python

config.py
import json
import os
myfolder = os.path.dirname(os.path.realpath(__file__))
configfile = os.path.join(myfolder, '../appconfig.json')
appconfig = None
def get_config():
if myfolder is None:
return myfolder
if appconfig is not None:
return appconfig
else:
#load the config
try:
with open(configfile) as json_data:
c = json.load(json_data)
appconfig = c
return c
except Exception, e:
raise Exception("Cannot load config file %s : %s"%(configfile, `e`))
Now import it and use it:
tmp.py
import config
config.get_config()
python tmp.py
Traceback (most recent call last):
File "tmp.py", line 2, in <module>
config.get_config()
File "D:\projects\flask_ndc\lib\config.py", line 12, in get_config
if appconfig is not None:
UnboundLocalError: local variable 'appconfig' referenced before assignment
Comment out line 18 in config.py
#appconfig = c
Now the code works - (but of course without saving the content in the global variable)
Can somebody explain why the python interpreter is not able to see that the assignment of appconfig in line 18 refers to the module-global variable appconfig, declared in line 7 ????

You problem is this line:
appconfig = c
It means define a new name in locals of function get_config.
So when Interpreter run this line:
if appconfig is not None:
It treat name "appconfig" as a local variable, but it is not defined in former local codes, so the exception cames out.
If you don't assign any thing to appconfig in function get_config, the Interpreter considers appconfig as a enclosing name, and use appconfig in module-level.
If you want to assign value to appconfig in function, just use "global" to declare, add
global appconfig
before the very first line appconfig appears.
Hope I can help you. Feel free to comment any other questions about this post.

Related

NameError: global name 'myPars' is not defined

I need some help because I keep getting this erros:
Traceback (most recent call last):
File "/home/kostas_ubuntu/HemTools/bin/chromHMM.py", line 173, in <module>
main()
File "/home/kostas_ubuntu/HemTools/bin/chromHMM.py", line 100, in main
args = my_args()
File "/home/kostas_ubuntu/HemTools/bin/chromHMM.py", line 43, in my_args
input.add_argument('-bin',"--chromHMM_jar", help="chromHMM bin location",default=myPars['chromHMM_jar'])
NameError: global name 'myPars' is not defined
I run the script and get this error although in the script I import the utils.py module that sets the myPars variable. The below code snippet comes from the utils.py module.
p_dir = os.path.dirname(os.path.realpath(__file__)) + "/"
username = getpass.getuser()
myData = parse_config(p_dir+"../config/data.config")
myPars = parse_config(p_dir+"../config/parameters.config")
More information of the scripts you can find on the github links below:
utils.py -> https://github.com/YichaoOU/HemTools/blob/master/utils/utils.py
chromHMM.py ->https://github.com/YichaoOU/HemTools/blob/master/bin/chromHMM.py
Thanks in advance!
In Python 3 you should declare on every new scope the global variables it uses. In your case it'd be like the following:
def my_args():
global myPars, myData
# ... The remaining code
# ...
def main():
global myData, myPipelines
# ... The remaining code

pytest mock variable calling the actual method

I have two files foo.py and bar.py
foo.py
NAME = os.getenv('NAME').lower()
bar.py
from foo import NAME
def helper():
print (NAME)
I have a test file test/test_name.py
import bar
#mock.patch('bar.NAME', "Alice")
def test__get_file(monkeypatch):
print(bar.NAME)
Giving an error:
../bar.py:6: in <module>
from foo import NAME
../foo.py:17: in <module>
NAME = os.getenv('NAME').lower()
E AttributeError: 'NoneType' object has no attribute 'lower'
What I am missing?
A per os module documentation, os.getenv can return a default value if the environment variable does not exist.
So, you could modify foo.py to avoid raising an error when running your test (for the reason given by #MrBeanBremen in his comment) like this:
NAME = os.getenv('NAME', default="MISSING").lower()

ImportError: cannot import name - Python

I am trying to import some variables from a different python file resides in the same directory from a another python file.
I have two files in the same directory as below:
constantvariables.py
test.py
This is how constantvariables.py looks like
class CONST(object):
FOO = 1234
NAMESPACE = "default"
DEPLOYMENT_NAME = "deployment-test"
DOCKER_IMAGE_NAME = "banukajananathjayarathna/bitesizetroubleshooter:v1"
SERVICE_CLUSTER = "deployment-test-clusterip"
SERVICE_NODEPORT = "deployment-test-nodeport"
INGRESS_NAME = "deployment-test-ingress"
def __setattr__(self, *_):
pass
CONST = CONST()
and this is how my test.py looks like:
import os
from . import constantvariables
print(constantsvariables.NAMESPACE)
But I get this error:
Traceback (most recent call last):
File "test.py", line 7, in
from . import constantsvariables
ImportError: cannot import name 'constantsvariables'
can someone please help me?
Python version I am using python 2.7.5
Make constant file like that constant.py and put inside config folder for proper management.
FOO = 1234
NAMESPACE = "default"
DEPLOYMENT_NAME = "deployment-test"
DOCKER_IMAGE_NAME = "banukajananathjayarathna/bitesizetroubleshooter:v1"
SERVICE_CLUSTER = "deployment-test-clusterip"
SERVICE_NODEPORT = "deployment-test-nodeport"
INGRESS_NAME = "deployment-test-ingress"
Inside your base directory create main.py file and call the constant inside that.
import os
from config.constants import NAMESPACE, FOO
print(NAMESPACE)
If you want to keep your constant file as it is, you can write this:
import os
from constantvariables import CONST
print(CONST.NAMESPACE)

Creating importable Python 3 package / module

I am having trouble creating an importable Python package/library/module or whatever the right nomenclature is. I am using Python 3.7
The file structure I am using is:
Python37//Lib//mypackage
mypackage
__init__.py
mypackage_.py
The code in __init__.py is:
from mypackage.mypackage_ import MyClass
The code in mypackage_.py is:
class MyClass:
def __init__(self, myarg = None):
self.myvar = myarg
And from my desktop I try running the following code:
import mypackage
x = MyClass(None)
But get the following error:
Traceback (most recent call last):
File "C:\Users\***\Desktop\importtest.py", line 3, in <module>
x = MyClass(None)
NameError: name 'MyClass' is not defined
You haven't imported the name MyClass into your current namespace. You've imported mypackage. To access anything within mypackage, you need to prefix the name with mypackage.<Name>
import mypackage
x = mypackage.MyClass(None)
As #rdas says, you need to prefix the name with mypackage.<Name>.
I don't recommend doing this, but you can wildcard import in order to make x = MyClass(None) work:
from mypackage import *
Now, everything from mypackage is imported and usable in the current namespace. However, you have to be careful with wildcard imports because they can create definition conflictions (if multiple modules have the same name for different things).

Importing classes from different files in a subdirectory

Here's the structure I'm working with:
directory/
script.py
subdir/
__init__.py
myclass01.py
myclass02.py
What I want to do is import in script.py the classes defined in myclass01.py and myclass02.py. If I do:
from subdir.myclass01 import *
It works fine for the class defined in myclass01.py. But with this solution if there are many classes defined in different files in subdir and I want to import all of them, I'd have to type one line for each file. There must be a shortcut for this. I tried:
from subdir.* import *
But it didn't work out.
EDIT: here are the contents of the files:
This is __init__.py (using __all__ as Apalala suggested):
__all__ = ['MyClass01','MyClass02']
This is myclass01.py:
class MyClass01:
def printsomething():
print 'hey'
This is myclass02.py:
class MyClass02:
def printsomething():
print 'sup'
This is script.py:
from subdir import *
MyClass01().printsomething()
MyClass02().printsomething()
This is the traceback that I get when I try to run script.py:
File "script.py", line 1, in <module>
from subdir import *
AttributeError: 'module' object has no attribute 'MyClass01'
Although the names used there are different from what's shown in your question's directory structure, you could use my answer to the question titled Namespacing and classes. The __init__.py shown there would have also allowed the usepackage.py script to have been written this way (package maps to subdir in your question, and Class1 to myclass01, etc):
from package import *
print Class1
print Class2
print Class3
Revision (updated):
Oops, sorry, the code in my other answer doesn't quite do what you want — it only automatically imports the names of any package submodules. To make it also import the named attributes from each submodule requires a few more lines of code. Here's a modified version of the package's __init__.py file (which also works in Python 3.4.1):
def _import_package_files():
""" Dynamically import all the public attributes of the python modules in this
file's directory (the package directory) and return a list of their names.
"""
import os
exports = []
globals_, locals_ = globals(), locals()
package_path = os.path.dirname(__file__)
package_name = os.path.basename(package_path)
for filename in os.listdir(package_path):
modulename, ext = os.path.splitext(filename)
if modulename[0] != '_' and ext in ('.py', '.pyw'):
subpackage = '{}.{}'.format(package_name, modulename) # pkg relative
module = __import__(subpackage, globals_, locals_, [modulename])
modict = module.__dict__
names = (modict['__all__'] if '__all__' in modict else
[name for name in modict if name[0] != '_']) # all public
exports.extend(names)
globals_.update((name, modict[name]) for name in names)
return exports
if __name__ != '__main__':
__all__ = ['__all__'] + _import_package_files() # '__all__' in __all__
Alternatively you can put the above into a separate .py module file of its own in the package directory—such as _import_package_files.py—and use it from the package's __init__.py like this:
if __name__ != '__main__':
from ._import_package_files import * # defines __all__
__all__.remove('__all__') # prevent export (optional)
Whatever you name the file, it should be something that starts with an _ underscore character so it doesn't try to import itself recursively.
Your best option, though probably not the best style, is to import everything into the package's namespace:
# this is subdir/__init__.py
from myclass01 import *
from myclass02 import *
from myclass03 import *
Then, in other modules, you can import what you want directly from the package:
from subdir import Class1
I know it's been a couple months since this question was answered, but I was looking for the same thing and ran across this page. I wasn't very satisfied with the chosen answer, so I ended up writing my own solution and thought I'd share it. Here's what I came up with:
# NOTE: The function name starts with an underscore so it doesn't get deleted by iself
def _load_modules(attr_filter=None):
import os
curdir = os.path.dirname(__file__)
imports = [os.path.splitext(fname)[0] for fname in os.listdir(curdir) if fname.endswith(".py")]
pubattrs = {}
for mod_name in imports:
mod = __import__(mod_name, globals(), locals(), ['*'], -1)
for attr in mod.__dict__:
if not attr.startswith('_') and (not attr_filter or attr_filter(mod_name, attr)):
pubattrs[attr] = getattr(mod, attr)
# Restore the global namespace to it's initial state
for var in globals().copy():
if not var.startswith('_'):
del globals()[var]
# Update the global namespace with the specific items we want
globals().update(pubattrs)
# EXAMPLE: Only load classes that end with "Resource"
_load_modules(attr_filter=lambda mod, attr: True if attr.endswith("Resource") else False)
del _load_modules # Keep the namespace clean
This simply imports * from all .py files in the package directory and then only pulls the public ones into the global namespace. Additionally, it allows a filter if only certain public attributes are desired.
I use this simple way:
add the directory to the system path, then
import module or from module import function1, class1 in that directory.
notice that the module is nothing but the name of your *.py file, without the extension part.
Here is a general example:
import sys
sys.path.append("/path/to/folder/")
import module # in that folder
In your case it could be something like this:
import sys
sys.path.append("subdir/")
import myclass01
# or
from myclass01 import func1, class1, class2 # .. etc
from subdir.* import *
You can not use '*' this way directly after the 'from' statement.
You need explict imports. Please check with the Python documentation on imports and packages.

Categories