coady / multimethod

Multiple argument dispatching.
https://coady.github.io/multimethod
Other
277 stars 24 forks source link

Support for postponed evaluation of annotation #18

Closed hzhangxyz closed 3 years ago

hzhangxyz commented 3 years ago

Postponed evaluation will be added into python3.10, see this, and we can already use it since python 3.7

But multimethod does not support it very well. For example, I have three file in same directory:

a.py:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from __future__ import annotations
from multimethod import multimethod
import b

class A:
    @multimethod
    def ping(self, v: b.B):
        print(self, "ping", v)

b.py:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from __future__ import annotations
from multimethod import multimethod
import a

class B:
    @multimethod
    def ping(self, v: a.A):
        print(self, "ping", v)

and main.py:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from __future__ import annotations

import a
import b

a.A().ping(b.B())

run python main.py and the program crash

the output is

Traceback (most recent call last):
  File "/mnt/d/Home/Downloads/main.py", line 6, in <module>
    import a
  File "/mnt/d/Home/Downloads/a.py", line 6, in <module>
    import b
  File "/mnt/d/Home/Downloads/b.py", line 8, in <module>
    class B:
  File "/mnt/d/Home/Downloads/b.py", line 10, in B
    def ping(self, v: a.A):
  File "/usr/lib/python3.9/site-packages/multimethod/__init__.py", line 121, in __init__
    self[get_types(func)] = func
  File "/usr/lib/python3.9/site-packages/multimethod/__init__.py", line 25, in get_types
    annotations = dict(typing.get_type_hints(func))
  File "/usr/lib/python3.9/typing.py", line 1386, in get_type_hints
    value = _eval_type(value, globalns, localns)
  File "/usr/lib/python3.9/typing.py", line 254, in _eval_type
    return t._evaluate(globalns, localns, recursive_guard)
  File "/usr/lib/python3.9/typing.py", line 493, in _evaluate
    eval(self.__forward_code__, globalns, localns),
  File "<string>", line 1, in <module>
AttributeError: partially initialized module 'a' has no attribute 'A' (most likely due to a circular import)
coady commented 3 years ago

Thanks for the report.