testa.py
class A:
s1 = 333
__age = 0
def __init__(self,age ):
self.__age=age
return
def __del__(self):
return
#private
def __doSomething(self, s):
print self.__age
return
#public
def doSomething(self, s):
self.__doSomething(s)
print s
test.py
import sys
import testa
a=A(111)
a.doSomething('222')
run
python test.py
it reports error:
NameError: name 'A' is not defined
your comment welcome
Use
a=testa.A(111)
You must name the package unless you import A explicitly e.g
from testa import A
Remember this:
Doing: import mymodule does not import the whole methods and attributes of mymodule to the namespace, so you will need to refer to mymodule, everytime you need a method or attribute from it, using the . notation, example:
x = mymodule.mymethod()
However, if you use:
from mymodule import *
This will bring every method and attribute of mymodule into the namespace and they are available directly, so you don't need to refer to mymodule each time you need to call one of its method or attribute, example:
from mymodule import *
x = mymethod() #mymethod being a method from mymodule
You can also import specific method if you don't want to bring the whole module:
from mymodule import myMethod
For further details, read the Python docs:
https://docs.python.org/2/tutorial/modules.html
Related
Given the following files:
a.py
-----
class CommonClass(object):
def do_thing(self):
pass
b.py
-----
from a import CommonClass
class SubClassA(CommonClass):
def do_thing(self):
print("I am A")
class SubClassB(CommonClass):
def do_thing(self):
print("I am B")
c.py
-----
from a import CommonClass
from b import SubClassA
if __name__ == "__main__":
for member in CommonClass.__subclasses__():
member().do_thing()
I would expect only SubClassA is imported, and visible when looping through subclasses of CommonClass, but it seems SubClassB is imported as well.
I am running Python 3.8.5 and this is the output of python3 c.py:
$ python3 c.py
I am A
I am B
How can I only import the classes I want?
You did import only SubClassA to c.py. This can be tested by doing
x = SubClassB()
or
x = b.SubClassB()
Both will result in a NameError.
The thing is, that when you import a file, it is actually being ran, even when using from x import y!
This can be easily seen by adding a print("I'm from b.py") at the end of b.py and then running c.py.
This makes both SubClassA and SubClassB be subclasses of CommonClass, which you imported. So, while you don't have access to the SubClassB name, it is still a subclass of CommonClass and you can access it from there.
In general you don't have to import a module to be able to use its objects. Importing expands your namespace to include that module so you can create an object directly. You can still use this module's objects even without importing it if you acquired them in some other way (like importing a third module which returns objects from the second one).
Anyway right now, you are not really using even the imported SubClassA. If you want to "allow" certain classes to be considered only from an external source, you can create an allowed set of classes:
from a import CommonClass
from b import SubClassA
allowed_classes = {SubClassA}
if __name__ == "__main__":
for member in CommonClass.__subclasses__():
if member in allowed_classes:
member().do_thing()
Which only prints I am A
from a import CommonClass
from b import SubClassA
if __name__ == "__main__":
h = CommonClass.__subclasses__()[0]()
h.do_thing()
You can do this.
I have a function that uses typing.get_type_hints. I want to add a documentation test to it. However, it looks like get_type_hints fails to resolve types that are defined in a doctest.
Here is a simplified example:
import typing
def f(clazz):
"""
>>> class MyClass:
... my_field: 'MyClass'
>>> f(MyClass)
"""
typing.get_type_hints(clazz)
When running it with python3 -m doctest test.py it throws NameError: name 'MyClass' is not defined.
In order to get it to work in doctest, you would need to provide the correct evaluation scope.
Try this:
import typing
def f(clazz, globalns=None, localns=None):
"""
>>> class MyClass:
... my_field: 'MyClass'
>>> f(MyClass, globals(), locals())
"""
typing.get_type_hints(clazz, globalns, localns)
In doctest, a special set of values are used in the "eval scope" that happens with get_typing_hints.
It is looking for "test.MyClass" which doesn't actually exist otherwise.
from __future__ import annotations
import typing
def f(clazz):
"""
>>> test = 1
>>> class MyClass:
... my_field:'MyClass'
>>> f(MyClass)
"""
typing.get_type_hints(clazz)
add from __future__ import annotations at the beginning of the file, it work for me on python3.7
I have a test_a.py, a.py and b.py in 3 different directories in my test environment.
b.py
class SBD():
def __init__(self):
print("SBD created (In B)")
a.py
import b
from b import *
print("In module A")
def fun1():
a=SBD()
print("SBD created(In A)")
test_a.py
import unittest
import sys
from unittest.mock import Mock,patch,MagicMock
sys.path.append("../abc/")
import b as c
sys.modules['b'] = MagicMock(spec=c)
sys.path.append("../xyz/")
import a
class TestStringMethods(unittest.TestCase):
def test_isupper(self):
a.fun1()
if __name__ == '__main__':
unittest.main()
In a real situation, b.py will have multiple classes and I wanted to mock all of them, so I tried mocking the module b with the same specifications. But when i run the test_a.py it gives me an error saying "SBD" is not defined. What am I doing wrong here?
A MagicMock instance does not provide the same information to the import machinery as a module would. Even with a spec, there is no actual SDB attribute defined on the mock, so from b import * won't find it.
The from * import machinery tries two different things:
It tries to access the name __all__; if defined it must be a list of strings of names to import.
If __all__ is not defined, the keys of the __dict__ attribute are taken, filtering out names that start with an underscore.
Because your b module has no __all__ list defined, the __dict__ keys are taken instead. For a MagicMock instance specced against a module, the __dict__ attribute only consists of names with _ underscores and the mock_calls attribute. from b import * only imports mock_calls:
>>> import a as c
>>> module_mock = MagicMock(spec=c)
>>> [n for n in module_mock.__dict__ if n[:1] != '_']
['method_calls']
I would strongly advice against mocking the whole module; doing this would require that you postpone importing a, and is fragile. The patch is permanent (is not undone automatically when tests end) and won't support repeated runs of the test or running tests in random order.
But if you had to make this work, you could add a __all__ attribute to the mock first:
sys.modules['b'] = MagicMock(spec=c, __all__=[n for n in c.__dict__ if n[:1] != '_'])
Personally, I'd a) avoid using from module import * syntax altogether. If I could not prevent this from being used anyway, the next step would be to apply patches to a after importing, looping over the b module to obtain specced replacements:
# avoid manipulating sys.path if at all possible. Move that to a PYTHONPATH
# variable or install the modules properly.
import unittest
from unittest import mock
import a
import b
class TestStringMethods(unittest.TestCase):
def setUp(self):
# mock everything `from b import *` would import
b_names = getattr(b, '__all__', None)
if b_names is None:
b_names = [n for n in b.__dict__ if n[:1] != '_']
self.b_mocks = {}
for name in b_names:
orig = getattr(b, name, None)
if orig is None:
continue
self.b_mocks[name] = mock.patch.object(a, name, spec=orig)
self.b_mocks[name].start()
self.addCleanup(self.b_mocks[name].stop)
def test_isupper(self):
a.fun1()
This leaves sys.modules['b'] untouched, and processes the exact same names that from * would load. The patches are removed again after the test ends.
The above test outputs:
$ python test_a.py
In module A
SBD created(In A)
.
----------------------------------------------------------------------
Ran 1 test in 0.001s
OK
Is there any way to make an implicit initializer for modules (not packages)?
Something like:
#file: mymodule.py
def __init__(val):
global value
value = 5
And when you import it:
#file: mainmodule.py
import mymodule(5)
The import statement uses the builtin __import__ function.
Therefore it's not possible to have a module __init__ function.
You'll have to call it yourself:
import mymodule
mymodule.__init__(5)
These things often are not closed as duplicates, so here's a really nice solution from Pass Variable On Import. TL;DR: use a config module, configure that before importing your module.
[...] A cleaner way to do it which is very useful for multiple configuration
items in your project is to create a separate Configuration module
that is imported by your wrapping code first, and the items set at
runtime, before your functional module imports it. This pattern is
often used in other projects.
myconfig/__init__.py :
PATH_TO_R_SOURCE = '/default/R/source/path'
OTHER_CONFIG_ITEM = 'DEFAULT'
PI = 3.14
mymodule/__init__.py :
import myconfig
PATH_TO_R_SOURCE = myconfig.PATH_TO_R_SOURCE
robjects.r.source(PATH_TO_R_SOURCE, chdir = True) ## this takes time
class SomeClass:
def __init__(self, aCurve):
self._curve = aCurve
if myconfig.VERSION is not None:
version = myconfig.VERSION
else:
version = "UNDEFINED"
two_pi = myconfig.PI * 2
And you can change the behaviour of your module at runtime from the
wrapper:
run.py :
import myconfig
myconfig.PATH_TO_R_SOURCE = 'actual/path/to/R/source'
myconfig.PI = 3.14159
# we can even add a new configuration item that isn't present in the original myconfig:
myconfig.VERSION="1.0"
import mymodule
print "Mymodule.two_pi = %r" % mymodule.two_pi
print "Mymodule.version is %s" % mymodule.version
Output:
> Mymodule.two_pi = 6.28318
> Mymodule.version is 1.0
I am trying to Mock a function (that returns some external content) using the python mock module.
I'm having some trouble mocking functions that are imported into a module.
For example, in util.py I have
def get_content():
return "stuff"
I want to mock util.get_content so that it returns something else.
I am trying this:
util.get_content=Mock(return_value="mocked stuff")
If get_content gets invoked inside another module, it never actually seems to return the mocked object. Am I missing something in terms of how to use Mock?
Note that if I invoke the following, things work correctly:
>>> util.get_content=Mock(return_value="mocked stuff")
>>> util.get_content()
"mocked stuff"
However, if get_content is called from inside another module, it invokes the original function instead of the mocked version:
>>> from mymodule import MyObj
>>> util.get_content=Mock(return_value="mocked stuff")
>>> m=MyObj()
>>> m.func()
"stuff"
Contents of mymodule.py
from util import get_content
class MyObj:
def func():
get_content()
So I guess my question is - how do I get invoke the Mocked version of a function from inside a module that I call?
It appears that the from module import function may be to blame here, in that it doesn't point to the Mocked function.
The general case would be to use patch from mock. Consider the following:
utils.py
def get_content():
return 'stuff'
mymodule.py
from util import get_content
class MyClass(object):
def func(self):
return get_content()
test.py
import unittest
from mock import patch
from mymodule import MyClass
class Test(unittest.TestCase):
#patch('mymodule.get_content')
def test_func(self, get_content_mock):
get_content_mock.return_value = 'mocked stuff'
my_class = MyClass()
self.assertEqual(my_class.func(), 'mocked stuff')
self.assertEqual(get_content_mock.call_count, 1)
get_content_mock.assert_called_once()
Note how get_content is mocked, it is not util.get_content, rather mymodule.get_content since we are using it in mymodule.
Above has been tested with mock v2.0.0, nosetests v1.3.7 and python v2.7.9.
I think I have a workaround, though it's still not quite clear on how to solve the general case
In mymodule, if I replace
from util import get_content
class MyObj:
def func():
get_content()
with
import util
class MyObj:
def func():
util.get_content()
The Mock seems to get invoked. It looks like the namespaces need to match (which makes sense). However, the weird thing is that I would expect
import mymodule
mymodule.get_content = mock.Mock(return_value="mocked stuff")
to do the trick in the original case where I am using the from/import syntax (which now pulls in get_content into mymodule). But this still refers to the unmocked get_content.
Turns out the namespace matters - just need to keep that in mind when writing your code.
You have to patch the function where it is being used. In your case that would be in the mymodule module.
import mymodule
>>> mymodule.get_content = Mock(return_value="mocked stuff")
>>> m = mymodule.MyObj()
>>> m.func()
"mocked stuff"
There is a reference in the docs here: http://docs.python.org/dev/library/unittest.mock.html#where-to-patch
Let's assume you're creating your mock inside module foobar:
import util, mock
util.get_content = mock.Mock(return_value="mocked stuff")
If you import mymodule and call util.get_content without first importing foobar, your mock will not be installed:
import util
def func()
print util.get_content()
func()
"stuff"
Instead:
import util
import foobar # substitutes the mock
def func():
print util.get_content()
func()
"mocked stuff"
Note that foobar can be imported from anywhere (module A imports B which imports foobar) as long as foobar is evaluated before util.get_content is called.
While it doesn't provide an answer to your question directly, another possible alternative is to transform your function to a static method using the #staticmethod.
So you could transform your module utils into a class using something like:
class util(object):
#staticmethod
def get_content():
return "stuff"
Then mock patches it correctly.