connor-makowski / type_enforced

A pure python type enforcer for annotations. Enforce types in python functions and methods.
MIT License
45 stars 2 forks source link

Future annotations does errors when using type_enforced.Enforcer #35

Open liadlevy-pando opened 8 months ago

liadlevy-pando commented 8 months ago

Hi,

I have an issue when importing from __future__ import annotations

It will lead to

TypeError: (xxx.__init__): Type mismatch for typed variableyyyy. Expected one of the following['dict']but got<class 'dict'>instead.

@type_enforced.Enforcer(enabled=True)
class xxx:
    def __init__(self, vvvv=None, metadata: bbb = None, ccc=None) -> None:
        pass

xxx(vvvv="1 data", bbb={"s": "s"})

When deleting the import all works as expected

Thanks

connor-makowski commented 8 months ago

Hi @liadlevy-pando! Thanks for creating an issue.

Unfortunately __future__.annotations is actually quite the breaking change in python deep under the hood. It has been delayed until python 4.0 as of my last check.

With that said, I should probably add some notes to the documentation to make this more clear.

I will also consider adding __future_.annotations support. Let me mull this over a bit and update my thoughts here soon.

Tagging https://github.com/connor-makowski/type_enforced/issues/27 as a related issue.

Connor

Ashark commented 7 months ago

I am having exactly #27 issue. There seems to be no workaround (besides commenting from __future__ import annotations)?

I tried:

import sys
if sys.version_info < (3, 10):
    from __future__ import annotations

but then I get SyntaxError: from __future__ imports must occur at the beginning of the file.

I also tried

from __future__ import annotations
import sys
if sys.version_info > (3, 9):
    sys.modules.pop("annotations")

it says KeyError: 'annotations'.

Also tried:

from __future__ import annotations
import sys
if sys.version_info > (3, 9):
    del annotations

but still getting Type mismatch for typed variable `options`. Expected one of the following `['list']` but got `<class 'list'>` instead..

Ashark commented 7 months ago

It also seems I cannot just omit from __future__ import annotations for python > 3.9, because then cleaner annotations cannot be used with TYPE_CHECKING (see https://stackoverflow.com/a/39757388/7869636):

I.e. I would need to use string instead of class name:

# some_file.py

# <-- See, I do not have from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
    from main import Main

class MyObject(object):
    def func2(self, some_param: 'Main'):  # <-- see, I have to use 'Main' as a string

In other words, I cannot have cleaner annotations and type-enforcer at the same time :(.

Also, even if I go with string approach, then type-enforcer (1.4.0) still fails to understand that:

Type mismatch for typed variable some_param. Expected one of the following ["Main"] but got <class "Main"> instead.

connor-makowski commented 7 months ago

Hey. Unfortunately, solving this issue about future is not something I can currently work on. For now, I just updated the main documentation to note that this is not supported at the moment. This may be something that is worked on in the future.

Tagging related commit: https://github.com/connor-makowski/type_enforced/commit/08d8d24d7c360f9280412b7903f1a0a175a9bf2a

connor-makowski commented 7 months ago

It also seems I cannot just omit from __future__ import annotations for python > 3.9, because then cleaner annotations cannot be used with TYPE_CHECKING (see https://stackoverflow.com/a/39757388/7869636):

I.e. I would need to use string instead of class name:

# some_file.py

# <-- See, I do not have from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
    from main import Main

class MyObject(object):
    def func2(self, some_param: 'Main'):  # <-- see, I have to use 'Main' as a string

In other words, I cannot have cleaner annotations and type-enforcer at the same time :(.

Also, even if I go with string approach, then type-enforcer (1.4.0) still fails to understand that:

Type mismatch for typed variable some_param. Expected one of the following ["Main"] but got <class "Main"> instead.

See my comments here: https://github.com/connor-makowski/type_enforced/issues/32#issuecomment-2034614463

Note: If you want cleaner annotations, most of them are supported after python 3.9. You might consider bumping to a version of python greater than 3.10.