Skip to content

Commit

Permalink
Merge pull request #62 from jodal/tooling
Browse files Browse the repository at this point in the history
Update project tooling
  • Loading branch information
jodal authored Feb 23, 2024
2 parents 5306c46 + 5b30983 commit 7530f42
Show file tree
Hide file tree
Showing 56 changed files with 672 additions and 896 deletions.
21 changes: 9 additions & 12 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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 @@ def _setup_server(self, config, core):
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

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

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):
self.zeroconf_service = zeroconf.Zeroconf(
name=self.zeroconf_name, stype="_mpd._tcp", port=self.port
)
Expand All @@ -83,9 +79,7 @@ def on_stop(self):

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))
else:
self.send_idle(_CORE_EVENTS_TO_IDLE_SUBSYSTEMS[event])

Expand Down
83 changes: 40 additions & 43 deletions mopidy_mpd/dispatcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,7 @@ def handle_idle(self, subsystem):
# 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 @@ def _call_next_filter(self, request, response, filter_chain):
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 @@ def _catch_mpd_ack_errors_filter(self, request, response, filter_chain):
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 @@ def _idle_filter(self, request, response, filter_chain):

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 _add_ok_filter(self, request, response, filter_chain):
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

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 @@ class MpdContext:

_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 @@ def lookup_playlist_name_from_uri(self, uri):
"""
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 @@ def browse(self, path, recursive=True, lookup=True):
"""

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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
@@ -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
Loading

0 comments on commit 7530f42

Please sign in to comment.