Compare commits

..

15 Commits

Author SHA1 Message Date
32b1acf4aa Updated to 0.2.2
All checks were successful
Tests / test (3.10) (push) Successful in 1m4s
Tests / test (3.11) (push) Successful in 1m13s
Tests / test (3.8) (push) Successful in 1m9s
Tests / test (3.9) (push) Successful in 1m1s
2023-08-06 22:00:14 +02:00
1c1c71d40b Fixed PyroClient.bot_locale 2023-08-06 21:59:48 +02:00
65838450ee Fixed typing of Dict
All checks were successful
Tests / test (3.10) (push) Successful in 1m9s
Tests / test (3.11) (push) Successful in 1m52s
Tests / test (3.8) (push) Successful in 1m23s
Tests / test (3.9) (push) Successful in 1m25s
2023-08-06 21:22:24 +02:00
3f39e07d04 Added coverage display 2023-08-06 21:21:55 +02:00
c5fdd60d13 Added container
Some checks failed
Tests / test (3.10) (push) Successful in 1m26s
Tests / test (3.11) (push) Successful in 1m1s
Tests / test (3.8) (push) Failing after 1m3s
Tests / test (3.9) (push) Successful in 1m11s
2023-08-06 21:11:06 +02:00
35fe69d2a8 Tried another Python versions set
Some checks reported warnings
Tests / test (3.11) (push) Has been cancelled
Tests / test (3.8) (push) Has been cancelled
Tests / test (3.9) (push) Has been cancelled
Tests / test (3.10) (push) Has been cancelled
2023-08-06 19:24:16 +02:00
3bb7ecca7e Updated python versions
Some checks failed
Tests / test (3.10.12) (push) Failing after 5s
Tests / test (3.11.3) (push) Failing after 5s
Tests / test (3.8.17) (push) Failing after 6s
Tests / test (3.9.17) (push) Failing after 4s
2023-08-06 19:14:44 +02:00
64aa2686ea Updated to 0.2.1
Some checks failed
Tests / test (3.10) (push) Failing after 55s
Tests / test (3.11) (push) Failing after 5s
Tests / test (3.8) (push) Failing after 6s
Tests / test (3.9) (push) Failing after 5s
2023-08-06 19:11:16 +02:00
461642a529 Added nested_set tests 2023-08-06 12:51:32 +02:00
e5c0f5c1d1 Added i18n tests 2023-08-06 12:51:23 +02:00
00b1058014 BotLocale now has default_locale 2023-08-06 12:51:06 +02:00
bc5be37ff1 locale is now Union[str, None] 2023-08-06 12:50:34 +02:00
7c756d7065 Switched versioning to semantic 2023-08-06 12:43:41 +02:00
3273b86b75 nested_set raises KeyError if not create_missing 2023-08-06 12:43:01 +02:00
783443e448 Changed imports 2023-08-06 12:42:37 +02:00
30 changed files with 440 additions and 83 deletions

View File

@@ -0,0 +1,28 @@
name: Tests
on:
- push
- pull_request
jobs:
test:
runs-on: ubuntu-latest
container: catthehacker/ubuntu:act-latest
strategy:
matrix:
python-version: ["3.8", "3.9", "3.10", "3.11"]
steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v3
with:
python-version: ${{ matrix.python-version }}
env:
AGENT_TOOLSDIRECTORY: /opt/hostedtoolcache
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install tox tox-gh-actions
- name: Test with tox
run: tox

View File

@@ -1,9 +0,0 @@
__name__ = "libbot"
__version__ = "1.9"
__license__ = "GPL3"
__author__ = "Profitroll"
from .__main__ import *
from . import sync
from . import i18n
from . import pyrogram

View File

