0

Please consider the following working code

from __future__ import annotations


class A(object):
    def __init__(self, val: int):
        self.val = val

    @property
    def b(self) -> B:
        return B(self)


class B(object):
    def __init__(self, a: A):
        self.a = a


a = A(val=1)
print(a.b.a.val)

Which only works when both classes are defined within the same file. output: 1


I want to put each class in a different file, and doing it like so:

file uv_dataset.cvbnhxx.b2:

from uv_dataset.cvbnhxx.a2 import A


class B(object):
    def __init__(self, a: A):
        self.a = a

file uv_dataset.cvbnhxx.a2:

from uv_dataset.cvbnhxx.b2 import B


class A(object):
    def __init__(self, val: int):
        self.val = val

    @property
    def b(self) -> B:
        return B(self)


a = A(val=1)
print(a.b.a.val)

now gives

ImportError: cannot import name 'B' from partially initialized module 'uv_dataset.cvbnhxx.b2' (most likely due to a circular import) (/home/noam.s/src/uv_metadata/uv_dataset/cvbnhxx/b2.py)


How to make circular annotations resolve properly? I was not able to do it correctly with forward declaration, but likely because I got the syntax wrong.

This answer doesn't work for multiple files.

Gulzar
  • 23,452
  • 27
  • 113
  • 201

1 Answers1

0

Switching to module-only imports and forward-references should work as the documentation says.

First have a directory structure similar to the following.

foo/
  __init__.py
  a.py
  b.py

a.py and b.py import each others module but not the class and __init__.py imports from a and b

__init__.py

from foo.a import A
from foo.b import B

a.py

from foo import b


class A(object):
    def __init__(self, val: int):
        self.val = val

    @property
    def b(self) -> 'b.B':
        return b.B(self)


if __name__ == '__main__':
    a = A(val=1)
    print(a.b.a.val)

b.py

from foo import a


class B(object):
    def __init__(self, a: 'a.A'):
        self.a = a
Iain Shelvington
  • 31,030
  • 3
  • 31
  • 50
  • I am still getting the circular error in my actual code. Can you please show how this should be done in case the file hierarchy is more than one level deep? – Gulzar Nov 09 '22 at 12:46
  • I am getting the error on the init file – Gulzar Nov 09 '22 at 12:48
  • @Gulzar do you have a and b in the `uv_dataset.cvbnhxx` module/folder? If so you should change the imports similar to `from uv_dataset.cvbnhxx.a import A` in `__init__.py` and `from uv_dataset.cvbnhxx import a` in a/b – Iain Shelvington Nov 09 '22 at 12:50
  • I have the imports in the init as you wrote (importing the class) and in the files, importing the files. Even with the imports commented out in the files, I am getting the circular dependency in the init file. Can you show please how to do it correctly when the imports arise from different folders? The file running everything is a different one than the file defining a is a different from the one defining b. Assume everything is in its own directory structure. – Gulzar Nov 09 '22 at 12:56
  • Sorry for it getting complicated, I didn't expect this. – Gulzar Nov 09 '22 at 12:56
  • Which init should the imports go into? – Gulzar Nov 09 '22 at 12:56
  • @Gulzar I would have thought `uv_dataset.cvbnhxx.__init__.py` – Iain Shelvington Nov 09 '22 at 12:57
  • I will have to get back to it and accept when I have more time. For now I will have to leave it untyped. Thanks! – Gulzar Nov 09 '22 at 13:03
  • Any chance the class and file being named exactly the same cause problems? When putting the imports in the correct init it starts failing only when importing the class from a different file – Gulzar Nov 09 '22 at 13:05