Make PyICU optional

Fix more locale issues
Update README.md
This commit is contained in:
Timmy Welch 2023-04-18 21:03:50 -07:00
parent e2dfcc91ce
commit bf55037690
No known key found for this signature in database
11 changed files with 129 additions and 21 deletions

View File

@ -33,21 +33,13 @@ For details, screen-shots, and more, visit [the Wiki](https://github.com/comicta
## Installation
It is reccomended to either use the Binaries or a package manager for the best experience
### Binaries
Windows and macOS binaries are provided in the [Releases Page](https://github.com/comictagger/comictagger/releases).
Windows, Linux and MacOS binaries are provided in the [Releases Page](https://github.com/comictagger/comictagger/releases).
Just unzip the archive in any folder and run, no additional installation steps are required.
### PIP installation
A pip package is provided, you can install it with:
```
$ pip3 install comictagger[GUI]
```
There are two optional dependencies GUI and CBR. You can install the optional dependencies by specifying one or more of `GUI`,`CBR` or `all` in braces e.g. `comictagger[CBR,GUI]`
Unzip the archive in any folder and run, no additional installation steps are required.
### Chocolatey installation (Windows only)
@ -55,12 +47,26 @@ A [Chocolatey package](https://community.chocolatey.org/packages/comictagger), m
```powershell
choco install comictagger
```
### PyPi installation
! Please note that pages may not be sorted correctly if ICU is not installed on Linux and MacOS.
If you have issues installing ICU please see the PyICU documentation [here](https://pyicu.org)
A PyPi package is provided, you can install it with:
```
$ pip3 install comictagger[GUI,ICU]
```
There are several optional dependencies GUI, CBR, 7Z and ICU. You can install the optional dependencies by specifying one or more of `GUI`,`CBR` or `all` in braces e.g. `comictagger[CBR,GUI,ICU]`
### From source
1. Ensure you have python 3.9 installed
2. Clone this repository `git clone https://github.com/comictagger/comictagger.git`
3. `pip3 install -r requirements_dev.txt`
7. `pip3 install .` or `pip3 install .[GUI]`
7. `pip3 install .` or `pip3 install .[GUI,ICU]`
## Contributors

View File

@ -22,7 +22,6 @@ import shutil
import sys
from typing import cast
import natsort
import wordninja
from comicapi import filenamelexer, filenameparser, utils
@ -280,7 +279,7 @@ class ComicArchive:
# seems like some archive creators are on Windows, and don't know about case-sensitivity!
if sort_list:
files = cast(list[str], natsort.os_sorted(files))
files = cast(list[str], utils.os_sorted(files))
# make a sub-list of image files
self.page_list = []

View File

@ -15,25 +15,69 @@
from __future__ import annotations
import json
import locale
import logging
import os
import pathlib
import unicodedata
from collections import defaultdict
from collections.abc import Mapping
from collections.abc import Iterable, Mapping
from shutil import which # noqa: F401
from typing import Any
import natsort
import pycountry
import rapidfuzz.fuzz
import comicapi.data
try:
import icu
del icu
icu_available = True
except ImportError:
icu_available = False
logger = logging.getLogger(__name__)
class UtilsVars:
already_fixed_encoding = False
def _custom_key(tup):
lst = []
for x in natsort.os_sort_keygen()(tup):
ret = x
if len(x) > 1 and isinstance(x[1], int) and isinstance(x[0], str) and x[0] == "":
ret = (str(x[1]), *x[1:])
lst.append(ret)
return tuple(lst)
def os_sorted(lst: Iterable) -> Iterable:
if icu_available:
raise Exception("fuck off")
return natsort.os_sorted(lst)
return sorted(lst, key=_custom_key)
def save_locale() -> dict[int, tuple[str | None, str | None]]:
locales: dict[int, tuple[str | None, str | None]] = {
locale.LC_ALL: (None, None),
locale.LC_COLLATE: (None, None),
locale.LC_CTYPE: (None, None),
locale.LC_MESSAGES: (None, None),
locale.LC_MONETARY: (None, None),
locale.LC_NUMERIC: (None, None),
locale.LC_TIME: (None, None),
}
for x in locales:
locales[x] = locale.getlocale(x)
return locales
def set_locale(locales: dict[int, tuple[str | None, str | None]]) -> None:
for x, value in locales.items():
locale.setlocale(x, value)
def combine_notes(existing_notes: str | None, new_notes: str | None, split: str) -> str:

View File

@ -9,14 +9,20 @@ import types
import settngs
from comicapi.utils import save_locale, set_locale
from comictaggerlib.graphics import graphics_path
from comictalker.comictalker import ComicTalker
logger = logging.getLogger("comictagger")
try:
qt_available = True
loc = save_locale()
from PyQt5 import QtCore, QtGui, QtWidgets
qt_available = True
set_locale(loc)
def show_exception_box(log_msg: str) -> None:
"""Checks if a QApplication instance is available and shows a messagebox with the exception message.
If unavailable (non-console application), log an additional notice.

View File

@ -25,11 +25,15 @@ import tempfile
import requests
from comicapi.utils import save_locale, set_locale
from comictaggerlib import ctversion
try:
loc = save_locale()
from PyQt5 import QtCore, QtNetwork
set_locale(loc)
qt_available = True
except ImportError:
qt_available = False

View File

@ -25,6 +25,7 @@ import settngs
import comicapi
import comictalker
from comicapi.utils import save_locale, set_locale
from comictaggerlib import cli, ctsettings
from comictaggerlib.ctversion import version
from comictaggerlib.log import setup_logging
@ -36,9 +37,13 @@ else:
logger = logging.getLogger("comictagger")
try:
loc = save_locale()
from comictaggerlib import gui
set_locale(loc)
qt_available = gui.qt_available
except Exception:
logger.exception("Qt unavailable")

View File

@ -6,13 +6,17 @@ import io
import logging
import traceback
from comicapi.utils import save_locale, set_locale
from comictaggerlib.graphics import graphics_path
logger = logging.getLogger(__name__)
try:
loc = save_locale()
from PyQt5 import QtGui, QtWidgets
set_locale(loc)
qt_available = True
except ImportError:
qt_available = False

1
requirements-ICU.txt Normal file
View File

@ -0,0 +1 @@
pyicu; sys_platform == 'linux' or sys_platform == 'darwin'

View File

@ -5,7 +5,6 @@ natsort>=8.1.0
pathvalidate
pillow>=9.1.0, <10
pycountry
#pyicu; sys_platform == 'linux' or sys_platform == 'darwin'
rapidfuzz>=2.12.0
requests==2.*
settngs==0.6.2

View File

@ -12,7 +12,7 @@ from testing.filenames import datadir
@pytest.mark.xfail(not comicapi.archivers.rar.rar_support, reason="rar support")
def test_getPageNameList():
def test_get_page_name_list():
c = comicapi.comicarchive.ComicArchive(datadir / "fake_cbr.cbr")
assert c.seems_to_be_a_comic_archive()
pageNameList = c.get_page_name_list()

View File

@ -7,6 +7,46 @@ import pytest
import comicapi.utils
def test_os_sorted():
page_name_list = [
"cover.jpg",
"Page1.jpeg",
"!cover.jpg",
"page4.webp",
"test/!cover.tar.gz",
"!cover.tar.gz",
"00.jpg",
"ignored.txt",
"page0.jpg",
"test/00.tar.gz",
".ignored.jpg",
"Page3.gif",
"!cover.tar.gz",
"Page2.png",
"page10.jpg",
"!cover",
]
assert comicapi.utils.os_sorted(page_name_list) == [
"!cover",
"!cover.jpg",
"!cover.tar.gz",
"!cover.tar.gz", # Depending on locale punctuation or numbers might come first (Linux, MacOS)
".ignored.jpg",
"00.jpg",
"cover.jpg",
"ignored.txt",
"page0.jpg",
"Page1.jpeg",
"Page2.png",
"Page3.gif",
"page4.webp",
"page10.jpg",
"test/!cover.tar.gz",
"test/00.tar.gz",
]
def test_recursive_list_with_file(tmp_path) -> None:
foo_png = tmp_path / "foo.png"
foo_png.write_text("not a png")