Skip to content

Commit

Permalink
Require Python 3.9+ and fix CI (#75)
Browse files Browse the repository at this point in the history
* Require Python 3.9+ and fix CI

* Formatting
  • Loading branch information
jodal authored Jun 21, 2023
1 parent 179bb05 commit 5906887
Show file tree
Hide file tree
Showing 15 changed files with 172 additions and 60 deletions.
41 changes: 20 additions & 21 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,52 +1,51 @@
name: CI

on: [push, pull_request]
on:
pull_request:
push:
branches:
- main

jobs:
main:
strategy:
fail-fast: false
matrix:
include:
- name: "Test: Python 3.7"
python: "3.7"
tox: py37
- name: "Test: Python 3.8"
python: "3.8"
tox: py38
- name: "Test: Python 3.9"
python: "3.9"
tox: py39
- name: "Test: Python 3.10"
python: "3.10"
tox: py310
- name: "Test: Python 3.11"
python: "3.11"
tox: py311
coverage: true
- name: "Lint: check-manifest"
python: "3.9"
python: "3.11"
tox: check-manifest
- name: "Lint: flake8"
python: "3.9"
python: "3.11"
tox: flake8

name: ${{ matrix.name }}
runs-on: ubuntu-20.04
runs-on: ubuntu-22.04
container: ghcr.io/mopidy/ci:latest

steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python }}
- uses: actions/checkout@v3
- name: Fix home dir permissions to enable pip caching
run: chown -R root /github/home
- name: Cache pip
uses: actions/cache@v2
- uses: actions/setup-python@v4
with:
path: ~/.cache/pip
key: ${{ runner.os }}-${{ matrix.python }}-${{ matrix.tox }}-pip-${{ hashFiles('setup.cfg') }}-${{ hashFiles('tox.ini') }}
restore-keys: |
${{ runner.os }}-${{ matrix.python }}-${{ matrix.tox }}-pip-
python-version: ${{ matrix.python }}
cache: pip
cache-dependency-path: setup.cfg
- run: python -m pip install pygobject tox
- run: python -m tox -e ${{ matrix.tox }}
if: ${{ ! matrix.coverage }}
- run: python -m tox -e ${{ matrix.tox }} -- --cov-report=xml
if: ${{ matrix.coverage }}
- uses: codecov/codecov-action@v1
- uses: codecov/codecov-action@v3
if: ${{ matrix.coverage }}
2 changes: 1 addition & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Mopidy-Local
:target: https://pypi.org/project/Mopidy-Local/
:alt: Latest PyPI version

.. image:: https://img.shields.io/github/workflow/status/mopidy/mopidy-local/CI
.. image:: https://img.shields.io/github/actions/workflow/status/mopidy/mopidy-local/ci.yml?branch=main
:target: https://github.com/mopidy/mopidy-local/actions
:alt: CI build status

Expand Down
8 changes: 6 additions & 2 deletions mopidy_local/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ def get_config_schema(self):
schema["data_dir"] = config.Deprecated()
schema["playlists_dir"] = config.Deprecated()
schema["tag_cache_file"] = config.Deprecated()
schema["scan_timeout"] = config.Integer(minimum=1000, maximum=1000 * 60 * 60)
schema["scan_timeout"] = config.Integer(
minimum=1000, maximum=1000 * 60 * 60
)
schema["scan_flush_threshold"] = config.Integer(minimum=0)
schema["scan_follow_symlinks"] = config.Boolean()
schema["included_file_extensions"] = config.List(optional=True)
Expand All @@ -38,7 +40,9 @@ def setup(self, registry):
from .actor import LocalBackend

registry.add("backend", LocalBackend)
registry.add("http:app", {"name": self.ext_name, "factory": self.webapp})
registry.add(
"http:app", {"name": self.ext_name, "factory": self.webapp}
)

def get_command(self):
from .commands import LocalCommand
Expand Down
35 changes: 28 additions & 7 deletions mopidy_local/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,9 @@ def run(self, args, config):

def _find_files(self, *, media_dir, follow_symlinks):
logger.info(f"Finding files in {media_dir.as_uri()} ...")
file_mtimes, file_errors = mtimes.find_mtimes(media_dir, follow=follow_symlinks)
file_mtimes, file_errors = mtimes.find_mtimes(
media_dir, follow=follow_symlinks
)
logger.info(f"Found {len(file_mtimes)} files in {media_dir.as_uri()}")

if file_errors:
Expand Down Expand Up @@ -169,7 +171,9 @@ def _extension_filters(
):
if included_file_exts:
if relative_path.suffix.lower() in included_file_exts:
logger.debug(f"Added {file_uri}: File extension on included list")
logger.debug(
f"Added {file_uri}: File extension on included list"
)
return True
else:
logger.debug(
Expand All @@ -178,7 +182,9 @@ def _extension_filters(
return False
else:
if relative_path.suffix.lower() in excluded_file_exts:
logger.debug(f"Skipped {file_uri}: File extension on excluded list")
logger.debug(
f"Skipped {file_uri}: File extension on excluded list"
)
return False
else:
logger.debug(
Expand All @@ -193,17 +199,30 @@ def _extension_filters(
if (
not _is_hidden_file(relative_path, file_uri)
and _extension_filters(
relative_path, file_uri, included_file_exts, excluded_file_exts
relative_path,
file_uri,
included_file_exts,
excluded_file_exts,
)
and absolute_path not in files_in_library
):
files_to_update.add(absolute_path)

logger.info(f"Found {len(files_to_update)} tracks which need to be updated")
logger.info(
f"Found {len(files_to_update)} tracks which need to be updated"
)
return files_to_update

def _scan_metadata(
self, *, media_dir, file_mtimes, files, library, timeout, flush_threshold, limit
self,
*,
media_dir,
file_mtimes,
files,
library,
timeout,
flush_threshold,
limit,
):
logger.info("Scanning...")

Expand Down Expand Up @@ -237,7 +256,9 @@ def _scan_metadata(
)
mtime = file_mtimes.get(absolute_path)
track = tags.convert_tags_to_track(result.tags).replace(
uri=local_uri, length=result.duration, last_modified=mtime
uri=local_uri,
length=result.duration,
last_modified=mtime,
)
library.add(track, result.tags, result.duration)
logger.debug(f"Added {track.uri}")
Expand Down
20 changes: 15 additions & 5 deletions mopidy_local/library.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@

def date_ref(date):
return Ref.directory(
uri=uritools.uricompose("local", None, "directory", {"date": date}), name=date
uri=uritools.uricompose("local", None, "directory", {"date": date}),
name=date,
)


Expand All @@ -27,7 +28,9 @@ def genre_ref(genre):
class LocalLibraryProvider(backend.LibraryProvider):
ROOT_DIRECTORY_URI = "local:directory"

root_directory = models.Ref.directory(uri=ROOT_DIRECTORY_URI, name="Local media")
root_directory = models.Ref.directory(
uri=ROOT_DIRECTORY_URI, name="Local media"
)

def __init__(self, backend, config):
super().__init__(backend)
Expand Down Expand Up @@ -152,9 +155,13 @@ def _browse_directory(self, uri, order=("type", "name COLLATE NOCASE")):
# TODO: handle these in schema (generically)?
if type == "date":
format = query.get("format", "%Y-%m-%d")
return list(map(date_ref, schema.dates(self._connect(), format=format)))
return list(
map(date_ref, schema.dates(self._connect(), format=format))
)
if type == "genre":
return list(map(genre_ref, schema.list_distinct(self._connect(), "genre")))
return list(
map(genre_ref, schema.list_distinct(self._connect(), "genre"))
)

# Fix #38: keep sort order of album tracks; this also applies
# to composers and performers
Expand Down Expand Up @@ -186,7 +193,10 @@ def _browse_directory(self, uri, order=("type", "name COLLATE NOCASE")):
refs.append(
Ref.directory(
uri=uritools.uricompose(
"local", None, "directory", dict(query, **{role: ref.uri})
"local",
None,
"directory",
dict(query, **{role: ref.uri}),
),
name=ref.name,
)
Expand Down
5 changes: 4 additions & 1 deletion mopidy_local/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,10 @@ def exists(c, uri):

def browse(c, type=None, order=("type", "name COLLATE NOCASE"), **kwargs):
filters, params = _filters(_BROWSE_FILTERS[type], **kwargs)
sql = _BROWSE_QUERIES[type] % (" AND ".join(filters) or "1", ", ".join(order))
sql = _BROWSE_QUERIES[type] % (
" AND ".join(filters) or "1",
", ".join(order),
)
logger.debug("SQLite browse query %r: %s", params, sql)
return [Ref(**row) for row in c.execute(sql, params)]

Expand Down
8 changes: 6 additions & 2 deletions mopidy_local/storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,9 @@ def _validate_album(self, model):
raise ValueError("Empty album name")
if not model.uri:
model = model.replace(uri=model_uri("album", model))
return model.replace(artists=list(map(self._validate_artist, model.artists)))
return model.replace(
artists=list(map(self._validate_artist, model.artists))
)

def _validate_track(self, model):
if not model.uri:
Expand Down Expand Up @@ -237,6 +239,8 @@ def _get_or_create_image_file(self, path, data=None):
name = f"{digest}.{what}"
image_path = self._image_dir / name
if not image_path.is_file():
logger.info(f"Creating file {image_path.as_uri()} from {data_source}")
logger.info(
f"Creating file {image_path.as_uri()} from {data_source}"
)
image_path.write_bytes(data)
return uritools.urijoin(self._base_uri, name)
4 changes: 3 additions & 1 deletion mopidy_local/translator.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ def path_to_file_uri(path: Union[str, bytes, Path]) -> str:
return ppath.as_uri()


def path_to_local_track_uri(path: Union[str, bytes, Path], media_dir: Path) -> str:
def path_to_local_track_uri(
path: Union[str, bytes, Path], media_dir: Path
) -> str:
"""Convert path to local track URI."""
ppath = Path(os.fsdecode(path))
if ppath.is_absolute():
Expand Down
17 changes: 17 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[build-system]
requires = ["setuptools >= 30.3.0", "wheel"]


[tool.black]
target-version = ["py39", "py310", "py311"]
line-length = 80


[tool.isort]
multi_line_output = 3
include_trailing_comma = true
force_grid_wrap = 0
use_parentheses = true
line_length = 88
known_tests = "tests"
sections = "FUTURE,STDLIB,THIRDPARTY,FIRSTPARTY,TESTS,LOCALFOLDER"
6 changes: 3 additions & 3 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,17 @@ classifiers =
License :: OSI Approved :: Apache Software License
Operating System :: OS Independent
Programming Language :: Python :: 3
Programming Language :: Python :: 3.7
Programming Language :: Python :: 3.8
Programming Language :: Python :: 3.9
Programming Language :: Python :: 3.10
Programming Language :: Python :: 3.11
Topic :: Multimedia :: Sound/Audio :: Players


[options]
zip_safe = False
include_package_data = True
packages = find:
python_requires = >= 3.7
python_requires = >= 3.9
install_requires =
Mopidy >= 3.0.0
Pykka >= 2.0.1
Expand Down
9 changes: 7 additions & 2 deletions tests/test_library.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@

class LocalLibraryProviderTest(unittest.TestCase):
config = {
"core": {"data_dir": path_to_data_dir(""), "max_tracklist_length": 10000},
"core": {
"data_dir": path_to_data_dir(""),
"max_tracklist_length": 10000,
},
"local": {
"media_dir": path_to_data_dir(""),
"directories": [],
Expand Down Expand Up @@ -45,7 +48,9 @@ def tearDown(self): # noqa: N802

def test_add_noname_ascii(self):
name = "Test.mp3"
uri = translator.path_to_local_track_uri(name, pathlib.Path("/media/dir"))
uri = translator.path_to_local_track_uri(
name, pathlib.Path("/media/dir")
)
track = Track(name=name, uri=uri)
self.storage.begin()
self.storage.add(track)
Expand Down
16 changes: 13 additions & 3 deletions tests/test_playback.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,22 @@

from mopidy_local import actor
from unittest import mock
from tests import dummy_audio, generate_song, path_to_data_dir, populate_tracklist
from tests import (
dummy_audio,
generate_song,
path_to_data_dir,
populate_tracklist,
)

# TODO Test 'playlist repeat', e.g. repeat=1,single=0


class LocalPlaybackProviderTest(unittest.TestCase):
config = {
"core": {"data_dir": path_to_data_dir(""), "max_tracklist_length": 10000},
"core": {
"data_dir": path_to_data_dir(""),
"max_tracklist_length": 10000,
},
"local": {
"media_dir": path_to_data_dir(""),
"directories": [],
Expand Down Expand Up @@ -552,7 +560,9 @@ def test_end_of_track_with_random(self, shuffle_mock):

@populate_tracklist
@mock.patch("random.shuffle")
def test_end_of_track_track_with_random_after_append_playlist(self, shuffle_mock):
def test_end_of_track_track_with_random_after_append_playlist(
self, shuffle_mock
):
shuffle_mock.side_effect = lambda tracks: tracks.reverse()

self.tracklist.set_random(True)
Expand Down
Loading

0 comments on commit 5906887

Please sign in to comment.