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

Translator class #22

Merged
merged 3 commits into from
May 9, 2020
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
104 changes: 76 additions & 28 deletions src/dressup/converter.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,76 @@
"""Convert Unicode characters."""
import pathlib
import re
from typing import Any, Dict, MutableMapping
from typing import Any, Dict, MutableMapping, Optional

import toml

from . import exceptions


def _read_translator() -> MutableMapping[str, Any]:
class Translator(dict):
"""Translator for converting text to Unicode.

Attributes:
items (Dict[str, str]): Keys and values to prepopulate Translator.
Optional.
strict_case (bool): Whether to forbid characters from being
converted to an upper or lower case counterpart if an exact
match is not found. By default set to False.
"""

def __init__(
self, items: Optional[Dict[str, str]] = None, strict_case: bool = False
) -> None:
"""Constructor."""
if items is not None:
self.update(items)
self.strict_case = strict_case
pass

def __repr__(self) -> str:
"""Representation of Translator."""
dict_repr = (
"{"
+ ", ".join(
": ".join((f"'{item}'", f"'{key}'")) for item, key in self.items()
)
+ "}"
)
return f"Translator({dict_repr}, {self.strict_case})"

def __missing__(self, key: str) -> str:
"""Return value in the case of a missing key.

If ``strict_case`` is True, will return the key itself. If
False, will first try to return a value matching the upper or
lowercase variant of the key.

Args:
key (str): The key missing from Translator.

Returns:
str: The returned value.
"""
if self.strict_case:
return key
else:
if key.upper() in self:
return self[key.upper()]
elif key.lower() in self:
return self[key.lower()]
else:
return key


def _read_translator(strict_case: bool = False) -> MutableMapping[str, Any]:
"""Read translator from config file.

Args:
strict_case (bool): Whether to forbid characters from being
converted to an upper or lower case counterpart if an exact
match is not found. By default set to False.

Returns:
MutableMapping[str, Any]: A dictionary where the keys are the
unicode type, and the values are nested dictionaries with the
Expand All @@ -19,7 +79,11 @@ def _read_translator() -> MutableMapping[str, Any]:
"""
toml_path = pathlib.Path(__file__).parent / pathlib.Path("translator.toml")
toml_text = toml_path.read_text()
translator = toml.loads(toml_text)
unicode_mapping = toml.loads(toml_text)
translator = {
unicode_type: Translator(unicode_mapping[unicode_type], strict_case=strict_case)
for unicode_type in unicode_mapping
}
return translator


Expand Down Expand Up @@ -72,33 +136,17 @@ def show_all(
'Ħɇłłø', 'Subscript': 'ₕₑₗₗₒ', 'Superscript': 'ᴴᵉˡˡᵒ',
'Inverted': 'ɥǝןןo', 'Reversed': 'Hɘ⅃⅃o'}
"""
translator = _read_translator()
translator = _read_translator(strict_case=strict_case)
if reverse:
characters = characters[::-1]
if strict_case:
converted_characters = {
_format_names(character_type): "".join(
translator[normalize_text(character_type)].get(character, character)
for character in characters
)
for character_type in translator
}
else:
converted_characters = {
_format_names(character_type): "".join(
translator[normalize_text(character_type)].get(
character,
translator[normalize_text(character_type)].get(
character.upper(),
translator[normalize_text(character_type)].get(
character.lower(), character
),
),
)
for character in characters
)
for character_type in translator
}
converted_characters = {
_format_names(character_type): "".join(
translator[normalize_text(character_type)][character]
for character in characters
)
for character_type in translator
}

return converted_characters


Expand Down
33 changes: 33 additions & 0 deletions tests/test_converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,39 @@
from dressup import converter, exceptions


def test_translator_repr() -> None:
"""Its string representation contains the init parameters."""
translator = converter.Translator({letter: "b" for letter in "ab"}, False)
assert str(translator) == "Translator({'a': 'b', 'b': 'b'}, False)"


def test_default_translatortor() -> None:
"""It returns an empty dictionary when provided to items."""
translator = converter.Translator()
assert translator == {}


def test_strict_case_translator() -> None:
"""It returns the key when no match is found."""
values = {"a": "<3"}
translator = converter.Translator(values, strict_case=True)
assert translator["A"] == "A"


def test_missing_translator_upper() -> None:
"""It returns the upper case match when no match is found."""
values = {"A": "<3"}
translator = converter.Translator(values, strict_case=False)
assert translator["a"] == "<3"


def test_missing_translator_lower() -> None:
"""It returns the lower case match when no match is found."""
values = {"a": "<3"}
translator = converter.Translator(values, strict_case=False)
assert translator["A"] == "<3"


def test_valid_toml() -> None:
"""It is a valid TOML file."""
file_text = pathlib.Path("src/dressup/translator.toml").read_text()
Expand Down