@@ -1,15 +1,15 @@
[build-system] [build-system]
requires = ["setuptools>=62.6,<66"] requires = ["setuptools>=62.6", "wheel"]
build-backend = "setuptools.build_meta" build-backend = "setuptools.build_meta"
[project] [project]
name = "libbot" name = "libbot"
version = "1.9" dynamic = ["version", "dependencies", "optional-dependencies"]
authors = [{ name = "Profitroll" }] authors = [{ name = "Profitroll" }]
description = "Universal bot library with functions needed for basic Discord/Telegram bot development." description = "Universal bot library with functions needed for basic Discord/Telegram bot development."
readme = "README.md" readme = "README.md"
requires-python = ">=3.8" requires-python = ">=3.8"
license = { text = "GPL3" } license = { file = "LICENSE" }
classifiers = [ classifiers = [
"Development Status :: 3 - Alpha", "Development Status :: 3 - Alpha",
"Intended Audience :: Developers", "Intended Audience :: Developers",
@@ -22,30 +22,24 @@ classifiers = [
"Topic :: Software Development :: Libraries :: Python Modules", "Topic :: Software Development :: Libraries :: Python Modules",
"Topic :: Utilities", "Topic :: Utilities",
] ]
dependencies = ["aiofiles~=23.1.0"]
[project.optional-dependencies] [tool.setuptools.dynamic]
pycord = ["py-cord~=2.4.1"] version = { attr = "libbot.__version__" }
pyrogram = ["pyrogram~=2.0.106", "apscheduler~=3.10.1"] dependencies = { file = "requirements/_.txt" }
speed = ["ujson~=5.8.0"]
[tool.setuptools.dynamic.optional-dependencies]
dev = { file = "requirements/dev.txt" }
pycord = { file = "requirements/pycord.txt" }
pyrogram = { file = "requirements/pyrogram.txt" }
speed = { file = "requirements/speed.txt" }
[project.urls] [project.urls]
Source = "https://git.end-play.xyz/profitroll/LibBotUniversal" Source = "https://git.end-play.xyz/profitroll/LibBotUniversal"
Documentation = "https://git.end-play.xyz/profitroll/LibBotUniversal/wiki" Documentation = "https://git.end-play.xyz/profitroll/LibBotUniversal/wiki"
Tracker = "https://git.end-play.xyz/profitroll/LibBotUniversal/issues" Tracker = "https://git.end-play.xyz/profitroll/LibBotUniversal/issues"
[tool.setuptools] [tool.setuptools.packages.find]
packages = [ where = ["src"]
"libbot",
"libbot.sync",
"libbot.pyrogram",
"libbot.pyrogram.classes",
"libbot.i18n",
"libbot.i18n.sync",
"libbot.i18n.classes",
]
[tool.setuptools_scm]
[tool.black] [tool.black]
target-version = ['py38', 'py39', 'py310', 'py311'] target-version = ['py38', 'py39', 'py310', 'py311']
@@ -58,3 +52,16 @@ minversion = "6.0"
python_files = ["test_*.py"] python_files = ["test_*.py"]
pythonpath = "." pythonpath = "."
testpaths = ["tests"] testpaths = ["tests"]
[tool.mypy]
namespace_packages = true
install_types = true
strict = true
show_error_codes = true
[tool.pylint.main]
extension-pkg-whitelist = ["ujson"]
py-version = 3.8
[tool.coverage.run]
source = ["libbot"]

1
requirements/_.txt Normal file
View File

@@ -0,0 +1 @@
aiofiles~=23.1.0

10
requirements/dev.txt Normal file
View File

@@ -0,0 +1,10 @@
black==23.7.0
isort==5.12.0
mypy==1.4.1
pylint==2.17.5
pytest-asyncio==0.21.1
pytest-cov==4.1.0
pytest==7.4.0
tox==4.6.4
types-aiofiles==23.1.0.5
types-ujson==5.8.0.1

1
requirements/pycord.txt Normal file
View File

@@ -0,0 +1 @@
py-cord~=2.4.1

View File

@@ -0,0 +1,2 @@
apscheduler~=3.10.1
pyrogram~=2.0.106

1
requirements/speed.txt Normal file
View File

@@ -0,0 +1 @@
ujson~=5.8.0

View File

@@ -1,3 +0,0 @@
[metadata]
description_file=README.md
license_files=LICENSE

View File

@@ -1,4 +0,0 @@
from setuptools import setup
if __name__ == "__main__":
setup()

6
src/libbot/__init__.py Normal file
View File

@@ -0,0 +1,6 @@
__version__ = "0.2.2"
__license__ = "GPL3"
__author__ = "Profitroll"
from . import i18n, pyrogram, sync
from .__main__ import *

View File

@@ -2,14 +2,15 @@ from os import listdir
from pathlib import Path from pathlib import Path
from typing import Any, Dict, Union from typing import Any, Dict, Union
from libbot import config_get, json_read, sync import libbot
from libbot.i18n import sync
from libbot.i18n.classes.bot_locale import BotLocale from libbot.i18n.classes.bot_locale import BotLocale
async def _( async def _(
key: str, key: str,
*args: str, *args: str,
locale: str = "en", locale: Union[str, None] = "en",
locales_root: Union[str, Path] = Path("locale"), locales_root: Union[str, Path] = Path("locale"),
) -> Any: ) -> Any:
"""Get value of locale string """Get value of locale string
@@ -17,20 +18,20 @@ async def _(
### Args: ### Args:
* key (`str`): The last key of the locale's keys path. * key (`str`): The last key of the locale's keys path.
* *args (`list`): Path to key like: `dict[args][key]`. * *args (`list`): Path to key like: `dict[args][key]`.
* locale (`str`): Locale to looked up in. Defaults to `"en"`. * locale (`Union[str, None]`): Locale to looked up in. Defaults to `"en"`.
* locales_root (`Union[str, Path]`, *optional*): Folder where locales are located. Defaults to `Path("locale")`. * locales_root (`Union[str, Path]`, *optional*): Folder where locales are located. Defaults to `Path("locale")`.
### Returns: ### Returns:
* `Any`: Value of provided locale key. Is usually `str`, `dict` or `list` * `Any`: Value of provided locale key. Is usually `str`, `dict` or `list`
""" """
locale = sync.config_get("locale") if locale is None else locale locale = libbot.sync.config_get("locale") if locale is None else locale
try: try:
this_dict = await json_read(Path(f"{locales_root}/{locale}.json")) this_dict = await libbot.json_read(Path(f"{locales_root}/{locale}.json"))
except FileNotFoundError: except FileNotFoundError:
try: try:
this_dict = await json_read( this_dict = await libbot.json_read(
Path(f'{locales_root}/{await config_get("locale")}.json') Path(f'{locales_root}/{await libbot.config_get("locale")}.json')
) )
except FileNotFoundError: except FileNotFoundError:
return f'⚠️ Locale in config is invalid: could not get "{key}" in {args} from locale "{locale}"' return f'⚠️ Locale in config is invalid: could not get "{key}" in {args} from locale "{locale}"'
@@ -65,7 +66,7 @@ async def in_all_locales(
valid_locales = [".".join(entry.split(".")[:-1]) for entry in files_locales] valid_locales = [".".join(entry.split(".")[:-1]) for entry in files_locales]
for lc in valid_locales: for lc in valid_locales:
try: try:
this_dict = await json_read(Path(f"{locales_root}/{lc}.json")) this_dict = await libbot.json_read(Path(f"{locales_root}/{lc}.json"))
except FileNotFoundError: except FileNotFoundError:
continue continue
@@ -101,7 +102,7 @@ async def in_every_locale(
valid_locales = [".".join(entry.split(".")[:-1]) for entry in files_locales] valid_locales = [".".join(entry.split(".")[:-1]) for entry in files_locales]
for lc in valid_locales: for lc in valid_locales:
try: try:
this_dict = await json_read(Path(f"{locales_root}/{lc}.json")) this_dict = await libbot.json_read(Path(f"{locales_root}/{lc}.json"))
except FileNotFoundError: except FileNotFoundError:
continue continue

View File

@@ -10,6 +10,7 @@ class BotLocale:
def __init__( def __init__(
self, self,
default_locale: Union[str, None] = "en",
locales_root: Union[str, Path] = Path("locale"), locales_root: Union[str, Path] = Path("locale"),
) -> None: ) -> None:
if isinstance(locales_root, str): if isinstance(locales_root, str):
@@ -23,7 +24,9 @@ class BotLocale:
".".join(entry.split(".")[:-1]) for entry in files_locales ".".join(entry.split(".")[:-1]) for entry in files_locales
] ]
self.default: str = sync.config_get("locale") self.default: str = (
sync.config_get("locale") if default_locale is None else default_locale
)
self.locales: dict = {} self.locales: dict = {}
for lc in valid_locales: for lc in valid_locales:

View File

@@ -2,14 +2,13 @@ from os import listdir
from pathlib import Path from pathlib import Path
from typing import Any, Dict, Union from typing import Any, Dict, Union
from libbot import sync import libbot
from libbot.sync import config_get, json_read
def _( def _(
key: str, key: str,
*args: str, *args: str,
locale: str = "en", locale: Union[str, None] = "en",
locales_root: Union[str, Path] = Path("locale"), locales_root: Union[str, Path] = Path("locale"),
) -> Any: ) -> Any:
"""Get value of locale string """Get value of locale string
@@ -17,20 +16,22 @@ def _(
### Args: ### Args:
* key (`str`): The last key of the locale's keys path. * key (`str`): The last key of the locale's keys path.
* *args (`list`): Path to key like: `dict[args][key]`. * *args (`list`): Path to key like: `dict[args][key]`.
* locale (`str`): Locale to looked up in. Defaults to `"en"`. * locale (`Union[str, None]`): Locale to looked up in. Defaults to `"en"`.
* locales_root (`Union[str, Path]`, *optional*): Folder where locales are located. Defaults to `Path("locale")`. * locales_root (`Union[str, Path]`, *optional*): Folder where locales are located. Defaults to `Path("locale")`.
### Returns: ### Returns:
* `Any`: Value of provided locale key. Is usually `str`, `dict` or `list` * `Any`: Value of provided locale key. Is usually `str`, `dict` or `list`
""" """
if locale is None: if locale is None:
locale = sync.config_get("locale") locale = libbot.sync.config_get("locale")
try: try:
this_dict = json_read(Path(f"{locales_root}/{locale}.json")) this_dict = libbot.sync.json_read(Path(f"{locales_root}/{locale}.json"))
except FileNotFoundError: except FileNotFoundError:
try: try:
this_dict = json_read(Path(f'{locales_root}/{config_get("locale")}.json')) this_dict = libbot.sync.json_read(
Path(f'{locales_root}/{libbot.sync.config_get("locale")}.json')
)
except FileNotFoundError: except FileNotFoundError:
return f'⚠️ Locale in config is invalid: could not get "{key}" in {args} from locale "{locale}"' return f'⚠️ Locale in config is invalid: could not get "{key}" in {args} from locale "{locale}"'
@@ -64,7 +65,7 @@ def in_all_locales(
valid_locales = [".".join(entry.split(".")[:-1]) for entry in files_locales] valid_locales = [".".join(entry.split(".")[:-1]) for entry in files_locales]
for lc in valid_locales: for lc in valid_locales:
try: try:
this_dict = json_read(Path(f"{locales_root}/{lc}.json")) this_dict = libbot.sync.json_read(Path(f"{locales_root}/{lc}.json"))
except FileNotFoundError: except FileNotFoundError:
continue continue
@@ -100,7 +101,7 @@ def in_every_locale(
valid_locales = [".".join(entry.split(".")[:-1]) for entry in files_locales] valid_locales = [".".join(entry.split(".")[:-1]) for entry in files_locales]
for lc in valid_locales: for lc in valid_locales:
try: try:
this_dict = json_read(Path(f"{locales_root}/{lc}.json")) this_dict = libbot.sync.json_read(Path(f"{locales_root}/{lc}.json"))
except FileNotFoundError: except FileNotFoundError:
continue continue

View File

@@ -102,7 +102,8 @@ class PyroClient(Client):
self.start_time: float = 0 self.start_time: float = 0
self.bot_locale: BotLocale = BotLocale( self.bot_locale: BotLocale = BotLocale(
(Path("locale") if locales_root is None else locales_root) default_locale=self.config["locale"],
locales_root=(Path("locale") if locales_root is None else locales_root)
) )
self.default_locale: str = self.bot_locale.default self.default_locale: str = self.bot_locale.default
self.locales: dict = self.bot_locale.locales self.locales: dict = self.bot_locale.locales
@@ -115,7 +116,7 @@ class PyroClient(Client):
self.scopes_placeholders: Dict[str, int] = {"owner": self.owner} self.scopes_placeholders: Dict[str, int] = {"owner": self.owner}
async def start(self, register_commands: bool = True): async def start(self, register_commands: bool = True) -> None:
await super().start() await super().start()
self.start_time = time() self.start_time = time()
@@ -151,7 +152,7 @@ class PyroClient(Client):
except BadRequest: except BadRequest:
logger.warning("Unable to send message to report chat.") logger.warning("Unable to send message to report chat.")
async def stop(self, exit_completely: bool = True): async def stop(self, exit_completely: bool = True) -> None:
try: try:
await self.send_message( await self.send_message(
chat_id=self.owner chat_id=self.owner
@@ -269,7 +270,7 @@ class PyroClient(Client):
def add_command( def add_command(
self, self,
command: str, command: str,
): ) -> None:
"""Add command to the bot's internal commands list """Add command to the bot's internal commands list
### Args: ### Args:
@@ -288,7 +289,7 @@ class PyroClient(Client):
async def register_commands( async def register_commands(
self, command_sets: Union[List[CommandSet], None] = None self, command_sets: Union[List[CommandSet], None] = None
): ) -> None:
"""Register commands stored in bot's 'commands' attribute""" """Register commands stored in bot's 'commands' attribute"""
if command_sets is None: if command_sets is None:
@@ -317,7 +318,9 @@ class PyroClient(Client):
language_code=command_set.language_code, language_code=command_set.language_code,
) )
async def remove_commands(self, command_sets: Union[List[CommandSet], None] = None): async def remove_commands(
self, command_sets: Union[List[CommandSet], None] = None
) -> None:
"""Remove commands stored in bot's 'commands' attribute""" """Remove commands stored in bot's 'commands' attribute"""
if command_sets is None: if command_sets is None:

View File

@@ -55,7 +55,9 @@ def nested_set(target: dict, value: Any, *path: str, create_missing=True) -> dic
elif create_missing: elif create_missing:
d = d.setdefault(key, {}) d = d.setdefault(key, {})
else: else:
return target raise KeyError(
f"Key '{key}' is not found under path provided ({path}) and create_missing is False"
)
if path[-1] in d or create_missing: if path[-1] in d or create_missing:
d[path[-1]] = value d[path[-1]] = value
return target return target

20
tests/conftest.py Normal file
View File

@@ -0,0 +1,20 @@
from pathlib import Path
import pytest
from libbot.i18n import BotLocale
@pytest.fixture()
def location_config() -> Path:
return Path("tests/config.json")
@pytest.fixture()
def location_locale() -> Path:
return Path("tests/data/locale/")
@pytest.fixture()
def bot_locale(location_locale: Path) -> BotLocale:
return BotLocale(locales_root=location_locale)

11
tests/data/locale/en.json Normal file
View File

@@ -0,0 +1,11 @@
{
"foo": "bar",
"messages": {
"example": "okay"
},
"callbacks": {
"default": {
"nested": "sure"
}
}
}

11
tests/data/locale/uk.json Normal file
View File

@@ -0,0 +1,11 @@
{
"foo": "бар",
"messages": {
"example": "окей"
},
"callbacks": {
"default": {
"nested": "авжеж"
}
}
}

59
tests/test_bot_locale.py Normal file
View File

@@ -0,0 +1,59 @@
from pathlib import Path
from typing import Any, List, Union
import pytest
from libbot.i18n import BotLocale
@pytest.mark.parametrize(
"key, args, locale, expected",
[
("foo", [], None, "bar"),
("foo", [], "uk", "бар"),
("example", ["messages"], None, "okay"),
("example", ["messages"], "uk", "окей"),
("nested", ["callbacks", "default"], None, "sure"),
("nested", ["callbacks", "default"], "uk", "авжеж"),
],
)
def test_bot_locale_get(
key: str,
args: List[str],
locale: Union[str, None],
expected: Any,
bot_locale: BotLocale,
):
assert (
bot_locale._(key, *args, locale=locale)
if locale is not None
else bot_locale._(key, *args)
) == expected
@pytest.mark.parametrize(
"key, args, expected",
[
("foo", [], ["bar", "бар"]),
("example", ["messages"], ["okay", "окей"]),
("nested", ["callbacks", "default"], ["sure", "авжеж"]),
],
)
def test_i18n_in_all_locales(
key: str, args: List[str], expected: Any, bot_locale: BotLocale
):
assert (bot_locale.in_all_locales(key, *args)) == expected
@pytest.mark.parametrize(
"key, args, expected",
[
("foo", [], {"en": "bar", "uk": "бар"}),
("example", ["messages"], {"en": "okay", "uk": "окей"}),
("nested", ["callbacks", "default"], {"en": "sure", "uk": "авжеж"}),
],
)
def test_i18n_in_every_locale(
key: str, args: List[str], expected: Any, bot_locale: BotLocale
):
assert (bot_locale.in_every_locale(key, *args)) == expected

View File

@@ -14,11 +14,8 @@ from libbot import config_get, config_set
(["bot_token", "bot"], "sample_token"), (["bot_token", "bot"], "sample_token"),
], ],
) )
async def test_config_get_valid(args: List[str], expected: str): async def test_config_get_valid(args: List[str], expected: str, location_config: Path):
assert ( assert await config_get(args[0], *args[1:], config_file=location_config) == expected
await config_get(args[0], *args[1:], config_file=Path("tests/config.json"))
== expected
)
@pytest.mark.asyncio @pytest.mark.asyncio
@@ -28,10 +25,12 @@ async def test_config_get_valid(args: List[str], expected: str):
(["bot_stonks", "bot"], pytest.raises(KeyError)), (["bot_stonks", "bot"], pytest.raises(KeyError)),
], ],
) )
async def test_config_get_invalid(args: List[str], expected: Any): async def test_config_get_invalid(
args: List[str], expected: Any, location_config: Path
):
with expected: with expected:
assert ( assert (
await config_get(args[0], *args[1:], config_file=Path("tests/config.json")) await config_get(args[0], *args[1:], config_file=location_config)
== expected == expected
) )
@@ -44,6 +43,6 @@ async def test_config_get_invalid(args: List[str], expected: Any):
("bot_token", ["bot"], "sample_token"), ("bot_token", ["bot"], "sample_token"),
], ],
) )
async def test_config_set(key: str, path: List[str], value: Any): async def test_config_set(key: str, path: List[str], value: Any, location_config: Path):
await config_set(key, value, *path, config_file=Path("tests/config.json")) await config_set(key, value, *path, config_file=location_config)
assert await config_get(key, *path, config_file=Path("tests/config.json")) == value assert await config_get(key, *path, config_file=location_config) == value

