Skip to content

Bad circular imports are not rejected #61

Open

Description

@ashleyh

If a.py contains

import b
name = 'a'
print(b.name)

and b.py contains

import a
name = 'b'
print(a.name)

then mypy compiles a.py without error, but the generated python throws an error because of the circular import.

(Found this one while refactoring mypy itself into packages)

Activity

  1. JukkaL commented on Jun 27, 2013

    @JukkaL
    Collaborator

    When using the new Python-compatible syntax, the issue is that we do not detect invalid circular imports statically. This is a potential new feature -- updated labels accordingly.

  2. changed the title [-]Circular imports cause invalid python to be generated[/-] [+]Circular imports are not rejected[/+] on Jul 25, 2014
  3. o11c commented on Jul 14, 2015

    @o11c
    Contributor

    Circular imports are valid somtimes, but mypy is buggy, I hit this in #721

  4. JukkaL commented on Jul 26, 2015

    @JukkaL
    Collaborator

    Yeah, circular imports are pretty common in larger programs (even mypy has several). Some circular imports cause the program to always fail, and mypy could detect some of these. I'll edit the title to be less confusing.

  5. changed the title [-]Circular imports are not rejected[/-] [+]Bad circular imports are not rejected[/+] on Jul 26, 2015
  6. o11c commented on Jul 26, 2015

    @o11c
    Contributor

    @JukkaL in my driver PR I remove all the circular imports I think. They are only needed for typechecking (i.e. in string-quoted types), not actually running mypy.

    The workaround I use is if False: import mypy.foo. Any fix that mypy forms should take this into account.

  7. JukkaL commented on Jul 26, 2015

    @JukkaL
    Collaborator

    @o11c I saw that and it's a pretty neat trick. Alternatively, we could define a constant such as MYPY that is always False and do something like this:

    from bar import MYPY
    if MYPY: import foo
    
    def f(x: 'foo.ClassName') -> None: ...
    

    The if statement trick also supports from ... import, unlike a real circular import:

    from bar import MYPY
    if MYPY: from foo import ClassName
    
    def f(x: 'ClassName') -> None: ...
    

    It may be worth it to describe this in mypy documentation.

    Also, mypy could complain if a type imported as above is used without literal escapes.

  8. dosisod commented on May 4, 2020

    @dosisod
    Contributor

    Instead of a MYPY constant, we can use TYPE_CHECKING:

    from typing import TYPE_CHECKING
    
    if TYPE_CHECKING:
        from foo import ClassName
    
    def f(x: 'ClassName') -> None: ...
  9. mahmoudajawad commented on Dec 25, 2020

    @mahmoudajawad
  10. JelleZijlstra commented on Dec 28, 2020

    @JelleZijlstra
  11. hauntsaninja commented on Dec 28, 2020

    @hauntsaninja
  12. mahmoudajawad commented on Dec 28, 2020

    @mahmoudajawad
  13. mahmoudajawad commented on Dec 29, 2020

    @mahmoudajawad
  14. JelleZijlstra commented on Dec 29, 2020

    @JelleZijlstra
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions