-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
101 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
from chordparser.music.notationparser import NotationParser | ||
from chordparser.music.note import NoteNotationParser | ||
from chordparser.utils.regex_patterns import (submode_pattern, | ||
mode_pattern, | ||
short_minor_pattern, | ||
short_major_pattern) | ||
|
||
|
||
class ModeError(Exception): | ||
"""Exception where a `Key`'s `mode` is invalid.""" | ||
pass | ||
|
||
|
||
class ModeNotationParser(NotationParser): | ||
"""Parse mode notation into mode and submode.""" | ||
_pattern = ( | ||
fr"(\s?({submode_pattern})?\s?({mode_pattern}))|" | ||
f"({short_minor_pattern})|" | ||
f"({short_major_pattern})" | ||
) | ||
|
||
def _split_into_groups(self, regex): | ||
"""Split into mode and submode.""" | ||
mode = self._get_mode( | ||
regex.group(3), regex.group(4), regex.group(5) | ||
) | ||
submode = self._get_submode( | ||
regex.group(2), self._is_minor(mode) | ||
) | ||
return mode, submode | ||
|
||
def _get_mode(self, long_mode, short_minor, short_major): | ||
if short_major is not None: | ||
return "major" | ||
if short_minor: | ||
return "minor" | ||
return long_mode.lower() | ||
|
||
def _is_minor(self, mode): | ||
return mode in ("minor", "aeolian") | ||
|
||
def _get_submode(self, submode, is_minor): | ||
if submode and not is_minor: | ||
raise ModeError("Only minor can have a submode") | ||
if not is_minor: | ||
return "" | ||
if is_minor and not submode: | ||
return "natural" | ||
return submode.lower() | ||
|
||
|
||
class KeyNotationParser: | ||
"""Parse key notation into tonic and mode groups.""" | ||
_NNP = NoteNotationParser() | ||
_MNP = ModeNotationParser() | ||
_pattern = ( | ||
f"({_NNP.get_regex_pattern})" | ||
f"({_MNP.get_regex_pattern})" | ||
) | ||
|
||
|
||
class Key: | ||
def __init__(self, notation): | ||
pass |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import pytest | ||
|
||
from chordparser.music.key import (ModeError, ModeNotationParser, | ||
KeyNotationParser, Key) | ||
|
||
|
||
class TestMNPParseNotation: | ||
@pytest.fixture | ||
def parser(self): | ||
return ModeNotationParser() | ||
|
||
@pytest.mark.parametrize( | ||
"notation, expected_mode", [ | ||
("", "major"), | ||
("m", "minor"), | ||
(" major", "major"), | ||
(" Dorian", "dorian"), | ||
] | ||
) | ||
def test_correct_mode(self, parser, notation, expected_mode): | ||
mode, _ = parser.parse_notation(notation) | ||
assert expected_mode == mode | ||
|
||
@pytest.mark.parametrize( | ||
"notation, expected_submode", [ | ||
(" minor", "natural"), | ||
("harmonic minor", "harmonic"), | ||
(" major", ""), | ||
] | ||
) | ||
def test_correct_submode(self, parser, notation, expected_submode): | ||
_, submode = parser.parse_notation(notation) | ||
assert expected_submode == submode | ||
|
||
def test_mode_error(self, parser): | ||
with pytest.raises(ModeError): | ||
parser.parse_notation("natural major") |