mirror of
https://github.com/beetbox/beets.git
synced 2025-12-06 08:39:17 +01:00
Add NullPathType and types to PathType
This commit is contained in:
parent
1a045c9166
commit
b40ce836d5
5 changed files with 73 additions and 68 deletions
|
|
@ -49,3 +49,5 @@ f36bc497c8c8f89004f3f6879908d3f0b25123e1
|
||||||
c490ac5810b70f3cf5fd8649669838e8fdb19f4d
|
c490ac5810b70f3cf5fd8649669838e8fdb19f4d
|
||||||
# Importer restructure
|
# Importer restructure
|
||||||
9147577b2b19f43ca827e9650261a86fb0450cef
|
9147577b2b19f43ca827e9650261a86fb0450cef
|
||||||
|
# Copy paste query, types from library to dbcore
|
||||||
|
1a045c91668c771686f4c871c84f1680af2e944b
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,8 @@ else:
|
||||||
# To use the SQLite "blob" type, it doesn't suffice to provide a byte
|
# To use the SQLite "blob" type, it doesn't suffice to provide a byte
|
||||||
# string; SQLite treats that as encoded text. Wrapping it in a
|
# string; SQLite treats that as encoded text. Wrapping it in a
|
||||||
# `memoryview` tells it that we actually mean non-text data.
|
# `memoryview` tells it that we actually mean non-text data.
|
||||||
|
# needs to be defined in here due to circular import.
|
||||||
|
# TODO: remove it from this module and define it in dbcore/types.py instead
|
||||||
BLOB_TYPE = memoryview
|
BLOB_TYPE = memoryview
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ import typing
|
||||||
from abc import ABC
|
from abc import ABC
|
||||||
from typing import TYPE_CHECKING, Any, Generic, TypeVar, cast
|
from typing import TYPE_CHECKING, Any, Generic, TypeVar, cast
|
||||||
|
|
||||||
|
import beets
|
||||||
from beets import util
|
from beets import util
|
||||||
|
|
||||||
from . import query
|
from . import query
|
||||||
|
|
@ -345,7 +346,7 @@ class DateType(Float):
|
||||||
return self.null
|
return self.null
|
||||||
|
|
||||||
|
|
||||||
class PathType(Type[bytes, bytes]):
|
class BasePathType(Type[bytes, N]):
|
||||||
"""A dbcore type for filesystem paths.
|
"""A dbcore type for filesystem paths.
|
||||||
|
|
||||||
These are represented as `bytes` objects, in keeping with
|
These are represented as `bytes` objects, in keeping with
|
||||||
|
|
@ -356,27 +357,10 @@ class PathType(Type[bytes, bytes]):
|
||||||
query = query.PathQuery
|
query = query.PathQuery
|
||||||
model_type = bytes
|
model_type = bytes
|
||||||
|
|
||||||
def __init__(self, nullable=False):
|
def parse(self, string: str) -> bytes:
|
||||||
"""Create a path type object.
|
return util.normpath(string)
|
||||||
|
|
||||||
`nullable` controls whether the type may be missing, i.e., None.
|
def normalize(self, value: Any) -> bytes | N:
|
||||||
"""
|
|
||||||
self.nullable = nullable
|
|
||||||
|
|
||||||
@property
|
|
||||||
def null(self):
|
|
||||||
if self.nullable:
|
|
||||||
return None
|
|
||||||
else:
|
|
||||||
return b""
|
|
||||||
|
|
||||||
def format(self, value):
|
|
||||||
return util.displayable_path(value)
|
|
||||||
|
|
||||||
def parse(self, string):
|
|
||||||
return util.normpath(util.bytestring_path(string))
|
|
||||||
|
|
||||||
def normalize(self, value):
|
|
||||||
if isinstance(value, str):
|
if isinstance(value, str):
|
||||||
# Paths stored internally as encoded bytes.
|
# Paths stored internally as encoded bytes.
|
||||||
return util.bytestring_path(value)
|
return util.bytestring_path(value)
|
||||||
|
|
@ -391,12 +375,30 @@ class PathType(Type[bytes, bytes]):
|
||||||
def from_sql(self, sql_value):
|
def from_sql(self, sql_value):
|
||||||
return self.normalize(sql_value)
|
return self.normalize(sql_value)
|
||||||
|
|
||||||
def to_sql(self, value):
|
def to_sql(self, value: bytes) -> BLOB_TYPE:
|
||||||
if isinstance(value, bytes):
|
if isinstance(value, bytes):
|
||||||
value = BLOB_TYPE(value)
|
value = BLOB_TYPE(value)
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
|
class NullPathType(BasePathType[None]):
|
||||||
|
@property
|
||||||
|
def null(self) -> None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def format(self, value: bytes | None) -> str:
|
||||||
|
return util.displayable_path(value or b"")
|
||||||
|
|
||||||
|
|
||||||
|
class PathType(BasePathType[bytes]):
|
||||||
|
@property
|
||||||
|
def null(self) -> bytes:
|
||||||
|
return b""
|
||||||
|
|
||||||
|
def format(self, value: bytes) -> str:
|
||||||
|
return util.displayable_path(value or b"")
|
||||||
|
|
||||||
|
|
||||||
class MusicalKey(String):
|
class MusicalKey(String):
|
||||||
"""String representing the musical key of a song.
|
"""String representing the musical key of a song.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -910,7 +910,7 @@ class Album(LibModel):
|
||||||
_always_dirty = True
|
_always_dirty = True
|
||||||
_fields = {
|
_fields = {
|
||||||
"id": types.PRIMARY_ID,
|
"id": types.PRIMARY_ID,
|
||||||
"artpath": types.PathType(True),
|
"artpath": types.NullPathType(),
|
||||||
"added": types.DATE,
|
"added": types.DATE,
|
||||||
"albumartist": types.STRING,
|
"albumartist": types.STRING,
|
||||||
"albumartist_sort": types.STRING,
|
"albumartist_sort": types.STRING,
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,11 @@
|
||||||
import time
|
import time
|
||||||
import unittest
|
|
||||||
|
|
||||||
import beets
|
import beets
|
||||||
from beets.dbcore import types
|
from beets.dbcore import types
|
||||||
from beets.util import normpath
|
from beets.util import normpath
|
||||||
|
|
||||||
|
|
||||||
class LibraryFieldTypesTest(unittest.TestCase):
|
def test_datetype():
|
||||||
"""Test format() and parse() for library-specific field types"""
|
|
||||||
|
|
||||||
def test_datetype(self):
|
|
||||||
t = types.DATE
|
t = types.DATE
|
||||||
|
|
||||||
# format
|
# format
|
||||||
|
|
@ -22,7 +18,8 @@ class LibraryFieldTypesTest(unittest.TestCase):
|
||||||
assert t.null == t.parse("not123456789.0")
|
assert t.null == t.parse("not123456789.0")
|
||||||
assert t.null == t.parse("1973-11-29")
|
assert t.null == t.parse("1973-11-29")
|
||||||
|
|
||||||
def test_pathtype(self):
|
|
||||||
|
def test_pathtype():
|
||||||
t = types.PathType()
|
t = types.PathType()
|
||||||
|
|
||||||
# format
|
# format
|
||||||
|
|
@ -32,7 +29,8 @@ class LibraryFieldTypesTest(unittest.TestCase):
|
||||||
assert normpath(b"/tmp") == t.parse("/tmp")
|
assert normpath(b"/tmp") == t.parse("/tmp")
|
||||||
assert normpath(b"/tmp/\xc3\xa4lbum") == t.parse("/tmp/\u00e4lbum/")
|
assert normpath(b"/tmp/\xc3\xa4lbum") == t.parse("/tmp/\u00e4lbum/")
|
||||||
|
|
||||||
def test_musicalkey(self):
|
|
||||||
|
def test_musicalkey():
|
||||||
t = types.MusicalKey()
|
t = types.MusicalKey()
|
||||||
|
|
||||||
# parse
|
# parse
|
||||||
|
|
@ -40,7 +38,8 @@ class LibraryFieldTypesTest(unittest.TestCase):
|
||||||
assert "Gm" == t.parse("g minor")
|
assert "Gm" == t.parse("g minor")
|
||||||
assert "Not c#m" == t.parse("not C#m")
|
assert "Not c#m" == t.parse("not C#m")
|
||||||
|
|
||||||
def test_durationtype(self):
|
|
||||||
|
def test_durationtype():
|
||||||
t = types.DurationType()
|
t = types.DurationType()
|
||||||
|
|
||||||
# format
|
# format
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue