Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ jobs:
- name: Set up Python 3.11
uses: actions/setup-python@v4
with:
python-version: 3.11
python-version: "3.11"

- name: Install dependencies
run: |
Expand All @@ -42,7 +42,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"]
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]

steps:
- uses: actions/checkout@v3
Expand Down Expand Up @@ -110,10 +110,10 @@ jobs:
with:
fetch-depth: 0

- name: Set up Python 3.9
- name: Set up Python 3.10
uses: actions/setup-python@v4
with:
python-version: 3.9
python-version: "3.10"

- name: Install dependencies
run: |
Expand Down
2 changes: 1 addition & 1 deletion alsa_midi/address.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ def __new__(cls, arg1: 'SequencerClient', arg2: int = 0) -> 'Address':
...

def __new__(cls,
arg1: Union[int, str, AddressType, 'SequencerClient'],
arg1: int | str | AddressType | 'SequencerClient',
arg2: int = 0) -> 'Address':
if isinstance(arg1, str):
tple: Any = cls._parse(arg1)
Expand Down
136 changes: 69 additions & 67 deletions alsa_midi/client.py

Large diffs are not rendered by default.

52 changes: 27 additions & 25 deletions alsa_midi/event.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
from __future__ import annotations

from collections.abc import Iterable
from enum import IntEnum, IntFlag
from functools import total_ordering
from typing import TYPE_CHECKING, Any, NewType, Optional, Union
from typing import TYPE_CHECKING, Any, NewType

from ._ffi import alsa, ffi
from .address import Address, AddressType
Expand Down Expand Up @@ -30,7 +32,7 @@ class RealTime:
seconds: int
nanoseconds: int

def __init__(self, seconds: Union[float, int, str, 'RealTime'] = 0, nanoseconds: int = 0):
def __init__(self, seconds: float | int | str | 'RealTime' = 0, nanoseconds: int = 0):
if isinstance(seconds, RealTime):
self.seconds = seconds.seconds
self.nanoseconds = seconds.nanoseconds + nanoseconds
Expand Down Expand Up @@ -229,28 +231,28 @@ class Event:
_specialized = {}
type = None

flags: Optional[EventFlags]
flags: EventFlags | None
tag: int
queue_id: Optional[int]
time: Optional[RealTime]
tick: Optional[int]
source: Optional[Address]
dest: Optional[Address]
relative: Optional[bool]
raw_data: Optional[bytes]
queue_id: int | None
time: RealTime | None
tick: int | None
source: Address | None
dest: Address | None
relative: bool | None
raw_data: bytes | None

def __init__(self,
type: Optional[EventType] = None,
type: EventType | None = None,
*,
flags: Optional[Union[EventFlags, int]] = 0,
flags: EventFlags | int = 0,
tag: int = 0,
queue_id: Optional[int] = None,
time: Optional[Union[RealTime, float, int]] = None,
tick: Optional[int] = None,
source: Optional[AddressType] = None,
dest: Optional[AddressType] = None,
relative: Optional[bool] = None,
raw_data: bytes = None,
queue_id: int | None = None,
time: RealTime | float | int | None = None,
tick: int | None = None,
source: AddressType | None = None,
dest: AddressType | None = None,
relative: bool | None = None,
raw_data: bytes | None = None,
):

if type is None and self.__class__.type is not None:
Expand Down Expand Up @@ -323,8 +325,8 @@ def _from_alsa(cls, a_event: _snd_seq_event_t, **kwargs):
**kwargs)

def _to_alsa(self, a_event: _snd_seq_event_t, *,
queue: Union['Queue', int] = None,
port: Union['Port', int] = None,
queue: 'Queue' | int = None,
port: 'Port' | int = None,
dest: AddressType = None
) -> _snd_seq_event_t:
if self.type is not None:
Expand Down Expand Up @@ -404,7 +406,7 @@ class MidiBytesEvent(Event):
midi_bytes: bytes

def __init__(self,
midi_bytes: Union[bytes, Iterable[int]],
midi_bytes: bytes | Iterable[int],
**kwargs):
super().__init__(**kwargs)
self.midi_bytes = bytes(midi_bytes)
Expand Down Expand Up @@ -603,10 +605,10 @@ class QueueControlEventBase(Event):

:ivar control_queue: affected queue id
"""
control_queue: Optional[int]
control_queue: int | None

def __init__(self,
control_queue: Optional[Union[int, 'Queue']] = None,
control_queue: int | 'Queue' | None = None,
**kwargs):
assert self.type is not None
super().__init__(self.type, **kwargs)
Expand Down Expand Up @@ -945,7 +947,7 @@ class SetQueuePositionTimeEvent(QueueControlEventBase):
position: RealTime

def __init__(self,
position: Union[RealTime, int, float],
position: RealTime | int | float,
*args, **kwargs):
super().__init__(*args, **kwargs)
self.position = RealTime(position)
Expand Down
12 changes: 7 additions & 5 deletions alsa_midi/mido_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@
.. _MIDO: https://mido.readthedocs.io/
"""

from __future__ import annotations

import logging
import queue
import sys
import threading
from collections.abc import MutableMapping
from typing import Any, Callable, Optional
from typing import Any, Callable
from weakref import WeakValueDictionary

from mido.messages import Message
Expand All @@ -27,7 +29,7 @@


class _Client:
instance: Optional['_Client'] = None
instance: '_Client' | None = None

client: alsa_midi.SequencerClient
in_thread: threading.Thread
Expand Down Expand Up @@ -142,10 +144,10 @@ class PortCommon:

_parser: Parser
_virtual: bool = False
_callback: Optional[Callable[[Message], Any]] = None
_callback: Callable[[Message], Any] | None = None

