I want to refer to an object in the namespace of the file that imports the one that I am writing.
this is an example:
main.py
from imp import * # main is importing the file I'm writing
...more code...
obj=1 # main defines obj
f() # f(), defined in imp, needs to use obj
...more code using obj...
This is the file that defines f():
imp.py
def f():
return obj # I want to refer to main's obj here
error on runtime:
error: global name 'obj' is not defined
How can it be done?
Thanks.
Relying on global variables across modules is not really a good idea. You should pass obj as a parameter to the function f(), like this:
f(obj)
Then just declare the parameter in the function:
def f(obj):
# code to operate on obj
return obj
Related
I have a pytest file called test_util that looks like this:
import pytest
class TestUtil:
def test_split_kwargs(self, mocker):
def testfunction_extra(e='5',f='6'):
return e+f
mocker.patch(...)
I would like to use the assert_has_calls method on my testfunction_extra function, but I'm not sure what to put into my mocker.patch statement. I have already tried
mocker.patch(__name__ + '.TestUtil.test_split_kwargs.testfunction_extra')
but this returns the error AttributeError: <function TestUtil.test_split_kwargs at 0x7fce6612e790> does not have the attribute 'testfunction_extra'
You can't patch local variables, only global names and attributes of objects you have a reference to. But good news! You don't need to patch this, because you have a reference to the function right there to wrap in a Mock object yourself.
import unittest.mock
class TestUtil:
def test_split_kwargs(self):
def _(e='5', f='6'):
return e + f
testfunction_extra = unittest.mock.Mock(wraps=_)
...
You could even use a decorator for this, starting in Python 3.9:
class TestUtil:
def test_split_kwargs(self):
#lambda f: unittest.mock.Mock(wraps=f)
def testfunction_extra(e='5', f='6'):
return e + f
...
Context variables are convenient when we need to pass a variable along the chain of calls so that they share the same context, in the case when this cannot be done through a global variable in the case of concurrency. Context variables can be used as an alternative to global variables both in multi-threaded code and in asynchronous (with coroutines).
I can use contextvars in Python 3.7 and above like below and It's usually really easy:
Sample 1:
import contextvars
user_id = contextvars.ContextVar("user_id")
def f1(user, operation):
user_id.set(user.id)
f2()
def f2():
f3()
def f3():
print(user_id.get()) # gets the user_id value
Sample 2:
But when I am using the contextvars to another module's function it is not accessible, showing below error. It seems I am misunderstanding the usage of contextvars :)
NameError: name 'user_id' is not defined
test2.py
def abc():
print("inside abc")
print(user_id.get())
if __name__=='__main__':
abc()
test1.py
import contextvars
from test2 import abc
import uuid
user_id = contextvars.ContextVar("user_id")
request_id = uuid.uuid4()
def f1():
f2()
def f2():
f3()
def f3():
print("inside f3")
print(user_id.get())
user_id.set(request_id)
f1_calling = f1()
abc_calling = ABC()
Full Output:
inside f3
cdd36594-372d-438a-9bac-da53751af08a
inside abc
Traceback (most recent call last):
File "/var/www/test1.py", line 19, in <module>
abc_calling = abc()
File "/var/www/test2.py", line 3, in abc
print(user_id.get())
NameError: name 'user_id' is not defined
So my fundamental question is how can I pass and access the context variable that I set from one function and access that variable from any sub-function that is called by the main module.?
"Global" variables in Python are not actually global, but are rather attributes of the module that defines them.
You can therefore access a global variable defined in the main module from a sub-module by accessing it as an attribute of sys.modules['__main__']:
test2.py
import sys
def abc():
print("inside abc")
print(sys.modules['__main__'].user_id.get())
Demo: https://replit.com/#blhsing/TurquoiseAltruisticPercent#main.py
I'm trying to bypass importing from a module, so in my __init__.py I can inject code like this:
globals().update(
{
"foo": lambda: print("Hello stackoverflow!")
}
)
so if I do import mymodule I will be able to call mymodule.foo. That is a simple concept, useless for the purpose because you can actually just define foo.
So, the idea is to modify the globals module dictionary, so in case it doesn't find the function foo it will go wherever and I can inject the code, for that I tried:
from importer import load #a load function to search for the code
from functools import wraps
def global_get_wrapper(f):
#wraps(f)
def wrapper(*args):
module_name, default = args
res = f(*args)
if res is None:
return load(module_name)
return res
return wrapper
globals().get = global_get_wrapper(globals().get) # trying to substitute get method
But it gives me an error:
AttributeError: 'dict' object attribute 'get' is read-only
The other idea I had is to preload the available function, class, etc names into the module dictionary and lazily load them later.
I run out of ideas to accomplish this and I don't know if this is even possible.
Should I go for writing my own python importer? or is there any other possibility I could not think about?
Thanks in advance.
Instead of hacking globals() it would be better to define __getattr__ for your module as follows:
module_name.py
foo = 'foo'
def bar():
return 'bar'
my_module.py
import sys
import module_name
class MyModule(object):
def foobar(self):
return 'foobar'
def __getattr__(self, item):
return getattr(module_name, item)
sys.modules[__name__] = MyModule()
and then:
>>> import my_module
>>> my_module.foo
'foo'
>>> my_module.bar()
'bar'
>>> my_module.foobar()
'foobar'
PEP 562, which targets Python 3.7, introduces __getattr__ for modules. In the rationale it also describes workarounds for previous Python versions.
It is sometimes convenient to customize or otherwise have control over access to module attributes. A typical example is managing deprecation warnings. Typical workarounds are assigning __class__ of a module object to a custom subclass of types.ModuleType or replacing the sys.modules item with a custom wrapper instance. It would be convenient to simplify this procedure by recognizing __getattr__ defined directly in a module that would act like a normal __getattr__ method, except that it will be defined on module instances.
So your mymodule can look like:
foo = 'bar'
def __getattr__(name):
print('load you custom module and return it')
Here's how it behaves:
>>> import mymodule
>>> mymodule.foo
'bar'
>>> mymodule.baz
load you custom module and return it
I don't quite understand. Would this work for you?
try:
mymodule.foo()
except:
print("whatever you wanted to do")
This is clearly a scope or import issue of some kind, but I can't figure it out. Something like:
classes.py
class Thing(object):
#property
def global_test(self):
return the_global
And then...
test.py
from classes import Thing
global the_global
the_global = 'foobar'
t = Thing()
t.global_test
:(
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "classes.py", line 4, in global_test
return the_global
NameError: global name 'the_global' is not defined
Any help would be great!
"global" in Python is a variable accessible in top level within module.
This message:
NameError: global name 'the_global' is not defined
raised within classes.py means you do not have a global named the_global within your classes.py file.
Python modules do not share global variables. (well, not in the way you want them to share)
The 'global' variables only defines a variable as global inside the scope of the module
where it is used. You can not use 'global' here to access a variable outside the module
scope of the 'classes' module.
The proper solution here if you have to deal with global defines or so: move the "global"
variables into a dedicated module and use a proper import statement to import the variables
into your 'classes' module.
myvars.py:
MY_GLOBAL_VAR = 42
classes.py:
import myvars
class Thing():
def method(self):
return myvars.MY_GLOBAL_VAR # if you need such a weird pattern for whatever reason
I am trying to load the function in a remote environment using cPickle. But I got the
error "the 'module' object has no attribute ..." . Where I really stuck is the namespace has
already contain that attributes , even though it fails to load
Please Help
import inspect
import cPickle as pickle
from run import run
def get_source(func):
sourcelines = inspect.getsourcelines(func)[0]
sourcelines[0] = sourcelines[0].lstrip()
return "".join(sourcelines)
def fun(f):
return f()
def fun1():
return 10
funcs = (fun, fun1)
sources = [get_source(func) for func in funcs]
funcs_serialized = pickle.dumps((fun.func_name,sources),0)
args_serialized = pickle.dumps(fun1,0)
#Creating the Environment where fun & fun1 doesnot exist
del globals()['fun']
del globals()['fun1']
r = run()
r.work(funcs_serialized,args_serialized)
Here is run.py
import cPickle as pickle
class run():
def __init__(self):
pass
def work(self,funcs_serialized,args_serialized):
func, fsources = pickle.loads(funcs_serialized)
fobjs = [compile(fsource, '<string>', 'exec') for fsource in fsources]
#After eval fun and fun1 should be there in globals/locals
for fobj in fobjs:
try:
eval(fobj)
globals().update(locals())
except:
pass
print "Fun1 in Globals: ",globals()['fun1']
print "Fun1 in locals: ",locals()['fun1']
arg = pickle.loads(args_serialized)
The error is
Fun1 in Globals: <function fun1 at 0xb7dae6f4>
Fun1 in locals: <function fun1 at 0xb7dae6f4>
Traceback (most recent call last):
File "fun.py", line 32, in <module>
r.work(funcs_serialized,args_serialized)
File "/home/guest/kathi/python/workspace/run.py", line 23, in work
arg = pickle.loads(args_serialized)
AttributeError: 'module' object has no attribute 'fun1'
I found this link helpful:
http://stefaanlippens.net/python-pickling-and-dealing-with-attributeerror-module-object-has-no-attribute-thing.html
It gives two solutions. The better solution is to add to the head of the loading module (or __main__):
from myclassmodule import MyClass
But I think a better solution should exist.
From http://docs.python.org/library/pickle.html#what-can-be-pickled-and-unpickled:
Note that functions (built-in and
user-defined) are pickled by “fully
qualified” name reference, not by
value. This means that only the
function name is pickled, along with
the name of module the function is
defined in. Neither the function’s
code, nor any of its function
attributes are pickled. Thus the
defining module must be importable in
the unpickling environment, and the
module must contain the named object,
otherwise an exception will be raised.
You deleted the reference to fun1 in the module that defines fun1, thus the error.
The module name of the function is saved into the pickle, when you are doing the loads it is looking for fun1 in __main__ or whereever it was originally
try to add
from your_first_module import fun,fun1
into run.py