1
0
mirror of https://github.com/spl0k/supysonic.git synced 2024-09-19 10:51:04 +00:00

Dropping Python 2 support

This commit is contained in:
Alban Féron 2019-12-23 16:23:57 +01:00
parent 2f9fa0da6f
commit 1d01450f33
No known key found for this signature in database
GPG Key ID: 8CE0313646D16165
31 changed files with 41 additions and 176 deletions

View File

@ -1,7 +1,6 @@
dist: xenial dist: xenial
language: python language: python
python: python:
- 2.7
- 3.5 - 3.5
- 3.6 - 3.6
- 3.7 - 3.7

View File

@ -4,7 +4,7 @@ _Supysonic_ is a Python implementation of the [Subsonic][] server API.
[![Build Status](https://travis-ci.org/spl0k/supysonic.svg?branch=master)](https://travis-ci.org/spl0k/supysonic) [![Build Status](https://travis-ci.org/spl0k/supysonic.svg?branch=master)](https://travis-ci.org/spl0k/supysonic)
[![codecov](https://codecov.io/gh/spl0k/supysonic/branch/master/graph/badge.svg)](https://codecov.io/gh/spl0k/supysonic) [![codecov](https://codecov.io/gh/spl0k/supysonic/branch/master/graph/badge.svg)](https://codecov.io/gh/spl0k/supysonic)
![Python](https://img.shields.io/badge/python-2.7%2C%203.5%2C%203.6%2C%203.7-blue.svg) ![Python](https://img.shields.io/badge/python-3.5%2C%203.6%2C%203.7-blue.svg)
Current supported features are: Current supported features are:
* browsing (by folders or tags) * browsing (by folders or tags)
@ -51,20 +51,20 @@ or
$ pip install . $ pip install .
but not both. Please note that the `pip` method doesn't seem to work with but not both.
Python 2.7.
### Prerequisites ### Prerequisites
You'll need these to run _Supysonic_: You'll need these to run _Supysonic_:
* Python 2.7 or >= 3.5 * Python >= 3.5
* [Flask](http://flask.pocoo.org/) * [Flask](http://flask.pocoo.org/)
* [PonyORM](https://ponyorm.com/) * [PonyORM](https://ponyorm.com/)
* [Python Imaging Library](https://github.com/python-pillow/Pillow) * [Python Imaging Library](https://github.com/python-pillow/Pillow)
* [requests](http://docs.python-requests.org/) * [requests](http://docs.python-requests.org/)
* [mutagen](https://mutagen.readthedocs.io/en/latest/) * [mutagen](https://mutagen.readthedocs.io/en/latest/)
* [watchdog](https://github.com/gorakhargosh/watchdog) * [watchdog](https://github.com/gorakhargosh/watchdog)
* [zipstream](https://github.com/allanlei/python-zipstream)
All the dependencies will automatically be installed by the All the dependencies will automatically be installed by the
installation command above. installation command above.
@ -142,7 +142,7 @@ _Supysonic_ can run as a WSGI application with the `cgi-bin/supysonic.wsgi`
file. To run it within an _Apache2_ server, first you need to install the WSGI file. To run it within an _Apache2_ server, first you need to install the WSGI
module and enable it. module and enable it.
$ apt install libapache2-mod-wsgi $ apt install libapache2-mod-wsgi-py3
$ a2enmod wsgi $ a2enmod wsgi
Next, edit the _Apache_ configuration to load the application. Here's a basic Next, edit the _Apache_ configuration to load the application. Here's a basic

View File

@ -20,7 +20,6 @@ reqs = [
"Pillow", "Pillow",
"requests>=1.0.0", "requests>=1.0.0",
"mutagen>=1.33", "mutagen>=1.33",
"scandir<2.0.0; python_version <= '2.7'",
"watchdog>=0.8.0", "watchdog>=0.8.0",
"zipstream", "zipstream",
] ]
@ -55,8 +54,6 @@ setup(
"Intended Audience :: End Users/Desktop", "Intended Audience :: End Users/Desktop",
"Intended Audience :: System Administrators", "Intended Audience :: System Administrators",
"License :: OSI Approved :: GNU Affero General Public License v3", "License :: OSI Approved :: GNU Affero General Public License v3",
"Programming Language :: Python :: 2",
"Programming Language :: Python :: 2.7",
"Programming Language :: Python :: 3", "Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.5",
"Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.6",

View File

@ -18,7 +18,6 @@ from pony.orm import ObjectNotFound
from pony.orm import commit from pony.orm import commit
from ..managers.user import UserManager from ..managers.user import UserManager
from ..py23 import dict
from .exceptions import Unauthorized from .exceptions import Unauthorized
from .formatters import JSONFormatter, JSONPFormatter, XMLFormatter from .formatters import JSONFormatter, JSONPFormatter, XMLFormatter

View File

@ -24,7 +24,6 @@ from ..db import (
User, User,
) )
from ..db import now from ..db import now
from ..py23 import dict
from . import api from . import api
from .exceptions import GenericError, NotFound from .exceptions import GenericError, NotFound

View File

@ -19,7 +19,6 @@ from ..db import Track, Album, Artist, Folder, User
from ..db import StarredTrack, StarredAlbum, StarredArtist, StarredFolder from ..db import StarredTrack, StarredAlbum, StarredArtist, StarredFolder
from ..db import RatingTrack, RatingFolder from ..db import RatingTrack, RatingFolder
from ..lastfm import LastFm from ..lastfm import LastFm
from ..py23 import dict
from . import api, get_entity, get_entity_id from . import api, get_entity, get_entity_id
from .exceptions import AggregateException, GenericError, MissingParameter, NotFound from .exceptions import AggregateException, GenericError, MissingParameter, NotFound
@ -150,7 +149,9 @@ def rate():
if rating == 0: if rating == 0:
if tid is not None: if tid is not None:
delete( delete(
r for r in RatingTrack if r.user.id == request.user.id and r.rated.id == tid r
for r in RatingTrack
if r.user.id == request.user.id and r.rated.id == tid
) )
else: else:
delete( delete(

View File

@ -14,7 +14,6 @@ from flask import request
from pony.orm import ObjectNotFound, select from pony.orm import ObjectNotFound, select
from ..db import Folder, Artist, Album, Track from ..db import Folder, Artist, Album, Track
from ..py23 import dict
from . import api, get_entity, get_entity_id from . import api, get_entity, get_entity_id

View File

@ -10,7 +10,6 @@
from flask import request from flask import request
from ..db import ChatMessage, User from ..db import ChatMessage, User
from ..py23 import dict
from . import api from . import api

View File

@ -10,7 +10,6 @@
from flask import json, jsonify, make_response from flask import json, jsonify, make_response
from xml.etree import ElementTree from xml.etree import ElementTree
from ..py23 import dict, strtype
from . import API_VERSION from . import API_VERSION
@ -103,7 +102,7 @@ class XMLFormatter(BaseFormatter):
""" """
if not isinstance(dictionary, dict): if not isinstance(dictionary, dict):
raise TypeError("Expecting a dict") raise TypeError("Expecting a dict")
if not all(map(lambda x: isinstance(x, strtype), dictionary)): if not all(map(lambda x: isinstance(x, str), dictionary)):
raise TypeError("Dictionary keys must be strings") raise TypeError("Dictionary keys must be strings")
for name, value in dictionary.items(): for name, value in dictionary.items():
@ -125,7 +124,7 @@ class XMLFormatter(BaseFormatter):
def __value_tostring(self, value): def __value_tostring(self, value):
if value is None: if value is None:
return None return None
if isinstance(value, strtype): if isinstance(value, str):
return value return value
if isinstance(value, bool): if isinstance(value, bool):
return str(value).lower() return str(value).lower()

View File

@ -8,7 +8,6 @@
# #
# Distributed under terms of the GNU AGPLv3 license. # Distributed under terms of the GNU AGPLv3 license.
import codecs
import logging import logging
import mimetypes import mimetypes
import os.path import os.path
@ -33,7 +32,6 @@ from .. import scanner
from ..cache import CacheMiss from ..cache import CacheMiss
from ..covers import get_embedded_cover from ..covers import get_embedded_cover
from ..db import Track, Album, Artist, Folder, User, ClientPrefs, now from ..db import Track, Album, Artist, Folder, User, ClientPrefs, now
from ..py23 import dict
from . import api, get_entity, get_entity_id from . import api, get_entity, get_entity_id
from .exceptions import ( from .exceptions import (
@ -137,9 +135,7 @@ def stream_media():
raise GenericError(message) raise GenericError(message)
transcoder, decoder, encoder = [ transcoder, decoder, encoder = [
prepare_transcoding_cmdline( prepare_transcoding_cmdline(x, res, src_suffix, dst_suffix, dst_bitrate)
x, res, src_suffix, dst_suffix, dst_bitrate
)
for x in (transcoder, decoder, encoder) for x in (transcoder, decoder, encoder)
] ]
try: try:
@ -304,7 +300,8 @@ def lyrics():
logger.debug("Found lyrics file: " + lyrics_path) logger.debug("Found lyrics file: " + lyrics_path)
try: try:
lyrics = read_file_as_unicode(lyrics_path) with open(lyrics_path, "rt") as f:
lyrics = f.read()
except UnicodeError: except UnicodeError:
# Lyrics file couldn't be decoded. Rather than displaying an error, try with the potential next files or # Lyrics file couldn't be decoded. Rather than displaying an error, try with the potential next files or
# return no lyrics. Log it anyway. # return no lyrics. Log it anyway.
@ -350,22 +347,3 @@ def lyrics():
logger.warning("Error while requesting the ChartLyrics API: " + str(e)) logger.warning("Error while requesting the ChartLyrics API: " + str(e))
return request.formatter("lyrics", lyrics) return request.formatter("lyrics", lyrics)
def read_file_as_unicode(path):
""" Opens a file trying with different encodings and returns the contents as a unicode string """
encodings = ["utf-8", "latin1"] # Should be extended to support more encodings
for enc in encodings:
try:
contents = codecs.open(path, "r", encoding=enc).read()
logger.debug("Read file {} with {} encoding".format(path, enc))
# Maybe save the encoding somewhere to prevent going through this loop each time for the same file
return contents
except UnicodeError:
pass
# Fallback to ASCII
logger.debug("Reading file {} with ascii encoding".format(path))
return unicode(open(path, "r").read())

View File

@ -12,7 +12,6 @@ import uuid
from flask import request from flask import request
from ..db import Playlist, User, Track from ..db import Playlist, User, Track
from ..py23 import dict
from . import api, get_entity from . import api, get_entity
from .exceptions import Forbidden, MissingParameter, NotFound from .exceptions import Forbidden, MissingParameter, NotFound

View File

@ -13,7 +13,6 @@ from flask import request
from pony.orm import select from pony.orm import select
from ..db import Folder, Track, Artist, Album from ..db import Folder, Track, Artist, Album
from ..py23 import dict
from . import api from . import api
from .exceptions import MissingParameter from .exceptions import MissingParameter

View File

@ -9,7 +9,6 @@
from flask import request from flask import request
from ..py23 import dict
from . import api from . import api

View File

@ -12,7 +12,6 @@ from functools import wraps
from ..db import User from ..db import User
from ..managers.user import UserManager from ..managers.user import UserManager
from ..py23 import dict
from . import api, decode_password from . import api, decode_password
from .exceptions import Forbidden, GenericError, NotFound from .exceptions import Forbidden, GenericError, NotFound

View File

@ -18,8 +18,6 @@ import tempfile
import threading import threading
from time import time from time import time
from .py23 import scandir, osreplace
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -80,7 +78,7 @@ class Cache(object):
for mtime, size, key in sorted( for mtime, size, key in sorted(
[ [
(f.stat().st_mtime, f.stat().st_size, f.name) (f.stat().st_mtime, f.stat().st_size, f.name)
for f in scandir(self._cache_dir) for f in os.scandir(self._cache_dir)
if f.is_file() if f.is_file()
] ]
): ):
@ -158,7 +156,7 @@ class Cache(object):
with self._lock: with self._lock:
if self._auto_prune: if self._auto_prune:
self._make_space(size, key=key) self._make_space(size, key=key)
osreplace(f.name, self._filepath(key)) os.replace(f.name, self._filepath(key))
self._record_file(key, size) self._record_file(key, size)
except OSError as e: except OSError as e:
# Ignore error from trying to delete the renamed temp file # Ignore error from trying to delete the renamed temp file

View File

@ -8,14 +8,11 @@
# #
# Distributed under terms of the GNU AGPLv3 license. # Distributed under terms of the GNU AGPLv3 license.
try:
from configparser import RawConfigParser
except ImportError:
from ConfigParser import RawConfigParser
import os import os
import tempfile import tempfile
from configparser import RawConfigParser
current_config = None current_config = None
@ -92,11 +89,6 @@ class IniConfig(DefaultConfig):
return True return True
if lv in ("no", "false", "off"): if lv in ("no", "false", "off"):
return False return False
try:
if isinstance(value, unicode):
return str(value)
except NameError:
pass
return value return value
@classmethod @classmethod

View File

@ -16,8 +16,8 @@ from mutagen.easyid3 import EasyID3
from mutagen.flac import FLAC, Picture from mutagen.flac import FLAC, Picture
from mutagen._vorbis import VCommentDict from mutagen._vorbis import VCommentDict
from PIL import Image from PIL import Image
from os import scandir
from .py23 import scandir, strtype
EXTENSIONS = (".jpg", ".jpeg", ".png", ".bmp") EXTENSIONS = (".jpg", ".jpeg", ".png", ".bmp")
NAMING_SCORE_RULES = ( NAMING_SCORE_RULES = (
@ -90,7 +90,7 @@ def find_cover_in_folder(path, album_name=None):
def get_embedded_cover(path): def get_embedded_cover(path):
if not isinstance(path, strtype): # pragma: nocover if not isinstance(path, str): # pragma: nocover
raise TypeError("Expecting string, got " + str(type(path))) raise TypeError("Expecting string, got " + str(type(path)))
if not os.path.exists(path): if not os.path.exists(path):

View File

@ -11,7 +11,6 @@ from multiprocessing.connection import Client
from .exceptions import DaemonUnavailableError from .exceptions import DaemonUnavailableError
from ..config import get_current_config from ..config import get_current_config
from ..py23 import strtype
from ..utils import get_secret_key from ..utils import get_secret_key
__all__ = ["DaemonClient"] __all__ = ["DaemonClient"]
@ -86,13 +85,13 @@ class DaemonClient(object):
) )
def add_watched_folder(self, folder): def add_watched_folder(self, folder):
if not isinstance(folder, strtype): if not isinstance(folder, str):
raise TypeError("Expecting string, got " + str(type(folder))) raise TypeError("Expecting string, got " + str(type(folder)))
with self.__get_connection() as c: with self.__get_connection() as c:
c.send(AddWatchedFolderCommand(folder)) c.send(AddWatchedFolderCommand(folder))
def remove_watched_folder(self, folder): def remove_watched_folder(self, folder):
if not isinstance(folder, strtype): if not isinstance(folder, str):
raise TypeError("Expecting string, got " + str(type(folder))) raise TypeError("Expecting string, got " + str(type(folder)))
with self.__get_connection() as c: with self.__get_connection() as c:
c.send(RemoveWatchedFolder(folder)) c.send(RemoveWatchedFolder(folder))

View File

@ -20,15 +20,9 @@ from pony.orm import ObjectNotFound, DatabaseError
from pony.orm import buffer from pony.orm import buffer
from pony.orm import min, max, avg, sum, exists from pony.orm import min, max, avg, sum, exists
from pony.orm import db_session from pony.orm import db_session
from urllib.parse import urlparse, parse_qsl
from uuid import UUID, uuid4 from uuid import UUID, uuid4
from .py23 import dict, strtype
try:
from urllib.parse import urlparse, parse_qsl
except ImportError:
from urlparse import urlparse, parse_qsl
SCHEMA_VERSION = "20190915" SCHEMA_VERSION = "20190915"
@ -538,7 +532,7 @@ class Playlist(db.Entity):
tid = track tid = track
elif isinstance(track, Track): elif isinstance(track, Track):
tid = track.id tid = track.id
elif isinstance(track, strtype): elif isinstance(track, str):
tid = UUID(track) tid = UUID(track)
if self.tracks and len(self.tracks) > 0: if self.tracks and len(self.tracks) > 0:
@ -557,7 +551,7 @@ class Playlist(db.Entity):
def parse_uri(database_uri): def parse_uri(database_uri):
if not isinstance(database_uri, strtype): if not isinstance(database_uri, str):
raise TypeError("Expecting a string") raise TypeError("Expecting a string")
uri = urlparse(database_uri) uri = urlparse(database_uri)

View File

@ -17,7 +17,6 @@ from pony.orm import ObjectNotFound
from ..db import User, ClientPrefs from ..db import User, ClientPrefs
from ..lastfm import LastFm from ..lastfm import LastFm
from ..managers.user import UserManager from ..managers.user import UserManager
from ..py23 import dict
from . import admin_only, frontend from . import admin_only, frontend

View File

@ -11,8 +11,6 @@ import hashlib
import logging import logging
import requests import requests
from .py23 import strtype
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -87,7 +85,7 @@ class LastFm:
sig_str = b"" sig_str = b""
for k, v in sorted(kwargs.items()): for k, v in sorted(kwargs.items()):
k = k.encode("utf-8") k = k.encode("utf-8")
v = v.encode("utf-8") if isinstance(v, strtype) else str(v).encode("utf-8") v = v.encode("utf-8") if isinstance(v, str) else str(v).encode("utf-8")
sig_str += k + v sig_str += k + v
sig = hashlib.md5(sig_str + self.__api_secret).hexdigest() sig = hashlib.md5(sig_str + self.__api_secret).hexdigest()

View File

@ -16,7 +16,6 @@ from pony.orm import ObjectNotFound
from ..daemon.client import DaemonClient from ..daemon.client import DaemonClient
from ..daemon.exceptions import DaemonUnavailableError from ..daemon.exceptions import DaemonUnavailableError
from ..db import Folder, Track, Artist, Album, User, RatingTrack, StarredTrack from ..db import Folder, Track, Artist, Album, User, RatingTrack, StarredTrack
from ..py23 import strtype
class FolderManager: class FolderManager:

View File

@ -16,7 +16,6 @@ import uuid
from pony.orm import ObjectNotFound from pony.orm import ObjectNotFound
from ..db import User from ..db import User
from ..py23 import strtype
class UserManager: class UserManager:
@ -24,7 +23,7 @@ class UserManager:
def get(uid): def get(uid):
if isinstance(uid, uuid.UUID): if isinstance(uid, uuid.UUID):
pass pass
elif isinstance(uid, strtype): elif isinstance(uid, str):
uid = uuid.UUID(uid) uid = uuid.UUID(uid)
else: else:
raise ValueError("Invalid user id") raise ValueError("Invalid user id")

View File

@ -1,70 +0,0 @@
# coding: utf-8
#
# This file is part of Supysonic.
# Supysonic is a Python implementation of the Subsonic server API.
#
# Copyright (C) 2018-2019 Alban 'spl0k' Féron
# 2018-2019 Carey 'pR0Ps' Metcalfe
#
# Distributed under terms of the GNU AGPLv3 license.
# Try built-in scandir, fall back to the package for Python 2.7
try:
from os import scandir
except ImportError:
from scandir import scandir
# os.replace was added in Python 3.3, provide a fallback for Python 2.7
try:
from os import replace as osreplace
except ImportError:
# os.rename is equivalent to os.replace except on Windows
# On Windows an existing file will not be overwritten
# This fallback just attempts to delete the dst file before using rename
import sys
if sys.platform != "win32":
from os import rename as osreplace
else:
import os
def osreplace(src, dst):
try:
os.remove(dst)
except OSError:
pass
os.rename(src, dst)
try:
from queue import Queue, Empty as QueueEmpty
except ImportError:
from Queue import Queue, Empty as QueueEmpty
try:
# Python 2
strtype = basestring
_builtin_dict = dict
class DictMeta(type):
def __instancecheck__(cls, instance):
return isinstance(instance, _builtin_dict)
class dict(dict):
__metaclass__ = DictMeta
def keys(self):
return self.viewkeys()
def values(self):
return self.viewvalues()
def items(self):
return self.viewitems()
except NameError:
# Python 3
strtype = str
dict = dict

View File

@ -14,13 +14,13 @@ import time
from datetime import datetime from datetime import datetime
from pony.orm import db_session from pony.orm import db_session
from queue import Queue, Empty as QueueEmpty
from threading import Thread, Event from threading import Thread, Event
from .covers import find_cover_in_folder, has_embedded_cover, CoverFile from .covers import find_cover_in_folder, has_embedded_cover, CoverFile
from .db import Folder, Artist, Album, Track, User from .db import Folder, Artist, Album, Track, User
from .db import StarredFolder, StarredArtist, StarredAlbum, StarredTrack from .db import StarredFolder, StarredArtist, StarredAlbum, StarredTrack
from .db import RatingFolder, RatingTrack from .db import RatingFolder, RatingTrack
from .py23 import scandir, strtype, Queue, QueueEmpty
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -93,7 +93,7 @@ class Scanner(Thread):
self.__progress(folder_name, scanned) self.__progress(folder_name, scanned)
def queue_folder(self, folder_name): def queue_folder(self, folder_name):
if not isinstance(folder_name, strtype): if not isinstance(folder_name, str):
raise TypeError("Expecting string, got " + str(type(folder_name))) raise TypeError("Expecting string, got " + str(type(folder_name)))
self.__queue.put(folder_name) self.__queue.put(folder_name)
@ -131,7 +131,7 @@ class Scanner(Thread):
scanned = 0 scanned = 0
while not self.__stopped.is_set() and to_scan: while not self.__stopped.is_set() and to_scan:
path = to_scan.pop() path = to_scan.pop()
for entry in scandir(path): for entry in os.scandir(path):
if entry.name.startswith("."): if entry.name.startswith("."):
continue continue
if entry.is_symlink() and not self.__follow_symlinks: if entry.is_symlink() and not self.__follow_symlinks:
@ -194,7 +194,7 @@ class Scanner(Thread):
@db_session @db_session
def scan_file(self, path_or_direntry): def scan_file(self, path_or_direntry):
if isinstance(path_or_direntry, strtype): if isinstance(path_or_direntry, str):
path = path_or_direntry path = path_or_direntry
if not os.path.exists(path): if not os.path.exists(path):
@ -286,7 +286,7 @@ class Scanner(Thread):
@db_session @db_session
def remove_file(self, path): def remove_file(self, path):
if not isinstance(path, strtype): if not isinstance(path, str):
raise TypeError("Expecting string, got " + str(type(path))) raise TypeError("Expecting string, got " + str(type(path)))
tr = Track.get(path=path) tr = Track.get(path=path)
@ -298,9 +298,9 @@ class Scanner(Thread):
@db_session @db_session
def move_file(self, src_path, dst_path): def move_file(self, src_path, dst_path):
if not isinstance(src_path, strtype): if not isinstance(src_path, str):
raise TypeError("Expecting string, got " + str(type(src_path))) raise TypeError("Expecting string, got " + str(type(src_path)))
if not isinstance(dst_path, strtype): if not isinstance(dst_path, str):
raise TypeError("Expecting string, got " + str(type(dst_path))) raise TypeError("Expecting string, got " + str(type(dst_path)))
if src_path == dst_path: if src_path == dst_path:
@ -326,7 +326,7 @@ class Scanner(Thread):
@db_session @db_session
def find_cover(self, dirpath): def find_cover(self, dirpath):
if not isinstance(dirpath, strtype): # pragma: nocover if not isinstance(dirpath, str): # pragma: nocover
raise TypeError("Expecting string, got " + str(type(dirpath))) raise TypeError("Expecting string, got " + str(type(dirpath)))
if not os.path.exists(dirpath): if not os.path.exists(dirpath):
@ -346,7 +346,7 @@ class Scanner(Thread):
@db_session @db_session
def add_cover(self, path): def add_cover(self, path):
if not isinstance(path, strtype): # pragma: nocover if not isinstance(path, str): # pragma: nocover
raise TypeError("Expecting string, got " + str(type(path))) raise TypeError("Expecting string, got " + str(type(path)))
folder = Folder.get(path=os.path.dirname(path)) folder = Folder.get(path=os.path.dirname(path))

View File

@ -18,7 +18,6 @@ from watchdog.events import PatternMatchingEventHandler
from . import covers from . import covers
from .db import Folder from .db import Folder
from .py23 import dict, strtype
from .scanner import Scanner from .scanner import Scanner
OP_SCAN = 1 OP_SCAN = 1
@ -267,7 +266,7 @@ class SupysonicWatcher(object):
def add_folder(self, folder): def add_folder(self, folder):
if isinstance(folder, Folder): if isinstance(folder, Folder):
path = folder.path path = folder.path
elif isinstance(folder, strtype): elif isinstance(folder, str):
path = folder path = folder
else: else:
raise TypeError("Expecting string or Folder, got " + str(type(folder))) raise TypeError("Expecting string or Folder, got " + str(type(folder)))
@ -279,7 +278,7 @@ class SupysonicWatcher(object):
def remove_folder(self, folder): def remove_folder(self, folder):
if isinstance(folder, Folder): if isinstance(folder, Folder):
path = folder.path path = folder.path
elif isinstance(folder, strtype): elif isinstance(folder, str):
path = folder path = folder
else: else:
raise TypeError("Expecting string or Folder, got " + str(type(folder))) raise TypeError("Expecting string or Folder, got " + str(type(folder)))

View File

@ -11,7 +11,6 @@ import re
from lxml import etree from lxml import etree
from supysonic.managers.user import UserManager from supysonic.managers.user import UserManager
from supysonic.py23 import strtype
from ..testbase import TestBase from ..testbase import TestBase
@ -68,7 +67,7 @@ class ApiTestBase(TestBase):
if not isinstance(args, dict): if not isinstance(args, dict):
raise TypeError("'args', expecting a dict, got " + type(args).__name__) raise TypeError("'args', expecting a dict, got " + type(args).__name__)
if tag and not isinstance(tag, strtype): if tag and not isinstance(tag, str):
raise TypeError("'tag', expecting a str, got " + type(tag).__name__) raise TypeError("'tag', expecting a str, got " + type(tag).__name__)
args.update({"c": "tests", "v": "1.9.0"}) args.update({"c": "tests", "v": "1.9.0"})

View File

@ -14,7 +14,6 @@ import flask.json
from xml.etree import ElementTree from xml.etree import ElementTree
from supysonic.api.formatters import JSONFormatter, JSONPFormatter, XMLFormatter from supysonic.api.formatters import JSONFormatter, JSONPFormatter, XMLFormatter
from supysonic.py23 import strtype
from ..testbase import TestBase from ..testbase import TestBase
@ -98,7 +97,7 @@ class ResponseHelperJsonTestCase(TestBase, UnwrapperMixin.create_from(JSONFormat
self.assertIn("list", d) self.assertIn("list", d)
self.assertNotIn("emptyList", d) self.assertNotIn("emptyList", d)
self.assertIn("subdict", d) self.assertIn("subdict", d)
self.assertIsInstance(d["value"], strtype) self.assertIsInstance(d["value"], str)
self.assertIsInstance(d["list"], list) self.assertIsInstance(d["list"], list)
self.assertIsInstance(d["subdict"], dict) self.assertIsInstance(d["subdict"], dict)

View File

@ -15,13 +15,9 @@ import tempfile
import unittest import unittest
from contextlib import contextmanager from contextlib import contextmanager
from io import StringIO
from pony.orm import db_session from pony.orm import db_session
try: # Don't use io.StringIO on py2, it only accepts unicode and the CLI spits strs
from StringIO import StringIO
except ImportError:
from io import StringIO
from supysonic.db import Folder, User, init_database, release_database from supysonic.db import Folder, User, init_database, release_database
from supysonic.cli import SupysonicCLI from supysonic.cli import SupysonicCLI

View File

@ -11,7 +11,6 @@
import unittest import unittest
from supysonic.config import IniConfig from supysonic.config import IniConfig
from supysonic.py23 import strtype
class ConfigTestCase(unittest.TestCase): class ConfigTestCase(unittest.TestCase):
@ -26,7 +25,7 @@ class ConfigTestCase(unittest.TestCase):
self.assertIsInstance(conf.TYPES["float"], float) self.assertIsInstance(conf.TYPES["float"], float)
self.assertIsInstance(conf.TYPES["int"], int) self.assertIsInstance(conf.TYPES["int"], int)
self.assertIsInstance(conf.TYPES["string"], strtype) self.assertIsInstance(conf.TYPES["string"], str)
for t in ("bool", "switch", "yn"): for t in ("bool", "switch", "yn"):
self.assertIsInstance(conf.BOOLEANS[t + "_false"], bool) self.assertIsInstance(conf.BOOLEANS[t + "_false"], bool)

View File

@ -11,7 +11,6 @@
from supysonic import db from supysonic import db
from supysonic.managers.user import UserManager from supysonic.managers.user import UserManager
from supysonic.py23 import strtype
import io import io
import unittest import unittest