_port: Optional[alsa_midi.Port] = None
_dest_port: Optional[alsa_midi.PortInfo] = None
_port: alsa_midi.Port | None = None
_dest_port: alsa_midi.PortInfo | None = None
name: str

@classmethod
Expand Down
12 changes: 7 additions & 5 deletions alsa_midi/port.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
from __future__ import annotations

from dataclasses import InitVar, dataclass, field
from enum import IntFlag
from typing import TYPE_CHECKING, Any, Callable, NewType, Optional
from typing import TYPE_CHECKING, Any, Callable, NewType

from ._ffi import alsa, ffi
from .address import Address, AddressType
Expand Down Expand Up @@ -73,7 +75,7 @@ class Port:
:ivar port_id: port identifier
"""

client: Optional['SequencerClientBase']
client: 'SequencerClientBase' | None
client_id: int
port_id: int

Expand Down Expand Up @@ -217,7 +219,7 @@ class PortInfo:
"""

client_id: int = 0
port_id: Optional[int] = None
port_id: int | None = None
name: str = ""
capability: PortCaps = PortCaps._NONE
type: PortType = PortType.ANY
Expand All @@ -226,12 +228,12 @@ class PortInfo:
synth_voices: int = 0
read_use: int = 0
write_use: int = 0
port_specified: InitVar[Optional[bool]] = None
port_specified: InitVar[bool | None] = None
timestamping: bool = False
timestamp_real: bool = False
timestamp_queue_id: int = 0

client_name: Optional[str] = field(init=False, default=None)
client_name: str | None = field(init=False, default=None)

def __post_init__(self, port_specified=None):
if port_specified is not None and not port_specified:
Expand Down
18 changes: 10 additions & 8 deletions alsa_midi/queue.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
from __future__ import annotations

from dataclasses import dataclass, field
from enum import IntEnum
from typing import TYPE_CHECKING, NamedTuple, NewType, Optional, Union
from typing import TYPE_CHECKING, NamedTuple, NewType

from ._ffi import alsa, ffi
from .event import EventType, RealTime
Expand Down Expand Up @@ -128,8 +130,8 @@ class QueueTempo:

tempo: int = 500000
ppq: int = 96
skew: Optional[int] = None
skew_base: Optional[int] = None
skew: int | None = None
skew_base: int | None = None

@classmethod
def _from_alsa(cls, tempo: _snd_seq_queue_tempo_t):
Expand Down Expand Up @@ -245,11 +247,11 @@ class Queue:
release or free on close).
"""

client: Optional['SequencerClientBase']
client: 'SequencerClientBase' | None
queue_id: int
_own: Optional[bool]
_own: bool | None

def __init__(self, client: 'SequencerClientBase', queue_id: int, *, _own: bool = None):
def __init__(self, client: 'SequencerClientBase', queue_id: int, *, _own: bool | None = None):
self.client = client
self.queue_id = queue_id
self._own = _own
Expand Down Expand Up @@ -287,8 +289,8 @@ def close(self):
else:
alsa.snd_seq_set_queue_usage(handle, queue, 0)

def set_tempo(self, tempo: Union[int, QueueTempo] = None, ppq: int = None,
skew=None, skew_base=None, bpm=None):
def set_tempo(self, tempo: int | QueueTempo = None, ppq: int | None = None,
skew: int | None = None, skew_base: int | None = None, bpm: float | None = None):
"""Set the tempo of the queue.

:param tempo: MIDI tempo – microseconds per quarter note
Expand Down
4 changes: 2 additions & 2 deletions build-wheels.sh
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ fi
git config --global --add safe.directory "$GITHUB_WORKSPACE"

# Compile wheels
for PYBIN in /opt/python/cp{39,310,311,312,313,314}*/bin; do
for PYBIN in /opt/python/cp{310,311,312,313,314}*/bin; do
[ -d "$PYBIN" ] || continue
if [[ "$PYBIN" =~ 313t ]] ; then
echo "Skipping 313t variant, as it is incompatible with cffi"
Expand All @@ -80,7 +80,7 @@ rm wheelhouse/*-linux_*.whl

# Install packages and test
cd /
for PYBIN in /opt/python/cp{39,310,311,312,313,314}*/bin/; do
for PYBIN in /opt/python/cp{310,311,312,313,314}*/bin/; do
[ -d "$PYBIN" ] || continue
if [[ "$PYBIN" =~ 313t ]] ; then
echo "Skipping 313t variant, as it is incompatible with cffi"
Expand Down
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ license = MIT
classifiers =
License :: OSI Approved :: MIT License
Programming Language :: Python :: 3
Programming Language :: Python :: 3.9
Programming Language :: Python :: 3.10
Programming Language :: Python :: 3.11
Programming Language :: Python :: 3.12
Expand All @@ -27,6 +26,7 @@ project_urls =
packages =
alsa_midi
zip_safe = False
python_requires = >=3.10
setup_requires =
cffi>=1.16.0
install_requires =
Expand Down
5 changes: 2 additions & 3 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import subprocess
import sys
from statistics import mean
from typing import Optional

import pytest
import pytest_asyncio
Expand Down Expand Up @@ -42,7 +41,7 @@ class AlsaClientState:
client_id: int
name: str
type: str
version: Optional[str]
version: str | None
ports: dict[int, AlsaPortState]
queues: dict[int, 'AlsaQueueState']

Expand Down Expand Up @@ -326,7 +325,7 @@ def aseqdump():
from alsa_midi import Address

class Aseqdump:
process: Optional[subprocess.Popen]
process: subprocess.Popen | None
output: list[tuple[Address, str]]
port: Address

Expand Down
Loading