Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update project tooling #62

Merged
merged 4 commits into from Feb 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
21 changes: 9 additions & 12 deletions .github/workflows/ci.yml
Expand Up @@ -12,22 +12,19 @@ jobs:
fail-fast: false
matrix:
include:
- 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
- name: "Test: Python 3.12"
python: "3.12"
tox: py312
coverage: true
- name: "Lint: check-manifest"
python: "3.11"
tox: check-manifest
- name: "Lint: flake8"
python: "3.11"
tox: flake8
- name: "Lint: ruff lint"
python: "3.12"
tox: ruff-lint
- name: "Lint: ruff format"
python: "3.12"
tox: ruff-format

name: ${{ matrix.name }}
runs-on: ubuntu-22.04
Expand Down
1 change: 0 additions & 1 deletion mopidy_mpd/__init__.py
@@ -1,7 +1,6 @@
import pathlib

import pkg_resources

from mopidy import config, ext

__version__ = pkg_resources.get_distribution("Mopidy-MPD").version
Expand Down
16 changes: 5 additions & 11 deletions mopidy_mpd/actor.py
@@ -1,9 +1,9 @@
import logging

import pykka

from mopidy import exceptions, listener, zeroconf
from mopidy.core import CoreListener

from mopidy_mpd import network, session, uri_mapper

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -54,18 +54,14 @@
timeout=config["mpd"]["connection_timeout"],
)
except OSError as exc:
raise exceptions.FrontendError(f"MPD server startup failed: {exc}")
raise exceptions.FrontendError(f"MPD server startup failed: {exc}") from exc

Check warning on line 57 in mopidy_mpd/actor.py

View check run for this annotation

Codecov / codecov/patch

mopidy_mpd/actor.py#L57

Added line #L57 was not covered by tests

logger.info(
f"MPD server running at {network.format_address(server.address)}"
)
logger.info(f"MPD server running at {network.format_address(server.address)}")

Check warning on line 59 in mopidy_mpd/actor.py

View check run for this annotation

Codecov / codecov/patch

mopidy_mpd/actor.py#L59

Added line #L59 was not covered by tests

return server

def on_start(self):
if self.zeroconf_name and not network.is_unix_socket(
self.server.server_socket
):
if self.zeroconf_name and not network.is_unix_socket(self.server.server_socket):

Check warning on line 64 in mopidy_mpd/actor.py

View check run for this annotation

Codecov / codecov/patch

mopidy_mpd/actor.py#L64

Added line #L64 was not covered by tests
self.zeroconf_service = zeroconf.Zeroconf(
name=self.zeroconf_name, stype="_mpd._tcp", port=self.port
)
Expand All @@ -83,9 +79,7 @@

def on_event(self, event, **kwargs):
if event not in _CORE_EVENTS_TO_IDLE_SUBSYSTEMS:
logger.warning(
"Got unexpected event: %s(%s)", event, ", ".join(kwargs)
)
logger.warning("Got unexpected event: %s(%s)", event, ", ".join(kwargs))

Check warning on line 82 in mopidy_mpd/actor.py

View check run for this annotation

Codecov / codecov/patch

mopidy_mpd/actor.py#L82

Added line #L82 was not covered by tests
else:
self.send_idle(_CORE_EVENTS_TO_IDLE_SUBSYSTEMS[event])

Expand Down
83 changes: 40 additions & 43 deletions mopidy_mpd/dispatcher.py
Expand Up @@ -49,9 +49,7 @@
# TODO: validate against mopidy_mpd/protocol/status.SUBSYSTEMS
self.context.events.add(subsystem)

subsystems = self.context.subscriptions.intersection(
self.context.events
)
subsystems = self.context.subscriptions.intersection(self.context.events)
if not subsystems:
return

Expand All @@ -67,10 +65,9 @@
if filter_chain:
next_filter = filter_chain.pop(0)
return next_filter(request, response, filter_chain)
else:
return response
return response

