Python nested package issue - python

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

Related

"from module import class" importing other classes from same module

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.

Python import on sub-folders

It`s been a while since I create my classes and import them to my script, using
from <folder> import <file>
and my file.py looks like this:
class myClass:
def __init__():
and so on.
However, whenever I want to use this class on my main script, I have to do:
file.myClass()
Is thera a better way so I could use only "myClass()"?
I have recreated the scenario with the following directory structure:
.
├── outer.py
└── some_folder
└── inner.py
You missed the self in __init__ method:
some_folder/inner.py:
class myClass:
def __init__(self):
print("myClass is initiated")
Import the class from the file when you want to directly use the class name.
outer.py:
from some_folder.inner import myClass
some_object = myClass()
Output:
myClass is initiated
Instead of importing the file, you can import the class
from package.module import MyClass

How to import one class from many classes on one python file

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

'AttributeError: module 'usbiss' has no attribute Aclass' when creating class instance

Trying to write a python package and I cant create an instance of a class in one of my source files.
package layout is:
-packagedir
----README.md
----setup.py
----packagename
--------__init__.py
--------package.py
--------modules
------------file1.py
------------file2.py
in init.py within packagename i have:
from . modules import file1
from . modules import file2
The file file1.py contains a class:
class File1():
def __init__(self):
self.val = 0
# Other methods and such
The file file2.py contains a class:
class File2():
def __init__(self):
self.type = 0
# Other methods and such
and in package.py I have a class as thus:
class Aclass(file1.File1, file2.File2):
def __init__(self):
# nothing important in here yet
I have build and installed my package like this:
python3 setup.py sdist
sudo pip3 install dist/package-0.1.tar.gz
Now I create a file called test.py and put in it the following:
import package
iss = package.Aclass()
when I run the test file i get the following error:
AttributeError: module 'usbiss' has no attribute 'Aclass'
I do not understand why it is that python is not letting me create an instance of class Aclass and thinks I am accessing an attribute. I am sure there is something fundamentally wrong with my import statements or something but i am at a loss as to what it is. How do I correct this so that I can create an instance of Aclass and use its methods?
Thanks.
The problem here was that I was importing the package itself but not a module within that package. I changed my import in test.py to:
from package import package
and this fixed my issue.
Are you sure you are handling your import properly and not introducing any circular dependencies?
Also:
def __init__(file1.File1, file2.File2):
def __init__():
Your init methods are lacking self. They should be:
def __init__(self, file1.File1, file2.File2):
def __init__(self):

Using class from another file in python package and conflicts in __init__()

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

Categories