Source code for string_py.string_py
from datetime import datetime
from time import sleep
from asyncio import sleep as aio_sleep
from random import choices, randint
import string
[docs]class Color:
"""Color variations for prints"""
bold = "\u001b[1m",
underline = "\u001b[4m",
reset = "\u001b[0m",
force = "\u001b[0m",
error = "\u001b[31m",
basic = "\u001b[37m"
[docs]class Printer:
"""Adds new print methods to work with.
:param active: `True`
If set to False, no more prints are executed. Exception: force Parameter is set to True.
"""
def __init__(self, active: bool = True):
self.active = active
[docs] def time(self, args: str, dt: bool = True, force: bool = False, error: bool = False) -> None:
""" Timestamp print: Print with the current day and time.
:param args: `str`
The text to print.
:param dt: `True`
Set to `False` to turn off timestamp.
:param force: `False`
Set to `True` to print always, even if :class:`active` is set to False.
:param error: `False`
Set to `True` to print always, even if :class:`active` is set to False, gets highlighted with red color.
"""
if self.active or force or error:
color = Color.error if error else Color.force if force else Color.basic
if dt:
print(f"[{datetime.now().strftime('%d.%m | %H:%M:%S')}] {color}{args}\u001b[0m")
else:
print(f"{color}{args}\u001b[0m")
[docs] def slow(self, args: str, speed: float = 0.2, force: bool = False, error: bool = False) -> None:
"""Slow print: Char after char gets printed in a certain speed
:param args: `str`
The text to print.
:param speed: `0.1`
The speed in wich the chars will get printed out
:param force: `False`
Set to `True` to print always, even if :class:`active` is set to False.
:param error: `False`
Set to `True` to print always, even if :class:`active` is set to False, gets highlighted with red color.
"""
if self.active or force or error:
color = Color.error if error else Color.force if force else Color.basic
for char in args:
print(color + char, end="")
sleep(speed)
[docs] async def aio_slow(self, args: str, speed: float = 0.1, force: bool = False, error: bool = False) -> None:
"""Async slow print: Char after char gets printed in a certain speed
:param args: `str`
The text to print.
:param speed: `0.1`
The speed in wich the chars will get printed out
:param force: `False`
Set to `True` to print always, even if :class:`active` is set to False.
:param error: `False`
Set to `True` to print always, even if :class:`active` is set to False, gets highlighted with red color.
"""
if self.active or force or error:
color = Color.error if error else Color.force if force else Color.basic
for char in args:
print(color + char, end="")
await aio_sleep(speed)
[docs]class Str(str):
"""Functions to work with strings
:param values: `str`
The value you want to work with
"""
def __init__(self, values: str | int):
self.values = str(values)
self.chars = [*self.values]
self._ascii = {
"ascii_lowercase": string.ascii_lowercase,
"ascii_uppercase": string.ascii_uppercase,
"digits": string.digits,
"punctuation": string.punctuation
}
[docs] def generate(self, length: int = None, min_: int = None, max_: int = None) -> str:
"""Generate a random string out of :class:`values`
:param length:
Generate with certain length
:param min_:
Generate with random length, `max_` required
:param max_:
Generate with random length, `min_` required
:return:
Returns random string out of :class:`values` with length out of parameters
"""
if (min_ is None and max_ is None) and length is None:
raise AttributeError("min_ and max_ or length must have a value")
elif length:
return "".join(choices(self.chars, k=length))
elif min_ is not None and max_ is not None:
if min_ > max_:
raise AttributeError("min_ must have a smaller value then max_")
return "".join(choices(self.chars, k=randint(min_, max_)))
else:
raise AttributeError("min_ and max_ or length must have a value")
[docs] def remove(self, *chars: str) -> str:
"""Remove chars from string
:param chars:
The chars you want to remove
"""
for x in chars:
self.values = self.values.replace(x, "")
return self.values
[docs] def split(self, each: int = None, chars: str = None) -> list[str]:
"""An extension of the built-in .split method. Also split on certain index
:param each:
The index you want to split at
:param chars:
The char or word you want to split at
:return:
Returns list with splittet :class:`values`
"""
if not each and not chars:
raise AttributeError("each or chars must have a value")
if each:
return [self.values[i:i + each] for i in range(0, len(self.values), each)]
else:
return self.values.split(chars)
[docs] def first(self, length: int = 1, remove=False) -> str:
"""A simplification for getting/removing the first chars in a string
:param length:
The amount of chars
:param remove:
If set to `True` removes `length` of :class:`values`
"""
if len(self.values) < length:
raise AttributeError("Length must be smaller then value")
if remove:
return self.values[length:]
else:
return self.values[:length]
[docs] def last(self, length: int = 1, remove=False) -> str:
"""A simplification for getting/removing the last chars in a string
:param length:
The amount of chars
:param remove:
If set to `True` removes `length` of :class:`values`
"""
if len(self.values) < length:
raise AttributeError("Length must be smaller then value")
if remove:
return self.values[:-length]
else:
return self.values[-length:]
def __get(self, type_: str, index: bool) -> list[str] | dict[int, str]:
gets = [] if index is False else {}
for num, char in enumerate(self.values):
if char in self._ascii[type_]:
if index is False:
gets.append(char)
else:
gets[num] = char
return gets
[docs] def get_upper(self, chars: bool = True, index: bool = False) -> int | list[str] | dict[int, str]:
"""Get how many upper chars are in :class:`values`
:param chars: `True`
If set to True, returns a list of all uppercase chars
If set to False, returns the number of uppercase chars
:param index: `False`
If set to True, also returns the Indexes of lower chars (`chars` MUST be `True`)
"""
upper = self.__get("ascii_uppercase", index)
return upper if chars else len(upper)
[docs] def get_lower(self, chars: bool = True, index: bool = False) -> int | list[str] | dict[int, str]:
"""Get how many lower chars are in :class:`values`
:param chars: `True`
If set to True, returns a list of all lower chars
If set to False, returns the number of lower chars
:param index: `False`
If set to True, also returns the Indexes of lower chars (`chars` MUST be `True`)
"""
if not chars and index:
raise AttributeError("If index is set to True, chars can't be False")
lower = self.__get("ascii_lowercase", index)
return lower if chars else len(lower)
[docs] def get_numeric(self, chars: bool = True, index: bool = False) -> int | list[str] | dict[int, str]:
"""Get how many numeric chars are in :class:`values`
:param chars: `True`
If set to True, returns a list of all numeric chars
If set to False, returns the number of numeric chars
:param index: `False`
If set to True, also returns the Indexes of numeric chars (`chars` MUST be `True`)
"""
if not chars and index:
raise AttributeError("If index is set to True, chars can't be False")
numeric = self.__get("digits", index)
return numeric if chars else len(numeric)
[docs] def get_punctuation(self, chars: bool = True, index: bool = False) -> int | list[str] | dict[int, str]:
"""Get how many punctuation chars are in :class:`values`
:param chars: `True`
If set to True, returns a list of all punctuation chars
If set to False, returns the number of punctuation chars
:param index: `False`
If set to True, also returns the Indexes of punctuation chars (`chars` MUST be `True`)
"""
if not chars and index:
raise AttributeError("If index is set to True, chars can't be False")
punctuation = self.__get("punctuation", index)
return punctuation if chars else len(punctuation)
[docs]class Format:
"""Format texts"""
[docs] @staticmethod
def surround(values: str | list[str],
all_: str = None,
left: str = "\u2502",
top: str = "\u2500",
bottom: str = "\u2500",
top_left: str = "\u250c",
top_right: str = "\u2510",
bottom_left: str = "\u2514",
bottom_right: str = "\u2518"
) -> str:
"""Surround a text with chars
:param bottom:
Char to surround the bottom with
:param top:
Char to surround the top with
:param values:`str`
Text to surround
:param all_:
Char to surround everything with (Overrides all other chars)
:param bottom_right:
Char to surround the bottom right corner with
:param bottom_left:
Char to surround the bottom left corner with
:param top_right:
Char to surround the top right corner with
:param top_left:
Char to surround the top left corner with
:param left:
Char to surround the left side with
:return:
Returns a string with the text surrounded with certain chars
"""
if all_:
top = all_
bottom = all_
left = all_
top_left = all_
top_right = all_
bottom_left = all_
bottom_right = all_
text = ""
length_values = []
for part_values in values if isinstance(values, list) else [values]:
length_values += part_values.split("\n")
length = max([len(x) for x in length_values])
row_values = []
for num1, part_values in enumerate(values if isinstance(values, list) else [values]):
row_values += (part_values + ("\n" + bottom * length if num1 != len(
values if isinstance(values, list) else [values]) - 1 else "")).split("\n")
length = max([len(x) for x in row_values])
for num2, value in enumerate(row_values):
if num2 == 0:
text += top_left + top * length + top_right + "\n"
text += left + value + " " * (length - len(value)) + left + "\n"
if num2 == len(row_values) - 1:
text += bottom_left + bottom * length + bottom_right
return text
[docs] @staticmethod
def align(values: dict[str, str]):
"""Align a text
:param values: `dict[str, str]`
Texts to align {"Left side": "Right side"}
:return:
Returns a string with the key aligned left and the value right dependent from the keys
Examples
--------
.. code-block::
values = {"Username:": "John", "Register Date:": "01.01.2001"}
Username: John
Register Date: 01.01.2001
"""
length = max([len(x) for x in list(values.keys())])
aligned_text = ""
for key in values:
aligned_text += key + " " * ((length + 3) - len(key)) + values[key] + "\n"
return aligned_text
[docs] @staticmethod
def table(values: list[list[str]], border: bool = True) -> str:
"""Create a table
:param values: `list[list[str]]`
The values to create the table with
:param border: `True`
Set to `False` to remove the border
:return:
Returns the table as string
"""
length = [max([len(str(x)) for x in column]) for column in zip(*values)]
if border:
table = "\u250C" + "\u2500" * (sum(length) + (3 * len(values) - 1)) + "\u2510\n"
for index, row in enumerate(values):
table += "\u2502"
for i, column in enumerate(row):
table += " " + column + " " * (length[i] - len(column)) + " \u2502"
if index == 0:
table += "\n\u251C" + "\u2500" * (sum(length) + (3 * len(values) - 1)) + "\u2524" + "\n"
else:
if index != len(values) - 1:
table += "\n\u2502" + "\u2500" * (sum(length) + (3 * len(values) - 1)) + "\u2502" + "\n"
else:
table += "\n\u2514" + "\u2500" * (sum(length) + (3 * len(values) - 1)) + "\u2518"
else:
table = ""
for index, row in enumerate(values):
for i, column in enumerate(row):
table += " " + column + " " * (length[i] - len(column)) + " "
if index != len(values) - 1:
table += "\n"
return table
[docs] @staticmethod
def embed(
title: str,
description: str = None,
url: str = None,
fields: list[dict[str, str]] = None,
footer: str = None,
author: str = None,
image: str = None
):
"""Create an embed
:param title: `str`
Title of the embed
:param description: `str`
Description of the embed
:param url: `str`
Url of the embed
:param fields: `list[dict[str, str]]`
Fields of the embed
:param footer: `str`
Footer of the embed
:param author: `str`
Author of the embed
:param image: `str`
Image of the embed
:return: `str`
"""
embed = []
if author:
embed.append(author)
if title:
embed.append(title)
if description:
embed.append(description)
if url:
embed.append(url)
if fields:
for field in fields:
embed.append(field["name"] + ": " + field["value"])
if footer:
embed.append(footer)
if image:
embed.append(image)
return Format.surround(embed)