mirror of
https://github.com/spl0k/supysonic.git
synced 2024-12-22 08:56:17 +00:00
Dropping Python 2 support
This commit is contained in:
parent
2f9fa0da6f
commit
1d01450f33
@ -1,7 +1,6 @@
|
||||
dist: xenial
|
||||
language: python
|
||||
python:
|
||||
- 2.7
|
||||
- 3.5
|
||||
- 3.6
|
||||
- 3.7
|
||||
|
10
README.md
10
README.md
@ -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)
|
||||
[![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:
|
||||
* browsing (by folders or tags)
|
||||
@ -51,20 +51,20 @@ or
|
||||
|
||||
$ pip install .
|
||||
|
||||
but not both. Please note that the `pip` method doesn't seem to work with
|
||||
Python 2.7.
|
||||
but not both.
|
||||
|
||||
### Prerequisites
|
||||
|
||||
You'll need these to run _Supysonic_:
|
||||
|
||||
* Python 2.7 or >= 3.5
|
||||
* Python >= 3.5
|
||||
* [Flask](http://flask.pocoo.org/)
|
||||
* [PonyORM](https://ponyorm.com/)
|
||||
* [Python Imaging Library](https://github.com/python-pillow/Pillow)
|
||||
* [requests](http://docs.python-requests.org/)
|
||||
* [mutagen](https://mutagen.readthedocs.io/en/latest/)
|
||||
* [watchdog](https://github.com/gorakhargosh/watchdog)
|
||||
* [zipstream](https://github.com/allanlei/python-zipstream)
|
||||
|
||||
All the dependencies will automatically be installed by the
|
||||
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
|
||||
module and enable it.
|
||||
|
||||
$ apt install libapache2-mod-wsgi
|
||||
$ apt install libapache2-mod-wsgi-py3
|
||||
$ a2enmod wsgi
|
||||
|
||||
Next, edit the _Apache_ configuration to load the application. Here's a basic
|
||||
|
3
setup.py
3
setup.py
@ -20,7 +20,6 @@ reqs = [
|
||||
"Pillow",
|
||||
"requests>=1.0.0",
|
||||
"mutagen>=1.33",
|
||||
"scandir<2.0.0; python_version <= '2.7'",
|
||||
"watchdog>=0.8.0",
|
||||
"zipstream",
|
||||
]
|
||||
@ -55,8 +54,6 @@ setup(
|
||||
"Intended Audience :: End Users/Desktop",
|
||||
"Intended Audience :: System Administrators",
|
||||
"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.5",
|
||||
"Programming Language :: Python :: 3.6",
|
||||
|
@ -18,7 +18,6 @@ from pony.orm import ObjectNotFound
|
||||
from pony.orm import commit
|
||||
|
||||
from ..managers.user import UserManager
|
||||
from ..py23 import dict
|
||||
|
||||
from .exceptions import Unauthorized
|
||||
from .formatters import JSONFormatter, JSONPFormatter, XMLFormatter
|
||||
|
@ -24,7 +24,6 @@ from ..db import (
|
||||
User,
|
||||
)
|
||||
from ..db import now
|
||||
from ..py23 import dict
|
||||
|
||||
from . import api
|
||||
from .exceptions import GenericError, NotFound
|
||||
|
@ -19,7 +19,6 @@ from ..db import Track, Album, Artist, Folder, User
|
||||
from ..db import StarredTrack, StarredAlbum, StarredArtist, StarredFolder
|
||||
from ..db import RatingTrack, RatingFolder
|
||||
from ..lastfm import LastFm
|
||||
from ..py23 import dict
|
||||
|
||||
from . import api, get_entity, get_entity_id
|
||||
from .exceptions import AggregateException, GenericError, MissingParameter, NotFound
|
||||
@ -150,7 +149,9 @@ def rate():
|
||||
if rating == 0:
|
||||
if tid is not None:
|
||||
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:
|
||||
delete(
|
||||
|
@ -14,7 +14,6 @@ from flask import request
|
||||
from pony.orm import ObjectNotFound, select
|
||||
|
||||
from ..db import Folder, Artist, Album, Track
|
||||
from ..py23 import dict
|
||||
|
||||
from . import api, get_entity, get_entity_id
|
||||
|
||||
|
@ -10,7 +10,6 @@
|
||||
from flask import request
|
||||
|
||||
from ..db import ChatMessage, User
|
||||
from ..py23 import dict
|
||||
from . import api
|
||||
|
||||
|
||||
|
@ -10,7 +10,6 @@
|
||||
from flask import json, jsonify, make_response
|
||||
from xml.etree import ElementTree
|
||||
|
||||
from ..py23 import dict, strtype
|
||||
from . import API_VERSION
|
||||
|
||||
|
||||
@ -103,7 +102,7 @@ class XMLFormatter(BaseFormatter):
|
||||
"""
|
||||
if not isinstance(dictionary, 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")
|
||||
|
||||
for name, value in dictionary.items():
|
||||
@ -125,7 +124,7 @@ class XMLFormatter(BaseFormatter):
|
||||
def __value_tostring(self, value):
|
||||
if value is None:
|
||||
return None
|
||||
if isinstance(value, strtype):
|
||||
if isinstance(value, str):
|
||||
return value
|
||||
if isinstance(value, bool):
|
||||
return str(value).lower()
|
||||
|
@ -8,7 +8,6 @@
|
||||
#
|
||||
# Distributed under terms of the GNU AGPLv3 license.
|
||||
|
||||
import codecs
|
||||
import logging
|
||||
import mimetypes
|
||||
import os.path
|
||||
@ -33,7 +32,6 @@ from .. import scanner
|
||||
from ..cache import CacheMiss
|
||||
from ..covers import get_embedded_cover
|
||||
from ..db import Track, Album, Artist, Folder, User, ClientPrefs, now
|
||||
from ..py23 import dict
|
||||
|
||||
from . import api, get_entity, get_entity_id
|
||||
from .exceptions import (
|
||||
@ -137,9 +135,7 @@ def stream_media():
|
||||
raise GenericError(message)
|
||||
|
||||
transcoder, decoder, encoder = [
|
||||
prepare_transcoding_cmdline(
|
||||
x, res, src_suffix, dst_suffix, dst_bitrate
|
||||
)
|
||||
prepare_transcoding_cmdline(x, res, src_suffix, dst_suffix, dst_bitrate)
|
||||
for x in (transcoder, decoder, encoder)
|
||||
]
|
||||
try:
|
||||
@ -304,7 +300,8 @@ def lyrics():
|
||||
logger.debug("Found lyrics file: " + lyrics_path)
|
||||
|
||||
try:
|
||||
lyrics = read_file_as_unicode(lyrics_path)
|
||||
with open(lyrics_path, "rt") as f:
|
||||
lyrics = f.read()
|
||||
except UnicodeError:
|
||||
# Lyrics file couldn't be decoded. Rather than displaying an error, try with the potential next files or
|
||||
# return no lyrics. Log it anyway.
|
||||
@ -350,22 +347,3 @@ def lyrics():
|
||||
logger.warning("Error while requesting the ChartLyrics API: " + str(e))
|
||||
|
||||
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())
|
||||
|
@ -12,7 +12,6 @@ import uuid
|
||||
from flask import request
|
||||
|
||||
from ..db import Playlist, User, Track
|
||||
from ..py23 import dict
|
||||
|
||||
from . import api, get_entity
|
||||
from .exceptions import Forbidden, MissingParameter, NotFound
|
||||
|
@ -13,7 +13,6 @@ from flask import request
|
||||
from pony.orm import select
|
||||
|
||||
from ..db import Folder, Track, Artist, Album
|
||||
from ..py23 import dict
|
||||
|
||||
from . import api
|
||||
from .exceptions import MissingParameter
|
||||
|
@ -9,7 +9,6 @@
|
||||
|
||||
from flask import request
|
||||
|
||||
from ..py23 import dict
|
||||
from . import api
|
||||
|
||||
|
||||
|
@ -12,7 +12,6 @@ from functools import wraps
|
||||
|
||||
from ..db import User
|
||||
from ..managers.user import UserManager
|
||||
from ..py23 import dict
|
||||
|
||||
from . import api, decode_password
|
||||
from .exceptions import Forbidden, GenericError, NotFound
|
||||
|
@ -18,8 +18,6 @@ import tempfile
|
||||
import threading
|
||||
from time import time
|
||||
|
||||
from .py23 import scandir, osreplace
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -80,7 +78,7 @@ class Cache(object):
|
||||
for mtime, size, key in sorted(
|
||||
[
|
||||
(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()
|
||||
]
|
||||
):
|
||||
@ -158,7 +156,7 @@ class Cache(object):
|
||||
with self._lock:
|
||||
if self._auto_prune:
|
||||
self._make_space(size, key=key)
|
||||
osreplace(f.name, self._filepath(key))
|
||||
os.replace(f.name, self._filepath(key))
|
||||
self._record_file(key, size)
|
||||
except OSError as e:
|
||||
# Ignore error from trying to delete the renamed temp file
|
||||
|
@ -8,14 +8,11 @@
|
||||
#
|
||||
# Distributed under terms of the GNU AGPLv3 license.
|
||||
|
||||
try:
|
||||
from configparser import RawConfigParser
|
||||
except ImportError:
|
||||
from ConfigParser import RawConfigParser
|
||||
|
||||
import os
|
||||
import tempfile
|
||||
|
||||
from configparser import RawConfigParser
|
||||
|
||||
current_config = None
|
||||
|
||||
|
||||
@ -92,11 +89,6 @@ class IniConfig(DefaultConfig):
|
||||
return True
|
||||
if lv in ("no", "false", "off"):
|
||||
return False
|
||||
try:
|
||||
if isinstance(value, unicode):
|
||||
return str(value)
|
||||
except NameError:
|
||||
pass
|
||||
return value
|
||||
|
||||
@classmethod
|
||||
|
@ -16,8 +16,8 @@ from mutagen.easyid3 import EasyID3
|
||||
from mutagen.flac import FLAC, Picture
|
||||
from mutagen._vorbis import VCommentDict
|
||||
from PIL import Image
|
||||
from os import scandir
|
||||
|
||||
from .py23 import scandir, strtype
|
||||
|
||||
EXTENSIONS = (".jpg", ".jpeg", ".png", ".bmp")
|
||||
NAMING_SCORE_RULES = (
|
||||
@ -90,7 +90,7 @@ def find_cover_in_folder(path, album_name=None):
|
||||
|
||||
|
||||
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)))
|
||||
|
||||
if not os.path.exists(path):
|
||||
|
@ -11,7 +11,6 @@ from multiprocessing.connection import Client
|
||||
|
||||
from .exceptions import DaemonUnavailableError
|
||||
from ..config import get_current_config
|
||||
from ..py23 import strtype
|
||||
from ..utils import get_secret_key
|
||||
|
||||
__all__ = ["DaemonClient"]
|
||||
@ -86,13 +85,13 @@ class DaemonClient(object):
|
||||
)
|
||||
|
||||
def add_watched_folder(self, folder):
|
||||
if not isinstance(folder, strtype):
|
||||
if not isinstance(folder, str):
|
||||
raise TypeError("Expecting string, got " + str(type(folder)))
|
||||
with self.__get_connection() as c:
|
||||
c.send(AddWatchedFolderCommand(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)))
|
||||
with self.__get_connection() as c:
|
||||
c.send(RemoveWatchedFolder(folder))
|
||||
|
@ -20,15 +20,9 @@ from pony.orm import ObjectNotFound, DatabaseError
|
||||
from pony.orm import buffer
|
||||
from pony.orm import min, max, avg, sum, exists
|
||||
from pony.orm import db_session
|
||||
from urllib.parse import urlparse, parse_qsl
|
||||
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"
|
||||
|
||||
|
||||
@ -538,7 +532,7 @@ class Playlist(db.Entity):
|
||||
tid = track
|
||||
elif isinstance(track, Track):
|
||||
tid = track.id
|
||||
elif isinstance(track, strtype):
|
||||
elif isinstance(track, str):
|
||||
tid = UUID(track)
|
||||
|
||||
if self.tracks and len(self.tracks) > 0:
|
||||
@ -557,7 +551,7 @@ class Playlist(db.Entity):
|
||||
|
||||
|
||||
def parse_uri(database_uri):
|
||||
if not isinstance(database_uri, strtype):
|
||||
if not isinstance(database_uri, str):
|
||||
raise TypeError("Expecting a string")
|
||||
|
||||
uri = urlparse(database_uri)
|
||||
|
@ -17,7 +17,6 @@ from pony.orm import ObjectNotFound
|
||||
from ..db import User, ClientPrefs
|
||||
from ..lastfm import LastFm
|
||||
from ..managers.user import UserManager
|
||||
from ..py23 import dict
|
||||
|
||||
from . import admin_only, frontend
|
||||
|
||||
|
@ -11,8 +11,6 @@ import hashlib
|
||||
import logging
|
||||
import requests
|
||||
|
||||
from .py23 import strtype
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@ -87,7 +85,7 @@ class LastFm:
|
||||
sig_str = b""
|
||||
for k, v in sorted(kwargs.items()):
|
||||
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 = hashlib.md5(sig_str + self.__api_secret).hexdigest()
|
||||
|
||||
|
@ -16,7 +16,6 @@ from pony.orm import ObjectNotFound
|
||||
from ..daemon.client import DaemonClient
|
||||
from ..daemon.exceptions import DaemonUnavailableError
|
||||
from ..db import Folder, Track, Artist, Album, User, RatingTrack, StarredTrack
|
||||
from ..py23 import strtype
|
||||
|
||||
|
||||
class FolderManager:
|
||||
|
@ -16,7 +16,6 @@ import uuid
|
||||
from pony.orm import ObjectNotFound
|
||||
|
||||
from ..db import User
|
||||
from ..py23 import strtype
|
||||
|
||||
|
||||
class UserManager:
|
||||
@ -24,7 +23,7 @@ class UserManager:
|
||||
def get(uid):
|
||||
if isinstance(uid, uuid.UUID):
|
||||
pass
|
||||
elif isinstance(uid, strtype):
|
||||
elif isinstance(uid, str):
|
||||
uid = uuid.UUID(uid)
|
||||
else:
|
||||
raise ValueError("Invalid user id")
|
||||
|
@ -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
|
@ -14,13 +14,13 @@ import time
|
||||
|
||||
from datetime import datetime
|
||||
from pony.orm import db_session
|
||||
from queue import Queue, Empty as QueueEmpty
|
||||
from threading import Thread, Event
|
||||
|
||||
from .covers import find_cover_in_folder, has_embedded_cover, CoverFile
|
||||
from .db import Folder, Artist, Album, Track, User
|
||||
from .db import StarredFolder, StarredArtist, StarredAlbum, StarredTrack
|
||||
from .db import RatingFolder, RatingTrack
|
||||
from .py23 import scandir, strtype, Queue, QueueEmpty
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@ -93,7 +93,7 @@ class Scanner(Thread):
|
||||
self.__progress(folder_name, scanned)
|
||||
|
||||
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)))
|
||||
|
||||
self.__queue.put(folder_name)
|
||||
@ -131,7 +131,7 @@ class Scanner(Thread):
|
||||
scanned = 0
|
||||
while not self.__stopped.is_set() and to_scan:
|
||||
path = to_scan.pop()
|
||||
for entry in scandir(path):
|
||||
for entry in os.scandir(path):
|
||||
if entry.name.startswith("."):
|
||||
continue
|
||||
if entry.is_symlink() and not self.__follow_symlinks:
|
||||
@ -194,7 +194,7 @@ class Scanner(Thread):
|
||||
|
||||
@db_session
|
||||
def scan_file(self, path_or_direntry):
|
||||
if isinstance(path_or_direntry, strtype):
|
||||
if isinstance(path_or_direntry, str):
|
||||
path = path_or_direntry
|
||||
|
||||
if not os.path.exists(path):
|
||||
@ -286,7 +286,7 @@ class Scanner(Thread):
|
||||
|
||||
@db_session
|
||||
def remove_file(self, path):
|
||||
if not isinstance(path, strtype):
|
||||
if not isinstance(path, str):
|
||||
raise TypeError("Expecting string, got " + str(type(path)))
|
||||
|
||||
tr = Track.get(path=path)
|
||||
@ -298,9 +298,9 @@ class Scanner(Thread):
|
||||
|
||||
@db_session
|
||||
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)))
|
||||
if not isinstance(dst_path, strtype):
|
||||
if not isinstance(dst_path, str):
|
||||
raise TypeError("Expecting string, got " + str(type(dst_path)))
|
||||
|
||||
if src_path == dst_path:
|
||||
@ -326,7 +326,7 @@ class Scanner(Thread):
|
||||
|
||||
@db_session
|
||||
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)))
|
||||
|
||||
if not os.path.exists(dirpath):
|
||||
@ -346,7 +346,7 @@ class Scanner(Thread):
|
||||
|
||||
@db_session
|
||||
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)))
|
||||
|
||||
folder = Folder.get(path=os.path.dirname(path))
|
||||
|
@ -18,7 +18,6 @@ from watchdog.events import PatternMatchingEventHandler
|
||||
|
||||
from . import covers
|
||||
from .db import Folder
|
||||
from .py23 import dict, strtype
|
||||
from .scanner import Scanner
|
||||
|
||||
OP_SCAN = 1
|
||||
@ -267,7 +266,7 @@ class SupysonicWatcher(object):
|
||||
def add_folder(self, folder):
|
||||
if isinstance(folder, Folder):
|
||||
path = folder.path
|
||||
elif isinstance(folder, strtype):
|
||||
elif isinstance(folder, str):
|
||||
path = folder
|
||||
else:
|
||||
raise TypeError("Expecting string or Folder, got " + str(type(folder)))
|
||||
@ -279,7 +278,7 @@ class SupysonicWatcher(object):
|
||||
def remove_folder(self, folder):
|
||||
if isinstance(folder, Folder):
|
||||
path = folder.path
|
||||
elif isinstance(folder, strtype):
|
||||
elif isinstance(folder, str):
|
||||
path = folder
|
||||
else:
|
||||
raise TypeError("Expecting string or Folder, got " + str(type(folder)))
|
||||
|
@ -11,7 +11,6 @@ import re
|
||||
|
||||
from lxml import etree
|
||||
from supysonic.managers.user import UserManager
|
||||
from supysonic.py23 import strtype
|
||||
|
||||
from ..testbase import TestBase
|
||||
|
||||
@ -68,7 +67,7 @@ class ApiTestBase(TestBase):
|
||||
|
||||
if not isinstance(args, dict):
|
||||
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__)
|
||||
|
||||
args.update({"c": "tests", "v": "1.9.0"})
|
||||
|
@ -14,7 +14,6 @@ import flask.json
|
||||
from xml.etree import ElementTree
|
||||
|
||||
from supysonic.api.formatters import JSONFormatter, JSONPFormatter, XMLFormatter
|
||||
from supysonic.py23 import strtype
|
||||
|
||||
from ..testbase import TestBase
|
||||
|
||||
@ -98,7 +97,7 @@ class ResponseHelperJsonTestCase(TestBase, UnwrapperMixin.create_from(JSONFormat
|
||||
self.assertIn("list", d)
|
||||
self.assertNotIn("emptyList", d)
|
||||
self.assertIn("subdict", d)
|
||||
self.assertIsInstance(d["value"], strtype)
|
||||
self.assertIsInstance(d["value"], str)
|
||||
self.assertIsInstance(d["list"], list)
|
||||
self.assertIsInstance(d["subdict"], dict)
|
||||
|
||||
|
@ -15,13 +15,9 @@ import tempfile
|
||||
import unittest
|
||||
|
||||
from contextlib import contextmanager
|
||||
from io import StringIO
|
||||
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.cli import SupysonicCLI
|
||||
|
||||
|
@ -11,7 +11,6 @@
|
||||
import unittest
|
||||
|
||||
from supysonic.config import IniConfig
|
||||
from supysonic.py23 import strtype
|
||||
|
||||
|
||||
class ConfigTestCase(unittest.TestCase):
|
||||
@ -26,7 +25,7 @@ class ConfigTestCase(unittest.TestCase):
|
||||
|
||||
self.assertIsInstance(conf.TYPES["float"], float)
|
||||
self.assertIsInstance(conf.TYPES["int"], int)
|
||||
self.assertIsInstance(conf.TYPES["string"], strtype)
|
||||
self.assertIsInstance(conf.TYPES["string"], str)
|
||||
|
||||
for t in ("bool", "switch", "yn"):
|
||||
self.assertIsInstance(conf.BOOLEANS[t + "_false"], bool)
|
||||
|
@ -11,7 +11,6 @@
|
||||
|
||||
from supysonic import db
|
||||
from supysonic.managers.user import UserManager
|
||||
from supysonic.py23 import strtype
|
||||
|
||||
import io
|
||||
import unittest
|
||||
|
Loading…
Reference in New Issue
Block a user