mirror of
https://github.com/beetbox/beets.git
synced 2025-12-06 16:42:42 +01:00
Replace py3_path and cpu_count implementations with builtins (#5227)
Replace py3_path by standard os.fsdecode and use native os.cpu_count. These functions had been written before builtins achieving the same have been made available (in Python 3.2 and 3.4). Now that they are available though, this PR updates the codebase to use builtin implementations rather than the custom ones.
This commit is contained in:
commit
0e87389994
19 changed files with 79 additions and 129 deletions
|
|
@ -51,7 +51,7 @@ from typing import (
|
||||||
from unidecode import unidecode
|
from unidecode import unidecode
|
||||||
|
|
||||||
import beets
|
import beets
|
||||||
from beets.util import functemplate, py3_path
|
from beets.util import functemplate
|
||||||
|
|
||||||
from ..util.functemplate import Template
|
from ..util.functemplate import Template
|
||||||
from . import types
|
from . import types
|
||||||
|
|
@ -1059,9 +1059,9 @@ class Database:
|
||||||
"""
|
"""
|
||||||
# Make a new connection. The `sqlite3` module can't use
|
# Make a new connection. The `sqlite3` module can't use
|
||||||
# bytestring paths here on Python 3, so we need to
|
# bytestring paths here on Python 3, so we need to
|
||||||
# provide a `str` using `py3_path`.
|
# provide a `str` using `os.fsdecode`.
|
||||||
conn = sqlite3.connect(
|
conn = sqlite3.connect(
|
||||||
py3_path(self.path),
|
os.fsdecode(self.path),
|
||||||
timeout=self.timeout,
|
timeout=self.timeout,
|
||||||
# We have our own same-thread checks in _connection(), but need to
|
# We have our own same-thread checks in _connection(), but need to
|
||||||
# call conn.close() in _close()
|
# call conn.close() in _close()
|
||||||
|
|
|
||||||
|
|
@ -1136,7 +1136,7 @@ class ArchiveImportTask(SentinelImportTask):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
for path_test, _ in cls.handlers():
|
for path_test, _ in cls.handlers():
|
||||||
if path_test(util.py3_path(path)):
|
if path_test(os.fsdecode(path)):
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
@ -1186,11 +1186,11 @@ class ArchiveImportTask(SentinelImportTask):
|
||||||
`toppath` to that directory.
|
`toppath` to that directory.
|
||||||
"""
|
"""
|
||||||
for path_test, handler_class in self.handlers():
|
for path_test, handler_class in self.handlers():
|
||||||
if path_test(util.py3_path(self.toppath)):
|
if path_test(os.fsdecode(self.toppath)):
|
||||||
break
|
break
|
||||||
|
|
||||||
extract_to = mkdtemp()
|
extract_to = mkdtemp()
|
||||||
archive = handler_class(util.py3_path(self.toppath), mode="r")
|
archive = handler_class(os.fsdecode(self.toppath), mode="r")
|
||||||
try:
|
try:
|
||||||
archive.extractall(extract_to)
|
archive.extractall(extract_to)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -209,19 +209,19 @@ class TestCase(unittest.TestCase, Assertions):
|
||||||
# temporary directory.
|
# temporary directory.
|
||||||
self.temp_dir = util.bytestring_path(tempfile.mkdtemp())
|
self.temp_dir = util.bytestring_path(tempfile.mkdtemp())
|
||||||
|
|
||||||
beets.config["statefile"] = util.py3_path(
|
beets.config["statefile"] = os.fsdecode(
|
||||||
os.path.join(self.temp_dir, b"state.pickle")
|
os.path.join(self.temp_dir, b"state.pickle")
|
||||||
)
|
)
|
||||||
beets.config["library"] = util.py3_path(
|
beets.config["library"] = os.fsdecode(
|
||||||
os.path.join(self.temp_dir, b"library.db")
|
os.path.join(self.temp_dir, b"library.db")
|
||||||
)
|
)
|
||||||
beets.config["directory"] = util.py3_path(
|
beets.config["directory"] = os.fsdecode(
|
||||||
os.path.join(self.temp_dir, b"libdir")
|
os.path.join(self.temp_dir, b"libdir")
|
||||||
)
|
)
|
||||||
|
|
||||||
# Set $HOME, which is used by Confuse to create directories.
|
# Set $HOME, which is used by Confuse to create directories.
|
||||||
self._old_home = os.environ.get("HOME")
|
self._old_home = os.environ.get("HOME")
|
||||||
os.environ["HOME"] = util.py3_path(self.temp_dir)
|
os.environ["HOME"] = os.fsdecode(self.temp_dir)
|
||||||
|
|
||||||
# Initialize, but don't install, a DummyIO.
|
# Initialize, but don't install, a DummyIO.
|
||||||
self.io = DummyIO()
|
self.io = DummyIO()
|
||||||
|
|
|
||||||
|
|
@ -166,7 +166,7 @@ class TestHelper:
|
||||||
Make sure you call ``teardown_beets()`` afterwards.
|
Make sure you call ``teardown_beets()`` afterwards.
|
||||||
"""
|
"""
|
||||||
self.create_temp_dir()
|
self.create_temp_dir()
|
||||||
os.environ["BEETSDIR"] = util.py3_path(self.temp_dir)
|
os.environ["BEETSDIR"] = os.fsdecode(self.temp_dir)
|
||||||
|
|
||||||
self.config = beets.config
|
self.config = beets.config
|
||||||
self.config.clear()
|
self.config.clear()
|
||||||
|
|
@ -179,7 +179,7 @@ class TestHelper:
|
||||||
|
|
||||||
self.libdir = os.path.join(self.temp_dir, b"libdir")
|
self.libdir = os.path.join(self.temp_dir, b"libdir")
|
||||||
os.mkdir(syspath(self.libdir))
|
os.mkdir(syspath(self.libdir))
|
||||||
self.config["directory"] = util.py3_path(self.libdir)
|
self.config["directory"] = os.fsdecode(self.libdir)
|
||||||
|
|
||||||
if disk:
|
if disk:
|
||||||
dbpath = util.bytestring_path(self.config["library"].as_filename())
|
dbpath = util.bytestring_path(self.config["library"].as_filename())
|
||||||
|
|
|
||||||
|
|
@ -1633,7 +1633,7 @@ def _load_plugins(options, config):
|
||||||
log.debug("plugin paths: {0}", util.displayable_path(paths))
|
log.debug("plugin paths: {0}", util.displayable_path(paths))
|
||||||
|
|
||||||
# On Python 3, the search paths need to be unicode.
|
# On Python 3, the search paths need to be unicode.
|
||||||
paths = [util.py3_path(p) for p in paths]
|
paths = [os.fsdecode(p) for p in paths]
|
||||||
|
|
||||||
# Extend the `beetsplug` package to include the plugin paths.
|
# Extend the `beetsplug` package to include the plugin paths.
|
||||||
import beetsplug
|
import beetsplug
|
||||||
|
|
|
||||||
|
|
@ -803,21 +803,6 @@ def legalize_path(
|
||||||
return second_stage_path, retruncated
|
return second_stage_path, retruncated
|
||||||
|
|
||||||
|
|
||||||
def py3_path(path: Union[bytes, str]) -> str:
|
|
||||||
"""Convert a bytestring path to Unicode.
|
|
||||||
|
|
||||||
This helps deal with APIs on Python 3 that *only* accept Unicode
|
|
||||||
(i.e., `str` objects). I philosophically disagree with this
|
|
||||||
decision, because paths are sadly bytes on Unix, but that's the way
|
|
||||||
it is. So this function helps us "smuggle" the true bytes data
|
|
||||||
through APIs that took Python 3's Unicode mandate too seriously.
|
|
||||||
"""
|
|
||||||
if isinstance(path, str):
|
|
||||||
return path
|
|
||||||
assert isinstance(path, bytes)
|
|
||||||
return os.fsdecode(path)
|
|
||||||
|
|
||||||
|
|
||||||
def str2bool(value: str) -> bool:
|
def str2bool(value: str) -> bool:
|
||||||
"""Returns a boolean reflecting a human-entered string."""
|
"""Returns a boolean reflecting a human-entered string."""
|
||||||
return value.lower() in ("yes", "1", "true", "t", "y")
|
return value.lower() in ("yes", "1", "true", "t", "y")
|
||||||
|
|
@ -848,41 +833,6 @@ def plurality(objs: Sequence[T]) -> T:
|
||||||
return c.most_common(1)[0]
|
return c.most_common(1)[0]
|
||||||
|
|
||||||
|
|
||||||
def cpu_count() -> int:
|
|
||||||
"""Return the number of hardware thread contexts (cores or SMT
|
|
||||||
threads) in the system.
|
|
||||||
"""
|
|
||||||
# Adapted from the soundconverter project:
|
|
||||||
# https://github.com/kassoulet/soundconverter
|
|
||||||
if sys.platform == "win32":
|
|
||||||
try:
|
|
||||||
num = int(os.environ["NUMBER_OF_PROCESSORS"])
|
|
||||||
except (ValueError, KeyError):
|
|
||||||
num = 0
|
|
||||||
elif sys.platform == "darwin":
|
|
||||||
try:
|
|
||||||
num = int(
|
|
||||||
command_output(
|
|
||||||
[
|
|
||||||
"/usr/sbin/sysctl",
|
|
||||||
"-n",
|
|
||||||
"hw.ncpu",
|
|
||||||
]
|
|
||||||
).stdout
|
|
||||||
)
|
|
||||||
except (ValueError, OSError, subprocess.CalledProcessError):
|
|
||||||
num = 0
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
num = os.sysconf("SC_NPROCESSORS_ONLN")
|
|
||||||
except (ValueError, OSError, AttributeError):
|
|
||||||
num = 0
|
|
||||||
if num >= 1:
|
|
||||||
return num
|
|
||||||
else:
|
|
||||||
return 1
|
|
||||||
|
|
||||||
|
|
||||||
def convert_command_args(args: List[bytes]) -> List[str]:
|
def convert_command_args(args: List[bytes]) -> List[str]:
|
||||||
"""Convert command arguments, which may either be `bytes` or `str`
|
"""Convert command arguments, which may either be `bytes` or `str`
|
||||||
objects, to uniformly surrogate-escaped strings."""
|
objects, to uniformly surrogate-escaped strings."""
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ from tempfile import NamedTemporaryFile
|
||||||
from urllib.parse import urlencode
|
from urllib.parse import urlencode
|
||||||
|
|
||||||
from beets import logging, util
|
from beets import logging, util
|
||||||
from beets.util import bytestring_path, displayable_path, py3_path, syspath
|
from beets.util import bytestring_path, displayable_path, syspath
|
||||||
|
|
||||||
PROXY_URL = "https://images.weserv.nl/"
|
PROXY_URL = "https://images.weserv.nl/"
|
||||||
|
|
||||||
|
|
@ -53,7 +53,7 @@ def temp_file_for(path):
|
||||||
specified path.
|
specified path.
|
||||||
"""
|
"""
|
||||||
ext = os.path.splitext(path)[1]
|
ext = os.path.splitext(path)[1]
|
||||||
with NamedTemporaryFile(suffix=py3_path(ext), delete=False) as f:
|
with NamedTemporaryFile(suffix=os.fsdecode(ext), delete=False) as f:
|
||||||
return bytestring_path(f.name)
|
return bytestring_path(f.name)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -386,7 +386,7 @@ class PILBackend(LocalBackend):
|
||||||
|
|
||||||
# progressive=False only affects JPEGs and is the default,
|
# progressive=False only affects JPEGs and is the default,
|
||||||
# but we include it here for explicitness.
|
# but we include it here for explicitness.
|
||||||
im.save(py3_path(path_out), quality=quality, progressive=False)
|
im.save(os.fsdecode(path_out), quality=quality, progressive=False)
|
||||||
|
|
||||||
if max_filesize > 0:
|
if max_filesize > 0:
|
||||||
# If maximum filesize is set, we attempt to lower the quality
|
# If maximum filesize is set, we attempt to lower the quality
|
||||||
|
|
@ -410,7 +410,7 @@ class PILBackend(LocalBackend):
|
||||||
lower_qual = 10
|
lower_qual = 10
|
||||||
# Use optimize flag to improve filesize decrease
|
# Use optimize flag to improve filesize decrease
|
||||||
im.save(
|
im.save(
|
||||||
py3_path(path_out),
|
os.fsdecode(path_out),
|
||||||
quality=lower_qual,
|
quality=lower_qual,
|
||||||
optimize=True,
|
optimize=True,
|
||||||
progressive=False,
|
progressive=False,
|
||||||
|
|
@ -447,7 +447,7 @@ class PILBackend(LocalBackend):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
im = Image.open(syspath(path_in))
|
im = Image.open(syspath(path_in))
|
||||||
im.save(py3_path(path_out), progressive=False)
|
im.save(os.fsdecode(path_out), progressive=False)
|
||||||
return path_out
|
return path_out
|
||||||
except OSError:
|
except OSError:
|
||||||
# FIXME: Should probably issue a warning?
|
# FIXME: Should probably issue a warning?
|
||||||
|
|
@ -473,7 +473,7 @@ class PILBackend(LocalBackend):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with Image.open(syspath(source)) as im:
|
with Image.open(syspath(source)) as im:
|
||||||
im.save(py3_path(target), progressive=not deinterlaced)
|
im.save(os.fsdecode(target), progressive=not deinterlaced)
|
||||||
return target
|
return target
|
||||||
except (
|
except (
|
||||||
ValueError,
|
ValueError,
|
||||||
|
|
@ -506,7 +506,7 @@ class PILBackend(LocalBackend):
|
||||||
meta = PngImagePlugin.PngInfo()
|
meta = PngImagePlugin.PngInfo()
|
||||||
for k, v in metadata.items():
|
for k, v in metadata.items():
|
||||||
meta.add_text(k, v, 0)
|
meta.add_text(k, v, 0)
|
||||||
im.save(py3_path(file), "PNG", pnginfo=meta)
|
im.save(os.fsdecode(file), "PNG", pnginfo=meta)
|
||||||
|
|
||||||
|
|
||||||
class Shareable(type):
|
class Shareable(type):
|
||||||
|
|
|
||||||
|
|
@ -15,11 +15,10 @@
|
||||||
"""An AURA server using Flask."""
|
"""An AURA server using Flask."""
|
||||||
|
|
||||||
|
|
||||||
import os.path
|
import os
|
||||||
import re
|
import re
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from mimetypes import guess_type
|
from mimetypes import guess_type
|
||||||
from os.path import getsize, isfile
|
|
||||||
from typing import ClassVar, Mapping, Type
|
from typing import ClassVar, Mapping, Type
|
||||||
|
|
||||||
from flask import (
|
from flask import (
|
||||||
|
|
@ -46,7 +45,6 @@ from beets.dbcore.query import (
|
||||||
from beets.library import Album, Item, LibModel, Library
|
from beets.library import Album, Item, LibModel, Library
|
||||||
from beets.plugins import BeetsPlugin
|
from beets.plugins import BeetsPlugin
|
||||||
from beets.ui import Subcommand, _open_library
|
from beets.ui import Subcommand, _open_library
|
||||||
from beets.util import py3_path
|
|
||||||
|
|
||||||
# Constants
|
# Constants
|
||||||
|
|
||||||
|
|
@ -482,7 +480,7 @@ class AlbumDocument(AURADocument):
|
||||||
}
|
}
|
||||||
# Add images relationship if album has associated images
|
# Add images relationship if album has associated images
|
||||||
if album.artpath:
|
if album.artpath:
|
||||||
path = py3_path(album.artpath)
|
path = os.fsdecode(album.artpath)
|
||||||
filename = path.split("/")[-1]
|
filename = path.split("/")[-1]
|
||||||
image_id = f"album-{album.id}-{filename}"
|
image_id = f"album-{album.id}-{filename}"
|
||||||
relationships["images"] = {
|
relationships["images"] = {
|
||||||
|
|
@ -660,7 +658,7 @@ class ImageDocument(AURADocument):
|
||||||
# Cut the filename off of artpath
|
# Cut the filename off of artpath
|
||||||
# This is in preparation for supporting images in the same
|
# This is in preparation for supporting images in the same
|
||||||
# directory that are not tracked by beets.
|
# directory that are not tracked by beets.
|
||||||
artpath = py3_path(album.artpath)
|
artpath = os.fsdecode(album.artpath)
|
||||||
dir_path = "/".join(artpath.split("/")[:-1])
|
dir_path = "/".join(artpath.split("/")[:-1])
|
||||||
else:
|
else:
|
||||||
# Images for other resource types are not supported
|
# Images for other resource types are not supported
|
||||||
|
|
@ -668,7 +666,7 @@ class ImageDocument(AURADocument):
|
||||||
|
|
||||||
img_path = os.path.join(dir_path, img_filename)
|
img_path = os.path.join(dir_path, img_filename)
|
||||||
# Check the image actually exists
|
# Check the image actually exists
|
||||||
if isfile(img_path):
|
if os.path.isfile(img_path):
|
||||||
return img_path
|
return img_path
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
@ -690,7 +688,7 @@ class ImageDocument(AURADocument):
|
||||||
attributes = {
|
attributes = {
|
||||||
"role": "cover",
|
"role": "cover",
|
||||||
"mimetype": guess_type(image_path)[0],
|
"mimetype": guess_type(image_path)[0],
|
||||||
"size": getsize(image_path),
|
"size": os.path.getsize(image_path),
|
||||||
}
|
}
|
||||||
try:
|
try:
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
|
@ -781,8 +779,8 @@ def audio_file(track_id):
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
path = py3_path(track.path)
|
path = os.fsdecode(track.path)
|
||||||
if not isfile(path):
|
if not os.path.isfile(path):
|
||||||
return AURADocument.error(
|
return AURADocument.error(
|
||||||
"404 Not Found",
|
"404 Not Found",
|
||||||
"No audio file for the requested track.",
|
"No audio file for the requested track.",
|
||||||
|
|
|
||||||
|
|
@ -114,7 +114,7 @@ class ConvertPlugin(BeetsPlugin):
|
||||||
"pretend": False,
|
"pretend": False,
|
||||||
"link": False,
|
"link": False,
|
||||||
"hardlink": False,
|
"hardlink": False,
|
||||||
"threads": util.cpu_count(),
|
"threads": os.cpu_count(),
|
||||||
"format": "mp3",
|
"format": "mp3",
|
||||||
"id3v23": "inherit",
|
"id3v23": "inherit",
|
||||||
"formats": {
|
"formats": {
|
||||||
|
|
@ -636,8 +636,8 @@ class ConvertPlugin(BeetsPlugin):
|
||||||
# Create a temporary file for the conversion.
|
# Create a temporary file for the conversion.
|
||||||
tmpdir = self.config["tmpdir"].get()
|
tmpdir = self.config["tmpdir"].get()
|
||||||
if tmpdir:
|
if tmpdir:
|
||||||
tmpdir = util.py3_path(util.bytestring_path(tmpdir))
|
tmpdir = os.fsdecode(util.bytestring_path(tmpdir))
|
||||||
fd, dest = tempfile.mkstemp(util.py3_path(b"." + ext), dir=tmpdir)
|
fd, dest = tempfile.mkstemp(os.fsdecode(b"." + ext), dir=tmpdir)
|
||||||
os.close(fd)
|
os.close(fd)
|
||||||
dest = util.bytestring_path(dest)
|
dest = util.bytestring_path(dest)
|
||||||
_temp_files.append(dest) # Delete the transcode later.
|
_temp_files.append(dest) # Delete the transcode later.
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ import requests
|
||||||
from mediafile import image_mime_type
|
from mediafile import image_mime_type
|
||||||
|
|
||||||
from beets import config, importer, plugins, ui, util
|
from beets import config, importer, plugins, ui, util
|
||||||
from beets.util import bytestring_path, py3_path, sorted_walk, syspath
|
from beets.util import bytestring_path, sorted_walk, syspath
|
||||||
from beets.util.artresizer import ArtResizer
|
from beets.util.artresizer import ArtResizer
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
@ -381,7 +381,7 @@ class RemoteArtSource(ArtSource):
|
||||||
ext,
|
ext,
|
||||||
)
|
)
|
||||||
|
|
||||||
suffix = py3_path(ext)
|
suffix = os.fsdecode(ext)
|
||||||
with NamedTemporaryFile(suffix=suffix, delete=False) as fh:
|
with NamedTemporaryFile(suffix=suffix, delete=False) as fh:
|
||||||
# write the first already loaded part of the image
|
# write the first already loaded part of the image
|
||||||
fh.write(header)
|
fh.write(header)
|
||||||
|
|
|
||||||
|
|
@ -49,13 +49,7 @@ from beets import ui
|
||||||
from beets.importer import ImportSession, ImportTask
|
from beets.importer import ImportSession, ImportTask
|
||||||
from beets.library import Album, Item, Library
|
from beets.library import Album, Item, Library
|
||||||
from beets.plugins import BeetsPlugin
|
from beets.plugins import BeetsPlugin
|
||||||
from beets.util import (
|
from beets.util import command_output, displayable_path, syspath
|
||||||
command_output,
|
|
||||||
cpu_count,
|
|
||||||
displayable_path,
|
|
||||||
py3_path,
|
|
||||||
syspath,
|
|
||||||
)
|
|
||||||
|
|
||||||
# Utilities.
|
# Utilities.
|
||||||
|
|
||||||
|
|
@ -942,7 +936,7 @@ class GStreamerBackend(Backend):
|
||||||
|
|
||||||
self._file = self._files.pop(0)
|
self._file = self._files.pop(0)
|
||||||
self._pipe.set_state(self.Gst.State.NULL)
|
self._pipe.set_state(self.Gst.State.NULL)
|
||||||
self._src.set_property("location", py3_path(syspath(self._file)))
|
self._src.set_property("location", os.fsdecode(syspath(self._file)))
|
||||||
self._pipe.set_state(self.Gst.State.PLAYING)
|
self._pipe.set_state(self.Gst.State.PLAYING)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
@ -972,7 +966,7 @@ class GStreamerBackend(Backend):
|
||||||
# Set a new file on the filesrc element, can only be done in the
|
# Set a new file on the filesrc element, can only be done in the
|
||||||
# READY state
|
# READY state
|
||||||
self._src.set_state(self.Gst.State.READY)
|
self._src.set_state(self.Gst.State.READY)
|
||||||
self._src.set_property("location", py3_path(syspath(self._file)))
|
self._src.set_property("location", os.fsdecode(syspath(self._file)))
|
||||||
|
|
||||||
self._decbin.link(self._conv)
|
self._decbin.link(self._conv)
|
||||||
self._pipe.set_state(self.Gst.State.READY)
|
self._pipe.set_state(self.Gst.State.READY)
|
||||||
|
|
@ -1050,7 +1044,9 @@ class AudioToolsBackend(Backend):
|
||||||
file format is not supported
|
file format is not supported
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
audiofile = self._mod_audiotools.open(py3_path(syspath(item.path)))
|
audiofile = self._mod_audiotools.open(
|
||||||
|
os.fsdecode(syspath(item.path))
|
||||||
|
)
|
||||||
except OSError:
|
except OSError:
|
||||||
raise ReplayGainError(f"File {item.path} was not found")
|
raise ReplayGainError(f"File {item.path} was not found")
|
||||||
except self._mod_audiotools.UnsupportedFile:
|
except self._mod_audiotools.UnsupportedFile:
|
||||||
|
|
@ -1226,7 +1222,7 @@ class ReplayGainPlugin(BeetsPlugin):
|
||||||
"overwrite": False,
|
"overwrite": False,
|
||||||
"auto": True,
|
"auto": True,
|
||||||
"backend": "command",
|
"backend": "command",
|
||||||
"threads": cpu_count(),
|
"threads": os.cpu_count(),
|
||||||
"parallel_on_import": False,
|
"parallel_on_import": False,
|
||||||
"per_disc": False,
|
"per_disc": False,
|
||||||
"peak": "true",
|
"peak": "true",
|
||||||
|
|
|
||||||
|
|
@ -222,7 +222,7 @@ class PathlibURI(URIGetter):
|
||||||
name = "Python Pathlib"
|
name = "Python Pathlib"
|
||||||
|
|
||||||
def uri(self, path):
|
def uri(self, path):
|
||||||
return PurePosixPath(util.py3_path(path)).as_uri()
|
return PurePosixPath(os.fsdecode(path)).as_uri()
|
||||||
|
|
||||||
|
|
||||||
def copy_c_string(c_string):
|
def copy_c_string(c_string):
|
||||||
|
|
|
||||||
|
|
@ -312,7 +312,7 @@ def item_file(item_id):
|
||||||
if os.name == "nt":
|
if os.name == "nt":
|
||||||
item_path = util.syspath(item.path)
|
item_path = util.syspath(item.path)
|
||||||
else:
|
else:
|
||||||
item_path = util.py3_path(item.path)
|
item_path = os.fsdecode(item.path)
|
||||||
|
|
||||||
base_filename = os.path.basename(item_path)
|
base_filename = os.path.basename(item_path)
|
||||||
# FIXME: Arguably, this should just use `displayable_path`: The latter
|
# FIXME: Arguably, this should just use `displayable_path`: The latter
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ import confuse
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
from beets.test.helper import TestHelper
|
from beets.test.helper import TestHelper
|
||||||
from beets.util import bluelet, py3_path
|
from beets.util import bluelet
|
||||||
from beetsplug import bpd
|
from beetsplug import bpd
|
||||||
|
|
||||||
gstplayer = importlib.util.module_from_spec(
|
gstplayer = importlib.util.module_from_spec(
|
||||||
|
|
@ -313,7 +313,7 @@ class BPDTestHelper(unittest.TestCase, TestHelper):
|
||||||
"""
|
"""
|
||||||
# Create a config file:
|
# Create a config file:
|
||||||
config = {
|
config = {
|
||||||
"pluginpath": [py3_path(self.temp_dir)],
|
"pluginpath": [os.fsdecode(self.temp_dir)],
|
||||||
"plugins": "bpd",
|
"plugins": "bpd",
|
||||||
# use port 0 to let the OS choose a free port
|
# use port 0 to let the OS choose a free port
|
||||||
"bpd": {"host": host, "port": 0, "control_port": 0},
|
"bpd": {"host": host, "port": 0, "control_port": 0},
|
||||||
|
|
@ -321,7 +321,10 @@ class BPDTestHelper(unittest.TestCase, TestHelper):
|
||||||
if password:
|
if password:
|
||||||
config["bpd"]["password"] = password
|
config["bpd"]["password"] = password
|
||||||
config_file = tempfile.NamedTemporaryFile(
|
config_file = tempfile.NamedTemporaryFile(
|
||||||
mode="wb", dir=py3_path(self.temp_dir), suffix=".yaml", delete=False
|
mode="wb",
|
||||||
|
dir=os.fsdecode(self.temp_dir),
|
||||||
|
suffix=".yaml",
|
||||||
|
delete=False,
|
||||||
)
|
)
|
||||||
config_file.write(
|
config_file.write(
|
||||||
yaml.dump(config, Dumper=confuse.Dumper, encoding="utf-8")
|
yaml.dump(config, Dumper=confuse.Dumper, encoding="utf-8")
|
||||||
|
|
@ -337,9 +340,9 @@ class BPDTestHelper(unittest.TestCase, TestHelper):
|
||||||
"--library",
|
"--library",
|
||||||
self.config["library"].as_filename(),
|
self.config["library"].as_filename(),
|
||||||
"--directory",
|
"--directory",
|
||||||
py3_path(self.libdir),
|
os.fsdecode(self.libdir),
|
||||||
"--config",
|
"--config",
|
||||||
py3_path(config_file.name),
|
os.fsdecode(config_file.name),
|
||||||
"bpd",
|
"bpd",
|
||||||
],
|
],
|
||||||
assigned_port,
|
assigned_port,
|
||||||
|
|
@ -399,7 +402,11 @@ class BPDTestHelper(unittest.TestCase, TestHelper):
|
||||||
"""Add the given item to the BPD playlist or queue."""
|
"""Add the given item to the BPD playlist or queue."""
|
||||||
paths = [
|
paths = [
|
||||||
"/".join(
|
"/".join(
|
||||||
[item.artist, item.album, py3_path(os.path.basename(item.path))]
|
[
|
||||||
|
item.artist,
|
||||||
|
item.album,
|
||||||
|
os.fsdecode(os.path.basename(item.path)),
|
||||||
|
]
|
||||||
)
|
)
|
||||||
for item in items
|
for item in items
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
|
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
from os import path, remove
|
from os import fsdecode, path, remove
|
||||||
from shutil import rmtree
|
from shutil import rmtree
|
||||||
from tempfile import mkdtemp
|
from tempfile import mkdtemp
|
||||||
from unittest.mock import MagicMock, Mock, PropertyMock
|
from unittest.mock import MagicMock, Mock, PropertyMock
|
||||||
|
|
@ -26,7 +26,7 @@ from beets.library import Album, Item, parse_query_string
|
||||||
from beets.test import _common
|
from beets.test import _common
|
||||||
from beets.test.helper import TestHelper
|
from beets.test.helper import TestHelper
|
||||||
from beets.ui import UserError
|
from beets.ui import UserError
|
||||||
from beets.util import CHAR_REPLACE, bytestring_path, py3_path, syspath
|
from beets.util import CHAR_REPLACE, bytestring_path, syspath
|
||||||
from beetsplug.smartplaylist import SmartPlaylistPlugin
|
from beetsplug.smartplaylist import SmartPlaylistPlugin
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -173,7 +173,7 @@ class SmartPlaylistTest(_common.TestCase):
|
||||||
|
|
||||||
dir = bytestring_path(mkdtemp())
|
dir = bytestring_path(mkdtemp())
|
||||||
config["smartplaylist"]["relative_to"] = False
|
config["smartplaylist"]["relative_to"] = False
|
||||||
config["smartplaylist"]["playlist_dir"] = py3_path(dir)
|
config["smartplaylist"]["playlist_dir"] = fsdecode(dir)
|
||||||
try:
|
try:
|
||||||
spl.update_playlists(lib)
|
spl.update_playlists(lib)
|
||||||
except Exception:
|
except Exception:
|
||||||
|
|
@ -218,7 +218,7 @@ class SmartPlaylistTest(_common.TestCase):
|
||||||
config["smartplaylist"]["output"] = "extm3u"
|
config["smartplaylist"]["output"] = "extm3u"
|
||||||
config["smartplaylist"]["prefix"] = "http://beets:8337/files"
|
config["smartplaylist"]["prefix"] = "http://beets:8337/files"
|
||||||
config["smartplaylist"]["relative_to"] = False
|
config["smartplaylist"]["relative_to"] = False
|
||||||
config["smartplaylist"]["playlist_dir"] = py3_path(dir)
|
config["smartplaylist"]["playlist_dir"] = fsdecode(dir)
|
||||||
try:
|
try:
|
||||||
spl.update_playlists(lib)
|
spl.update_playlists(lib)
|
||||||
except Exception:
|
except Exception:
|
||||||
|
|
@ -269,7 +269,7 @@ class SmartPlaylistTest(_common.TestCase):
|
||||||
dir = bytestring_path(mkdtemp())
|
dir = bytestring_path(mkdtemp())
|
||||||
config["smartplaylist"]["output"] = "extm3u"
|
config["smartplaylist"]["output"] = "extm3u"
|
||||||
config["smartplaylist"]["relative_to"] = False
|
config["smartplaylist"]["relative_to"] = False
|
||||||
config["smartplaylist"]["playlist_dir"] = py3_path(dir)
|
config["smartplaylist"]["playlist_dir"] = fsdecode(dir)
|
||||||
config["smartplaylist"]["fields"] = ["id", "genre"]
|
config["smartplaylist"]["fields"] = ["id", "genre"]
|
||||||
try:
|
try:
|
||||||
spl.update_playlists(lib)
|
spl.update_playlists(lib)
|
||||||
|
|
@ -316,7 +316,7 @@ class SmartPlaylistTest(_common.TestCase):
|
||||||
dir = bytestring_path(mkdtemp())
|
dir = bytestring_path(mkdtemp())
|
||||||
tpl = "http://beets:8337/item/$id/file"
|
tpl = "http://beets:8337/item/$id/file"
|
||||||
config["smartplaylist"]["uri_format"] = tpl
|
config["smartplaylist"]["uri_format"] = tpl
|
||||||
config["smartplaylist"]["playlist_dir"] = py3_path(dir)
|
config["smartplaylist"]["playlist_dir"] = fsdecode(dir)
|
||||||
# The following options should be ignored when uri_format is set
|
# The following options should be ignored when uri_format is set
|
||||||
config["smartplaylist"]["relative_to"] = "/data"
|
config["smartplaylist"]["relative_to"] = "/data"
|
||||||
config["smartplaylist"]["prefix"] = "/prefix"
|
config["smartplaylist"]["prefix"] = "/prefix"
|
||||||
|
|
@ -350,7 +350,7 @@ class SmartPlaylistCLITest(_common.TestCase, TestHelper):
|
||||||
{"name": "all.m3u", "query": ""},
|
{"name": "all.m3u", "query": ""},
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
config["smartplaylist"]["playlist_dir"].set(py3_path(self.temp_dir))
|
config["smartplaylist"]["playlist_dir"].set(fsdecode(self.temp_dir))
|
||||||
self.load_plugins("smartplaylist")
|
self.load_plugins("smartplaylist")
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ from beets.test.helper import (
|
||||||
capture_log,
|
capture_log,
|
||||||
has_program,
|
has_program,
|
||||||
)
|
)
|
||||||
from beets.util import bytestring_path, displayable_path, py3_path, syspath
|
from beets.util import bytestring_path, displayable_path, syspath
|
||||||
|
|
||||||
|
|
||||||
class ScrubbedImportTest(_common.TestCase, ImportHelper):
|
class ScrubbedImportTest(_common.TestCase, ImportHelper):
|
||||||
|
|
@ -261,10 +261,10 @@ class NonAutotaggedImportTest(_common.TestCase, ImportHelper):
|
||||||
|
|
||||||
|
|
||||||
def create_archive(session):
|
def create_archive(session):
|
||||||
(handle, path) = mkstemp(dir=py3_path(session.temp_dir))
|
(handle, path) = mkstemp(dir=os.fsdecode(session.temp_dir))
|
||||||
path = bytestring_path(path)
|
path = bytestring_path(path)
|
||||||
os.close(handle)
|
os.close(handle)
|
||||||
archive = ZipFile(py3_path(path), mode="w")
|
archive = ZipFile(os.fsdecode(path), mode="w")
|
||||||
archive.write(syspath(os.path.join(_common.RSRC, b"full.mp3")), "full.mp3")
|
archive.write(syspath(os.path.join(_common.RSRC, b"full.mp3")), "full.mp3")
|
||||||
archive.close()
|
archive.close()
|
||||||
path = bytestring_path(path)
|
path = bytestring_path(path)
|
||||||
|
|
@ -319,7 +319,7 @@ class ImportTarTest(ImportZipTest):
|
||||||
(handle, path) = mkstemp(dir=syspath(self.temp_dir))
|
(handle, path) = mkstemp(dir=syspath(self.temp_dir))
|
||||||
path = bytestring_path(path)
|
path = bytestring_path(path)
|
||||||
os.close(handle)
|
os.close(handle)
|
||||||
archive = TarFile(py3_path(path), mode="w")
|
archive = TarFile(os.fsdecode(path), mode="w")
|
||||||
archive.add(
|
archive.add(
|
||||||
syspath(os.path.join(_common.RSRC, b"full.mp3")), "full.mp3"
|
syspath(os.path.join(_common.RSRC, b"full.mp3")), "full.mp3"
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,6 @@ from datetime import datetime
|
||||||
from beets.library import Item
|
from beets.library import Item
|
||||||
from beets.test import _common
|
from beets.test import _common
|
||||||
from beets.test.helper import TestHelper
|
from beets.test.helper import TestHelper
|
||||||
from beets.util import py3_path
|
|
||||||
|
|
||||||
|
|
||||||
def _parsetime(s):
|
def _parsetime(s):
|
||||||
|
|
@ -46,11 +45,11 @@ class MetaSyncTest(_common.TestCase, TestHelper):
|
||||||
self.config["metasync"]["source"] = "itunes"
|
self.config["metasync"]["source"] = "itunes"
|
||||||
|
|
||||||
if _is_windows():
|
if _is_windows():
|
||||||
self.config["metasync"]["itunes"]["library"] = py3_path(
|
self.config["metasync"]["itunes"]["library"] = os.fsdecode(
|
||||||
self.itunes_library_windows
|
self.itunes_library_windows
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
self.config["metasync"]["itunes"]["library"] = py3_path(
|
self.config["metasync"]["itunes"]["library"] = os.fsdecode(
|
||||||
self.itunes_library_unix
|
self.itunes_library_unix
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -852,11 +852,11 @@ class ConfigTest(unittest.TestCase, TestHelper, _common.Assertions):
|
||||||
# directory there. Some tests will set `BEETSDIR` themselves.
|
# directory there. Some tests will set `BEETSDIR` themselves.
|
||||||
del os.environ["BEETSDIR"]
|
del os.environ["BEETSDIR"]
|
||||||
self._old_home = os.environ.get("HOME")
|
self._old_home = os.environ.get("HOME")
|
||||||
os.environ["HOME"] = util.py3_path(self.temp_dir)
|
os.environ["HOME"] = os.fsdecode(self.temp_dir)
|
||||||
|
|
||||||
# Also set APPDATA, the Windows equivalent of setting $HOME.
|
# Also set APPDATA, the Windows equivalent of setting $HOME.
|
||||||
self._old_appdata = os.environ.get("APPDATA")
|
self._old_appdata = os.environ.get("APPDATA")
|
||||||
os.environ["APPDATA"] = util.py3_path(
|
os.environ["APPDATA"] = os.fsdecode(
|
||||||
os.path.join(self.temp_dir, b"AppData", b"Roaming")
|
os.path.join(self.temp_dir, b"AppData", b"Roaming")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -992,7 +992,7 @@ class ConfigTest(unittest.TestCase, TestHelper, _common.Assertions):
|
||||||
self.assertEqual(config["anoption"].get(), "cli overwrite")
|
self.assertEqual(config["anoption"].get(), "cli overwrite")
|
||||||
|
|
||||||
def test_cli_config_file_overwrites_beetsdir_defaults(self):
|
def test_cli_config_file_overwrites_beetsdir_defaults(self):
|
||||||
os.environ["BEETSDIR"] = util.py3_path(self.beetsdir)
|
os.environ["BEETSDIR"] = os.fsdecode(self.beetsdir)
|
||||||
env_config_path = os.path.join(self.beetsdir, b"config.yaml")
|
env_config_path = os.path.join(self.beetsdir, b"config.yaml")
|
||||||
with open(env_config_path, "w") as file:
|
with open(env_config_path, "w") as file:
|
||||||
file.write("anoption: value")
|
file.write("anoption: value")
|
||||||
|
|
@ -1054,7 +1054,7 @@ class ConfigTest(unittest.TestCase, TestHelper, _common.Assertions):
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_cli_config_paths_resolve_relative_to_beetsdir(self):
|
def test_cli_config_paths_resolve_relative_to_beetsdir(self):
|
||||||
os.environ["BEETSDIR"] = util.py3_path(self.beetsdir)
|
os.environ["BEETSDIR"] = os.fsdecode(self.beetsdir)
|
||||||
|
|
||||||
cli_config_path = os.path.join(self.temp_dir, b"config.yaml")
|
cli_config_path = os.path.join(self.temp_dir, b"config.yaml")
|
||||||
with open(cli_config_path, "w") as file:
|
with open(cli_config_path, "w") as file:
|
||||||
|
|
@ -1089,7 +1089,7 @@ class ConfigTest(unittest.TestCase, TestHelper, _common.Assertions):
|
||||||
self.assertTrue(plugins.find_plugins()[0].is_test_plugin)
|
self.assertTrue(plugins.find_plugins()[0].is_test_plugin)
|
||||||
|
|
||||||
def test_beetsdir_config(self):
|
def test_beetsdir_config(self):
|
||||||
os.environ["BEETSDIR"] = util.py3_path(self.beetsdir)
|
os.environ["BEETSDIR"] = os.fsdecode(self.beetsdir)
|
||||||
|
|
||||||
env_config_path = os.path.join(self.beetsdir, b"config.yaml")
|
env_config_path = os.path.join(self.beetsdir, b"config.yaml")
|
||||||
with open(env_config_path, "w") as file:
|
with open(env_config_path, "w") as file:
|
||||||
|
|
@ -1101,11 +1101,11 @@ class ConfigTest(unittest.TestCase, TestHelper, _common.Assertions):
|
||||||
def test_beetsdir_points_to_file_error(self):
|
def test_beetsdir_points_to_file_error(self):
|
||||||
beetsdir = os.path.join(self.temp_dir, b"beetsfile")
|
beetsdir = os.path.join(self.temp_dir, b"beetsfile")
|
||||||
open(beetsdir, "a").close()
|
open(beetsdir, "a").close()
|
||||||
os.environ["BEETSDIR"] = util.py3_path(beetsdir)
|
os.environ["BEETSDIR"] = os.fsdecode(beetsdir)
|
||||||
self.assertRaises(ConfigError, self.run_command, "test")
|
self.assertRaises(ConfigError, self.run_command, "test")
|
||||||
|
|
||||||
def test_beetsdir_config_does_not_load_default_user_config(self):
|
def test_beetsdir_config_does_not_load_default_user_config(self):
|
||||||
os.environ["BEETSDIR"] = util.py3_path(self.beetsdir)
|
os.environ["BEETSDIR"] = os.fsdecode(self.beetsdir)
|
||||||
|
|
||||||
with open(self.user_config_path, "w") as file:
|
with open(self.user_config_path, "w") as file:
|
||||||
file.write("anoption: value")
|
file.write("anoption: value")
|
||||||
|
|
@ -1114,7 +1114,7 @@ class ConfigTest(unittest.TestCase, TestHelper, _common.Assertions):
|
||||||
self.assertFalse(config["anoption"].exists())
|
self.assertFalse(config["anoption"].exists())
|
||||||
|
|
||||||
def test_default_config_paths_resolve_relative_to_beetsdir(self):
|
def test_default_config_paths_resolve_relative_to_beetsdir(self):
|
||||||
os.environ["BEETSDIR"] = util.py3_path(self.beetsdir)
|
os.environ["BEETSDIR"] = os.fsdecode(self.beetsdir)
|
||||||
|
|
||||||
config.read()
|
config.read()
|
||||||
self.assert_equal_path(
|
self.assert_equal_path(
|
||||||
|
|
@ -1127,7 +1127,7 @@ class ConfigTest(unittest.TestCase, TestHelper, _common.Assertions):
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_beetsdir_config_paths_resolve_relative_to_beetsdir(self):
|
def test_beetsdir_config_paths_resolve_relative_to_beetsdir(self):
|
||||||
os.environ["BEETSDIR"] = util.py3_path(self.beetsdir)
|
os.environ["BEETSDIR"] = os.fsdecode(self.beetsdir)
|
||||||
|
|
||||||
env_config_path = os.path.join(self.beetsdir, b"config.yaml")
|
env_config_path = os.path.join(self.beetsdir, b"config.yaml")
|
||||||
with open(env_config_path, "w") as file:
|
with open(env_config_path, "w") as file:
|
||||||
|
|
|
||||||
|
|
@ -131,7 +131,7 @@ class InitTest(_common.LibTestCase):
|
||||||
|
|
||||||
class ParentalDirCreation(_common.TestCase):
|
class ParentalDirCreation(_common.TestCase):
|
||||||
def test_create_yes(self):
|
def test_create_yes(self):
|
||||||
non_exist_path = _common.util.py3_path(
|
non_exist_path = _common.os.fsdecode(
|
||||||
os.path.join(self.temp_dir, b"nonexist", str(random()).encode())
|
os.path.join(self.temp_dir, b"nonexist", str(random()).encode())
|
||||||
)
|
)
|
||||||
# Deepcopy instead of recovering because exceptions might
|
# Deepcopy instead of recovering because exceptions might
|
||||||
|
|
@ -143,10 +143,10 @@ class ParentalDirCreation(_common.TestCase):
|
||||||
lib._close()
|
lib._close()
|
||||||
|
|
||||||
def test_create_no(self):
|
def test_create_no(self):
|
||||||
non_exist_path_parent = _common.util.py3_path(
|
non_exist_path_parent = _common.os.fsdecode(
|
||||||
os.path.join(self.temp_dir, b"nonexist")
|
os.path.join(self.temp_dir, b"nonexist")
|
||||||
)
|
)
|
||||||
non_exist_path = _common.util.py3_path(
|
non_exist_path = _common.os.fsdecode(
|
||||||
os.path.join(non_exist_path_parent.encode(), str(random()).encode())
|
os.path.join(non_exist_path_parent.encode(), str(random()).encode())
|
||||||
)
|
)
|
||||||
test_config = deepcopy(config)
|
test_config = deepcopy(config)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue