2

I have a package that contains a module with compatible imports. However, I cannot import from the exposed modules directly; I have to use slightly more inconvenient workarounds.

Inside common/compat.py, I have this:

import bcrypt

In main.py, this does not work:

from common.compat.bcrypt import hashpw

with the error:

Traceback (most recent call last):
  File "main.py", line 2, in <module>
    from common.compat.bcrypt import hashpw
ImportError: No module named bcrypt

However, this works fine:

from common.compat import bcrypt
# now bcrypt.hashpw works fine

Is there any way to make the first one work properly without having to do the second solution? I would prefer from imports for quite a few classes and methods.

0

2 Answers 2

1

The problem is that bcrypt is not actually a submodule of common.compat; the module object is actually a member attribute of the common.compat module object with the name bcrypt within common.compat's namespace. As a consequence, if you want to be able to import bcrypt as if it is a submodule of common.compat as opposed to a value from its namespace, you need to monkey around a bit. You could create a dummy bcrypt module within your package structure then from bcrypt import * inside it to alias it, but probably the better way would be to directly modify sys.modules in compat.py.

import sys
import bcrypt

sys.modules['common.compat.bcrypt'] = bcrypt

As commenters have noted though, modifying sys.modules is dangerous. I'm inferring from the fact that you call your package common.compat that you are creating some sort of compatibility module that implements fallback logic in case some dependency is not available. Instead of hacking sys.modules, you'll likely be better served creating a common.compat.crypto module that looks something like

try:
    from bcrypt import hashpw
except ImportError:
    # Alternative import, hand-written alternative,
    # or function that raises NotImplementedError here

Then in your main.py, just from common.compat.crypto import hashpw.

Sign up to request clarification or add additional context in comments.

3 Comments

Argh, don't give him ideas about modifying sys.modules like this! :) -- +1 for the correct explanation though.
Please put a big warning that messing with sys.modules is not a good idea, especially if the OP doesn't know what he's doing (which he doesn't since he asked this question).
@FerdinandBeyer and Bakuriu, better?
0

Would the following be what you are looking for ?

from common.compat import bcrypt.hashpw

However, it seems a bad idea to build depedencies in such way, because you don't seem to need that compat.py even exist to get your bcrypt module. Thus I would rather do one of the following :

  1. Import bcrypt.hashpw in main.py, as a direct dependency
  2. Import bcrypt from the common/compat.py script like you suggest in your last snippet
  3. Do something with hashpw in common/compat.py (e.g. subclassing or wrapping), and import the subclass/wrapper from compat.py in main.py

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.