How can I import classes from import *, not modules - python

I have a folder structure as below
\root
|-collections
|-__init__.py
|-collection1.py => contains Collection1 class
|-collection2.py => contains Collection2 class
|-...so on
|-db.py
Inside of db.py, I need to use all of the Collection<n> classes. Is there any way to import them like the code below? Apparently __all__ variable in __init__.py only allows module names, not classes.
# db.py
from root.collections import *
a = Collection1()
b = Collection2()
...
Here's my trial and error
# collections\__init__.py
from collection1 import Collection1
from collection2 import Collection2
from collection3 import Collection3
__all__ = ['Collection1', 'Collection2', 'Collection3']
# db.py
def test_collections():
from root.collections import *
a = Collection1()
test_collections()
And this gives me...
SyntaxError: import * only allowed at module level

Import the classes in __init__.py:
__all__ = ['Collection1', 'Collection2']
from .collection1 import Collection1
from .collection2 import Collection2

Related

Structuring a python project

I need to know how to set up the __init__.py and imports in order to structure a python project where I can use fully qualified names throughout the package.
The package will contain a number of sub packages which may contain clashing names. The classes contained within the package will sub class each other and contain references to each other. The project will be generated so the use of fully qualified names would make life a lot simpler.
This sample project represents the structure I am aiming at, but only contains a single sub project, while the IDE seems happy with it fails when its run.
MyPackage/__init__.py
import SubPackage as SubPackage
MyPackage/SubPackage/__init__.py
from .FileB import ClassB
from .FileA import ClassA
MyPackage/SubPackage/FileA.py
from __future__ import absolute_import
import MyPackage
class ClassA(MyPackage.SubPackage.ClassB):
thingA: 'MyPackage.SubPackage.ClassA'
thingB: MyPackage.SubPackage.ClassB
def __init__(self):
self.thingA = None
self.thingB = None
def test(self):
self.thingA = MyPackage.SubPackage.ClassA()
self.thingB = MyPackage.SubPackage.ClassB()
MyPackage/SubPackage/FileB.py
from __future__ import absolute_import
import MyPackage
class ClassB(object):
nextB: 'MyPackage.SubPackage.ClassB'
def __init__(self):
self.nextB= None
def test(self):
self.nextB= MyPackage.SubPackage.ClassB()
test.py
import MyPackage
x = MyPackage.SubPackage.ClassA()
Error
File "C:\temp\Test.py", line 3, in <module>
import GeneratedLx
File "C:\temp\MyPackage\__init__.py", line 1, in <module>
import Bs as Bs
File "C:\temp\MyPackage\SubPackage\__init__.py", line 12, in <module>
from .FileA import ClassA
File "C:\temp\MyPackage\SubPackage\FileA.py", line 5, in <module>
class ClassA(MyPackage.SubPackage.ClassB):
AttributeError: module 'MyPackage' has no attribute 'SubPackage'
You already cannot have name conflicts at the SubPackage level, so adding MyPackage is entirely redundant, and doesn't work quite the way you're trying to use it. This may be due to when names are bound or something else, but ultimately there should be no instance when you need it. This leaves you to slightly edit the files: "FileA.py", and "FileB.py":
FileA.py
from __future__ import absolute_import
from MyPackage import SubPackage
class ClassA(SubPackage.ClassB):
thingA: 'SubPackage.ClassA'
thingB: SubPackage.ClassB
def __init__(self):
self.thingA = None
self.thingB = None
def test(self):
self.thingA = SubPackage.ClassA()
self.thingB = SubPackage.ClassB()
FileB.py
from __future__ import absolute_import
from MyPackage import SubPackage
class ClassB(object):
nextB: 'SubPackage.ClassB'
def __init__(self):
self.nextB= None
def test(self):
self.nextB= SubPackage.ClassB()
The import statement is also equivalent to from .. import Subpackage using relative imports rather than absolute if desired. Stylistically I tend to use relative imports to help me quickly pick out which imports are part of my project, and which ones are external dependencies.

How can I import all files under subdir in python

I have dir structure like this:
Proj/
run.py
Util/
__init__.py
x.py
y.py
In x.py, I define a function:
def p():
return 1
In y.py, I define:
def q():
return 2
Currently in run.py, I'll use
from Util import *
But I have to call them using
x.p()
y.q()
But I want to call them using
p()
q()
Is there a way that I can do that? Like (as I imagine)
from Util.* import *
Bring the names up into the package namespace, by using star imports in the __init__.py:
# in util/__init__.py
from util.x import *
from util.y import *
In each submodule, define the names which you want to export by using the __all__ name:
# in x.py
__all__ = ['p']
And:
# in y.py
__all__ = ['q']
This is a pretty standard usage of the __init__.py module within a package, documented here.

How to make Python absolute import lines shorter?

