I'm writing a python package (python 3.6) and have the following directory structure:
package/
| __init__.py
| fileA.py
| fileB.py
| tests/
| | __init__.py
| | test_classA.py
| | test_classB.py
Setup
My files have the following contents:
# package/fileA.py
from package import ClassB
def ClassA:
def __init__(self):
self.my_ClassB = ClassB()
-
# package/fileB.py
def ClassB:
def __init__(self):
self.foo = "bar"
-
# package/tests/test_classB.py
from package import ClassB
# <performs some unit tests here>
-
# package/tests/test_classA.py
from package import ClassA
# <performs some unit tests here>
-
# package/__init__.py
from .fileA import ClassA
from .fileB import ClassB
Circular importing
When I ran python test_classB.py, I get the following traceback error showing that I have circular import statements, which are not allowed by python. Note - the package is not literally called package and I have edited the Traceback to match the toy example above.
Traceback (most recent call last):
File "package/tests/test_classB.py", line 2, in <module>
from package import ClassB
File "/anaconda/lib/python3.5/site-packages/package/__init__.py", line 2, in <module>
from .fileA import ClassA
File "/anaconda/lib/python3.5/site-packages/package/merparse.py", line 2, in <module>
from package import ClassB
ImportError: cannot import name 'ClassB'
Correcting the error
However, when I remove those two lines in my package/__init__.py file:
# package/__init__.py
from .fileA import ClassA
from .fileB import ClassB
...and I change the import method for package/fileA.py:
# package/fileA.py
from package.fileB import ClassB
def ClassA:
def __init__(self):
self.my_ClassB = ClassB()
... package/tests/test_classB.py runs correctly.
My Question
My question is: How can I keep the one file: one class structure in my files and import with from package import ClassA instead of having to import with from package.fileA import ClassA?
In my package I would like to import classes from other files, but don't know how to get around circular importing.
Edit: Solution
Thanks to #mirandak and #martin-kalcok below for their help.
The only file that I had to edit was fileA.py to not refer to the package name in the import statement.
# package/fileA.py
from .fileB import ClassB
def ClassA:
def __init__(self):
self.my_ClassB = ClassB()
The package/__init__.py file still contains import statements in case I want to import the package from other scripts in the future that I don't couple with the package.
# package/__init__.py
from .fileA import ClassA
from .fileB import ClassB
The problem is with package/fileA.py. It's both a part of package and calling the __init__.py file of package as it's imported - creating a circular dependency.
Can you change fileA.py to look like this?
# package/fileA.py
from .fileB import ClassB
def ClassA:
def __init__(self):
self.my_ClassB = ClassB()
First of all, renaming your package to literary "package" really confuses this whole situation, but here's my take on it :D.
I don't think you are dealing with circular dependency, python just states that it cannot import classB from package and that is because there is no file named classB in package directory. Changing import statement to
from package.fileB import ClassB
works because there is directory package which contains file fileB which contains object ClassB.
To answer your question whether you can import classes with statement
from package import ClassB
you can't, unless your package is file and classB is object inside this file. However i don't see how this different import statement would be a dealbraker
Side Note: Your objects ClassB and ClassA are not classes, they are functions. Python uses keyword class to create classes and def to define functions.
Side note 2: Are you sure your __init__.py file needs to hold any code at all?
Personal Note: I know that keeping 1 File / 1 Class structure is matter of personal preferences, it is not required in python and I myself find it much more comfortable to group multiple related classes and functions into one file
Related
Here is is the directory structure:
->src/dir/classes.py
->src/run.py
# classes.py
class A():
def methA():
# class A
class B():
def MethB():
# class B
class C():
def methC():
# class C
then i need to import Class A in run.py file.
from dir.classes import A
A.methA()
i already tried with using from dir.classes import A but it gives me
ModuleNotFoundError: No module named 'dir.classes'; 'classes' is not a package error
So how can i do that?
You need to put__init__.py file on your dir folder.
This way dir will be recognized as python package.
First, you must have __init__.py in each directory for Python to recognize them as packages.
Then, you should use from dir.classes import A. A is the name of the class, you shouldn't use Class A
I'm new to python, but skilled on java. Now I'm facing a annoying question when training on python3.5, I have such a src structure:
/project-root
--main.py
--ModelImpl.py #subclass of BaseModel
--ActionImpl.py #subclass of BaseAction
--/base
----BaseModel.py #base class of all
----BaseAction.py #subclass of BaseModel
----modulescript.py
in main.py:
from ModelImpl import ModelImpl
from ActionImpl import ActionImpl
modelImpl = ModelImpl()
actionImpl = ActionImpl()
in modulescript.py:
from BaseAction import BaseAction
baseAction = BaseAction()
in BaseModel.py:
class BaseModel:
def __init__(self):
print("BaseModel")
in BaseAction.py:
from .BaseModel import BaseModel
class BaseAction(BaseModel):
def __init__(self):
super().__init__()
print("BaseAction")
in ModelImpl.py:
from base.BaseModel import BaseModel
class ModelImpl(BaseModel):
def __init__(self):
super().__init__()
print("ModelImpl")
in ActionImpl.py:
from base.BaseAction import BaseAction
class ActionImpl(BaseAction):
def __init__(self):
super().__init__()
print("ActionImpl")
Now when I input python3 main.py in terminal, I got printed result:
BaseModel
ModelImpl
BaseModel
BaseAction
ActionImpl
but if I input python3 module function.py, I got error:
Traceback (most recent call last):
File "modulescript.py", line 1, in (module) from BaseAction import BaseAction
File "/home/jerry/projects/test/python/base/BaseAction.py", line 1, in (module) from .BaseModel import BaseModel SystemError: Parent module '' not loaded, cannot perform relative import
I found that It's cause by import statement in BaseAction.py:
from .BaseModel import BaseModel
If I change to from BaseModel import BaseModel, the modulescript.py runs ok, but the main.py will got a error:
File "main.py", line 225, in (module) from ActionImpl import ActionImpl
File "/home/jerry/projects/test/python/ActionImpl.py", line 1, in (module) from base.BaseAction import BaseAction
File "/home/jerry/projects/test/python/base/BaseAction.py", line 1, in (module) from BaseModel import BaseModel
ImportError: No module named 'BaseModel'
Oops. annoying!
In java, you can import any Class from any where if you provide the right path of the class like import com.domain.MyClass;
so, what's the right way to import in python?
This is Python, not Java, you group modules related to eachother in a single package, which is a folder.
To be able to import from a package, you must do a few things first.
Create __init__.py in your package to let interpreter know that it's a package. If there's no such file in a folder, it won't even budge whether you want to import from there or not, it's not a package to it and that's all.
Additionally, if you want (and you should when you're creating a package for others to use) import classes functions and etc in your __init__.py to allow to import them from the package itself directly.
I made a simple example:
project tree:
/root
test.py
/examplepkg
__init__.py
somemodule.py
EDIT: if you want examplepkg to have a "nested" package, as in, package it depends on in some way, you create another folder, and put another __init__.py in it and do the same thing, then in __init__.py of examplepkg you can further "export" it for the top level modules to see. How you do it is up to you, just be consistent.
somemodule.py:
class SomeClass:
def __init__(self):
print("New Instance of SomeClass!")
__init__.py:
from .somemodule import SomeClass # you could see it as exporting
test.py:
from examplepkg import SomeClass
SomeClass()
For more information, read this.
I got the same error but the error got fixed when I changed
from .BaseModel import BaseModel
to
from base.BaseModel import BaseModel
Summary: Using PyDev, I can't get one Python module (FooTest) to import another (FooMock) in the same (test) source folder.
I have two source folders and four Python modules, with the directory structure below. The minimal example code is at the end of the question. Although I have provided a lot of information, please don't let this intimidate you - it's a simple problem scenario.
PyDevProject/
src/ (source folder for prod code)
foo/
__init__.py
Bar.py
Foo.py
test/ (source folder for tests)
foo/
__init__.py
FooMock.py
FooTest.py
The issue here is that when I attempt to import FooMock class in the FooTest module, I get the following error (running PyUnit to run the FooTest tests):
Finding files... done.
Importing test modules ... Traceback (most recent call last):
File "/Applications/Eclipse.app/Contents/Eclipse/plugins/org.python.pydev_4.5.4.201601292234/pysrc/_pydev_runfiles/pydev_runfiles.py", line 468, in __get_module_from_str
mod = __import__(modname)
File "/Users/me/Development/krtiWorkspace/ImportTest/test/foo/FooTest.py", line 4, in <module>
from foo.FooMock import FooMock
ImportError: No module named FooMock
ERROR: Module: FooTest could not be imported (file: /Users/me/Development/krtiWorkspace/ImportTest/test/foo/FooTest.py).
done.
----------------------------------------------------------------------
Ran 0 tests in 0.000s
OK
Things I've tried:
Even though FooMock and FooTest are both in the same Python package, FooMock can't be imported.
Moving FooMock to under the src/ directory works, even if placed under a unique Python package (as long as it's under src/). But this isn't acceptable for me (to have test code in production source folders).
I've ensured the PYTHONPATH settings in PyDev are set to specify both folders are source folders.
Copying and pasting the FooMock code into the FooTest code works. But this isn't acceptable for me (since I'd like to reference FooMock elsewhere, in multiple test files and I don't want multiple copies of FooMock floating around consequently).
Is there anything I can do about this?
Code:
# Code for Bar.py -----------------------------------------------------
class Bar(object):
def __init__(self, foo):
self.foo = foo
def next(self):
self.foo.incr()
# Code for Foo.py -----------------------------------------------------
class Foo(object):
def __init__(self):
self.num = 0
def incr(self):
self.num = self.num + 1
# Code for FooMock.py -------------------------------------------------
class FooMock(object):
def mock_incr(self):
self.hit = True
# Code for FooTest.py -------------------------------------------------
import unittest
from foo.Foo import Foo
from foo.Bar import Bar
from foo.FooMock import FooMock
class Test(unittest.TestCase):
def test_Foo(self):
foo = Foo()
foo.incr()
self.assertEquals(1, foo.num, "should be 1")
def test_Bar(self):
foo = FooMock()
bar = Bar(foo)
bar.next()
if __name__ == "__main__":
unittest.main()
Screenshot of directory:
Image showing directory structure and PYTHONPATH as previously explained
You have a module named foo in your PYTHONPATH twice. In the first directory, where the package foo is found, there is indeed no module named FooMock.
Can you rename the module foo under the test source directory to something else? Like footests instead of foo?
I tried to break up one large file into three smaller files for organization purposes and now nothing works. I'm sure the problem is with my import statements. Main.py imports Members.py and Members imports from RouteTools. However, even after including
import routeTools
...routeTools.tool()
In Members.py, it doesn't work after
Main.py
import Members
...Members.stuff()
I even tried putting
import routeTools
at the top of Main.py as well. What am I doing wrong or is there a better way to organize one file into multiple modules? Thanks.
Edit: "nothing works" = NameError: global name 'tool' is not defined when running routeTools.tool() from Members.py after it has been imported into Main.py
Here is my code:
import routetools
class Member(object):
def __init__(self, fields, scouts, id):
...
self.routes = [routeTools.Route(s) for s in self.scouts ]
...
And this is called in Main.py:
import Members
import routeTools
...
member = Members.Member(self.fields, self.scouts, i)
routeTools contains:
class Route(object):
...
I have been trying to fix this for a bit, and I must be missing something basic here (forgive me, I am relatively new to Python development):
I have a package structure like this:
base
|
-->util
__init__.py
Class1.py
Class2.py
__init__.py
Main.py
My classes are fairly benign:
class Class1(object):
def __init__(self):
# some methods...
class Class2(object):
def __init__(self):
# more methods...
In the Main.py, I have:
import utils
if __name__ == '__main__':
c1 = utils.Class1()
c2 = utils.Class2()
My PYTHONPATH is setup to include src, src\base, and src\base\utils. But, Python gives me this error when trying to run Main.py:
AttributeError: 'module' object has no attribute 'Class1'
Has someone encountered this, and do you know how to fix it? Thanks!
This is a little different than Java. In java each file is usually a class, in python, each file is a module. Given the scenario you describe here, you would do:
import utils.Class1
import utils.Class2
if __name__ == '__main__':
c1 = utils.Class1.Class1()
c2 = utils.Class2.Class2()
You could do a number of things here. For example, you could have a module called "resources" like this:
base ->
utils ->
resources.py
which contains both Class1 and Class2. Then you could do something like:
import utils.resources
c1 = utils.resources.Class1()
etc. But the key is that classes != files in python
did you import your classes into the main.py of the utils module?
just add to utils/init.py:
from Class1 import Class1
from Class2 import Class2
then in your main.py, "import utils" will import those files as utils.Class1 etc