From c2ffeee2b3da42391aeff819ba11199443b5e6ff Mon Sep 17 00:00:00 2001 From: Gaurav-Kumbhat Date: Wed, 10 Aug 2022 22:35:19 -0400 Subject: [PATCH 1/4] :bug: Fix lazy import error for type checking Signed-off-by: Gaurav-Kumbhat --- import_tracker/lazy_import_errors.py | 12 ++++++++---- test/sample_libs/type_check_deps/__init__.py | 0 .../sample_libs/type_check_deps/type_check_dict.py | 9 +++++++++ .../type_check_deps/type_check_union.py | 9 +++++++++ test/test_lazy_import_errors.py | 14 ++++++++++++++ 5 files changed, 40 insertions(+), 4 deletions(-) create mode 100644 test/sample_libs/type_check_deps/__init__.py create mode 100644 test/sample_libs/type_check_deps/type_check_dict.py create mode 100644 test/sample_libs/type_check_deps/type_check_union.py diff --git a/import_tracker/lazy_import_errors.py b/import_tracker/lazy_import_errors.py index 9563cc4..64be8c8 100644 --- a/import_tracker/lazy_import_errors.py +++ b/import_tracker/lazy_import_errors.py @@ -7,6 +7,7 @@ # Standard from contextlib import AbstractContextManager from functools import partial +from random import randint from types import ModuleType from typing import Callable, Optional, Set import importlib.abc @@ -88,6 +89,7 @@ def _make_extras_import_error( # Get the set of extras modules from the library extras_modules = get_extras_modules() + # Look through frames in the stack to see if there's an extras module extras_module = None @@ -153,7 +155,6 @@ def __new__( ): # When this is used as a base class, we need to pass __classcell__ # through to type.__new__ to avoid a runtime warning. - new_namespace = {} if isinstance(namespace, dict) and "__classcell__" in namespace: new_namespace["__classcell__"] = namespace.get("__classcell__") @@ -244,7 +245,8 @@ def __delitem__(self, *_, **__): self._raise() def __eq__(self, *_, **__): - self._raise() + if not _is_import_time(): + self._raise() def __float__(self, *_, **__): self._raise() @@ -258,14 +260,16 @@ def __ge__(self, *_, **__): def __get__(self, *_, **__): self._raise() - def __getitem__(self, *_, **__): + def __getitem__(self, *args, **kwargs): self._raise() def __gt__(self, *_, **__): self._raise() def __hash__(self, *_, **__): - self._raise() + if not _is_import_time(): + self._raise() + return randint(0, 100000000) def __iadd__(self, *_, **__): self._raise() diff --git a/test/sample_libs/type_check_deps/__init__.py b/test/sample_libs/type_check_deps/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/sample_libs/type_check_deps/type_check_dict.py b/test/sample_libs/type_check_deps/type_check_dict.py new file mode 100644 index 0000000..6bc42ab --- /dev/null +++ b/test/sample_libs/type_check_deps/type_check_dict.py @@ -0,0 +1,9 @@ +import import_tracker +from typing import Dict + +with import_tracker.lazy_import_errors(): + # Third Party + from foo.bar import Bar + + def dummy_type_func(var) -> Dict[str, Bar]: + pass diff --git a/test/sample_libs/type_check_deps/type_check_union.py b/test/sample_libs/type_check_deps/type_check_union.py new file mode 100644 index 0000000..1f286be --- /dev/null +++ b/test/sample_libs/type_check_deps/type_check_union.py @@ -0,0 +1,9 @@ +import import_tracker +from typing import Union + +with import_tracker.lazy_import_errors(): + # Third Party + from foo import Bar + + def dummy_type_func(var) -> Union[str, Bar]: + pass diff --git a/test/test_lazy_import_errors.py b/test/test_lazy_import_errors.py index 9cc4a30..7254882 100644 --- a/test/test_lazy_import_errors.py +++ b/test/test_lazy_import_errors.py @@ -433,3 +433,17 @@ def test_lazy_import_error_import_time_dep(): # calls out to a optional dependency via decorator (hence import time) # Third Party from decorator_deps import opt_decorator + +def test_lazy_import_error_type_dict(): + """Test lazy import error for the case where the call to optional + dependency happens because of type check for Dict + """ + + from type_check_deps import type_check_dict + +def test_lazy_import_error_type_union(): + """Test lazy import error for the case where the call to optional + dependency happens because of type check for Union + """ + + from type_check_deps import type_check_union \ No newline at end of file From 3d203e0a8afd3b8094d5c6dbdad0621b89e42131 Mon Sep 17 00:00:00 2001 From: Gaurav-Kumbhat Date: Wed, 10 Aug 2022 22:39:11 -0400 Subject: [PATCH 2/4] :art: Run formatter Signed-off-by: Gaurav-Kumbhat --- import_tracker/lazy_import_errors.py | 1 - test/sample_libs/type_check_deps/type_check_dict.py | 5 ++++- test/sample_libs/type_check_deps/type_check_union.py | 5 ++++- test/test_lazy_import_errors.py | 6 +++++- 4 files changed, 13 insertions(+), 4 deletions(-) diff --git a/import_tracker/lazy_import_errors.py b/import_tracker/lazy_import_errors.py index 64be8c8..b3d2df8 100644 --- a/import_tracker/lazy_import_errors.py +++ b/import_tracker/lazy_import_errors.py @@ -89,7 +89,6 @@ def _make_extras_import_error( # Get the set of extras modules from the library extras_modules = get_extras_modules() - # Look through frames in the stack to see if there's an extras module extras_module = None diff --git a/test/sample_libs/type_check_deps/type_check_dict.py b/test/sample_libs/type_check_deps/type_check_dict.py index 6bc42ab..4050273 100644 --- a/test/sample_libs/type_check_deps/type_check_dict.py +++ b/test/sample_libs/type_check_deps/type_check_dict.py @@ -1,6 +1,9 @@ -import import_tracker +# Standard from typing import Dict +# Local +import import_tracker + with import_tracker.lazy_import_errors(): # Third Party from foo.bar import Bar diff --git a/test/sample_libs/type_check_deps/type_check_union.py b/test/sample_libs/type_check_deps/type_check_union.py index 1f286be..75bcdb6 100644 --- a/test/sample_libs/type_check_deps/type_check_union.py +++ b/test/sample_libs/type_check_deps/type_check_union.py @@ -1,6 +1,9 @@ -import import_tracker +# Standard from typing import Union +# Local +import import_tracker + with import_tracker.lazy_import_errors(): # Third Party from foo import Bar diff --git a/test/test_lazy_import_errors.py b/test/test_lazy_import_errors.py index 7254882..c676582 100644 --- a/test/test_lazy_import_errors.py +++ b/test/test_lazy_import_errors.py @@ -434,16 +434,20 @@ def test_lazy_import_error_import_time_dep(): # Third Party from decorator_deps import opt_decorator + def test_lazy_import_error_type_dict(): """Test lazy import error for the case where the call to optional dependency happens because of type check for Dict """ + # Third Party from type_check_deps import type_check_dict + def test_lazy_import_error_type_union(): """Test lazy import error for the case where the call to optional dependency happens because of type check for Union """ - from type_check_deps import type_check_union \ No newline at end of file + # Third Party + from type_check_deps import type_check_union From e94db07eba8fe73e1c3501b50749489b5b9d640c Mon Sep 17 00:00:00 2001 From: Gaurav-Kumbhat Date: Thu, 11 Aug 2022 20:27:33 -0400 Subject: [PATCH 3/4] :technologist: Replace randint with id to remove non-determinism Signed-off-by: Gaurav-Kumbhat --- import_tracker/lazy_import_errors.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/import_tracker/lazy_import_errors.py b/import_tracker/lazy_import_errors.py index b3d2df8..879a258 100644 --- a/import_tracker/lazy_import_errors.py +++ b/import_tracker/lazy_import_errors.py @@ -7,7 +7,6 @@ # Standard from contextlib import AbstractContextManager from functools import partial -from random import randint from types import ModuleType from typing import Callable, Optional, Set import importlib.abc @@ -91,7 +90,6 @@ def _make_extras_import_error( # Look through frames in the stack to see if there's an extras module extras_module = None - for frame in inspect.stack(): frame_module = frame.frame.f_globals["__name__"] if frame_module in extras_modules: @@ -259,7 +257,7 @@ def __ge__(self, *_, **__): def __get__(self, *_, **__): self._raise() - def __getitem__(self, *args, **kwargs): + def __getitem__(self, *_, **__): self._raise() def __gt__(self, *_, **__): @@ -268,7 +266,7 @@ def __gt__(self, *_, **__): def __hash__(self, *_, **__): if not _is_import_time(): self._raise() - return randint(0, 100000000) + return id(self) def __iadd__(self, *_, **__): self._raise() From 192f78eda70a618fd4b6ebca5f1a8dbbb63801b4 Mon Sep 17 00:00:00 2001 From: Gaurav-Kumbhat Date: Fri, 12 Aug 2022 12:27:20 -0400 Subject: [PATCH 4/4] :necktie: Handle import time case for __eq__ Signed-off-by: Gaurav-Kumbhat --- import_tracker/lazy_import_errors.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/import_tracker/lazy_import_errors.py b/import_tracker/lazy_import_errors.py index 879a258..dce5b49 100644 --- a/import_tracker/lazy_import_errors.py +++ b/import_tracker/lazy_import_errors.py @@ -241,9 +241,10 @@ def __delete__(self, *_, **__): def __delitem__(self, *_, **__): self._raise() - def __eq__(self, *_, **__): + def __eq__(self, other, *_, **__): if not _is_import_time(): self._raise() + return id(self) == id(other) def __float__(self, *_, **__): self._raise()