# Filter: catch MPD ACK errors
# --- Filter: catch MPD ACK errors

def _catch_mpd_ack_errors_filter(self, request, response, filter_chain):
try:
Expand All @@ -80,53 +77,55 @@
mpd_ack_error.index = self.command_list_index
return [mpd_ack_error.get_mpd_ack()]

# Filter: authenticate
# --- Filter: authenticate

def _authenticate_filter(self, request, response, filter_chain):
if self.authenticated:
return self._call_next_filter(request, response, filter_chain)
elif self.config["mpd"]["password"] is None:

if self.config["mpd"]["password"] is None:
self.authenticated = True
return self._call_next_filter(request, response, filter_chain)
else:
command_name = request.split(" ")[0]
command = protocol.commands.handlers.get(command_name)
if command and not command.auth_required:
return self._call_next_filter(request, response, filter_chain)
else:
raise exceptions.MpdPermissionError(command=command_name)

# Filter: command list
command_name = request.split(" ")[0]
command = protocol.commands.handlers.get(command_name)

if command and not command.auth_required:
return self._call_next_filter(request, response, filter_chain)

raise exceptions.MpdPermissionError(command=command_name)

# --- Filter: command list

def _command_list_filter(self, request, response, filter_chain):
if self._is_receiving_command_list(request):
self.command_list.append(request)
return []
else:
response = self._call_next_filter(request, response, filter_chain)
if self._is_receiving_command_list(
request
) or self._is_processing_command_list(request):
if response and response[-1] == "OK":
response = response[:-1]
return response

response = self._call_next_filter(request, response, filter_chain)
if (
(
self._is_receiving_command_list(request)
or self._is_processing_command_list(request)
)
and response
and response[-1] == "OK"
):
response = response[:-1]
return response

def _is_receiving_command_list(self, request):
return self.command_list_receiving and request != "command_list_end"

def _is_processing_command_list(self, request):
return (
self.command_list_index is not None
and request != "command_list_end"
)
return self.command_list_index is not None and request != "command_list_end"

# Filter: idle
# --- Filter: idle

def _idle_filter(self, request, response, filter_chain):
if self._is_currently_idle() and not self._noidle.match(request):
logger.debug(
"Client sent us %s, only %s is allowed while in "
"the idle state",
"Client sent us %s, only %s is allowed while in " "the idle state",
repr(request),
repr("noidle"),
)
Expand All @@ -140,13 +139,13 @@

if self._is_currently_idle():
return []
else:
return response

return response

def _is_currently_idle(self):
return bool(self.context.subscriptions)

# Filter: add OK
# --- Filter: add OK

def _add_ok_filter(self, request, response, filter_chain):
response = self._call_next_filter(request, response, filter_chain)
Expand All @@ -157,23 +156,23 @@
def _has_error(self, response):
return response and response[-1].startswith("ACK")

# Filter: call handler
# --- Filter: call handler

def _call_handler_filter(self, request, response, filter_chain):
try:
response = self._format_response(self._call_handler(request))
return self._call_next_filter(request, response, filter_chain)
except pykka.ActorDeadError as e:
except pykka.ActorDeadError as exc:
logger.warning("Tried to communicate with dead actor.")
raise exceptions.MpdSystemError(e)
raise exceptions.MpdSystemError(exc) from exc

Check warning on line 167 in mopidy_mpd/dispatcher.py

View check run for this annotation

Codecov / codecov/patch

mopidy_mpd/dispatcher.py#L167

Added line #L167 was not covered by tests

def _call_handler(self, request):
tokens = tokenize.split(request)
# TODO: check that blacklist items are valid commands?
blacklist = self.config["mpd"].get("command_blacklist", [])
if tokens and tokens[0] in blacklist:
logger.warning("MPD client used blacklisted command: %s", tokens[0])
raise exceptions.MpdDisabled(command=tokens[0])
raise exceptions.MpdDisabledError(command=tokens[0])
try:
return protocol.commands.call(tokens, context=self.context)
except exceptions.MpdAckError as exc:
Expand Down Expand Up @@ -241,9 +240,7 @@