View File

@@ -13,11 +13,8 @@ from libbot import sync
(["bot_token", "bot"], "sample_token"), (["bot_token", "bot"], "sample_token"),
], ],
) )
def test_config_get_valid(args: List[str], expected: str): def test_config_get_valid(args: List[str], expected: str, location_config: Path):
assert ( assert sync.config_get(args[0], *args[1:], config_file=location_config) == expected
sync.config_get(args[0], *args[1:], config_file=Path("tests/config.json"))
== expected
)
@pytest.mark.parametrize( @pytest.mark.parametrize(
@@ -26,11 +23,10 @@ def test_config_get_valid(args: List[str], expected: str):
(["bot_stonks", "bot"], pytest.raises(KeyError)), (["bot_stonks", "bot"], pytest.raises(KeyError)),
], ],
) )
def test_config_get_invalid(args: List[str], expected: Any): def test_config_get_invalid(args: List[str], expected: Any, location_config: Path):
with expected: with expected:
assert ( assert (
sync.config_get(args[0], *args[1:], config_file=Path("tests/config.json")) sync.config_get(args[0], *args[1:], config_file=location_config) == expected
== expected
) )
@@ -41,6 +37,6 @@ def test_config_get_invalid(args: List[str], expected: Any):
("bot_token", ["bot"], "sample_token"), ("bot_token", ["bot"], "sample_token"),
], ],
) )
def test_config_set(key: str, path: List[str], value: Any): def test_config_set(key: str, path: List[str], value: Any, location_config: Path):
sync.config_set(key, value, *path, config_file=Path("tests/config.json")) sync.config_set(key, value, *path, config_file=location_config)
assert sync.config_get(key, *path, config_file=Path("tests/config.json")) == value assert sync.config_get(key, *path, config_file=location_config) == value

