Home > Back-end >  Struggling to get type hinting to work with Decorator on Class (vscode - python)
Struggling to get type hinting to work with Decorator on Class (vscode - python)

Time:10-28

I have "borrowed" the following singleton decorator:


class Singleton:
    
    def __init__(self, decorated: Callable) -> None: 
        self._decorated = decorated
        self.initialized = False
    
    def Instance(self) -> Callable:
        """
        Returns the singleton instance. Upon its first call, it creates a
        new instance of the decorated class and calls its `__init__` method.
        On all subsequent calls, the already created instance is returned.
    
        """
        try:
            return self._instance
        except AttributeError:
            self._instance = self._decorated()
            return self._instance
    
    def Initialize(self, *args, **kwargs) -> Callable:
        if self.initialized:
            raise Exception("Singleton already initialized")
        self._instance = self._decorated(*args, **kwargs)
        self.initialized = True
        return self._instance
    
    def __call__(self) -> Callable: 
        if not self.initialized:
            raise Exception("Singleton not initialized")
        return self._instance
    
    def __instancecheck__(self, inst):
        return isinstance(inst, self._decorated)

and i have applied it here:


@Singleton
class x_DB(DBHandler):
    def __init__(self, db_loc:Path):
        self.check_db_exists(db_loc)
        super().__init__(db_loc)
        self.query = self.session.query

        self.check_tables_exist()
        self.check_for_global()
    
    def check_db_exists(self, path:Path) -> bool:
        if not path.exists():
            logger.debug(f"DB: {path} does not exist, creating..")
            path.touch()
            logger.success(f"Successfully created {path}")
        return True

...

Now, generally when i am using an instance of the db class, i will get hints like this:

enter image description here

but for some reason, my hints all look like this:

enter image description here

any tips to fixing this and getting my type hinting back?

have tried messing around with the typing package, updating pylance, returning to jedi, installing pyright, ect. but nothing seems to work


CodePudding user response:

Autocomplete depends highly on your IDE's builtin type-checker, and decorators are notorious for confusing the type-checker. One solution is to make your singleton explicitly typed:

from collections.abc import Callable
from pathlib import Path

from typing import TypeVar, Generic, Type

T = TypeVar('T')


class Singleton(Generic[T]):

    def __init__(self, decorated: Type[T]) -> None:
        self._decorated = decorated
        self.initialized = False

    def Instance(self) -> T:
        """
        Returns the singleton instance. Upon its first call, it creates a
        new instance of the decorated class and calls its `__init__` method.
        On all subsequent calls, the already created instance is returned.

        """
        try:
            return self._instance
        except AttributeError:
            self._instance = self._decorated()
            return self._instance

    def Initialize(self, *args, **kwargs):
        if self.initialized:
            raise Exception("Singleton already initialized")
        self._instance = self._decorated(*args, **kwargs)
        self.initialized = True
        return self._instance

    def __call__(self) -> T:
        if not self.initialized:
            raise Exception("Singleton not initialized")
        return self._instance

    def __instancecheck__(self, inst):
        return isinstance(inst, self._decorated)

This works for me in PyCharm and VS Code.

  • Related