I have this error:
My project structure is:
All __init__.py are empty
main.py
from testclass import class1
from testclass import class2
l1 = class1()
l2 = class2()
class1.py
class class1():
def __init__(self):
print('hello')
if __name__ == '__main__':
ldummy = class1()`
class2.py
import class1
class class2(class1.class1):
def __init__(self):
class1.class1.__init__(self)
print('hola')
if __name__ == '__main__':
ldummy = class2()
I don't see what's not good about that
If you read your error message carefully, you will see that the actual error occurs when class2 tries to import class1 which it cannot. The reason for that is that the reference remains the level where main is located even for class2. So you need this content in class2:
from testclass import class1 # Instead of import class1
class class2(class1.class1):
def __init__(self):
class1.class1.__init__(self)
print('hola')
if __name__ == '__main__':
ldummy = class2()
EDIT:
Answering your comment:
There are a few ways to achieve the desired behaviour, but I wouldn't necessarily say that they are pythonic. Before importing, you can add the main folder to the python path in class2.py
import sys
def import():
sys.path.append(main_path)
Alternatively you could also add the path permanently to the python path.
A third option is to use a try-except-clause around your import:
try:
from testclass import class1
except ModuleNotFoundError:
import class1
I would argue that none of these options are great and could eventually cause errors. Better to have clear and unique ways of calling your functions.
Related
With the following setup of the two files a.py
#File a.py
import imp
import inspect
class A(object):
pass
if __name__ == "__main__":
mod = imp.load_source("B", "b.py")
for _, c in inspect.getmembers(mod, inspect.isclass):
print issubclass(c, A)
and
#b.py
from a import A
class B(A):
pass
How do I check in file a.py if a class found in b.py is a subclass of A.
The attempt you see in a.py results in two False being printed. Since B is a subclass of A how do I check it crrectly?
I have found the following solution:
#File a.py
import imp
import inspect
class A(object):
pass
if __name__ == "__main__":
mod = imp.load_source("B", "b.py")
#self import
import a
for _, c in inspect.getmembers(mod, inspect.isclass):
print issubclass(c, a.A)
but still I don't have any idea why it works (while your solution doesn't)
Sorry if this has already been answered using terminology I don't know to search for.
I have one project:
project1/
class1.py
class2.py
Where class2 imports some things from class1, but each has its own if __name__ == '__main__' that uses their respective classes I run frequently. But then, I have a second project which creates a subclass of each of the classes from project1. So I would like project1 to be a package, so that I can import it into project2 nicely:
project2/
project1/
__init__.py
class1.py
class2.py
subclass1.py
subclass2.py
However, I'm having trouble with the importing with this. If I make project1 a package then inside class2.py I would want to import class1.py code using from project1.class1 import class1. This makes project2 code run correctly. But now when I'm trying to use project1 not as a package, but just running code from directly within that directory, the project1 code fails (since it doesn't know what project1 is). If I set it up for project1 to work directly within that directory (i.e. the import in class2 is from class1 import Class1), then this import fails when trying to use project1 as a package from project2.
Is there a way to have it both ways (use project1 both as a package and not as a package)? If there is a way, is it a discouraged way and I should be restructuring my code anyway? Other suggestions on how I should be handling this? Thanks!
EDIT
Just to clarify, the problem arrises because subclass2 imports class2 which in turn imports class1. Depending on which way class2 imports class1 the import will fail from project2 or from project1 because one sees project1 as a package while the other sees it as the working directory.
EDIT 2
I'm using Python 3.5. Apparently this works in Python 2, but not in my current version of python.
EDIT 2: Added code to class2.py to attach the parent directory to the PYTHONPATH to comply with how Python3 module imports work.
import sys
import os
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
Removed relative import of Class1.
Folder structure:
project2
- class3.py
- project1
- __init__.py
- class1.py
- class2.py
project2/project1/class1.py
class Class1(object):
def __init__(self):
super(Class1, self).__init__()
self.name = "DAVE!"
def printname(self):
print(self.name)
def run():
thingamy = Class1()
thingamy.printname()
if __name__ == "__main__":
run()
project2/project1/class2.py
import sys
import os
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
from class1 import Class1
class Class2(Class1):
def childMethod(self):
print('Calling child method')
def run():
thingamy = Class2()
thingamy.printname()
thingamy.childMethod()
if __name__ == "__main__":
run()
project2/class3.py
from project1.class2 import Class2
from project1.class1 import Class1
class Class3(Class2):
def anotherChildMethod(self):
print('Calling another child method')
def run():
thingamy = Class3()
thingamy.printname()
thingamy.anotherChildMethod()
if __name__ == "__main__":
run()
With this setup each of class1, 2 and 3 can be run as standalone scripts.
You could run class2.py from inside the project2 folder, i.e. with the current working directory set to the project2 folder:
user#host:.../project2$ python project1/class2.py
On windows that would look like this:
C:\...project2> python project1/class2.py
Alternatively you could modify the python path inside of class2.py:
import sys
sys.path.append(".../project2")
from project1.class1 import class1
Or modify the PYTHONPATH environment variable similarly.
To be able to extend your project and import for example something in subclass1.py from subclass2.py you should consider starting the import paths always with project2, for example in class2.py:
from project2.project1.class1 import class1
Ofcourse you would need to adjust the methods I just showed to match the new path.
I am currently attempting to write unit tests for my Main.py's main() function
Here is a simplified version of my Main.py:
from Configuration import Configuration # Configuration.py is a file in the same dir
def main():
try:
Configuration('settings.ini')
except:
sys.exit(1) # Test path1
sys.exit(0) # Test path2
if __name__ == '__main__':
main()
In my Unit Tests\MainUnitTests.py I want to import ..\Main.py and fake the Configuration class in such a way that I can hit Test path1 and Test path2
I found that i can assert sys.exit() with the following:
with self.assertRaises(SystemExit) as cm:
main()
self.assertEqual(cm.exception.code, 1)
but I am having trouble overriding the from Configuration import Configuration
Thoughts?
So far I have tried the following within Unit Tests\MainUnitTests.py:
class FakeFactory(object):
def __init__(self, *a):
pass
sys.modules['Configuration'] = __import__('FakeFactory')
class Configuration(FakeFactory):
pass
Another example for demonstration:
foo.py:
from bar import a,b
x = a()
class a(object):
def __init__(self):
self.q = 2
y = a()
print x.q, y.q # prints '1 2' as intended
b() # I want this to print 2 without modifying bar.py
bar.py:
class a(object):
def __init__(self):
self.q = 1
def b():
t = a()
print t.q
when you use the import
from bar import a
it import the name directly into the module, so monkeypatching bar won't help, you need to override a directly in the main file:
def fake_a():
print("OVERRIDEN!")
main.a = fake_a
Do know that unittest has helper functions for this in the mock subpackage, I believe you could do something like:
from unittest.mock import patch
...
with patch("main.a", fake_a) as mock_obj: #there are additional things you can do with the mock_obj
do_stuff()
This would work in your first example with configuration since the class that needs to be patched is not used in the global scope although foo uses bar.a as soon as it is loaded so you would need to patch it before even loading foo:
from unittest.mock import patch
...
with patch("bar.a", fake_a) as mock_obj: #there are additional things you can do with the mock_obj
import foo #now when it loads it will be loaded with the patched name
However in this case foo.a would not be reverted at the end of the with block because it can't be caught by unittest... I really hope your actual use case doesn't use the stuff to be patched at module level.
I'm having trouble getting the if __name == '__main__' trick to work in an IPython, Spyder environment. I've tried every approach given in this thread:
if __name__ == '__main__' in IPython
Here are my super simplified modules
Module1.py
Class UnitTest():
print 'Mod1 UnitTest!'
if __name__ == '__main__':
UnitTest()
Module2.py
import Module1
Class UnitTest():
print 'Mod2 UnitTest!'
if __name__ == '__main__':
UnitTest()
So I run Module2.py and I always am seeing both Mod2 UnitTest and Mod1 UnitTest printed. These are executing in an IPython kernel. I want only the Mod2 UnitTest message to display.
Any idea what's up?
Well I deleted this question earlier out of embarrassment but might as well share in case any other newb sees this.
I forgot to put the UnitTest line inside of the __init__ method. So the unit test was being run every single time when the class was defined and not when the object was instantiated. The code should be:
Module1.py
Class UnitTest():
def __init__(self):
print 'Mod1 UnitTest!'
if __name__ == '__main__':
UnitTest()
Module2.py
import Module1
Class UnitTest():
def __init__(self):
print 'Mod1 UnitTest!'
if __name__ == '__main__':
print 'Mod2 UnitTest!'
I would like to ensure with tests that:
- the application cannot be imported
- the application can be started as a real application (i.e: python src.py)
I'm interested about that, why the following is not working:
src.py
class A:
def x(self):
print('this is x')
if __name__ == '__main__':
A().x()
test.py (snippet)
class Test(unittest.TestCase):
#mock.patch('src.A.x')
def test_main(self, mock_x):
import src
mock_x.assert_any_call()
This test fails... why?
Because the name of the module when imported is src, not __main__.
The easiest solution would be to move that code into a function:
def main():
A().x()
if __name__ == '__main__':
main()
and in your test, you would invoke src.main()
#mock.patch('src.A.x')
def test_main(self, mock_x):
import src
src.main()
mock_x.assert_any_call()
To test that a module is not importable you do not need to use mocks.
See assertRaises.
Just check if an error is thrown on import od module.
with self.assertRaises(...):
...