66
tests/test_i18n_async.py Normal file
View File

@@ -0,0 +1,66 @@
from pathlib import Path
from typing import Any, List, Union
import pytest
from libbot import i18n
@pytest.mark.asyncio
@pytest.mark.parametrize(
"key, args, locale, expected",
[
("foo", [], None, "bar"),
("foo", [], "uk", "бар"),
("example", ["messages"], None, "okay"),
("example", ["messages"], "uk", "окей"),
("nested", ["callbacks", "default"], None, "sure"),
("nested", ["callbacks", "default"], "uk", "авжеж"),
],
)
async def test_i18n_get(
key: str,
args: List[str],
locale: Union[str, None],
expected: Any,
location_locale: Path,
):
assert (
await i18n._(key, *args, locale=locale, locales_root=location_locale)
if locale is not None
else await i18n._(key, *args, locales_root=location_locale)
) == expected
@pytest.mark.asyncio
@pytest.mark.parametrize(
"key, args, expected",
[
("foo", [], ["bar", "бар"]),
("example", ["messages"], ["okay", "окей"]),
("nested", ["callbacks", "default"], ["sure", "авжеж"]),
],
)
async def test_i18n_in_all_locales(
key: str, args: List[str], expected: Any, location_locale: Path
):
assert (
await i18n.in_all_locales(key, *args, locales_root=location_locale)
) == expected
@pytest.mark.asyncio
@pytest.mark.parametrize(
"key, args, expected",
[
("foo", [], {"en": "bar", "uk": "бар"}),
("example", ["messages"], {"en": "okay", "uk": "окей"}),
("nested", ["callbacks", "default"], {"en": "sure", "uk": "авжеж"}),
],
)
async def test_i18n_in_every_locale(
key: str, args: List[str], expected: Any, location_locale: Path
):
assert (
await i18n.in_every_locale(key, *args, locales_root=location_locale)
) == expected

