diff --git a/tap_spotify/schemas/album.py b/tap_spotify/schemas/album.py index 69d7a6e..7bed0be 100644 --- a/tap_spotify/schemas/album.py +++ b/tap_spotify/schemas/album.py @@ -6,23 +6,20 @@ from tap_spotify.schemas.external import ExternalUrlObject from tap_spotify.schemas.image import ImageObject from tap_spotify.schemas.restriction import RestrictionObject as AlbumRestrictionObject -from tap_spotify.schemas.utils.custom_object import CustomObject - -class AlbumObject(CustomObject): - properties = th.PropertiesList( - th.Property("album_type", th.StringType), - th.Property("artists", th.ArrayType(ArtistObject)), - th.Property("available_markets", th.ArrayType(th.StringType)), - th.Property("external_urls", ExternalUrlObject), - th.Property("href", th.StringType), - th.Property("id", th.StringType), - th.Property("images", th.ArrayType(ImageObject)), - th.Property("name", th.StringType), - th.Property("release_date", th.StringType), - th.Property("release_date_precision", th.StringType), - th.Property("restrictions", AlbumRestrictionObject), - th.Property("total_tracks", th.IntegerType), - th.Property("type", th.StringType), - th.Property("uri", th.StringType), - ) +AlbumObject = th.PropertiesList( + th.Property("album_type", th.StringType), + th.Property("artists", th.ArrayType(ArtistObject)), + th.Property("available_markets", th.ArrayType(th.StringType)), + th.Property("external_urls", ExternalUrlObject), + th.Property("href", th.StringType), + th.Property("id", th.StringType), + th.Property("images", th.ArrayType(ImageObject)), + th.Property("name", th.StringType), + th.Property("release_date", th.StringType), + th.Property("release_date_precision", th.StringType), + th.Property("restrictions", AlbumRestrictionObject), + th.Property("total_tracks", th.IntegerType), + th.Property("type", th.StringType), + th.Property("uri", th.StringType), +) diff --git a/tap_spotify/schemas/artist.py b/tap_spotify/schemas/artist.py index e1b9a98..08e9a3f 100644 --- a/tap_spotify/schemas/artist.py +++ b/tap_spotify/schemas/artist.py @@ -5,19 +5,16 @@ from tap_spotify.schemas.external import ExternalUrlObject from tap_spotify.schemas.followers import FollowersObject from tap_spotify.schemas.image import ImageObject -from tap_spotify.schemas.utils.custom_object import CustomObject - -class ArtistObject(CustomObject): - properties = th.PropertiesList( - th.Property("external_urls", ExternalUrlObject), - th.Property("followers", FollowersObject), - th.Property("genres", th.ArrayType(th.StringType)), - th.Property("href", th.StringType), - th.Property("id", th.StringType), - th.Property("images", th.ArrayType(ImageObject)), - th.Property("name", th.StringType), - th.Property("popularity", th.IntegerType), - th.Property("type", th.StringType), - th.Property("uri", th.StringType), - ) +ArtistObject = th.PropertiesList( + th.Property("external_urls", ExternalUrlObject), + th.Property("followers", FollowersObject), + th.Property("genres", th.ArrayType(th.StringType)), + th.Property("href", th.StringType), + th.Property("id", th.StringType), + th.Property("images", th.ArrayType(ImageObject)), + th.Property("name", th.StringType), + th.Property("popularity", th.IntegerType), + th.Property("type", th.StringType), + th.Property("uri", th.StringType), +) diff --git a/tap_spotify/schemas/audio_features.py b/tap_spotify/schemas/audio_features.py index 59be6d7..56f0209 100644 --- a/tap_spotify/schemas/audio_features.py +++ b/tap_spotify/schemas/audio_features.py @@ -8,27 +8,23 @@ StringType, ) -from tap_spotify.schemas.utils.custom_object import CustomObject - - -class AudioFeaturesObject(CustomObject): - properties = PropertiesList( - Property("acousticness", NumberType), - Property("analysis_url", StringType), - Property("danceability", NumberType), - Property("duration_ms", IntegerType), - Property("energy", NumberType), - Property("id", StringType), - Property("instrumentalness", NumberType), - Property("key", IntegerType), - Property("liveness", NumberType), - Property("loudness", NumberType), - Property("mode", IntegerType), - Property("speechiness", NumberType), - Property("tempo", NumberType), - Property("time_signature", IntegerType), - Property("track_href", StringType), - Property("type", StringType), - Property("uri", StringType), - Property("valence", NumberType), - ) +AudioFeaturesObject = PropertiesList( + Property("acousticness", NumberType), + Property("analysis_url", StringType), + Property("danceability", NumberType), + Property("duration_ms", IntegerType), + Property("energy", NumberType), + Property("id", StringType), + Property("instrumentalness", NumberType), + Property("key", IntegerType), + Property("liveness", NumberType), + Property("loudness", NumberType), + Property("mode", IntegerType), + Property("speechiness", NumberType), + Property("tempo", NumberType), + Property("time_signature", IntegerType), + Property("track_href", StringType), + Property("type", StringType), + Property("uri", StringType), + Property("valence", NumberType), +) diff --git a/tap_spotify/schemas/external.py b/tap_spotify/schemas/external.py index 8c77551..efd1b30 100644 --- a/tap_spotify/schemas/external.py +++ b/tap_spotify/schemas/external.py @@ -2,18 +2,12 @@ from singer_sdk import typing as th -from tap_spotify.schemas.utils.custom_object import CustomObject - - -class ExternalIdObject(CustomObject): - properties = th.PropertiesList( - th.Property("ean", th.StringType), - th.Property("isrc", th.StringType), - th.Property("upc", th.StringType), - ) - - -class ExternalUrlObject(CustomObject): - properties = th.PropertiesList( - th.Property("spotify", th.StringType), - ) +ExternalIdObject = th.PropertiesList( + th.Property("ean", th.StringType), + th.Property("isrc", th.StringType), + th.Property("upc", th.StringType), +) + +ExternalUrlObject = th.PropertiesList( + th.Property("spotify", th.StringType), +) diff --git a/tap_spotify/schemas/followers.py b/tap_spotify/schemas/followers.py index 52eefd6..0124a67 100644 --- a/tap_spotify/schemas/followers.py +++ b/tap_spotify/schemas/followers.py @@ -2,11 +2,7 @@ from singer_sdk import typing as th -from tap_spotify.schemas.utils.custom_object import CustomObject - - -class FollowersObject(CustomObject): - properties = th.PropertiesList( - th.Property("href", th.StringType), - th.Property("total", th.IntegerType), - ) +FollowersObject = th.PropertiesList( + th.Property("href", th.StringType), + th.Property("total", th.IntegerType), +) diff --git a/tap_spotify/schemas/image.py b/tap_spotify/schemas/image.py index 1f53253..0fc2fef 100644 --- a/tap_spotify/schemas/image.py +++ b/tap_spotify/schemas/image.py @@ -2,12 +2,8 @@ from singer_sdk import typing as th -from tap_spotify.schemas.utils.custom_object import CustomObject - - -class ImageObject(CustomObject): - properties = th.PropertiesList( - th.Property("height", th.IntegerType), - th.Property("url", th.StringType), - th.Property("width", th.IntegerType), - ) +ImageObject = th.PropertiesList( + th.Property("height", th.IntegerType), + th.Property("url", th.StringType), + th.Property("width", th.IntegerType), +) diff --git a/tap_spotify/schemas/restriction.py b/tap_spotify/schemas/restriction.py index 9374c6f..f1205a4 100644 --- a/tap_spotify/schemas/restriction.py +++ b/tap_spotify/schemas/restriction.py @@ -2,10 +2,6 @@ from singer_sdk import typing as th -from tap_spotify.schemas.utils.custom_object import CustomObject - - -class RestrictionObject(CustomObject): - properties = th.PropertiesList( - th.Property("reason", th.StringType), - ) +RestrictionObject = th.PropertiesList( + th.Property("reason", th.StringType), +) diff --git a/tap_spotify/schemas/track.py b/tap_spotify/schemas/track.py index e76a5bf..0b89970 100644 --- a/tap_spotify/schemas/track.py +++ b/tap_spotify/schemas/track.py @@ -6,29 +6,26 @@ from tap_spotify.schemas.artist import ArtistObject from tap_spotify.schemas.external import ExternalIdObject, ExternalUrlObject from tap_spotify.schemas.restriction import RestrictionObject as TrackRestrictionObject -from tap_spotify.schemas.utils.custom_object import CustomObject - -class TrackObject(CustomObject): - properties = th.PropertiesList( - th.Property("album", AlbumObject), - th.Property("artists", th.ArrayType(ArtistObject)), - th.Property("available_markets", th.ArrayType(th.StringType)), - th.Property("disc_number", th.IntegerType), - th.Property("duration_ms", th.IntegerType), - th.Property("explicit", th.BooleanType), - th.Property("external_ids", ExternalIdObject()), - th.Property("external_urls", ExternalUrlObject), - th.Property("href", th.StringType), - th.Property("id", th.StringType), - th.Property("is_local", th.BooleanType), - th.Property("is_playable", th.BooleanType), - # th.Property("linked_from", TrackObject), # noqa: ERA001 - th.Property("name", th.StringType), - th.Property("popularity", th.IntegerType), - th.Property("preview_url", th.StringType), - th.Property("restrictions", TrackRestrictionObject), - th.Property("track_number", th.IntegerType), - th.Property("type", th.StringType), - th.Property("uri", th.StringType), - ) +TrackObject = th.PropertiesList( + th.Property("album", AlbumObject), + th.Property("artists", th.ArrayType(ArtistObject)), + th.Property("available_markets", th.ArrayType(th.StringType)), + th.Property("disc_number", th.IntegerType), + th.Property("duration_ms", th.IntegerType), + th.Property("explicit", th.BooleanType), + th.Property("external_ids", ExternalIdObject), + th.Property("external_urls", ExternalUrlObject), + th.Property("href", th.StringType), + th.Property("id", th.StringType), + th.Property("is_local", th.BooleanType), + th.Property("is_playable", th.BooleanType), + # th.Property("linked_from", TrackObject), # noqa: ERA001 + th.Property("name", th.StringType), + th.Property("popularity", th.IntegerType), + th.Property("preview_url", th.StringType), + th.Property("restrictions", TrackRestrictionObject), + th.Property("track_number", th.IntegerType), + th.Property("type", th.StringType), + th.Property("uri", th.StringType), +) diff --git a/tap_spotify/schemas/utils/custom_object.py b/tap_spotify/schemas/utils/custom_object.py deleted file mode 100644 index 4365e2c..0000000 --- a/tap_spotify/schemas/utils/custom_object.py +++ /dev/null @@ -1,31 +0,0 @@ -"""Base custom object defintion.""" - -from __future__ import annotations - -from singer_sdk import typing as th -from typing_extensions import Self, override - -# ruff: noqa: N805 - - -class CustomObject(th.JSONTypeHelper): - """Custom object.""" - - properties: th.PropertiesList - - @th.DefaultInstanceProperty - @override - def type_dict(cls): - return cls.properties.to_dict() - - @th.DefaultInstanceProperty - def schema(cls): # noqa: D102 - return cls.type_dict - - @classmethod - def extend_with(cls, *extras: type[Self]) -> type[Self]: - """Extend a custom object schema with other custom object types.""" - for e in extras: - for _, p in e.properties.items(): # noqa: PERF102 - cls.properties.append(p) - return cls diff --git a/tap_spotify/schemas/utils/rank.py b/tap_spotify/schemas/utils/rank.py index 0208013..9316d20 100644 --- a/tap_spotify/schemas/utils/rank.py +++ b/tap_spotify/schemas/utils/rank.py @@ -2,10 +2,6 @@ from singer_sdk import typing as th -from tap_spotify.schemas.utils.custom_object import CustomObject - - -class Rank(CustomObject): - properties = th.PropertiesList( - th.Property("rank", th.IntegerType), - ) +Rank = th.PropertiesList( + th.Property("rank", th.IntegerType), +) diff --git a/tap_spotify/schemas/utils/synced_at.py b/tap_spotify/schemas/utils/synced_at.py index e06a9b0..fefb62e 100644 --- a/tap_spotify/schemas/utils/synced_at.py +++ b/tap_spotify/schemas/utils/synced_at.py @@ -2,10 +2,6 @@ from singer_sdk import typing as th -from tap_spotify.schemas.utils.custom_object import CustomObject - - -class SyncedAt(CustomObject): - properties = th.PropertiesList( - th.Property("synced_at", th.DateTimeType), - ) +SyncedAt = th.PropertiesList( + th.Property("synced_at", th.DateTimeType), +) diff --git a/tap_spotify/streams.py b/tap_spotify/streams.py index 4930a11..cdbd0c8 100644 --- a/tap_spotify/streams.py +++ b/tap_spotify/streams.py @@ -5,6 +5,7 @@ from datetime import datetime, timezone from typing import Collection +from singer_sdk import typing as th from singer_sdk.streams.rest import RESTStream from typing_extensions import override @@ -43,7 +44,7 @@ class _AudioFeaturesStream(SpotifyStream): name = "_audio_features_stream" path = "/audio-features" records_jsonpath = "$.audio_features[*]" - schema = AudioFeaturesObject.schema + schema = AudioFeaturesObject.to_dict() max_tracks = 100 def __init__( @@ -122,14 +123,19 @@ class _UserTopTracksStream(_TracksStream, _UserTopItemsStream): """Define user top tracks stream.""" path = "/me/top/tracks" - schema = TrackObject.extend_with(Rank, SyncedAt, AudioFeaturesObject).schema + schema = th.PropertiesList( + *TrackObject, + *AudioFeaturesObject, + *Rank, + *SyncedAt, + ).to_dict() class _UserTopArtistsStream(_UserTopItemsStream): """Define user top artists stream.""" path = "/me/top/artists" - schema = ArtistObject.extend_with(Rank, SyncedAt).schema + schema = th.PropertiesList(*ArtistObject, *Rank, *SyncedAt).to_dict() class UserTopTracksShortTermStream( @@ -190,7 +196,12 @@ class _PlaylistTracksStream(_RankStream, _SyncedAtStream, _TracksStream): """Define playlist tracks stream.""" records_jsonpath = "$.tracks.items[*].track" - schema = TrackObject.extend_with(Rank, SyncedAt, AudioFeaturesObject).schema + schema = th.PropertiesList( + *TrackObject, + *AudioFeaturesObject, + *Rank, + *SyncedAt, + ).to_dict() primary_keys = ("rank", "synced_at") def parse_response(self, response): @@ -230,5 +241,5 @@ class UserSavedTracksStream(_SyncedAtStream, SpotifyStream): path = "/me/tracks" primary_keys = ("id", "synced_at") limit = 50 - schema = TrackObject.extend_with(SyncedAt).schema + schema = th.PropertiesList(*TrackObject, *SyncedAt).to_dict() records_jsonpath = "$.items[*].track"