diff --git a/CHANGELOG.md b/CHANGELOG.md index d5da6fd..40212f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ ## 1.0.0 Initial release of forked library with Open Subsonic endpoint extensions supported. + +## 1.0.1 + +Python packaging learning curve. The previous version seems to have built empty +libraries, hopefully this has fixed the problem. diff --git a/setup.py b/setup.py index c6cc8bc..b459514 100644 --- a/setup.py +++ b/setup.py @@ -17,25 +17,42 @@ along with py-opensonic. If not, see """ -import os +import re +from pathlib import Path from setuptools import setup,find_packages -req_file = os.path.join(os.path.dirname(__file__), 'requirements.txt') -with open(req_file, encoding="utf-8") as file: - requirements = [line for line in file if line] + +# read the contents of your README file +this_directory = Path(__file__).parent +long_description = (this_directory / "README.md").read_text() +requirements = (this_directory / 'requirements.txt').read_text() + +# Get package __version__ in our namespace +ver_path = (this_directory / 'src' / 'libopensonic' / '_version.py') +verstr = 'unknown' +try: + verstrline = open(ver_path, "rt").read() +except EnvironmentError: + pass # Okay, there is no version file. +else: + VSRE = r"^__version__ = ['\"]([^'\"]*)['\"]" + mo = re.search(VSRE, verstrline, re.M) + if mo: + verstr = mo.group(1) + else: + raise RuntimeError("unable to find version in yourpackage/_version.py") setup(name='py-opensonic', - version='1.0.0', + version=verstr, author='Eric B. Munson', author_email='eric@munsonfam.org', url='https://github.com/khers/py-opensonic', description='A python wrapper library for the Open Subsonic REST API. ' 'https://opensubsonic.netlify.app/', - long_description='This is a basic wrapper library for the Open Subsonic ' - 'REST API. This will allow you to connect to your server and retrieve ' - 'information and have it returned in basic Python types.', + long_description=long_description, package_dir={'': 'src'}, packages=find_packages('src'), + py_modules=['libopensonic'], install_requires=requirements, python_requires='>=3', classifiers=[ diff --git a/src/libopensonic/__init__.py b/src/libopensonic/__init__.py index f80c772..7ae78d2 100644 --- a/src/libopensonic/__init__.py +++ b/src/libopensonic/__init__.py @@ -27,6 +27,11 @@ """ -from .connection import * - -__version__ = '1.0.0' +from libopensonic import connection +from libopensonic import errors +__version__ = "unknown" +try: + from _version import __version__ +except ImportError: + # We're running in a tree that doesn't have a _version.py, so we don't know what our version is. + pass diff --git a/src/libopensonic/_version.py b/src/libopensonic/_version.py new file mode 100644 index 0000000..a094771 --- /dev/null +++ b/src/libopensonic/_version.py @@ -0,0 +1,20 @@ +""" +This file is part of py-opensonic. + +py-opensonic is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +py-opensonic is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with py-opensonic. If not, see +""" + + +#Semantic versioning string for the library +__version__ = '1.0.1' diff --git a/src/libopensonic/connection.py b/src/libopensonic/connection.py index 7913403..97c8c10 100644 --- a/src/libopensonic/connection.py +++ b/src/libopensonic/connection.py @@ -25,8 +25,7 @@ import json import os -from src.libopensonic.errors import * - +from . import errors API_VERSION = '1.16.1' @@ -112,7 +111,7 @@ def __init__(self, baseUrl, username=None, password=None, port=4040, if useNetrc is not None: self._process_netrc(useNetrc) elif username is None or password is None: - raise CredentialError('You must specify either a username/password ' + raise errors.CredentialError('You must specify either a username/password ' 'combination or "useNetrc" must be either True or a string ' 'representing a path to a netrc file') @@ -193,7 +192,7 @@ def ping(self): if res['status'] == 'ok': return True elif res['status'] == 'failed': - exc = getExcByCode(res['error']['code']) + exc = errors.getExcByCode(res['error']['code']) raise exc(res['error']['message']) return False @@ -477,7 +476,7 @@ def search(self, artist=None, album=None, title=None, any=None, newerThan:int Return matches newer than this timestamp """ if artist == album == title == any == None: - raise ArgumentError('Invalid search. You must supply search ' + raise errors.ArgumentError('Invalid search. You must supply search ' 'criteria') methodName = 'search' @@ -729,9 +728,9 @@ def createPlaylist(self, playlistId=None, name=None, songIds=None): songIds = [] if playlistId == name == None: - raise ArgumentError('You must supply either a playlistId or a name') + raise errors.ArgumentError('You must supply either a playlistId or a name') if playlistId is not None and name is not None: - raise ArgumentError('You can only supply either a playlistId ' + raise errors.ArgumentError('You can only supply either a playlistId ' 'OR a name, not both') q = self._getQueryDict({'playlistId': playlistId, 'name': name}) @@ -1460,7 +1459,7 @@ def jukeboxControl(self, action, index=None, sids=None, gain=None, if action == 'add': # We have to deal with the sids if not (isinstance(sids, list) or isinstance(sids, tuple)): - raise ArgumentError('If you are adding songs, "sids" must ' + raise errors.ArgumentError('If you are adding songs, "sids" must ' 'be a list or tuple!') req = self._getRequestWithList(methodName, 'id', sids, q) else: @@ -1665,10 +1664,10 @@ def setRating(self, item_id, rating): try: rating = int(rating) except Exception as exc: - raise ArgumentError('Rating must be an integer between 0 and 5: ' + raise errors.ArgumentError('Rating must be an integer between 0 and 5: ' '%r' % rating) from exc if rating < 0 or rating > 5: - raise ArgumentError('Rating must be an integer between 0 and 5: ' + raise errors.ArgumentError('Rating must be an integer between 0 and 5: ' '%r' % rating) q = self._getQueryDict({'id': item_id, 'rating': rating}) @@ -2839,7 +2838,7 @@ def _checkStatus(self, result): if result['status'] == 'ok': return True elif result['status'] == 'failed': - exc = getExcByCode(result['error']['code']) + exc = errors.getExcByCode(result['error']['code']) raise exc(result['error']['message']) @@ -2904,7 +2903,7 @@ def _process_netrc(self, use_netrc): netrc file to use """ if not use_netrc: - raise CredentialError('useNetrc must be either a boolean "True" ' + raise errors.CredentialError('useNetrc must be either a boolean "True" ' 'or a string representing a path to a netrc file, ' 'not {0}'.format(repr(use_netrc))) if isinstance(use_netrc, bool) and use_netrc: @@ -2914,7 +2913,7 @@ def _process_netrc(self, use_netrc): self._netrc = netrc(os.path.expanduser(use_netrc)) auth = self._netrc.authenticators(self._hostname) if not auth: - raise CredentialError('No machine entry found for {0} in ' + raise errors.CredentialError('No machine entry found for {0} in ' 'your netrc file'.format(self._hostname)) # If we get here, we have credentials diff --git a/src/libopensonic/errors.py b/src/libopensonic/errors.py index d76187c..adac83a 100644 --- a/src/libopensonic/errors.py +++ b/src/libopensonic/errors.py @@ -18,27 +18,35 @@ class SonicError(Exception): pass + class ParameterError(SonicError): pass + class VersionError(SonicError): pass + class CredentialError(SonicError): pass + class AuthError(SonicError): pass + class LicenseError(SonicError): pass + class DataNotFoundError(SonicError): pass + class ArgumentError(SonicError): pass + # This maps the error code numbers from the Subsonic server to their # appropriate Exceptions ERR_CODE_MAP = {