Repository: pyca/cryptography

Issue:
Circular import error (again) in 3.4.3
Opening a new issue as the old one (https://github.com/pyca/cryptography/issues/5756) wasn't re-opened after my comment:


@reaperhulk

Hi,

still got some circular import problems here with cryptography 3.4.3 :

`AttributeError: partially initialized module 'cryptography.hazmat.primitives.asymmetric.dh' has no attribute 'DHParameters' (most likely due to a circular import)`

reproducer used (gencrypto.py):

```
pip3 install -U cryptography
Collecting cryptography
  Downloading cryptography-3.4.3-cp36-abi3-manylinux2014_x86_64.whl (3.2 MB)
     |████████████████████████████████| 3.2 MB 5.3 MB/s 


python3 gencrypto.py

Traceback (most recent call last):
  File "gencrypto.py", line 2, in <module>
    from cryptography.hazmat.primitives.asymmetric import dh
  File "/home/xxxxx/.local/lib/python3.8/site-packages/cryptography/hazmat/primitives/asymmetric/dh.py", line 11, in <module>
    from cryptography.hazmat.primitives import serialization
  File "/home/xxxxx/.local/lib/python3.8/site-packages/cryptography/hazmat/primitives/serialization/__init__.py", line 15, in <module>
    from cryptography.hazmat.primitives.serialization.base import (
  File "/home/xxxxx/.local/lib/python3.8/site-packages/cryptography/hazmat/primitives/serialization/base.py", line 28, in <module>
    def load_pem_parameters(data: bytes, backend=None) -> dh.DHParameters:
AttributeError: partially initialized module 'cryptography.hazmat.primitives.asymmetric.dh' has no attribute 'DHParameters' (most likely due to a circular import)
```

**gencrypto.py**

```
import time
from cryptography.hazmat.primitives.asymmetric import dh


for i in [2048,3072,4096]:
    begin=time.time()
    params = dh.generate_parameters(
        generator=2,
        key_size=i,
    )
    end=time.time()
    print('took {}s for {} keysize'.format(int(end-begin), i))
```
Import serialization early to break cyclic import
Fixes: https://github.com/pyca/cryptography/issues/5794
Signed-off-by: Christian Heimes <cheimes@redhat.com>


Discussion:
Thanks, I've got a patch (soon to be a PR) and I think we'll do a point release for this.
Meh, import cycles from hell!

```
 ImportError while loading conftest '/home/runner/work/cryptography/cryptography/tests/conftest.py'.
tests/conftest.py:8: in <module>
    from cryptography.hazmat.backends.openssl import backend as openssl_backend
.tox/py39/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/__init__.py:6: in <module>
    from cryptography.hazmat.backends.openssl.backend import backend
.tox/py39/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/backend.py:12: in <module>
    from cryptography import utils, x509
.tox/py39/lib/python3.9/site-packages/cryptography/x509/__init__.py:7: in <module>
    from cryptography.x509.base import (
.tox/py39/lib/python3.9/site-packages/cryptography/x509/base.py:12: in <module>
    from cryptography.hazmat._types import _PRIVATE_KEY_TYPES, _PUBLIC_KEY_TYPES
.tox/py39/lib/python3.9/site-packages/cryptography/hazmat/_types.py:7: in <module>
    from cryptography.hazmat.primitives.asymmetric import (
.tox/py39/lib/python3.9/site-packages/cryptography/hazmat/primitives/__init__.py:6: in <module>
    from . import serialization
.tox/py39/lib/python3.9/site-packages/cryptography/hazmat/primitives/serialization/__init__.py:15: in <module>
    from cryptography.hazmat.primitives.serialization.base import (
.tox/py39/lib/python3.9/site-packages/cryptography/hazmat/primitives/serialization/base.py:8: in <module>
    from cryptography.hazmat._types import (
E   ImportError: cannot import name '_PRIVATE_KEY_TYPES' from partially initialized module 'cryptography.hazmat._types' (most likely due to a circular import) (/home/runner/work/cryptography/cryptography/.tox/py39/lib/python3.9/site-packages/cryptography/hazmat/_types.py)
ERROR: InvocationError for command /home/runner/work/cryptography/cryptography/.tox/py39/bin/pytest -n auto --cov=cryptography --cov=tests --capture=no --strict --durations=10 --color=yes --wycheproof-root=wycheproof (exited with code 4)
```

Resolving patch:
diff --git a/src/cryptography/hazmat/primitives/serialization/base.py b/src/cryptography/hazmat/primitives/serialization/base.py
--- a/src/cryptography/hazmat/primitives/serialization/base.py
+++ b/src/cryptography/hazmat/primitives/serialization/base.py
@@ -25,7 +25,7 @@ def load_pem_public_key(data: bytes, backend=None) -> _PUBLIC_KEY_TYPES:
     return backend.load_pem_public_key(data)
 
 
-def load_pem_parameters(data: bytes, backend=None) -> dh.DHParameters:
+def load_pem_parameters(data: bytes, backend=None) -> "dh.DHParameters":
     backend = _get_backend(backend)
     return backend.load_pem_parameters(data)
 
@@ -42,6 +42,6 @@ def load_der_public_key(data: bytes, backend=None) -> _PUBLIC_KEY_TYPES:
     return backend.load_der_public_key(data)
 
 
-def load_der_parameters(data: bytes, backend=None) -> dh.DHParameters:
+def load_der_parameters(data: bytes, backend=None) -> "dh.DHParameters":
     backend = _get_backend(backend)
     return backend.load_der_parameters(data)


Test patch: