bignose
bignose

Reputation: 32367

Relative import of a module within a package

How can I make a module-within-a-package .adipiscing.lorem_ipsum available, in a way which cleanly uses the import system and doesn't leave extraneous names unused?

Given a code base:

foo/
    consecteur.py
    adipiscing/
        lorem_ipsum.py

The consecteur module needs to access the adipiscing.lorem_ipsum module.

This is what I want to do:

# consecteur.py

from . import adipiscing.lorem_ipsum

dolor = adipiscing.lorem_ipsum.dolor_sit_amet()

That doesn't work; from . import adipiscing.lorem_ipsum is a SyntaxError.

Options that don't satisfy

Use implicit relative import

# consecteur.py

import adipiscing.lorem_ipsum

dolor = adipiscing.lorem_ipsum.dolor_sit_amet()

This needlessly confuses whether adipiscing.lorem_ipsum is an absolute or relative import. The code should instead be explicit when an import is relative.

Pull the module out of its namespace package

# consecteur.py

from .adipiscing import lorem_ipsum

dolor = lorem_ipsum.dolor_sit_amet()

This loses the valuable information that is conveyed by reading adipiscing.lorem_ipsum, especially if lorem_ipsum is instead a generic word that needs to be contextualised by the adipiscing package namespace.

Import with a mangled name

# consecteur.py

from .adipiscing import lorem_ipsum as adipiscing_lorem_ipsum

dolor = adipiscing_lorem_ipsum.dolor_sit_amet()

This is visually confusing; someone expecting adipiscing.lorem_ipsum can easily type that expecting it to work, but that name is not available. Making a confusingly-similar name is not a good solution; neither is making a distinct name, since the whole purpose is to make adipiscing.lorem_ipsum available.

This is also ambiguous if one or both of the package or the module names actually have underscores already. If an underscore represents a dot, that becomes indistinguishable from a name that actually contains an underscore.

Import the package, try using the module

# consecteur.py

from . import adipiscing

dolor = adipiscing.lorem_ipsum.dolor_sit_amet()

This is an AttributeError because adipiscing.lorem_ipsum is not available now; a module is not automatically available just by importing the containing package.

Import the package, then import the module but never use its name

# consecteur.py

from . import adipiscing
from .adipiscing import lorem_ipsum

dolor = adipiscing.lorem_ipsum.dolor_sit_amet()

This hack succeeds, but the import statement from .adipiscing import lorem_ipsum declares that we will be using the bare lorem_ipsum name.

Since that's not true, static code checkers will (correctly) complain about an unused import. I agree with those code checkers, so I don't just want to silence the warning; I want to avoid the hack and still get the adipiscing.lorem_ipsum name available.

So, how can I make the adipiscing.lorem_ipsum name available to the code by that name, using an explicit relative import, without unused imports?

Upvotes: 2

Views: 457

Answers (2)

Moinuddin Quadri
Moinuddin Quadri

Reputation: 48120

The syntax you want is not supported by the Python's interpreter. But you may use as as an workaround with "Pull the module out of its namespace package". For example:

from .lorem import ipsum as lorem_ipsum

dolor = lorem_ipsum.dolor_sit_amet()

Doing this you will get the full context that it is lorem's ipsum

Upvotes: 1

bignose
bignose

Reputation: 32367

Currently there seems to be no way to do this using the Python import system.

Upvotes: 0

Related Questions