59
tests/test_i18n_sync.py Normal file
View File

@@ -0,0 +1,59 @@
from pathlib import Path
from typing import Any, List, Union
import pytest
from libbot.i18n import sync
@pytest.mark.parametrize(
"key, args, locale, expected",
[
("foo", [], None, "bar"),
("foo", [], "uk", "бар"),
("example", ["messages"], None, "okay"),
("example", ["messages"], "uk", "окей"),
("nested", ["callbacks", "default"], None, "sure"),
("nested", ["callbacks", "default"], "uk", "авжеж"),
],
)
def test_i18n_get(
key: str,
args: List[str],
locale: Union[str, None],
expected: Any,
location_locale: Path,
):
assert (
sync._(key, *args, locale=locale, locales_root=location_locale)
if locale is not None
else sync._(key, *args, locales_root=location_locale)
) == expected
@pytest.mark.parametrize(
"key, args, expected",
[
("foo", [], ["bar", "бар"]),
("example", ["messages"], ["okay", "окей"]),
("nested", ["callbacks", "default"], ["sure", "авжеж"]),
],
)
def test_i18n_in_all_locales(
key: str, args: List[str], expected: Any, location_locale: Path
):
assert (sync.in_all_locales(key, *args, locales_root=location_locale)) == expected
@pytest.mark.parametrize(
"key, args, expected",
[
("foo", [], {"en": "bar", "uk": "бар"}),
("example", ["messages"], {"en": "okay", "uk": "окей"}),
("nested", ["callbacks", "default"], {"en": "sure", "uk": "авжеж"}),
],
)
def test_i18n_in_every_locale(
key: str, args: List[str], expected: Any, location_locale: Path
):
assert (sync.in_every_locale(key, *args, locales_root=location_locale)) == expected

