Skip to content

Commit a42632c

Browse files
committed
rel 2024.1
1 parent 6d2b091 commit a42632c

File tree

12 files changed

+116
-46
lines changed

12 files changed

+116
-46
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ patch-level version changes can be found in [commit messages](../../commits/mast
99
- use ruff
1010
- code quality improvements
1111
- fix 'Can't download packs with ":" (Colon) in it' - https://github.com/FHPythonUtils/SigStickers/issues/3
12+
- 98% test coverage
1213

1314
## 2024 - 2024/01/07
1415

documentation/reference/sigstickers/caching.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,12 @@ Get the appropriate cache verification function based on version.
2525
#### Returns
2626

2727
-------
28-
- `callable` - Cache verification function
28+
Callable[[dict[str, Any]], bool]: Cache verification function
2929

3030
#### Signature
3131

3232
```python
33-
def _get_verify_function(version: int): ...
33+
def _get_verify_function(version: int) -> Callable[[dict[str, Any]], bool]: ...
3434
```
3535

3636

documentation/reference/sigstickers/cli.md

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
## cli
1212

13-
[Show source in cli.py:12](../../../sigstickers/cli.py#L12)
13+
[Show source in cli.py:17](../../../sigstickers/cli.py#L17)
1414

1515
CLI entry point.
1616

@@ -24,12 +24,16 @@ def cli() -> None: ...
2424

2525
## main
2626

27-
[Show source in cli.py:35](../../../sigstickers/cli.py#L35)
27+
[Show source in cli.py:40](../../../sigstickers/cli.py#L40)
2828

29-
Main function to download sticker packs.
29+
Download, and convert sticker packs.
3030

3131
#### Signature
3232

3333
```python
34-
def main(packs): ...
35-
```
34+
def main(packs: list[str], cwd: Path = DEFAULT_CWD) -> int: ...
35+
```
36+
37+
#### See also
38+
39+
- [DEFAULT_CWD](./downloader.md#default_cwd)

documentation/reference/sigstickers/downloader.md

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,11 @@
99
- [convert_pack](#convert_pack)
1010
- [convert_with_pil](#convert_with_pil)
1111
- [download_pack](#download_pack)
12-
- [files_to_str](#files_to_str)
1312
- [save_sticker](#save_sticker)
1413

1514
## assure_dir_exists
1615

17-
[Show source in downloader.py:21](../../../sigstickers/downloader.py#L21)
16+
[Show source in downloader.py:22](../../../sigstickers/downloader.py#L22)
1817

1918
Make the directory if it does not exist.
2019

@@ -38,7 +37,7 @@ def assure_dir_exists(*parts: Path | str) -> Path: ...
3837

3938
## convert_pack
4039

41-
[Show source in downloader.py:141](../../../sigstickers/downloader.py#L141)
40+
[Show source in downloader.py:139](../../../sigstickers/downloader.py#L139)
4241

4342
Convert the webp images into png and gif images.
4443

@@ -52,14 +51,14 @@ Convert the webp images into png and gif images.
5251
#### Signature
5352

5453
```python
55-
async def convert_pack(swd: Path, pack_name: Path, no_cache=False): ...
54+
async def convert_pack(swd: Path, pack_name: Path, no_cache: bool = False) -> None: ...
5655
```
5756

5857

5958

6059
## convert_with_pil
6160

62-
[Show source in downloader.py:107](../../../sigstickers/downloader.py#L107)
61+
[Show source in downloader.py:105](../../../sigstickers/downloader.py#L105)
6362

6463
Convert the webp file to png.
6564

@@ -83,7 +82,7 @@ def convert_with_pil(input_path: Path) -> list[str]: ...
8382

8483
## download_pack
8584

86-
[Show source in downloader.py:67](../../../sigstickers/downloader.py#L67)
85+
[Show source in downloader.py:65](../../../sigstickers/downloader.py#L65)
8786

8887
Download a sticker pack.
8988

@@ -104,27 +103,19 @@ Download a sticker pack.
104103

105104
```python
106105
async def download_pack(
107-
pack_id: str, pack_key: str, cwd: Path = Path.cwd()
106+
pack_id: str, pack_key: str, cwd: Path = DEFAULT_CWD
108107
) -> tuple[Path, Path]: ...
109108
```
110109

110+
#### See also
111111

112-
113-
## files_to_str
114-
115-
[Show source in downloader.py:186](../../../sigstickers/downloader.py#L186)
116-
117-
#### Signature
118-
119-
```python
120-
def files_to_str(files: list[Path]) -> list[str]: ...
121-
```
112+
- [DEFAULT_CWD](#default_cwd)
122113

123114

124115

125116
## save_sticker
126117

127-
[Show source in downloader.py:38](../../../sigstickers/downloader.py#L38)
118+
[Show source in downloader.py:39](../../../sigstickers/downloader.py#L39)
128119

129120
Save a sticker.
130121

pyproject.toml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "sigstickers"
3-
version = "2024"
3+
version = "2024.1"
44
license = "mit"
55
description = "Download sticker packs from Signal"
66
authors = ["FredHappyface"]
@@ -37,8 +37,6 @@ handsdown = "^2.1.0"
3737
coverage = "^7.4.4"
3838
pytest-asyncio = "^0.23.5.post1"
3939

40-
41-
4240
[tool.ruff]
4341
line-length = 100
4442
indent-width = 4
@@ -72,6 +70,7 @@ line-ending = "lf"
7270
[tool.pyright]
7371
venvPath = "."
7472
venv = ".venv"
73+
7574
[tool.tox]
7675
legacy_tox_ini = """
7776
[tox]

sigstickers/caching.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
import json
66
from pathlib import Path
7-
from typing import Any
7+
from typing import Any, Callable
88

99
from loguru import logger
1010

@@ -93,7 +93,7 @@ def create_converted(pack_name: Path, data: dict) -> None:
9393
cache.write_text(json.dumps(data), encoding="utf-8")
9494

9595

96-
def _get_verify_function(version: int):
96+
def _get_verify_function(version: int) -> Callable[[dict[str, Any]], bool]:
9797
"""Get the appropriate cache verification function based on version.
9898
9999
Args:
@@ -102,7 +102,7 @@ def _get_verify_function(version: int):
102102
103103
Returns:
104104
-------
105-
callable: Cache verification function
105+
Callable[[dict[str, Any]], bool]: Cache verification function
106106
107107
"""
108108
return {

sigstickers/cli.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,16 @@
55
import asyncio
66
import functools
77
import operator
8+
from pathlib import Path
89
from sys import exit as sysexit
910
from urllib import parse
1011

1112
from loguru import logger
1213

13-
from sigstickers.downloader import convert_pack, download_pack
14+
from sigstickers.downloader import DEFAULT_CWD, convert_pack, download_pack
1415

1516

16-
def cli() -> None:
17+
def cli() -> None: # pragma: no cover
1718
"""CLI entry point."""
1819
parser = argparse.ArgumentParser("Welcome to SigSticker, providing all of your sticker needs")
1920
parser.add_argument(
@@ -33,11 +34,11 @@ def cli() -> None:
3334
if not name:
3435
break
3536
packs.append(name)
36-
return main(packs)
37+
sysexit(main(packs))
3738

3839

39-
def main(packs) -> None:
40-
"""Main function to download sticker packs."""
40+
def main(packs: list[str], cwd: Path = DEFAULT_CWD) -> int:
41+
"""Download, and convert sticker packs."""
4142
for pack in packs:
4243
pack_attrs: dict[str, list[str]] = parse.parse_qs(parse.urlparse(pack).fragment)
4344
if {"pack_id", "pack_key"} > pack_attrs.keys():
@@ -46,10 +47,11 @@ def main(packs) -> None:
4647
"addstickers/#pack_id=9acc9e8aba563d26a4994e69263e3b25&"
4748
"pack_key=5a6dff3948c28efb9b7aaf93ecc375c69fc316e78077ed26867a14d10a0f6a12"
4849
)
49-
sysexit(1)
50+
return 1
5051

5152
downloaded = asyncio.run(
52-
download_pack("".join(pack_attrs["pack_id"]), "".join(pack_attrs["pack_key"]))
53+
download_pack("".join(pack_attrs["pack_id"]), "".join(pack_attrs["pack_key"]), cwd=cwd)
5354
)
5455

5556
asyncio.run(convert_pack(*downloaded))
57+
return 0

sigstickers/downloader.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
from sigstickers.caching import create_converted, verify_converted
1717

1818
UNKNOWN = "🤷‍♂️"
19+
DEFAULT_CWD = Path.cwd()
1920

2021

2122
def assure_dir_exists(*parts: Path | str) -> Path:
@@ -61,7 +62,7 @@ def _sanitize_filename(filename: str) -> str:
6162
return unicodedata.normalize("NFKD", sanitized_filename).encode("ascii", "ignore").decode()
6263

6364

64-
async def download_pack(pack_id: str, pack_key: str, cwd: Path = Path.cwd()) -> tuple[Path, Path]:
65+
async def download_pack(pack_id: str, pack_key: str, cwd: Path = DEFAULT_CWD) -> tuple[Path, Path]:
6566
"""Download a sticker pack.
6667
6768
Args:
@@ -135,7 +136,7 @@ def convert_with_pil(input_path: Path) -> list[str]:
135136
return [png_file, gif_file]
136137

137138

138-
async def convert_pack(swd: Path, pack_name: Path, *, no_cache=False) -> None:
139+
async def convert_pack(swd: Path, pack_name: Path, *, no_cache: bool = False) -> None:
139140
"""Convert the webp images into png and gif images.
140141
141142
Args:
@@ -166,7 +167,8 @@ async def convert_pack(swd: Path, pack_name: Path, *, no_cache=False) -> None:
166167
converted_files.append(converted.result())
167168
end = time.time()
168169
logger.info(
169-
f"Time taken to convert {len(converted_files)}/{len(webp_files)} stickers - {end - start:.3f}s"
170+
f"Time taken to convert {len(converted_files)}/{len(webp_files)} "
171+
f"stickers - {end - start:.3f}s"
170172
)
171173

172174
logger.info("")
@@ -175,10 +177,10 @@ async def convert_pack(swd: Path, pack_name: Path, *, no_cache=False) -> None:
175177
data={
176178
"version": 2,
177179
"converted_files": converted_files,
178-
"webp_files": files_to_str(webp_files),
180+
"webp_files": _files_to_str(webp_files),
179181
},
180182
)
181183

182184

183-
def files_to_str(files: list[Path]) -> list[str]:
185+
def _files_to_str(files: list[Path]) -> list[str]:
184186
return [str(x.absolute()) for x in files]

tests/test_caching.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
file_exists = "pyproject.toml"
1111
file_exists_2 = ".gitignore"
1212

13+
file_not_exists = "file/not/exists"
14+
1315

1416
def test_verify_converted_v1() -> None:
1517
pack_name = "Test_Pack_v1"
@@ -23,6 +25,18 @@ def test_verify_converted_v1() -> None:
2325
assert verify_converted(Path(pack_name))
2426

2527

28+
def test_verify_converted_v1_not_exists() -> None:
29+
pack_name = "Test_Pack_v1_not_exists"
30+
cache_file = CACHE_DIR / pack_name
31+
cache_data = {
32+
"info": {"swd": file_not_exists},
33+
"converted": {"converted": 10, "total": 10},
34+
}
35+
cache_file.write_text(json.dumps(cache_data))
36+
37+
assert not verify_converted(Path(pack_name))
38+
39+
2640
def test_verify_converted_v2() -> None:
2741
pack_name = "Test_Pack_v2"
2842
cache_file = CACHE_DIR / pack_name
@@ -36,6 +50,32 @@ def test_verify_converted_v2() -> None:
3650
assert verify_converted(Path(pack_name))
3751

3852

53+
def test_verify_converted_v2_partial_convert() -> None:
54+
pack_name = "Test_Pack_v2_partial_convert"
55+
cache_file = CACHE_DIR / pack_name
56+
cache_data = {
57+
"version": 2,
58+
"webp_files": [file_exists, file_exists_2],
59+
"converted_files": [[file_exists]],
60+
}
61+
cache_file.write_text(json.dumps(cache_data))
62+
63+
assert not verify_converted(Path(pack_name))
64+
65+
66+
def test_verify_converted_v2_not_exists() -> None:
67+
pack_name = "Test_Pack_v2_not_exists"
68+
cache_file = CACHE_DIR / pack_name
69+
cache_data = {
70+
"version": 2,
71+
"webp_files": [file_exists, file_not_exists],
72+
"converted_files": [[file_exists], [file_exists_2]],
73+
}
74+
cache_file.write_text(json.dumps(cache_data))
75+
76+
assert not verify_converted(Path(pack_name))
77+
78+
3979
def test_create_converted() -> None:
4080
pack_name = "Test_Pack"
4181
cache_data = {"example_key": "example_value"}

tests/test_cli.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
from __future__ import annotations
2+
3+
import asyncio
4+
import sys
5+
from pathlib import Path
6+
7+
THISDIR = Path(__file__).resolve().parent
8+
PROJECT_DIR = THISDIR.parent
9+
sys.path.insert(0, str(PROJECT_DIR))
10+
11+
from sigstickers.cli import main
12+
13+
cwd = THISDIR / "data"
14+
15+
16+
def test_cli() -> None:
17+
assert main(["https://signal.art/addstickers/#pack_id=b676ec334ee2f771cadff5d095971e8c&pack_key=c957a57000626a2dc3cb69bf0e79c91c6b196b74d4d6ca1cbb830d3ad0ad4e36"], cwd=cwd,) == 0
18+
assert len(list(Path(f"{cwd}/downloads/DonutTheDog/png").iterdir())) == 28
19+
20+
21+
def test_cli_invalid_url() -> None:
22+
assert main(["https://signal.art/addstickers/#pack_key=c957a57000626a2dc3cb69bf0e79c91c6b196b74d4d6ca1cbb830d3ad0ad4e36"], cwd=cwd,) == 1

0 commit comments

Comments
 (0)