utils: simplify sentinel object
Use an enum to represent the sentinel rather than a singleton object. Signed-off-by: Eric Callahan <arksine.code@gmail.com>
This commit is contained in:
parent
0e80e301f0
commit
2cda75ff2c
|
@ -15,7 +15,7 @@ from io import BytesIO
|
|||
from functools import reduce
|
||||
from threading import Lock as ThreadLock
|
||||
import lmdb
|
||||
from ..utils import SentinelClass, ServerError
|
||||
from ..utils import Sentinel, ServerError
|
||||
|
||||
# Annotation imports
|
||||
from typing import (
|
||||
|
@ -61,8 +61,6 @@ RECORD_DECODE_FUNCS = {
|
|||
ord("{"): lambda x: json.loads(bytes(x)),
|
||||
}
|
||||
|
||||
SENTINEL = SentinelClass.get_instance()
|
||||
|
||||
def getitem_with_default(item: Dict, field: Any) -> Any:
|
||||
if not isinstance(item, Dict):
|
||||
raise ServerError(
|
||||
|
@ -346,14 +344,14 @@ class MoonrakerDatabase:
|
|||
def get_item(self,
|
||||
namespace: str,
|
||||
key: Optional[Union[List[str], str]] = None,
|
||||
default: Any = SENTINEL
|
||||
default: Any = Sentinel.MISSING
|
||||
) -> Future[Any]:
|
||||
return self._run_command(self._get_impl, namespace, key, default)
|
||||
|
||||
def _get_impl(self,
|
||||
namespace: str,
|
||||
key: Optional[Union[List[str], str]] = None,
|
||||
default: Any = SENTINEL
|
||||
default: Any = Sentinel.MISSING
|
||||
) -> Any:
|
||||
try:
|
||||
if key is None:
|
||||
|
@ -363,7 +361,7 @@ class MoonrakerDatabase:
|
|||
val = reduce(operator.getitem, # type: ignore
|
||||
key_list[1:], ns)
|
||||
except Exception as e:
|
||||
if not isinstance(default, SentinelClass):
|
||||
if default is not Sentinel.MISSING:
|
||||
return default
|
||||
if isinstance(e, self.server.error):
|
||||
raise
|
||||
|
@ -875,7 +873,7 @@ class NamespaceWrapper:
|
|||
return self.db._get_namespace(self.namespace)
|
||||
|
||||
def __getitem__(self, key: Union[List[str], str]) -> Future[Any]:
|
||||
return self.get(key, default=SENTINEL)
|
||||
return self.get(key, default=Sentinel.MISSING)
|
||||
|
||||
def __setitem__(self,
|
||||
key: Union[List[str], str],
|
||||
|
@ -908,13 +906,13 @@ class NamespaceWrapper:
|
|||
|
||||
def pop(self,
|
||||
key: Union[List[str], str],
|
||||
default: Any = SENTINEL
|
||||
default: Any = Sentinel.MISSING
|
||||
) -> Union[Future[Any], Task[Any]]:
|
||||
if not self.server.is_running():
|
||||
try:
|
||||
val = self.delete(key).result()
|
||||
except Exception:
|
||||
if isinstance(default, SentinelClass):
|
||||
if default is Sentinel.MISSING:
|
||||
raise
|
||||
val = default
|
||||
fut = self.eventloop.create_future()
|
||||
|
@ -925,7 +923,7 @@ class NamespaceWrapper:
|
|||
try:
|
||||
val = await self.delete(key)
|
||||
except Exception:
|
||||
if isinstance(default, SentinelClass):
|
||||
if default is Sentinel.MISSING:
|
||||
raise
|
||||
val = default
|
||||
return val
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
# This file may be distributed under the terms of the GNU GPLv3 license.
|
||||
|
||||
from __future__ import annotations
|
||||
from ..utils import SentinelClass
|
||||
from ..utils import Sentinel
|
||||
from ..websockets import WebRequest, Subscribable
|
||||
|
||||
# Annotation imports
|
||||
|
@ -35,7 +35,6 @@ SUBSCRIPTION_ENDPOINT = "objects/subscribe"
|
|||
STATUS_ENDPOINT = "objects/query"
|
||||
OBJ_LIST_ENDPOINT = "objects/list"
|
||||
REG_METHOD_ENDPOINT = "register_remote_method"
|
||||
SENTINEL = SentinelClass.get_instance()
|
||||
|
||||
class KlippyAPI(Subscribable):
|
||||
def __init__(self, config: ConfigHelper) -> None:
|
||||
|
@ -84,20 +83,20 @@ class KlippyAPI(Subscribable):
|
|||
self,
|
||||
method: str,
|
||||
params: Dict[str, Any],
|
||||
default: Any = SENTINEL
|
||||
default: Any = Sentinel.MISSING
|
||||
) -> Any:
|
||||
try:
|
||||
req = WebRequest(method, params, conn=self)
|
||||
result = await self.klippy.request(req)
|
||||
except self.server.error:
|
||||
if isinstance(default, SentinelClass):
|
||||
if default is Sentinel.MISSING:
|
||||
raise
|
||||
result = default
|
||||
return result
|
||||
|
||||
async def run_gcode(self,
|
||||
script: str,
|
||||
default: Any = SENTINEL
|
||||
default: Any = Sentinel.MISSING
|
||||
) -> str:
|
||||
params = {'script': script}
|
||||
result = await self._send_klippy_request(
|
||||
|
@ -123,21 +122,21 @@ class KlippyAPI(Subscribable):
|
|||
return await self.run_gcode(script)
|
||||
|
||||
async def pause_print(
|
||||
self, default: Union[SentinelClass, _T] = SENTINEL
|
||||
self, default: Union[Sentinel, _T] = Sentinel.MISSING
|
||||
) -> Union[_T, str]:
|
||||
self.server.send_event("klippy_apis:pause_requested")
|
||||
return await self._send_klippy_request(
|
||||
"pause_resume/pause", {}, default)
|
||||
|
||||
async def resume_print(
|
||||
self, default: Union[SentinelClass, _T] = SENTINEL
|
||||
self, default: Union[Sentinel, _T] = Sentinel.MISSING
|
||||
) -> Union[_T, str]:
|
||||
self.server.send_event("klippy_apis:resume_requested")
|
||||
return await self._send_klippy_request(
|
||||
"pause_resume/resume", {}, default)
|
||||
|
||||
async def cancel_print(
|
||||
self, default: Union[SentinelClass, _T] = SENTINEL
|
||||
self, default: Union[Sentinel, _T] = Sentinel.MISSING
|
||||
) -> Union[_T, str]:
|
||||
self.server.send_event("klippy_apis:cancel_requested")
|
||||
return await self._send_klippy_request(
|
||||
|
@ -163,7 +162,7 @@ class KlippyAPI(Subscribable):
|
|||
return result
|
||||
|
||||
async def list_endpoints(self,
|
||||
default: Union[SentinelClass, _T] = SENTINEL
|
||||
default: Union[Sentinel, _T] = Sentinel.MISSING
|
||||
) -> Union[_T, Dict[str, List[str]]]:
|
||||
return await self._send_klippy_request(
|
||||
LIST_EPS_ENDPOINT, {}, default)
|
||||
|
@ -173,7 +172,7 @@ class KlippyAPI(Subscribable):
|
|||
|
||||
async def get_klippy_info(self,
|
||||
send_id: bool = False,
|
||||
default: Union[SentinelClass, _T] = SENTINEL
|
||||
default: Union[Sentinel, _T] = Sentinel.MISSING
|
||||
) -> Union[_T, Dict[str, Any]]:
|
||||
params = {}
|
||||
if send_id:
|
||||
|
@ -182,7 +181,7 @@ class KlippyAPI(Subscribable):
|
|||
return await self._send_klippy_request(INFO_ENDPOINT, params, default)
|
||||
|
||||
async def get_object_list(self,
|
||||
default: Union[SentinelClass, _T] = SENTINEL
|
||||
default: Union[Sentinel, _T] = Sentinel.MISSING
|
||||
) -> Union[_T, List[str]]:
|
||||
result = await self._send_klippy_request(
|
||||
OBJ_LIST_ENDPOINT, {}, default)
|
||||
|
@ -192,7 +191,7 @@ class KlippyAPI(Subscribable):
|
|||
|
||||
async def query_objects(self,
|
||||
objects: Mapping[str, Optional[List[str]]],
|
||||
default: Union[SentinelClass, _T] = SENTINEL
|
||||
default: Union[Sentinel, _T] = Sentinel.MISSING
|
||||
) -> Union[_T, Dict[str, Any]]:
|
||||
params = {'objects': objects}
|
||||
result = await self._send_klippy_request(
|
||||
|
@ -203,7 +202,7 @@ class KlippyAPI(Subscribable):
|
|||
|
||||
async def subscribe_objects(self,
|
||||
objects: Mapping[str, Optional[List[str]]],
|
||||
default: Union[SentinelClass, _T] = SENTINEL
|
||||
default: Union[Sentinel, _T] = Sentinel.MISSING
|
||||
) -> Union[_T, Dict[str, Any]]:
|
||||
for obj, items in objects.items():
|
||||
if obj in self.host_subscription:
|
||||
|
|
|
@ -14,7 +14,7 @@ import threading
|
|||
import copy
|
||||
import logging
|
||||
from io import StringIO
|
||||
from .utils import SentinelClass
|
||||
from .utils import Sentinel
|
||||
from .components.template import JinjaTemplate
|
||||
|
||||
# Annotation imports
|
||||
|
@ -41,7 +41,6 @@ if TYPE_CHECKING:
|
|||
_T = TypeVar("_T")
|
||||
ConfigVal = Union[None, int, float, bool, str, dict, list]
|
||||
|
||||
SENTINEL = SentinelClass.get_instance()
|
||||
DOCS_URL = "https://moonraker.readthedocs.io/en/latest"
|
||||
|
||||
class ConfigError(Exception):
|
||||
|
@ -120,7 +119,7 @@ class ConfigHelper:
|
|||
def _get_option(self,
|
||||
func: Callable[..., Any],
|
||||
option: str,
|
||||
default: Union[SentinelClass, _T],
|
||||
default: Union[Sentinel, _T],
|
||||
above: Optional[Union[int, float]] = None,
|
||||
below: Optional[Union[int, float]] = None,
|
||||
minval: Optional[Union[int, float]] = None,
|
||||
|
@ -138,7 +137,7 @@ class ConfigHelper:
|
|||
try:
|
||||
val = func(section, option)
|
||||
except (configparser.NoOptionError, configparser.NoSectionError) as e:
|
||||
if isinstance(default, SentinelClass):
|
||||
if default is Sentinel.MISSING:
|
||||
raise ConfigError(str(e)) from None
|
||||
val = default
|
||||
section = self.section
|
||||
|
@ -198,7 +197,7 @@ class ConfigHelper:
|
|||
|
||||
def get(self,
|
||||
option: str,
|
||||
default: Union[SentinelClass, _T] = SENTINEL,
|
||||
default: Union[Sentinel, _T] = Sentinel.MISSING,
|
||||
deprecate: bool = False
|
||||
) -> Union[str, _T]:
|
||||
return self._get_option(
|
||||
|
@ -207,7 +206,7 @@ class ConfigHelper:
|
|||
|
||||
def getint(self,
|
||||
option: str,
|
||||
default: Union[SentinelClass, _T] = SENTINEL,
|
||||
default: Union[Sentinel, _T] = Sentinel.MISSING,
|
||||
above: Optional[int] = None,
|
||||
below: Optional[int] = None,
|
||||
minval: Optional[int] = None,
|
||||
|
@ -220,7 +219,7 @@ class ConfigHelper:
|
|||
|
||||
def getboolean(self,
|
||||
option: str,
|
||||
default: Union[SentinelClass, _T] = SENTINEL,
|
||||
default: Union[Sentinel, _T] = Sentinel.MISSING,
|
||||
deprecate: bool = False
|
||||
) -> Union[bool, _T]:
|
||||
return self._get_option(
|
||||
|
@ -229,7 +228,7 @@ class ConfigHelper:
|
|||
|
||||
def getfloat(self,
|
||||
option: str,
|
||||
default: Union[SentinelClass, _T] = SENTINEL,
|
||||
default: Union[Sentinel, _T] = Sentinel.MISSING,
|
||||
above: Optional[float] = None,
|
||||
below: Optional[float] = None,
|
||||
minval: Optional[float] = None,
|
||||
|
@ -242,7 +241,7 @@ class ConfigHelper:
|
|||
|
||||
def getlists(self,
|
||||
option: str,
|
||||
default: Union[SentinelClass, _T] = SENTINEL,
|
||||
default: Union[Sentinel, _T] = Sentinel.MISSING,
|
||||
list_type: Type = str,
|
||||
separators: Tuple[Optional[str], ...] = ('\n',),
|
||||
count: Optional[Tuple[Optional[int], ...]] = None,
|
||||
|
@ -292,7 +291,7 @@ class ConfigHelper:
|
|||
|
||||
def getlist(self,
|
||||
option: str,
|
||||
default: Union[SentinelClass, _T] = SENTINEL,
|
||||
default: Union[Sentinel, _T] = Sentinel.MISSING,
|
||||
separator: Optional[str] = '\n',
|
||||
count: Optional[int] = None,
|
||||
deprecate: bool = False
|
||||
|
@ -302,7 +301,7 @@ class ConfigHelper:
|
|||
|
||||
def getintlist(self,
|
||||
option: str,
|
||||
default: Union[SentinelClass, _T] = SENTINEL,
|
||||
default: Union[Sentinel, _T] = Sentinel.MISSING,
|
||||
separator: Optional[str] = '\n',
|
||||
count: Optional[int] = None,
|
||||
deprecate: bool = False
|
||||
|
@ -312,7 +311,7 @@ class ConfigHelper:
|
|||
|
||||
def getfloatlist(self,
|
||||
option: str,
|
||||
default: Union[SentinelClass, _T] = SENTINEL,
|
||||
default: Union[Sentinel, _T] = Sentinel.MISSING,
|
||||
separator: Optional[str] = '\n',
|
||||
count: Optional[int] = None,
|
||||
deprecate: bool = False
|
||||
|
@ -322,7 +321,7 @@ class ConfigHelper:
|
|||
|
||||
def getdict(self,
|
||||
option: str,
|
||||
default: Union[SentinelClass, _T] = SENTINEL,
|
||||
default: Union[Sentinel, _T] = Sentinel.MISSING,
|
||||
separators: Tuple[Optional[str], Optional[str]] = ('\n', '='),
|
||||
dict_type: Type = str,
|
||||
allow_empty_fields: bool = False,
|
||||
|
@ -356,7 +355,7 @@ class ConfigHelper:
|
|||
|
||||
def getgpioout(self,
|
||||
option: str,
|
||||
default: Union[SentinelClass, _T] = SENTINEL,
|
||||
default: Union[Sentinel, _T] = Sentinel.MISSING,
|
||||
initial_value: int = 0,
|
||||
deprecate: bool = False
|
||||
) -> Union[GpioOutputPin, _T]:
|
||||
|
@ -375,7 +374,7 @@ class ConfigHelper:
|
|||
|
||||
def gettemplate(self,
|
||||
option: str,
|
||||
default: Union[SentinelClass, _T] = SENTINEL,
|
||||
default: Union[Sentinel, _T] = Sentinel.MISSING,
|
||||
is_async: bool = False,
|
||||
deprecate: bool = False
|
||||
) -> Union[JinjaTemplate, _T]:
|
||||
|
@ -396,7 +395,7 @@ class ConfigHelper:
|
|||
|
||||
def load_template(self,
|
||||
option: str,
|
||||
default: Union[SentinelClass, str] = SENTINEL,
|
||||
default: Union[Sentinel, str] = Sentinel.MISSING,
|
||||
is_async: bool = False,
|
||||
deprecate: bool = False
|
||||
) -> JinjaTemplate:
|
||||
|
@ -409,7 +408,7 @@ class ConfigHelper:
|
|||
|
||||
def getpath(self,
|
||||
option: str,
|
||||
default: Union[SentinelClass, _T] = SENTINEL,
|
||||
default: Union[Sentinel, _T] = Sentinel.MISSING,
|
||||
deprecate: bool = False
|
||||
) -> Union[pathlib.Path, _T]:
|
||||
val = self.gettemplate(option, default, deprecate=deprecate)
|
||||
|
|
|
@ -21,7 +21,7 @@ from . import confighelper
|
|||
from .eventloop import EventLoop
|
||||
from .app import MoonrakerApp
|
||||
from .klippy_connection import KlippyConnection
|
||||
from .utils import ServerError, SentinelClass, get_software_version
|
||||
from .utils import ServerError, Sentinel, get_software_version
|
||||
from .loghelper import LogManager
|
||||
|
||||
# Annotation imports
|
||||
|
@ -43,7 +43,7 @@ if TYPE_CHECKING:
|
|||
from .components.machine import Machine
|
||||
from .components.extensions import ExtensionManager
|
||||
FlexCallback = Callable[..., Optional[Coroutine]]
|
||||
_T = TypeVar("_T")
|
||||
_T = TypeVar("_T", Sentinel, Any)
|
||||
|
||||
API_VERSION = (1, 2, 1)
|
||||
CORE_COMPONENTS = [
|
||||
|
@ -53,7 +53,6 @@ CORE_COMPONENTS = [
|
|||
'webcam', 'extensions',
|
||||
]
|
||||
|
||||
SENTINEL = SentinelClass.get_instance()
|
||||
|
||||
class Server:
|
||||
error = ServerError
|
||||
|
@ -245,11 +244,12 @@ class Server:
|
|||
config.validate_config()
|
||||
self._is_configured = True
|
||||
|
||||
def load_component(self,
|
||||
config: confighelper.ConfigHelper,
|
||||
component_name: str,
|
||||
default: Union[SentinelClass, _T] = SENTINEL
|
||||
) -> Union[_T, Any]:
|
||||
def load_component(
|
||||
self,
|
||||
config: confighelper.ConfigHelper,
|
||||
component_name: str,
|
||||
default: _T = Sentinel.MISSING
|
||||
) -> Union[_T, Any]:
|
||||
if component_name in self.components:
|
||||
return self.components[component_name]
|
||||
try:
|
||||
|
@ -265,19 +265,18 @@ class Server:
|
|||
logging.exception(msg)
|
||||
if component_name not in self.failed_components:
|
||||
self.failed_components.append(component_name)
|
||||
if isinstance(default, SentinelClass):
|
||||
if default is Sentinel.MISSING:
|
||||
raise
|
||||
return default
|
||||
self.components[component_name] = component
|
||||
logging.info(f"Component ({component_name}) loaded")
|
||||
return component
|
||||
|
||||
def lookup_component(self,
|
||||
component_name: str,
|
||||
default: Union[SentinelClass, _T] = SENTINEL
|
||||
) -> Union[_T, Any]:
|
||||
def lookup_component(
|
||||
self, component_name: str, default: _T = Sentinel.MISSING
|
||||
) -> Union[_T, Any]:
|
||||
component = self.components.get(component_name, default)
|
||||
if isinstance(component, SentinelClass):
|
||||
if component is Sentinel.MISSING:
|
||||
raise ServerError(f"Component ({component_name}) not found")
|
||||
return component
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ import shlex
|
|||
import re
|
||||
import struct
|
||||
import socket
|
||||
import enum
|
||||
from . import source_info
|
||||
|
||||
# Annotation imports
|
||||
|
@ -45,14 +46,8 @@ class ServerError(Exception):
|
|||
self.status_code = status_code
|
||||
|
||||
|
||||
class SentinelClass:
|
||||
_instance: ClassVar[Optional[SentinelClass]] = None
|
||||
|
||||
@staticmethod
|
||||
def get_instance() -> SentinelClass:
|
||||
if SentinelClass._instance is None:
|
||||
SentinelClass._instance = SentinelClass()
|
||||
return SentinelClass._instance
|
||||
class Sentinel(enum.Enum):
|
||||
MISSING = object()
|
||||
|
||||
def _run_git_command(cmd: str) -> str:
|
||||
prog = shlex.split(cmd)
|
||||
|
|
|
@ -12,7 +12,7 @@ import asyncio
|
|||
import copy
|
||||
from tornado.websocket import WebSocketHandler, WebSocketClosedError
|
||||
from tornado.web import HTTPError
|
||||
from .utils import ServerError, SentinelClass
|
||||
from .utils import ServerError, Sentinel
|
||||
|
||||
# Annotation imports
|
||||
from typing import (
|
||||
|
@ -44,7 +44,6 @@ if TYPE_CHECKING:
|
|||
AuthComp = Optional[Authorization]
|
||||
|
||||
CLIENT_TYPES = ["web", "mobile", "desktop", "display", "bot", "agent", "other"]
|
||||
SENTINEL = SentinelClass.get_instance()
|
||||
|
||||
class Subscribable:
|
||||
def send_status(self,
|
||||
|
@ -98,11 +97,11 @@ class WebRequest:
|
|||
|
||||
def _get_converted_arg(self,
|
||||
key: str,
|
||||
default: Union[SentinelClass, _T],
|
||||
default: Union[Sentinel, _T],
|
||||
dtype: Type[_C]
|
||||
) -> Union[_C, _T]:
|
||||
if key not in self.args:
|
||||
if isinstance(default, SentinelClass):
|
||||
if default is Sentinel.MISSING:
|
||||
raise ServerError(f"No data for argument: {key}")
|
||||
return default
|
||||
val = self.args[key]
|
||||
|
@ -124,34 +123,34 @@ class WebRequest:
|
|||
|
||||
def get(self,
|
||||
key: str,
|
||||
default: Union[SentinelClass, _T] = SENTINEL
|
||||
default: Union[Sentinel, _T] = Sentinel.MISSING
|
||||
) -> Union[_T, Any]:
|
||||
val = self.args.get(key, default)
|
||||
if isinstance(val, SentinelClass):
|
||||
if val is Sentinel.MISSING:
|
||||
raise ServerError(f"No data for argument: {key}")
|
||||
return val
|
||||
|
||||
def get_str(self,
|
||||
key: str,
|
||||
default: Union[SentinelClass, _T] = SENTINEL
|
||||
default: Union[Sentinel, _T] = Sentinel.MISSING
|
||||
) -> Union[str, _T]:
|
||||
return self._get_converted_arg(key, default, str)
|
||||
|
||||
def get_int(self,
|
||||
key: str,
|
||||
default: Union[SentinelClass, _T] = SENTINEL
|
||||
default: Union[Sentinel, _T] = Sentinel.MISSING
|
||||
) -> Union[int, _T]:
|
||||
return self._get_converted_arg(key, default, int)
|
||||
|
||||
def get_float(self,
|
||||
key: str,
|
||||
default: Union[SentinelClass, _T] = SENTINEL
|
||||
default: Union[Sentinel, _T] = Sentinel.MISSING
|
||||
) -> Union[float, _T]:
|
||||
return self._get_converted_arg(key, default, float)
|
||||
|
||||
def get_boolean(self,
|
||||
key: str,
|
||||
default: Union[SentinelClass, _T] = SENTINEL
|
||||
default: Union[Sentinel, _T] = Sentinel.MISSING
|
||||
) -> Union[bool, _T]:
|
||||
return self._get_converted_arg(key, default, bool)
|
||||
|
||||
|
@ -245,8 +244,8 @@ class JsonRPC:
|
|||
rpc_version: str = obj.get('jsonrpc', "")
|
||||
if rpc_version != "2.0":
|
||||
return self.build_error(-32600, "Invalid Request", req_id)
|
||||
method_name = obj.get('method', SENTINEL)
|
||||
if method_name is SENTINEL:
|
||||
method_name = obj.get('method', Sentinel.MISSING)
|
||||
if method_name is Sentinel.MISSING:
|
||||
self.process_response(obj, conn)
|
||||
return None
|
||||
if not isinstance(method_name, str):
|
||||
|
|
Loading…
Reference in New Issue