Skip to content

Simplify example to not use translate requirement #85

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

Merged
merged 2 commits into from
Nov 12, 2021
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
20 changes: 3 additions & 17 deletions constraints.txt
Original file line number Diff line number Diff line change
@@ -1,19 +1,5 @@
# Generated by build-support/generate_constraints.sh on Mon Aug 2 21:58:13 UTC 2021
# Generated by build-support/generate_constraints.sh on Fri Nov 12 13:02:01 MST 2021
ansicolors==1.1.8
certifi==2021.5.30
charset-normalizer==2.0.4
click==8.0.1
idna==3.2
importlib-metadata==4.6.3
libretranslatepy==2.1.1
lxml==4.6.3
pip==21.2.2
requests==2.26.0
pip==21.3.1
setuptools==56.2.0
six==1.16.0
translate==3.6.1
types-futures==0.1.6
types-setuptools==57.0.0
typing-extensions==3.10.0.0
urllib3==1.26.6
zipp==3.5.0
types-setuptools==57.4.2
12 changes: 1 addition & 11 deletions helloworld/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,8 @@
# Licensed under the Apache License, Version 2.0 (see LICENSE).

# This target sets the metadata for all the Python non-test files in this directory.
#
# * `name` defaults to the name of this directory, i.e., `helloworld`.
# * `sources` defaults to ['*.py', '!*_test.py', '!test_*.py', '!conftest.py'].
# * Pants cannot infer dependencies on resources targets, so we explicitly add it.
python_library(
dependencies=[":config_file"],
)

# This target teaches Pants about our JSON file, which allows for other targets to depend on it.
resources(
name="config_file",
sources=["config.json"],
name="lib",
)

# This target allows us to bundle our app into a PEX binary file via
Expand Down
15 changes: 0 additions & 15 deletions helloworld/config.json

This file was deleted.

22 changes: 14 additions & 8 deletions helloworld/greet/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,19 @@

# This target sets the metadata for all the Python non-test files in this directory.
#
# * `name` defaults to the name of this directory, i.e., `greet`.
# * `sources` defaults to ['*.py', '!*_test.py', '!test_*.py', '!conftest.py'].
# * `dependencies` are inferred.
python_library()
# * Pants cannot infer dependencies on `resources` targets, so we explicitly add the dep.
python_library(
name="lib",
dependencies=[":translations"],
)

# This target sets the metadata for all the Python test files in this directory.
#
# * `sources` defaults to ['*_test.py', 'test_*.py', 'conftest.py'].
# * `dependencies` are inferred.
python_tests(name='tests')
python_tests(
name="tests",
)
Comment on lines +13 to +15
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I very much prefer the style of keeping it on one-line. But tailor generates it this way, so probably good to be consistent with that.


# This target teaches Pants about our JSON file, which allows other targets to depend on it.
resources(
name="translations",
sources=["translations.json"],
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe glob *.json? A bit shorter, and less fragile.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In 2.8, I will update this to use resource instead of resources

)
29 changes: 19 additions & 10 deletions helloworld/greet/greeting.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,30 @@
# Copyright 2020 Pants project contributors.
# Licensed under the Apache License, Version 2.0 (see LICENSE).

from __future__ import annotations

import json
import random
from typing import List

from helloworld.util.lang import LanguageTranslator
import pkg_resources

from helloworld.translator.translator import LanguageTranslator

class Greeter:
def __init__(self, greetings: List[str], languages: List[str]) -> None:
self._greetings = greetings
self._language_translator = LanguageTranslator(languages=languages)

def translated_greeting(self) -> str:
random_greeting = random.choice(self._greetings)
return self._language_translator.translate_to_random_language(random_greeting)
class Greeter:
def __init__(
self, *, translations: dict[str, dict[str, str]] | None = None
) -> None:
self._translations = (
translations
if translations is not None
else json.loads(
pkg_resources.resource_string(__name__, "translations.json")
)
)
self._translator = LanguageTranslator(self._translations)

def greet(self, name: str) -> str:
greeting = self.translated_greeting()
random_greeting = random.choice(list(self._translations.keys()))
greeting = self._translator.translate_to_random_language(random_greeting)
return f"{greeting}, {name}!".capitalize()
4 changes: 2 additions & 2 deletions helloworld/greet/greeting_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@


def test_greeter() -> None:
greeter = Greeter(languages=["es"], greetings=["good morning"])
assert greeter.greet("world") == "Buenos días, world!"
greeter = Greeter(translations={"hello": {"es": "hola"}})
assert greeter.greet("test") == "Hola, test!"
18 changes: 18 additions & 0 deletions helloworld/greet/translations.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"hello": {
"es": "hola",
"fr": "bonjour",
"af": "hallo",
"ch": "你好",
"ru": "Привет",
"cs": "ahoj"
},
"good night": {
"es": "buenas noches",
"fr": "bonne nuit",
"af": "Goeie nag",
"ch": "晚安",
"ru": "спокойной ночи",
"cs": "dobrou noc"
}
}
7 changes: 2 additions & 5 deletions helloworld/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,11 @@
from colors import green