_uri_map = None

def __init__(
self, dispatcher, session=None, config=None, core=None, uri_map=None
):
def __init__(self, dispatcher, session=None, config=None, core=None, uri_map=None): # noqa: PLR0913
self.dispatcher = dispatcher
self.session = session
if config is not None:
Expand All @@ -265,7 +262,7 @@
"""
return self._uri_map.playlist_name_from_uri(uri)

def browse(self, path, recursive=True, lookup=True):
def browse(self, path, *, recursive=True, lookup=True): # noqa: C901, PLR0912
"""
Browse the contents of a given directory path.

Expand All @@ -285,7 +282,7 @@
"""

path_parts = re.findall(r"[^/]+", path or "")
root_path = "/".join([""] + path_parts)
root_path = "/".join(["", *path_parts])

uri = self._uri_map.uri_from_name(root_path)
if uri is None:
Expand Down
18 changes: 8 additions & 10 deletions mopidy_mpd/exceptions.py
Expand Up @@ -59,15 +59,15 @@ class MpdUnknownError(MpdAckError):
error_code = MpdAckError.ACK_ERROR_UNKNOWN


class MpdUnknownCommand(MpdUnknownError):
class MpdUnknownCommandError(MpdUnknownError):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
assert self.command is not None, "command must be given explicitly"
self.message = f'unknown command "{self.command}"'
self.command = ""


class MpdNoCommand(MpdUnknownCommand):
class MpdNoCommandError(MpdUnknownCommandError):
def __init__(self, *args, **kwargs):
kwargs["command"] = ""
super().__init__(*args, **kwargs)
Expand All @@ -86,7 +86,7 @@ class MpdSystemError(MpdAckError):
error_code = MpdAckError.ACK_ERROR_SYSTEM


class MpdInvalidPlaylistName(MpdAckError):
class MpdInvalidPlaylistNameError(MpdAckError):
error_code = MpdAckError.ACK_ERROR_ARG

def __init__(self, *args, **kwargs):
Expand All @@ -97,15 +97,15 @@ def __init__(self, *args, **kwargs):
)


class MpdNotImplemented(MpdAckError):
class MpdNotImplementedError(MpdAckError):
error_code = 0

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.message = "Not implemented"


class MpdInvalidTrackForPlaylist(MpdAckError):
class MpdInvalidTrackForPlaylistError(MpdAckError):
# NOTE: This is a custom error for Mopidy that does not exist in MPD.
error_code = 0

Expand All @@ -117,18 +117,16 @@ def __init__(self, playlist_scheme, track_scheme, *args, **kwargs):
)


class MpdFailedToSavePlaylist(MpdAckError):
class MpdFailedToSavePlaylistError(MpdAckError):
# NOTE: This is a custom error for Mopidy that does not exist in MPD.
error_code = 0

def __init__(self, backend_scheme, *args, **kwargs):
super().__init__(*args, **kwargs)
self.message = (
f'Backend with scheme "{backend_scheme}" failed to save playlist'
)
self.message = f'Backend with scheme "{backend_scheme}" failed to save playlist'


class MpdDisabled(MpdAckError):
class MpdDisabledError(MpdAckError):
# NOTE: This is a custom error for Mopidy that does not exist in MPD.
error_code = 0

Expand Down
2 changes: 1 addition & 1 deletion mopidy_mpd/formatting.py
@@ -1,4 +1,4 @@
def indent(string, places=4, linebreak="\n", singles=False):
def indent(string, *, places=4, linebreak="\n", singles=False):
lines = string.split(linebreak)
if not singles and len(lines) == 1:
return string
Expand Down