From e8aa96ef72edd8e9a8ff3f0967fd0d0c1caabb8e Mon Sep 17 00:00:00 2001 From: Callum Brown Date: Sun, 27 Sep 2020 18:58:39 +0100 Subject: [PATCH] AURA: Add argument info to docstrings Follows the google docstring style: https://google.github.io/styleguide/pyguide.html#38-comments-and-docstrings --- beetsplug/aura.py | 188 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 157 insertions(+), 31 deletions(-) diff --git a/beetsplug/aura.py b/beetsplug/aura.py index 8050cc621..f62dc2987 100644 --- a/beetsplug/aura.py +++ b/beetsplug/aura.py @@ -125,14 +125,25 @@ class AURADocument: @staticmethod def error(status, title, detail): - """Make a response for an error following the JSON:API spec.""" + """Make a response for an error following the JSON:API spec. + + Args: + status: An HTTP status code string, e.g. "404 Not Found". + title: A short, human-readable summary of the problem. + detail: A human-readable explanation specific to this + occurrence of the problem. + """ document = { "errors": [{"status": status, "title": title, "detail": detail}] } return make_response(document, status) def translate_attribute(self, aura_attr): - """Translate AURA attribute name to beets attribute name.""" + """Translate AURA attribute name to beets attribute name. + + Args: + aura_attr: The attribute name to convert, e.g. "title". + """ try: return self.attribute_map[aura_attr] except KeyError: @@ -161,7 +172,13 @@ class AURADocument: return AndQuery(queries) def translate_sorts(self, sort_arg): - """Translate an AURA sort parameter into a beets Sort.""" + """Translate an AURA sort parameter into a beets Sort. + + Args: + sort_arg: The value of the 'sort' query parameter; a comma + separated list of fields to sort by, in order. + E.g. "-year,title". + """ # Change HTTP query parameter to a list aura_sorts = sort_arg.strip(",").split(",") sorts = [] @@ -180,7 +197,13 @@ class AURADocument: return MultipleSort(sorts) def paginate(self, collection): - """Get a page of the collection and the URL to the next page.""" + """Get a page of the collection and the URL to the next page. + + Args: + collection: The raw data from which resource objects can be + built. Could be an sqlite3.Cursor object (tracks and + albums) or a list of strings (artists). + """ # Pages start from zero page = request.args.get("page", 0, int) # Use page limit defined in config by default. @@ -213,8 +236,10 @@ class AURADocument: def get_included(self, data, include_str): """Build a list of resource objects for inclusion. - :param data: Array of dicts in the form of resource objects - :param include_str: Comma separated list of resources to include + Args: + data: An array of dicts in the form of resource objects. + include_str: A comma separated list of resource types to + include. E.g. "tracks,images". """ # Change HTTP query parameter to a list to_include = include_str.strip(",").split(",") @@ -287,7 +312,12 @@ class AURADocument: return document def single_resource_document(self, resource_object): - """Build document for a specific requested resource.""" + """Build document for a specific requested resource. + + Args: + resource_object: A dictionary in the form of a JSON:API + resource object. + """ document = {"data": resource_object} include_str = request.args.get("include", None) if include_str is not None: @@ -304,11 +334,20 @@ class TrackDocument(AURADocument): attribute_map = TRACK_ATTR_MAP def get_collection(self, query=None, sort=None): - """Get Item objects from the library.""" + """Get Item objects from the library. + + Args: + query: A beets Query object or a beets query string. + sort: A beets Sort object. + """ return current_app.config["lib"].items(query, sort) def get_attribute_converter(self, beets_attr): - """Work out what data type an attribute should be for beets.""" + """Work out what data type an attribute should be for beets. + + Args: + beets_attr: The name of the beets attribute, e.g. "title". + """ # filesize is a special field (read from disk not db?) if beets_attr == "filesize": converter = int @@ -325,7 +364,11 @@ class TrackDocument(AURADocument): @staticmethod def resource_object(track): - """Construct a JSON:API resource object from a beets Item.""" + """Construct a JSON:API resource object from a beets Item. + + Args: + track: A beets Item object. + """ attributes = {} # Use aura => beets attribute map, e.g. size => filesize for aura_attr, beets_attr in TRACK_ATTR_MAP.items(): @@ -353,7 +396,11 @@ class TrackDocument(AURADocument): } def single_resource(self, track_id): - """Get track from the library and build a document.""" + """Get track from the library and build a document. + + Args: + track_id: The beets id of the track (integer). + """ track = current_app.config["lib"].get_item(track_id) if track is None: return self.error( @@ -372,12 +419,20 @@ class AlbumDocument(AURADocument): attribute_map = ALBUM_ATTR_MAP def get_collection(self, query=None, sort=None): - """Get Album objects from the library.""" + """Get Album objects from the library. + + Args: + query: A beets Query object or a beets query string. + sort: A beets Sort object. + """ return current_app.config["lib"].albums(query, sort) def get_attribute_converter(self, beets_attr): - """Work out what data type an attribute should be for beets.""" - # filesize is a special field (read from disk not db?) + """Work out what data type an attribute should be for beets. + + Args: + beets_attr: The name of the beets attribute, e.g. "title". + """ try: # Look for field in list of Album fields # and get python type of database type. @@ -390,7 +445,11 @@ class AlbumDocument(AURADocument): @staticmethod def resource_object(album): - """Construct a JSON:API resource object from a beets Album.""" + """Construct a JSON:API resource object from a beets Album. + + Args: + album: A beets Album object. + """ attributes = {} # Use aura => beets attribute name map for aura_attr, beets_attr in ALBUM_ATTR_MAP.items(): @@ -435,7 +494,11 @@ class AlbumDocument(AURADocument): } def single_resource(self, album_id): - """Get album from the library and build a document.""" + """Get album from the library and build a document. + + Args: + album_id: The beets id of the album (integer). + """ album = current_app.config["lib"].get_album(album_id) if album is None: return self.error( @@ -454,7 +517,12 @@ class ArtistDocument(AURADocument): attribute_map = ARTIST_ATTR_MAP def get_collection(self, query=None, sort=None): - """Get a list of artist names from the library.""" + """Get a list of artist names from the library. + + Args: + query: A beets Query object or a beets query string. + sort: A beets Sort object. + """ # Gets only tracks with matching artist information tracks = current_app.config["lib"].items(query, sort) collection = [] @@ -465,7 +533,11 @@ class ArtistDocument(AURADocument): return collection def get_attribute_converter(self, beets_attr): - """Work out what data type an attribute should be for beets.""" + """Work out what data type an attribute should be for beets. + + Args: + beets_attr: The name of the beets attribute, e.g. "artist". + """ try: # Look for field in list of Item fields # and get python type of database type. @@ -478,7 +550,11 @@ class ArtistDocument(AURADocument): @staticmethod def resource_object(artist_id): - """Construct a JSON:API resource object for the given artist.""" + """Construct a JSON:API resource object for the given artist. + + Args: + artist_id: A string which is the artist's name. + """ # Get tracks where artist field exactly matches artist_id query = MatchQuery("artist", artist_id) tracks = current_app.config["lib"].items(query) @@ -517,7 +593,11 @@ class ArtistDocument(AURADocument): } def single_resource(self, artist_id): - """Get info for the requested artist and build a document.""" + """Get info for the requested artist and build a document. + + Args: + artist_id: A string which is the artist's name. + """ artist_resource = self.resource_object(artist_id) if artist_resource is None: return self.error( @@ -538,7 +618,10 @@ class ImageDocument(AURADocument): """Works out the full path to the image with the given id. Returns None if there is no such image. - image_id is in the form -- + + Args: + image_id: A string in the form + "--". """ # Split image_id into its constituent parts id_split = image_id.split("-") @@ -572,7 +655,12 @@ class ImageDocument(AURADocument): @staticmethod def resource_object(image_id): - """Construct a JSON:API resource object for the given image.""" + """Construct a JSON:API resource object for the given image. + + Args: + image_id: A string in the form + "--". + """ # Could be called as a static method, so can't use # self.get_image_path() image_path = ImageDocument.get_image_path(image_id) @@ -609,7 +697,12 @@ class ImageDocument(AURADocument): } def single_resource(self, image_id): - """Get info for the requested image and build a document.""" + """Get info for the requested image and build a document. + + Args: + image_id: A string in the form + "--". + """ image_resource = self.resource_object(image_id) if image_resource is None: return self.error( @@ -644,14 +737,22 @@ def all_tracks(): @aura_bp.route("/tracks/") def single_track(track_id): - """Respond with info about the specified track.""" + """Respond with info about the specified track. + + Args: + track_id: The id of the track provided in the URL (integer). + """ doc = TrackDocument() return doc.single_resource(track_id) -@aura_bp.route("/tracks//audio") +@aura_bp.route("/tracks//audio") def audio_file(track_id): - """Supply an audio file for the specified track.""" + """Supply an audio file for the specified track. + + Args: + track_id: The id of the track provided in the URL (integer). + """ track = current_app.config["lib"].get_item(track_id) if track is None: return AURADocument.error( @@ -720,7 +821,11 @@ def all_albums(): @aura_bp.route("/albums/") def single_album(album_id): - """Respond with info about the specified album.""" + """Respond with info about the specified album. + + Args: + album_id: The id of the album provided in the URL (integer). + """ doc = AlbumDocument() return doc.single_resource(album_id) @@ -739,7 +844,12 @@ def all_artists(): # Using the path converter allows slashes in artist_id @aura_bp.route("/artists/") def single_artist(artist_id): - """Respond with info about the specified artist.""" + """Respond with info about the specified artist. + + Args: + artist_id: The id of the artist provided in the URL. A string + which is the artist's name. + """ doc = ArtistDocument() return doc.single_resource(artist_id) @@ -751,14 +861,24 @@ def single_artist(artist_id): @aura_bp.route("/images/") def single_image(image_id): - """Respond with info about the specified image.""" + """Respond with info about the specified image. + + Args: + image_id: The id of the image provided in the URL. A string in + the form "--". + """ doc = ImageDocument() return doc.single_resource(image_id) @aura_bp.route("/images//file") def image_file(image_id): - """Supply an image file for the specified image.""" + """Supply an image file for the specified image. + + Args: + image_id: The id of the image provided in the URL. A string in + the form "--". + """ img_path = ImageDocument.get_image_path(image_id) if img_path is None: return AURADocument.error( @@ -829,7 +949,13 @@ class AURAPlugin(BeetsPlugin): """Add subcommand used to run the AURA server.""" def run_aura(lib, opts, args): - """Run the application using Flask's built in-server.""" + """Run the application using Flask's built in-server. + + Args: + lib: A beets Library object (not used). + opts: Command line options. An optparse.Values object. + args: The list of arguments to process (not used). + """ app = create_app() # Start the built-in server (not intended for production) app.run(