63
tests/test_nested_set.py Normal file
View File

@@ -0,0 +1,63 @@
from typing import Any, Dict, List
import pytest
from libbot import sync
@pytest.mark.parametrize(
"target, value, path, create_missing, expected",
[
({"foo": "bar"}, "rab", ["foo"], True, {"foo": "rab"}),
({"foo": "bar"}, {"123": 456}, ["foo"], True, {"foo": {"123": 456}}),
(
{"foo": {"bar": {}}},
True,
["foo", "bar", "test"],
True,
{"foo": {"bar": {"test": True}}},
),
(
{"foo": {"bar": {}}},
True,
["foo", "bar", "test"],
False,
{"foo": {"bar": {}}},
),
],
)
def test_nested_set_valid(
target: Dict[str, Any],
value: Any,
path: List[str],
create_missing: bool,
expected: Any,
):
assert (
sync.nested_set(target, value, *path, create_missing=create_missing)
) == expected
@pytest.mark.parametrize(
"target, value, path, create_missing, expected",
[
(
{"foo": {"bar": {}}},
True,
["foo", "bar", "test1", "test2"],
False,
KeyError,
),
],
)
def test_nested_set_invalid(
target: Dict[str, Any],
value: Any,
path: List[str],
create_missing: bool,
expected: Any,
):
with pytest.raises(expected):
assert (
sync.nested_set(target, value, *path, create_missing=create_missing)
) == expected

23
tox.ini Normal file
View File

@@ -0,0 +1,23 @@
[tox]
minversion = 3.8.0
envlist = py38, py39, py310, py311
isolated_build = true
[gh-actions]
python =
3.8: py38
3.9: py39
3.10: py310
3.11: py311
[testenv]
setenv =
PYTHONPATH = {toxinidir}
deps =
-r{toxinidir}/requirements/_.txt
-r{toxinidir}/requirements/dev.txt
-r{toxinidir}/requirements/pycord.txt
-r{toxinidir}/requirements/pyrogram.txt
-r{toxinidir}/requirements/speed.txt
commands =
pytest --basetemp={envtmpdir} --cov=libbot