From 5a9c8242eafefc07bdbbeb3ee948b2403739079e Mon Sep 17 00:00:00 2001 From: Cliff Hill Date: Wed, 29 Sep 2021 22:01:21 -0400 Subject: [PATCH] Better living through type hints. Signed-off-by: Cliff Hill --- src/playlist/data/base.py | 12 ++++++------ src/playlist/data/settings.py | 25 ++++++++----------------- src/playlist/data/yaml_base.py | 33 +++++++++++++++++++++++++++++---- src/playlist/plex/server.py | 5 ++++- 4 files changed, 47 insertions(+), 28 deletions(-) diff --git a/src/playlist/data/base.py b/src/playlist/data/base.py index f29df80..a3144e8 100644 --- a/src/playlist/data/base.py +++ b/src/playlist/data/base.py @@ -12,7 +12,7 @@ import marshmallow.schema # type: ignore [import] import yaml -DataSubtype = typing.TypeVar("DataSubtype") +DataSub = typing.NewType("DataSub", "BaseData") DataDict = typing.TypeVar("DataDict") @@ -55,9 +55,9 @@ class BaseData(metaclass=DataMeta): __sa_dataclass_metadata_key__ = "sa" @classmethod - def load(cls: type[BaseData], data: DataDict) -> DataSubtype: + def load(cls: type[BaseData], data: DataDict) -> DataSub: """Load the given data dictionary into a class instance.""" - return typing.cast(DataSubtype, cls.Schema.load(data)) + return typing.cast(DataSub, cls.Schema.load(data)) def dump(self: BaseData) -> DataDict: """Dump the class instance into a data dictionary.""" @@ -70,7 +70,7 @@ class YAMLData(BaseData): """Data class base that contains functionality to read/write as YAML.""" @classmethod - def yaml_read(cls: type[YAMLData], filepath: pathlib.Path) -> DataSubtype: + def yaml_read(cls: type[YAMLData], filepath: pathlib.Path) -> DataSub: """Read the given YAML file and convert it into an object.""" with filepath.open() as fp: data = yaml.safe_load(fp) @@ -83,8 +83,8 @@ class YAMLData(BaseData): fp.write(yaml.dump(data)) @classmethod - def yaml_create(cls: type[YAMLData], filepath: pathlib.Path) -> DataSubtype: + def yaml_create(cls: type[YAMLData], filepath: pathlib.Path) -> DataSub: """Reload the YAML file with this object.""" data = cls() data.yaml_write(filepath) - return typing.cast(DataSubtype, data) + return typing.cast(DataSub, data) diff --git a/src/playlist/data/settings.py b/src/playlist/data/settings.py index 0f3f9c2..232b210 100644 --- a/src/playlist/data/settings.py +++ b/src/playlist/data/settings.py @@ -3,16 +3,15 @@ from __future__ import annotations import dataclasses import datetime -import functools - -from plsylist.data import yaml_base +import typing from playlist.data import base from playlist.data import const +from playlist.data import yaml_base __all__ = ["get", "write"] -SETTINGS_PATH = const.PATHS.CONFIG / "settings.yaml" +SETTINGS_FILE = "settings.yaml" @dataclasses.dataclass @@ -33,7 +32,7 @@ class CredentialSettings(base.BaseData): servername = input("Plex Server: ") data = server.get_creds(username, password, servername) - return cls.load(data) + return typing.cast(CredentialSettings, cls.load(data)) @dataclasses.dataclass @@ -93,19 +92,11 @@ class Settings(yaml_base.YAMLBase): ) -@functools.cache def get() -> Settings: - """Get the Settings object.""" - instance: Settings - try: - instance = Settings.yaml_read(SETTINGS_PATH) - except FileNotFoundError: - const.PATHS.CONFIG.mkdir(parents=True, exist_ok=True) - instance = Settings.yaml_create(SETTINGS_PATH) - - return instance + """Get the Settings object instance.""" + return typing.cast(Settings, Settings.get(SETTINGS_FILE)) def write() -> None: - """Store the current Settings object.""" - get().yaml_write(SETTINGS_PATH) + """Write the Settings object instance.""" + Settings.write(SETTINGS_FILE) diff --git a/src/playlist/data/yaml_base.py b/src/playlist/data/yaml_base.py index cd23c90..dea14cc 100644 --- a/src/playlist/data/yaml_base.py +++ b/src/playlist/data/yaml_base.py @@ -2,12 +2,17 @@ from __future__ import annotations import dataclasses +import functools import pathlib import typing import yaml from playlist.data import base +from playlist.data import const + + +YAMLSub = typing.NewType("YAMLSub", "YAMLBase") @dataclasses.dataclass @@ -15,11 +20,11 @@ class YAMLBase(base.BaseData): """Data class base that contains functionality to read/write as YAML.""" @classmethod - def yaml_read(cls: type[YAMLBase], filepath: pathlib.Path) -> base.DataSubtype: + def yaml_read(cls: type[YAMLBase], filepath: pathlib.Path) -> YAMLSub: """Read the given YAML file and convert it into an object.""" with filepath.open() as fp: data = yaml.safe_load(fp) - return cls.load(data) + return typing.cast(YAMLSub, cls.load(data)) def yaml_write(self: YAMLBase, filepath: pathlib.Path) -> None: """Write this object as the given YAML file.""" @@ -28,8 +33,28 @@ class YAMLBase(base.BaseData): fp.write(yaml.dump(data)) @classmethod - def yaml_create(cls: type[YAMLBase], filepath: pathlib.Path) -> base.DataSubtype: + def yaml_create(cls: type[YAMLBase], filepath: pathlib.Path) -> YAMLSub: """Reload the YAML file with this object.""" data = cls() data.yaml_write(filepath) - return typing.cast(base.DataSubtype, data) + return typing.cast(YAMLSub, data) + + @functools.cache + @classmethod + def get(cls: type[YAMLBase], filename: str) -> YAMLSub: + """Get the data from the given YAML file.""" + instance: YAMLBase + filepath = const.PATHS.CONFIG / filename + try: + instance = cls.yaml_read(filepath) + except FileNotFoundError: + const.PATHS.CONFIG.mkdir(parents=True, exist_ok=True) + instance = cls.yaml_create(filepath) + + return instance + + @classmethod + def write(cls: type[YAMLBase], filename: str) -> None: + """Store the current data to the YAML file.""" + filepath = const.PATHS.CONFIG / filename + cls.get(filepath).yaml_write(filepath) diff --git a/src/playlist/plex/server.py b/src/playlist/plex/server.py index 28f0c9d..c2c16f8 100644 --- a/src/playlist/plex/server.py +++ b/src/playlist/plex/server.py @@ -46,7 +46,10 @@ async def gen_tracks( times.append(process_time * weight) weights.append(weight) for track_data in batch: - track: models.Track = models.Track.load(track_data) + track: models.Track = typing.cast( + models.Track, + models.Track.load(track_data), + ) durations.append(track.duration) yield track