1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
|
"""
.. codeauthor:: Tsuyoshi Hombashi <tsuyoshi.hombashi@gmail.com>
"""
import ntpath
import platform
import re
import string
import sys
from pathlib import PurePath
from typing import Any, Final, Optional
from ._const import Platform
from ._types import PathType, PlatformType
_re_whitespaces: Final = re.compile(r"^[\s]+$")
def validate_pathtype(
text: PathType, allow_whitespaces: bool = False, error_msg: Optional[str] = None
) -> None:
from .error import ErrorReason, ValidationError
if _is_not_null_string(text) or isinstance(text, PurePath):
return
if allow_whitespaces and _re_whitespaces.search(str(text)):
return
if is_null_string(text):
raise ValidationError(reason=ErrorReason.NULL_NAME)
raise TypeError(f"text must be a string: actual={type(text)}")
def to_str(name: PathType) -> str:
if isinstance(name, PurePath):
return str(name)
return name
def is_nt_abspath(value: str) -> bool:
ver_info = sys.version_info[:2]
if ver_info <= (3, 10):
if value.startswith("\\\\"):
return True
elif ver_info >= (3, 13):
return ntpath.isabs(value)
drive, _tail = ntpath.splitdrive(value)
return ntpath.isabs(value) and len(drive) > 0
def is_null_string(value: Any) -> bool:
if value is None:
return True
try:
return len(value.strip()) == 0
except AttributeError:
return False
def _is_not_null_string(value: Any) -> bool:
try:
return len(value.strip()) > 0
except AttributeError:
return False
def _get_unprintable_ascii_chars() -> list[str]:
return [chr(c) for c in range(128) if chr(c) not in string.printable]
unprintable_ascii_chars: Final = tuple(_get_unprintable_ascii_chars())
def _get_ascii_symbols() -> list[str]:
symbol_list: list[str] = []
for i in range(128):
c = chr(i)
if c in unprintable_ascii_chars or c in string.digits + string.ascii_letters:
continue
symbol_list.append(c)
return symbol_list
ascii_symbols: Final = tuple(_get_ascii_symbols())
__RE_UNPRINTABLE_CHARS: Final = re.compile(
"[{}]".format(re.escape("".join(unprintable_ascii_chars))), re.UNICODE
)
__RE_ANSI_ESCAPE: Final = re.compile(
r"(?:\x1B[@-Z\\-_]|[\x80-\x9A\x9C-\x9F]|(?:\x1B\[|\x9B)[0-?]*[ -/]*[@-~])"
)
def validate_unprintable_char(text: str) -> None:
from .error import InvalidCharError
match_list = __RE_UNPRINTABLE_CHARS.findall(to_str(text))
if match_list:
raise InvalidCharError(f"unprintable character found: {match_list}")
def replace_unprintable_char(text: str, replacement_text: str = "") -> str:
try:
return __RE_UNPRINTABLE_CHARS.sub(replacement_text, text)
except (TypeError, AttributeError):
raise TypeError("text must be a string")
def replace_ansi_escape(text: str, replacement_text: str = "") -> str:
try:
return __RE_ANSI_ESCAPE.sub(replacement_text, text)
except (TypeError, AttributeError):
raise TypeError("text must be a string")
def normalize_platform(name: Optional[PlatformType]) -> Platform:
if isinstance(name, Platform):
return name
if not name:
return Platform.UNIVERSAL
platform_str = name.strip().casefold()
if platform_str == "posix":
return Platform.POSIX
if platform_str == "auto":
platform_str = platform.system().casefold()
if platform_str in ["linux"]:
return Platform.LINUX
if platform_str and platform_str.startswith("win"):
return Platform.WINDOWS
if platform_str in ["mac", "macos", "darwin"]:
return Platform.MACOS
return Platform.UNIVERSAL
def findall_to_str(match: list[Any]) -> str:
uniq_list = {repr(text) for text in match}
return ", ".join(uniq_list)
def truncate_str(text: str, encoding: str, max_bytes: int) -> str:
str_bytes = text.encode(encoding)
str_bytes = str_bytes[:max_bytes]
# last char might be malformed, ignore it
return str_bytes.decode(encoding, "ignore")
|