#!/usr/bin/env python3
+"""The MIT License (MIT)
+
+Copyright (c) 2016-2020 Davide Zanotti
+Modifications Copyright (c) 2021-2022 Scott Gasch
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+This class is based on: https://github.com/daveoncode/python-string-utils.
+"""
+
import base64
import contextlib
import datetime
ESCAPED_AT_SIGN = re.compile(r'(?!"[^"]*)@+(?=[^"]*")|\\@')
-EMAILS_RAW_STRING = r"[a-zA-Z\d._\+\-'`!%#$&*/=\?\^\{\}\|~\\]+@[a-z\d-]+\.?[a-z\d-]+\.[a-z]{2,4}"
+EMAILS_RAW_STRING = (
+ r"[a-zA-Z\d._\+\-'`!%#$&*/=\?\^\{\}\|~\\]+@[a-z\d-]+\.?[a-z\d-]+\.[a-z]{2,4}"
+)
EMAIL_RE = re.compile(r"^{}$".format(EMAILS_RAW_STRING))
EMAILS_RE = re.compile(r"({})".format(EMAILS_RAW_STRING))
-CAMEL_CASE_TEST_RE = re.compile(
- r"^[a-zA-Z]*([a-z]+[A-Z]+|[A-Z]+[a-z]+)[a-zA-Z\d]*$"
-)
+CAMEL_CASE_TEST_RE = re.compile(r"^[a-zA-Z]*([a-z]+[A-Z]+|[A-Z]+[a-z]+)[a-zA-Z\d]*$")
CAMEL_CASE_REPLACE_RE = re.compile(r"([a-z]|[A-Z]+)(?=[A-Z])")
"JCB": re.compile(r"^(?:2131|1800|35\d{3})\d{11}$"),
}
-JSON_WRAPPER_RE = re.compile(
- r"^\s*[\[{]\s*(.*)\s*[\}\]]\s*$", re.MULTILINE | re.DOTALL
-)
+JSON_WRAPPER_RE = re.compile(r"^\s*[\[{]\s*(.*)\s*[\}\]]\s*$", re.MULTILINE | re.DOTALL)
UUID_RE = re.compile(
r"^[a-f\d]{8}-[a-f\d]{4}-[a-f\d]{4}-[a-f\d]{4}-[a-f\d]{12}$", re.IGNORECASE
ANYWHERE_IP_V6_RE = re.compile(r"([a-z\d]{0,4}:){7}[a-z\d]{0,4}", re.IGNORECASE)
-MAC_ADDRESS_RE = re.compile(
- r"^([0-9A-F]{2}[:-]){5}([0-9A-F]{2})$", re.IGNORECASE
-)
+MAC_ADDRESS_RE = re.compile(r"^([0-9A-F]{2}[:-]){5}([0-9A-F]{2})$", re.IGNORECASE)
ANYWHERE_MAC_ADDRESS_RE = re.compile(
r"([0-9A-F]{2}[:-]){5}([0-9A-F]{2})", re.IGNORECASE
)
-WORDS_COUNT_RE = re.compile(
- r"\W*[^\W_]+\W*", re.IGNORECASE | re.MULTILINE | re.UNICODE
-)
+WORDS_COUNT_RE = re.compile(r"\W*[^\W_]+\W*", re.IGNORECASE | re.MULTILINE | re.UNICODE)
HTML_RE = re.compile(
r"((<([a-z]+:)?[a-z]+[^>]*/?>)(.*?(</([a-z]+:)?[a-z]+>))?|<!--.*-->|<!doctype.*>)",
SPACES_RE = re.compile(r"\s")
-NO_LETTERS_OR_NUMBERS_RE = re.compile(
- r"[^\w\d]+|_+", re.IGNORECASE | re.UNICODE
-)
+NO_LETTERS_OR_NUMBERS_RE = re.compile(r"[^\w\d]+|_+", re.IGNORECASE | re.UNICODE)
MARGIN_RE = re.compile(r"^[^\S\r\n]+")
return in_str
-def add_thousands_separator(
- in_str: str, *, separator_char=',', places=3
-) -> str:
+def add_thousands_separator(in_str: str, *, separator_char=',', places=3) -> str:
"""
Add thousands separator to a numeric string. Also handles numbers.
raise ValueError(in_str)
-def _add_thousands_separator(
- in_str: str, *, separator_char=',', places=3
-) -> str:
+def _add_thousands_separator(in_str: str, *, separator_char=',', places=3) -> str:
decimal_part = ""
if '.' in in_str:
(in_str, decimal_part) = in_str.split('.')
tmp = [iter(in_str[::-1])] * places
- ret = separator_char.join(
- "".join(x) for x in zip_longest(*tmp, fillvalue="")
- )[::-1]
+ ret = separator_char.join("".join(x) for x in zip_longest(*tmp, fillvalue=""))[::-1]
if len(decimal_part) > 0:
ret += '.'
ret += decimal_part
>>> is_email('@gmail.com')
False
"""
- if (
- not is_full_string(in_str)
- or len(in_str) > 320
- or in_str.startswith(".")
- ):
+ if not is_full_string(in_str) or len(in_str) > 320 or in_str.startswith("."):
return False
try:
# head's size must be <= 64, tail <= 255, head must not start
# with a dot or contain multiple consecutive dots.
- if (
- len(head) > 64
- or len(tail) > 255
- or head.endswith(".")
- or (".." in head)
- ):
+ if len(head) > 64 or len(tail) > 255 or head.endswith(".") or (".." in head):
return False
# removes escaped spaces, so that later on the test regex will
- it contains both lowercase and uppercase letters
- it does not start with a number
"""
- return (
- is_full_string(in_str) and CAMEL_CASE_TEST_RE.match(in_str) is not None
- )
+ return is_full_string(in_str) and CAMEL_CASE_TEST_RE.match(in_str) is not None
def is_snake_case(in_str: Any, *, separator: str = "_") -> bool:
"""
if is_full_string(in_str):
re_map = {"_": SNAKE_CASE_TEST_RE, "-": SNAKE_CASE_TEST_DASH_RE}
- re_template = (
- r"([a-z]+\d*{sign}[a-z\d{sign}]*|{sign}+[a-z\d]+[a-z\d{sign}]*)"
- )
+ re_template = r"([a-z]+\d*{sign}[a-z\d{sign}]*|{sign}+[a-z\d]+[a-z\d{sign}]*)"
r = re_map.get(
separator,
- re.compile(
- re_template.format(sign=re.escape(separator)), re.IGNORECASE
- ),
+ re.compile(re_template.format(sign=re.escape(separator)), re.IGNORECASE),
)
return r.match(in_str) is not None
return False
raise ValueError(in_str)
if not is_camel_case(in_str):
return in_str
- return CAMEL_CASE_REPLACE_RE.sub(
- lambda m: m.group(1) + separator, in_str
- ).lower()
+ return CAMEL_CASE_REPLACE_RE.sub(lambda m: m.group(1) + separator, in_str).lower()
def snake_case_to_camel_case(
"""
n = int(bits, 2)
- return (
- n.to_bytes((n.bit_length() + 7) // 8, 'big').decode(encoding, errors)
- or '\0'
- )
+ return n.to_bytes((n.bit_length() + 7) // 8, 'big').decode(encoding, errors) or '\0'
def ip_v4_sort_key(txt: str) -> Tuple[int]: