From c2ea83a6e5a1dd7f471b2ac24d803ecc5cda1092 Mon Sep 17 00:00:00 2001 From: Totto16 Date: Mon, 7 Aug 2023 00:38:23 +0200 Subject: [PATCH] improve schema --- schema/content_list.json | 61 ++++++++++++++----------------- src/content/collection_content.py | 2 + src/content/episode_content.py | 7 +++- src/content/general.py | 43 +++++++++++++++++----- src/content/season_content.py | 2 + src/content/series_content.py | 2 + 6 files changed, 74 insertions(+), 43 deletions(-) diff --git a/schema/content_list.json b/schema/content_list.json index d686906..47bcffe 100644 --- a/schema/content_list.json +++ b/schema/content_list.json @@ -22,12 +22,7 @@ "properties": { "type": { "type": "string", - "enum": [ - "series", - "season", - "episode", - "collection" - ] + "const": "episode" }, "scanned_file": { "$ref": "#/$defs/ScannedFile" @@ -51,23 +46,34 @@ "type": "object", "properties": { "path": { - "type": "string" + "type": "string", + "title": "file path", + "description": "The file path of the scanned file / folder" }, "parents": { "type": "array", "items": { "type": "string" - } + }, + "minItems": 0, + "maxItems": 3, + "uniqueItems": true, + "title": "parent folders", + "description": "The parent folders of this scanned file / folder" }, "type": { "type": "string", "enum": [ "file", "folder" - ] + ], + "title": "file type", + "description": "The type of the file: folder or file" }, "stats": { - "$ref": "#/$defs/Stats" + "$ref": "#/$defs/Stats", + "title": "file stats", + "description": "The stats of this file" } }, "required": [ @@ -104,10 +110,12 @@ "type": "string" }, "season": { - "type": "integer" + "type": "integer", + "minimum": 0 }, "episode": { - "type": "integer" + "type": "integer", + "minimum": 1 } }, "required": [ @@ -138,12 +146,7 @@ "properties": { "type": { "type": "string", - "enum": [ - "series", - "season", - "episode", - "collection" - ] + "const": "season" }, "scanned_file": { "$ref": "#/$defs/ScannedFile" @@ -170,7 +173,8 @@ "type": "object", "properties": { "season": { - "type": "integer" + "type": "integer", + "minimum": 0 } }, "required": [ @@ -183,12 +187,7 @@ "properties": { "type": { "type": "string", - "enum": [ - "series", - "season", - "episode", - "collection" - ] + "const": "series" }, "scanned_file": { "$ref": "#/$defs/ScannedFile" @@ -218,7 +217,8 @@ "type": "string" }, "year": { - "type": "integer" + "type": "integer", + "minimum": 1900 } }, "required": [ @@ -232,12 +232,7 @@ "properties": { "type": { "type": "string", - "enum": [ - "series", - "season", - "episode", - "collection" - ] + "const": "collection" }, "scanned_file": { "$ref": "#/$defs/ScannedFile" @@ -262,4 +257,4 @@ } }, "$schema": "http://json-schema.org/draft/2020-12/schema#" -} \ No newline at end of file +} diff --git a/src/content/collection_content.py b/src/content/collection_content.py index d73c2f1..f7f0ebb 100644 --- a/src/content/collection_content.py +++ b/src/content/collection_content.py @@ -4,6 +4,7 @@ from dataclasses import dataclass, field from pathlib import Path from typing import ( + Literal, Self, cast, ) @@ -37,6 +38,7 @@ class CollectionContentDict(ContentDict): @dataclass(slots=True, repr=True) class CollectionContent(Content): + __type: Literal[ContentType.collection] = field(metadata=alias("type")) __description: CollectionDescription = field(metadata=alias("description")) __series: list[SeriesContent] = field(metadata=alias("series")) diff --git a/src/content/episode_content.py b/src/content/episode_content.py index 3c17fd2..dfdd8e1 100644 --- a/src/content/episode_content.py +++ b/src/content/episode_content.py @@ -4,6 +4,7 @@ from dataclasses import dataclass, field from pathlib import Path from typing import ( + Literal, Optional, Self, ) @@ -51,6 +52,7 @@ def itr_print_percent() -> None: @dataclass(slots=True, repr=True) class EpisodeContent(Content): + __type: Literal[ContentType.episode] = field(metadata=alias("type")) __description: EpisodeDescription = field(metadata=alias("description")) __language: Language = field(metadata=alias("language")) @@ -68,7 +70,10 @@ def from_path( raise NameError(f"Couldn't get EpisodeDescription from '{path}'") return EpisodeContent( - ContentType.episode, scanned_file, description, Language.unknown(), + ContentType.episode, + scanned_file, + description, + Language.unknown(), ) @property diff --git a/src/content/general.py b/src/content/general.py index 5fbd26a..e0b92a3 100644 --- a/src/content/general.py +++ b/src/content/general.py @@ -1,11 +1,13 @@ #!/usr/bin/env python3 -from dataclasses import dataclass +from dataclasses import dataclass, field from enum import Enum from hashlib import sha256 from pathlib import Path from typing import Any, Generic, Optional, Self, TypedDict, TypeVar +from apischema import schema + from classifier import Language from enlighten import Manager @@ -56,8 +58,8 @@ class StatsDict(TypedDict): @dataclass(slots=True, repr=True) class EpisodeDescription: name: str - season: int - episode: int + season: int = field(metadata=schema(min=0)) + episode: int = field(metadata=schema(min=1)) def __str__(self: Self) -> str: return ( @@ -71,7 +73,7 @@ def __repr__(self: Self) -> str: @dataclass(slots=True, repr=True) class SeriesDescription: name: str - year: int + year: int = field(metadata=schema(min=1900)) def __str__(self: Self) -> str: return f"" @@ -82,7 +84,7 @@ def __repr__(self: Self) -> str: @dataclass(slots=True, repr=True) class SeasonDescription: - season: int + season: int = field(metadata=schema(min=0)) def __str__(self: Self) -> str: return f"y" @@ -336,10 +338,33 @@ def is_outdated( @dataclass(slots=True, repr=True) class ScannedFile: - path: Path - parents: list[str] - type: ScannedFileType # noqa: A003 - stats: Stats + path: Path = field( + metadata=schema( + title="file path", + description="The file path of the scanned file / folder", + ) + ) + parents: list[str] = field( + metadata=schema( + title="parent folders", + description="The parent folders of this scanned file / folder", + min_items=0, + max_items=3, + unique=True, + ), + ) + type: ScannedFileType = field( + metadata=schema( + title="file type", + description="The type of the file: folder or file", + ), + ) + stats: Stats = field( + metadata=schema( + title="file stats", + description="The stats of this file", + ), + ) @staticmethod def from_scan( diff --git a/src/content/season_content.py b/src/content/season_content.py index 9e915e2..14af93d 100644 --- a/src/content/season_content.py +++ b/src/content/season_content.py @@ -4,6 +4,7 @@ from dataclasses import dataclass, field from pathlib import Path from typing import ( + Literal, Optional, Self, cast, @@ -38,6 +39,7 @@ class SeasonContentDict(ContentDict): @dataclass(slots=True, repr=True) class SeasonContent(Content): + __type: Literal[ContentType.season] = field(metadata=alias("type")) # TODO: submit upstream path, to allow this: (to not add "type" in the required field twice) __description: SeasonDescription = field(metadata=alias("description")) __episodes: list[EpisodeContent] = field(metadata=alias("episodes")) diff --git a/src/content/series_content.py b/src/content/series_content.py index c3365af..8b42125 100644 --- a/src/content/series_content.py +++ b/src/content/series_content.py @@ -4,6 +4,7 @@ from dataclasses import dataclass, field from pathlib import Path from typing import ( + Literal, Optional, Self, cast, @@ -38,6 +39,7 @@ class SeriesContentDict(ContentDict): @dataclass(slots=True, repr=True) class SeriesContent(Content): + __type: Literal[ContentType.series] = field(metadata=alias("type")) __description: SeriesDescription = field(metadata=alias("description")) __seasons: list[SeasonContent] = field(metadata=alias("seasons"))