diff --git a/pylib/anki/BUILD.bazel b/pylib/anki/BUILD.bazel index 84b29dcc5..4a24cec0f 100644 --- a/pylib/anki/BUILD.bazel +++ b/pylib/anki/BUILD.bazel @@ -24,7 +24,7 @@ _py_srcs = glob( exclude = [ "hooks_gen.py", ], -) +) + ["//pylib/anki/_vendor"] py_library( name = "anki", @@ -49,7 +49,7 @@ py_library( requirement("flask"), requirement("waitress"), requirement("markdown"), - requirement("stringcase"), + "//pylib/anki/_vendor:stringcase", ] + orjson_if_available(), ) diff --git a/pylib/anki/_backend/BUILD.bazel b/pylib/anki/_backend/BUILD.bazel index e60346b55..a4f54cddc 100644 --- a/pylib/anki/_backend/BUILD.bazel +++ b/pylib/anki/_backend/BUILD.bazel @@ -10,7 +10,7 @@ py_binary( ], deps = [ requirement("black"), - requirement("stringcase"), + "//pylib/anki/_vendor:stringcase", requirement("protobuf"), "//pylib/anki:proto", ], @@ -30,7 +30,7 @@ py_binary( ], deps = [ requirement("black"), - requirement("stringcase"), + "//pylib/anki/_vendor:stringcase", ], ) diff --git a/pylib/anki/_legacy.py b/pylib/anki/_legacy.py index 1c46bea3d..f38ba41c3 100644 --- a/pylib/anki/_legacy.py +++ b/pylib/anki/_legacy.py @@ -9,7 +9,7 @@ import pathlib import traceback from typing import Any, Callable, Union, no_type_check -import stringcase +from anki._vendor import stringcase VariableTarget = tuple[Any, str] DeprecatedAliasTarget = Union[Callable, VariableTarget] diff --git a/pylib/anki/_vendor/BUILD.bazel b/pylib/anki/_vendor/BUILD.bazel new file mode 100644 index 000000000..15d475f7e --- /dev/null +++ b/pylib/anki/_vendor/BUILD.bazel @@ -0,0 +1,18 @@ +# export stringcase as a separate python library as well, as our build tools need it +py_library( + name = "stringcase", + srcs = ["stringcase.py"], + imports = [ + ".", + ], + visibility = ["//visibility:public"], +) + +filegroup( + name = "_vendor", + srcs = [ + "__init__.py", + "stringcase.py", + ], + visibility = ["//pylib:__subpackages__"], +) diff --git a/pylib/anki/_vendor/__init__.py b/pylib/anki/_vendor/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/pylib/anki/_vendor/stringcase.py b/pylib/anki/_vendor/stringcase.py new file mode 100644 index 000000000..517e43dbc --- /dev/null +++ b/pylib/anki/_vendor/stringcase.py @@ -0,0 +1,257 @@ +# stringcase 1.2.0 with python warning fix applied +# MIT: https://github.com/okunishinishi/python-stringcase + +# type: ignore + +""" +String convert functions +""" + +import re + + +def camelcase(string): + """Convert string into camel case. + + Args: + string: String to convert. + + Returns: + string: Camel case string. + + """ + + string = re.sub(r"\w[\s\W]+\w", "", str(string)) + if not string: + return string + return lowercase(string[0]) + re.sub( + r"[\-_\.\s]([a-z])", lambda matched: uppercase(matched.group(1)), string[1:] + ) + + +def capitalcase(string): + """Convert string into capital case. + First letters will be uppercase. + + Args: + string: String to convert. + + Returns: + string: Capital case string. + + """ + + string = str(string) + if not string: + return string + return uppercase(string[0]) + string[1:] + + +def constcase(string): + """Convert string into upper snake case. + Join punctuation with underscore and convert letters into uppercase. + + Args: + string: String to convert. + + Returns: + string: Const cased string. + + """ + + return uppercase(snakecase(string)) + + +def lowercase(string): + """Convert string into lower case. + + Args: + string: String to convert. + + Returns: + string: Lowercase case string. + + """ + + return str(string).lower() + + +def pascalcase(string): + """Convert string into pascal case. + + Args: + string: String to convert. + + Returns: + string: Pascal case string. + + """ + + return capitalcase(camelcase(string)) + + +def pathcase(string): + """Convert string into path case. + Join punctuation with slash. + + Args: + string: String to convert. + + Returns: + string: Path cased string. + + """ + string = snakecase(string) + if not string: + return string + return re.sub(r"_", "/", string) + + +def backslashcase(string): + """Convert string into spinal case. + Join punctuation with backslash. + + Args: + string: String to convert. + + Returns: + string: Spinal cased string. + + """ + str1 = re.sub(r"_", r"\\", snakecase(string)) + + return str1 + # return re.sub(r"\\n", "", str1)) # TODO: make regex fot \t ... + + +def sentencecase(string): + """Convert string into sentence case. + First letter capped and each punctuations are joined with space. + + Args: + string: String to convert. + + Returns: + string: Sentence cased string. + + """ + joiner = " " + string = re.sub(r"[\-_\.\s]", joiner, str(string)) + if not string: + return string + return capitalcase( + trimcase( + re.sub( + r"[A-Z]", lambda matched: joiner + lowercase(matched.group(0)), string + ) + ) + ) + + +def snakecase(string): + """Convert string into snake case. + Join punctuation with underscore + + Args: + string: String to convert. + + Returns: + string: Snake cased string. + + """ + + string = re.sub(r"[\-\.\s]", "_", str(string)) + if not string: + return string + return lowercase(string[0]) + re.sub( + r"[A-Z]", lambda matched: "_" + lowercase(matched.group(0)), string[1:] + ) + + +def spinalcase(string): + """Convert string into spinal case. + Join punctuation with hyphen. + + Args: + string: String to convert. + + Returns: + string: Spinal cased string. + + """ + + return re.sub(r"_", "-", snakecase(string)) + + +def dotcase(string): + + """Convert string into dot case. + Join punctuation with dot. + + Args: + string: String to convert. + + Returns: + string: Dot cased string. + + """ + + return re.sub(r"_", ".", snakecase(string)) + + +def titlecase(string): + """Convert string into sentence case. + First letter capped while each punctuations is capitalsed + and joined with space. + + Args: + string: String to convert. + + Returns: + string: Title cased string. + + """ + + return " ".join([capitalcase(word) for word in snakecase(string).split("_")]) + + +def trimcase(string): + """Convert string into trimmed string. + + Args: + string: String to convert. + + Returns: + string: Trimmed case string + """ + + return str(string).strip() + + +def uppercase(string): + """Convert string into upper case. + + Args: + string: String to convert. + + Returns: + string: Uppercase case string. + + """ + + return str(string).upper() + + +def alphanumcase(string): + """Cuts all non-alphanumeric symbols, + i.e. cuts all expect except 0-9, a-z and A-Z. + + Args: + string: String to convert. + + Returns: + string: String with cutted non-alphanumeric symbols. + + """ + # return filter(str.isalnum, str(string)) + return re.sub(r"\W+", "", string) diff --git a/pylib/tools/BUILD.bazel b/pylib/tools/BUILD.bazel index 3c97bdc7c..ef417a112 100644 --- a/pylib/tools/BUILD.bazel +++ b/pylib/tools/BUILD.bazel @@ -42,7 +42,7 @@ py_binary( visibility = ["//pylib:__subpackages__"], deps = [ requirement("black"), - requirement("stringcase"), + "//pylib/anki/_vendor:stringcase", ], ) @@ -53,7 +53,7 @@ py_binary( ], tags = ["manual"], deps = [ - requirement("stringcase"), + "//pylib/anki/_vendor:stringcase", ], ) diff --git a/python/requirements.in b/python/requirements.in index d364223ab..1fcc4aa62 100644 --- a/python/requirements.in +++ b/python/requirements.in @@ -19,7 +19,6 @@ pytest requests[socks] send2trash snakeviz -stringcase waitress>=2.0.0 fluent.syntax types-decorator diff --git a/python/requirements.txt b/python/requirements.txt index 44f65b4c1..ffec3e97a 100644 --- a/python/requirements.txt +++ b/python/requirements.txt @@ -129,8 +129,6 @@ snakeviz==2.1.0 # via -r requirements.in soupsieve==2.2.1 # via beautifulsoup4 -stringcase==1.2.0 - # via -r requirements.in toml==0.10.2 # via # mypy diff --git a/qt/BUILD.bazel b/qt/BUILD.bazel index 0344f763c..9413bc92c 100644 --- a/qt/BUILD.bazel +++ b/qt/BUILD.bazel @@ -11,7 +11,7 @@ py_binary( deps = [ "//pylib/tools:hookslib", requirement("black"), - requirement("stringcase"), + "//pylib/anki/_vendor:stringcase", ], ) diff --git a/scripts/copyright_headers.py b/scripts/copyright_headers.py index cf50238a4..20f117417 100644 --- a/scripts/copyright_headers.py +++ b/scripts/copyright_headers.py @@ -6,12 +6,13 @@ import sys from pathlib import Path nonstandard_header = { - "python/pyqt5/install_pyqt5.py", - "python/pyqt6/install_pyqt6.py", + "pylib/anki/_vendor/stringcase.py", "pylib/anki/importing/pauker.py", "pylib/anki/importing/supermemo_xml.py", "pylib/anki/statsbg.py", "pylib/tools/protoc-gen-mypy.py", + "python/pyqt5/install_pyqt5.py", + "python/pyqt6/install_pyqt6.py", "qt/aqt/mpv.py", "qt/aqt/winpaths.py", } diff --git a/ts/lib/BUILD.bazel b/ts/lib/BUILD.bazel index 14bb8df24..9992053cc 100644 --- a/ts/lib/BUILD.bazel +++ b/ts/lib/BUILD.bazel @@ -13,9 +13,10 @@ py_binary( ], deps = [ requirement("black"), - requirement("stringcase"), + "//pylib/anki/_vendor:stringcase", ], ) + _i18n_generated = [ "ftl.ts", "i18n/modules.ts",