from helloworld.greet.greeting import Greeter
from helloworld.util.config import Config


def say_hello() -> None:
config = Config.load_from_json_resource(__name__, "config.json")
greeter = Greeter(languages=config.languages, greetings=config.greetings)
sentence = greeter.greet("world")
print(green(sentence))
greeting = Greeter().greet("Pantsbuild")
print(green(greeting))


if __name__ == "__main__":
Expand Down
24 changes: 6 additions & 18 deletions helloworld/util/BUILD → helloworld/translator/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -2,36 +2,24 @@
# Licensed under the Apache License, Version 2.0 (see LICENSE).

# This target sets the metadata for all the Python non-test files in this directory.
#
# * `name` defaults to the name of this directory, i.e., `util`.
# * `sources` defaults to ['*.py', '!*_test.py', '!test_*.py', '!conftest.py'].
# * `dependencies` are inferred.
python_library()
python_library(
name="lib",
)

# This target sets the metadata for all the Python test files in this directory.
#
# * `sources` defaults to ['*_test.py', 'test_*.py', 'conftest.py'].
# * Pants cannot infer dependencies on `resources` targets, so we explicitly add the dep.
python_tests(
name='tests',
dependencies=[":test_data"],
)

# This target teaches Pants about our JSON file, which allows for other targets to depend on it.
resources(
name='test_data',
sources=['*_test_data.json'],
name="tests",
)

# This target allows us to build a `.whl` bdist and a `.tar.gz` sdist by auto-generating
# `setup.py`. See https://www.pantsbuild.org/docs/python-distributions.
#
# Because this target has no source code, Pants cannot infer dependencies. We depend on `:util`,
# Because this target has no source code, Pants cannot infer dependencies. We depend on `:lib`,
# which means we'll include all the non-test Python files in this directory, and any of
# their dependencies.
python_distribution(
name="dist",
dependencies=[":util"],
dependencies=[":lib"],
setup_py_commands=["bdist_wheel", "sdist"],
provides=setup_py(
name='helloworld.util',
Expand Down
File renamed without changes.
46 changes: 46 additions & 0 deletions helloworld/translator/translator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Copyright 2020 Pants project contributors.
# Licensed under the Apache License, Version 2.0 (see LICENSE).

from __future__ import annotations

import random
from dataclasses import dataclass


class UnknownLanguage(Exception):
pass


class UnknownPhrase(Exception):
pass


@dataclass
class LanguageTranslator:
"""A mapping of phrases (in English) to ISO 639 language codes (like `es`,
`fr`) and their translation.

Assumes that every phrase is translated into the same languages.
"""

phrases_to_translations: dict[str, dict[str, str]]

@property
def all_languages(self) -> set[str]:
return {
lang
for translations in self.phrases_to_translations.values()
for lang in translations.keys()
}

def translate(self, lang: str, phrase: str) -> str:
if phrase not in self.phrases_to_translations:
raise UnknownPhrase(phrase)
translations = self.phrases_to_translations[phrase]
if lang not in translations:
raise UnknownLanguage(lang)
return translations[lang]

def translate_to_random_language(self, phrase: str) -> str:
lang = random.choice(sorted(self.all_languages))
return self.translate(lang, phrase)
34 changes: 34 additions & 0 deletions helloworld/translator/translator_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Copyright 2020 Pants project contributors.
# Licensed under the Apache License, Version 2.0 (see LICENSE).

import pytest

from helloworld.translator.translator import (
LanguageTranslator,
UnknownLanguage,
UnknownPhrase,
)


def test_language_translator() -> None:
translator = LanguageTranslator(
{
"hello": {"es": "hola", "ar": "مرحبًا"},
"computer": {"es": "computadora", "ar": "حاسوب"},
}
)
assert translator.translate("es", "hello") == "hola"
assert translator.translate("ar", "hello") == "مرحبًا"
assert translator.translate("es", "computer") == "computadora"


def test_unknown_phrase() -> None:
translator = LanguageTranslator({"hello": {"es": "hola"}})
with pytest.raises(UnknownPhrase):
translator.translate("es", "good morning")


def test_unknown_language() -> None:
translator = LanguageTranslator({"hello": {"es": "hola"}})
with pytest.raises(UnknownLanguage):
translator.translate("ch", "hello")
21 changes: 0 additions & 21 deletions helloworld/util/config.py

This file was deleted.

10 changes: 0 additions & 10 deletions helloworld/util/config_test.py

This file was deleted.

10 changes: 0 additions & 10 deletions helloworld/util/config_test_data.json

This file was deleted.

27 changes: 0 additions & 27 deletions helloworld/util/lang.py

This file was deleted.

17 changes: 0 additions & 17 deletions helloworld/util/lang_test.py

This file was deleted.

3 changes: 0 additions & 3 deletions mypy.ini
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,5 @@ error_summary = True
[mypy-colors]
ignore_missing_imports = True

[mypy-translate]
ignore_missing_imports = True

[mypy-pytest]
ignore_missing_imports = True
Loading