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:
but for some reason, my hints all look like this:
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.