this is my project structure (just an example to illustrate the problem):
.
├── hello_world
│   ├── __init__.py
│   └── some
│   └── very_nested
│   └── stuff.py
└── tests
└── test_stuff.py
The test_stuff.py file (for py.test):
from hello_world.some.very_nested.stuff import Magic
from hello_world.some.very_nested.other_stuff import MoreMagic
def test_magic_fact_works():
assert Magic().fact(3) == 6
# ...
Is there any way how to make the import lines shorter? They get too long in the real project.
For example, this would be nice, but it doesn't work :)
import hello_world.some.very_nested as vn
from vn.stuff import Magic
from vn.other_stuff import MoreMagic
I cannot use relative imports (I assume) beucase the tests are not inside the package. I could move them, but is it possible without changing project structure?
As #jonrsharpe says, you can aggregate your packages in a django style:
"""
Django validation and HTML form handling.
"""
from django.core.exceptions import ValidationError # NOQA
from django.forms.boundfield import * # NOQA
from django.forms.fields import * # NOQA
from django.forms.forms import * # NOQA
from django.forms.formsets import * # NOQA
from django.forms.models import * # NOQA
from django.forms.widgets import * # NOQA
And in your subpackage, eg.: django.forms.widgets add this:
__all__ = (
'Media', 'MediaDefiningClass', 'Widget', 'TextInput', 'NumberInput',
'EmailInput', 'URLInput', 'PasswordInput', 'HiddenInput',
'MultipleHiddenInput', 'FileInput', 'ClearableFileInput', 'Textarea',
'DateInput', 'DateTimeInput', 'TimeInput', 'CheckboxInput', 'Select',
'NullBooleanSelect', 'SelectMultiple', 'RadioSelect',
'CheckboxSelectMultiple', 'MultiWidget', 'SplitDateTimeWidget',
'SplitHiddenDateTimeWidget', 'SelectDateWidget',
)
To specify which items you want to import when using import *, this way you can organize your packages as deep as you want and keep them accessible at the same time.
In your case it would be something like:
hello_world/__init__.py
from hello_world.some.very_nested.stuff import *
from hello_world.some.very_nested.other_stuff import *
SO when importing your packages in tests for instance, you get this: from hello_world import Magic
Put into hello_world/__init__.py:
from __future__ import absolute_import
from .some import *
Into hello_world/some/__init__.py:
from __future__ import absolute_import
from .very_nested import *
Into hello_world/some/very_nested/__init__.py:
from __future__ import absolute_import
from .stuff import Magic
from .other_stuff import MoreMagic
So if hello_world/some/very_nested/stuff.py contains:
class Magic:
pass
And hello_world/some/very_nested/other_stuff.py contains:
class OtherMagic:
pass
Then you can easy import it. tests/test_stuff.py:
import pytest
from hello_world import Magic
from hello_world import MoreMagic
#pytest.mark.parametrize('cls', [Magic, MoreMagic])
def test_magic(cls):
assert cls()

Import classes from submodules into (aliased) namespace

I have the following package structure:
package_name/
__init__.py
some_module.py
another_module.py
# other classes
I'm using this package from another Python file, in which I would like to do the following:
declare an alias for package_name
import package_name as pn
and refer to classes inside some_module.py, another_module.py, etc. as follows:
instance = pn.SomeClass(pn.AnotherClass(x, y))
i.e. omitting the module name and instead using only the package name alias.
Something like this:
import package_name as pn
from package_name import some_module to pn
Is this, or anything equivalent, possible?
I can do this:
from package_name.some_module import SomeClass
from package_name.another_module import AnotherClass
instance = SomeClass(AnotherClass(x, y))
and this:
import package_name.some_module
import package_name.another_module
instance = pn.some_module.SomeClass(pn.some_module.AnotherClass(x, y))
but this doesn't work
import package_name.some_module as pn
import package_name.another_module as pn
instance = pn.SomeClass(pn.AnotherClass(x, y))
because the second as pn overrides the first one.
The syntax to import a single module from the package is:
from package_name import some_module as pn
To have access from package_name to the classes defined inside the other modules, the right thing to do is to import these classes, explictly or using some tool, to the __init__.py file inside package_name:
package_name/__init__.py:
from .some_module import a_class
from .another_module import another_class
And that will allow you to simply do:
import package_name as pn
pn.a_class

Python: cannot import name funct Error

So I have this directory structure:
proj/
|
---/subDirA
|
---__init__.py
---fileA.py
|
---/subDirB
|
---__init__.py
---fileB.py
|
---start.py
So what I'm trying to do is from fileB.py import a function in FileA.py. So I tried this:
from subDirA.fileA import funct
When I do this I get the following error:
ImportError: cannot import name funct
But If I do this instead:
from subDirA.fileA import *
I dont get the error.. Can some one explain why am I getting this error?
I also tried the following without any success: (using absolute_import)
from .subDirA.fileA import funct
(The real function name is send_message())
UPDATE
Here are the real imports for better reference, in File A I have the following imports:
import pika
import logging
import tasks
import ConfigParser
and here I have a function def:
def send_message():
and in FileB I have:
from celery.utils.log import get_task_logger
from jsonpath_rw import parse
import dateutil.parser
import json
from pikahelper.rabbit import * # Tried using send_message and it exploded, weird..
##
# SubDirA/FileA.py => pikahelper/rabbit.py ;)
##
Also I'm calling start.py which also calls SubDirA/FileA.py for another function..

Categories

Resources