# A lookup dictionary which, given a letter will return the morse code equivalent
_letter_to_morse = {'a':'.-', 'b':'-...', 'c':'-.-.', 'd':'-..', 'e':'.', 'f':'..-.',
'g':'--.', 'h':'....', 'i':'..', 'j':'.---', 'k':'-.-', 'l':'.-..', 'm':'--',
'n':'-.', 'o':'---', 'p':'.--.', 'q':'--.-', 'r':'.-.', 's':'...', 't':'-',
'u':'..-', 'v':'...-', 'w':'.--', 'x':'-..-', 'y':'-.--', 'z':'--..',
'0':'-----', '1':'.----', '2':'..---', '3':'...--', '4':'....-',
'5':'.....', '6':'-....', '7':'--...', '8':'---..', '9':'----.',
' ':'/'}
# This will create a dictionary that can go from the morse back to the letter
_morse_to_letter = {}
for letter in _letter_to_morse:
morse = _letter_to_morse[letter]
_morse_to_letter[morse] = letter
def encode(message):
"""
Encode a message from English to Morse Code
Args:
message (str): the English message to encode
Returns:
str: The encoded message
Examples:
>>> encode("Help us")
'.... . .-.. .--. / ..- ...'
"""
morse = []
for letter in message:
letter = letter.lower()
if letter not in _letter_to_morse:
raise ValueError(f"Cannot encode \"{message}\". Character \"{letter}\" not in Morse dictionary")
morse.append(_letter_to_morse[letter])
# We need to join together Morse code letters with spaces
morse_message = " ".join(morse)
return morse_message
def decode(message):
"""
Decode a message from Morse Code to English
Args:
message (str): the Morse Code message to decode
Returns:
str: The decoded English message
Examples:
>>> decode(".... . .-.. .--. / ..- ...")
'help us'
"""
english = []
# Now we cannot read by letter. We know that morse letters are
# separated by a space, so we split the morse string by spaces
morse_letters = message.split(" ")
for letter in morse_letters:
english.append(_morse_to_letter[letter])
# Rejoin, but now we don't need to add any spaces
english_message = "".join(english)
return english_message
import string
_lower_cipher = string.ascii_lowercase[13:] + string.ascii_lowercase[:13]
_upper_cipher = string.ascii_uppercase[13:] + string.ascii_uppercase[:13]
def encode(message):
"""
Encode a message from English to ROT13
Args:
message (str): the English message to encode
Returns:
str: The encoded message
Examples:
>>> encode("Secretmessage")
'Frpergzrffntr'
"""
output = []
for letter in message:
if letter in string.ascii_lowercase:
i = string.ascii_lowercase.find(letter)
output.append(_lower_cipher[i])
elif letter in string.ascii_uppercase:
i = string.ascii_uppercase.find(letter)
output.append(_upper_cipher[i])
else: # Add this else statement
raise ValueError(f"Cannot encode \"{message}\". Character \"{letter}\" not valid")
return "".join(output)
def decode(message):
"""
Encode a message from ROT13 to English
Args:
message (str): the ROT13 message to encode
Returns:
str: The decoded message
Examples:
>>> encode("Frpergzrffntr")
'Secretmessage'
"""
output = []
for letter in message:
if letter in _lower_cipher:
i = _lower_cipher.find(letter)
output.append(string.ascii_lowercase[i]) # ascii_uppercase → ascii_lowercase
elif letter in _upper_cipher:
i = _upper_cipher.find(letter)
output.append(string.ascii_uppercase[i])
else: # Add this else statement
raise ValueError(f"Cannot decode \"{message}\". Character \"{letter}\" not valid")
return "".join(output)
import pytest
from morse import encode, decode
@pytest.mark.parametrize("message", [
"sos",
"help us please",
"An Uppercase String",
])
def test_roundtrip(message):
assert decode(encode(message)) == message
import pytest
from rot13 import encode, decode
@pytest.mark.parametrize("message", [
"sos",
"helpusplease",
"AnUppercaseString",
])
def test_roundtrip(message):
assert decode(encode(message)) == message
pytest -v morse.py rot13.py test_morse.py test_rot13.py
The Morse Code converter does not maintain the case of the string. All messages passed into it will be converted to lower case. This means that a message like "SOS" will, after round-tripping be "sos". This means that in this case, the invariant of the round-trip is not that the messages are identical, but rather that they are "identical if you ignore case".
To make our test do this, we can compare the round-tripped message against the lower case message with message.lower()
:
import pytest
from morse import encode, decode
@pytest.mark.parametrize("message", [
"sos",
"help us please",
"An Uppercase String",
])
def test_roundtrip(message):
assert decode(encode(message)) == message.lower() # This line has changed
pytest -v morse.py rot13.py test_morse.py test_rot13.py