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 = {