From 9d3650cc7009183d92422e70cf0089b2674e1e9b Mon Sep 17 00:00:00 2001 From: Scott Date: Sun, 30 Jan 2022 17:34:51 -0800 Subject: [PATCH] Adds MIT license / copyright to string utils from original source of code. --- string_utils.py | 96 +++++++++++++++++++++++-------------------------- 1 file changed, 44 insertions(+), 52 deletions(-) diff --git a/string_utils.py b/string_utils.py index 244c450..9f67207 100644 --- a/string_utils.py +++ b/string_utils.py @@ -1,5 +1,31 @@ #!/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 @@ -55,15 +81,15 @@ URLS_RE = re.compile(r"({})".format(URLS_RAW_STRING), re.IGNORECASE) 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])") @@ -88,9 +114,7 @@ CREDIT_CARDS = { "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 @@ -109,17 +133,13 @@ IP_V6_RE = re.compile(r"^([a-z\d]{0,4}:){7}[a-z\d]{0,4}$", 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]+[^>]*/?>)(.*?())?||)", @@ -133,9 +153,7 @@ HTML_TAG_ONLY_RE = re.compile( 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]+") @@ -390,9 +408,7 @@ def strip_escape_sequences(in_str: str) -> str: 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. @@ -417,16 +433,12 @@ def add_thousands_separator( 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 @@ -467,11 +479,7 @@ def is_email(in_str: Any) -> bool: >>> 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: @@ -481,12 +489,7 @@ def is_email(in_str: Any) -> bool: # 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 @@ -603,9 +606,7 @@ def is_camel_case(in_str: Any) -> bool: - 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: @@ -630,14 +631,10 @@ 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 @@ -926,9 +923,7 @@ def camel_case_to_snake_case(in_str, *, separator="_"): 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( @@ -1531,10 +1526,7 @@ def from_bitstring(bits: str, encoding='utf-8', errors='surrogatepass') -> str: """ 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]: -- 2.45.2