xulbux 1.5.5__py3-none-any.whl → 1.5.8__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of xulbux might be problematic. Click here for more details.

xulbux/xx_path.py CHANGED
@@ -5,41 +5,48 @@ import sys as _sys
5
5
  import os as _os
6
6
 
7
7
 
8
-
9
-
10
8
  class Path:
11
9
 
12
10
  @staticmethod
13
- def get(cwd:bool = False, base_dir:bool = False) -> str|list:
11
+ def get(cwd: bool = False, base_dir: bool = False) -> str | list:
14
12
  paths = []
15
13
  if cwd:
16
14
  paths.append(_os.getcwd())
17
15
  if base_dir:
18
- if getattr(_sys, 'frozen', False):
16
+ if getattr(_sys, "frozen", False):
19
17
  base_path = _os.path.dirname(_sys.executable)
20
18
  else:
21
- main_module = _sys.modules['__main__']
22
- if hasattr(main_module, '__file__'):
19
+ main_module = _sys.modules["__main__"]
20
+ if hasattr(main_module, "__file__"):
23
21
  base_path = _os.path.dirname(_os.path.abspath(main_module.__file__))
24
- elif hasattr(main_module, '__spec__') and main_module.__spec__ and getattr(main_module.__spec__, 'origin', None):
22
+ elif (
23
+ hasattr(main_module, "__spec__") and main_module.__spec__ and getattr(main_module.__spec__, "origin", None)
24
+ ):
25
25
  base_path = _os.path.dirname(_os.path.abspath(main_module.__spec__.origin))
26
26
  else:
27
- raise RuntimeError('Can only get base directory if ran from a file.')
27
+ raise RuntimeError("Can only get base directory if ran from a file.")
28
28
  paths.append(base_path)
29
29
  return paths[0] if len(paths) == 1 else paths
30
30
 
31
31
  @staticmethod
32
- def extend(path:str, search_in:str|list[str] = None, raise_error:bool = False, correct_path:bool = False) -> str:
33
- if path in (None, ''):
32
+ def extend(
33
+ path: str,
34
+ search_in: str | list[str] = None,
35
+ raise_error: bool = False,
36
+ correct_path: bool = False,
37
+ ) -> str:
38
+ if path in (None, ""):
34
39
  return path
35
- def get_closest_match(dir:str, part:str) -> str|None:
40
+
41
+ def get_closest_match(dir: str, part: str) -> str | None:
36
42
  try:
37
43
  files_and_dirs = _os.listdir(dir)
38
44
  matches = _difflib.get_close_matches(part, files_and_dirs, n=1, cutoff=0.6)
39
45
  return matches[0] if matches else None
40
- except:
46
+ except Exception:
41
47
  return None
42
- def find_path(start:str, parts:list[str]) -> str|None:
48
+
49
+ def find_path(start: str, parts: list[str]) -> str | None:
43
50
  current = start
44
51
  for part in parts:
45
52
  if _os.path.isfile(current):
@@ -49,23 +56,30 @@ class Path:
49
56
  if current is None:
50
57
  return None
51
58
  return current if _os.path.exists(current) and current != start else None
52
- def expand_env_path(p:str) -> str:
53
- if not '%' in p:
59
+
60
+ def expand_env_path(p: str) -> str:
61
+ if "%" not in p:
54
62
  return p
55
- parts = p.split('%')
63
+ parts = p.split("%")
56
64
  for i in range(1, len(parts), 2):
57
65
  if parts[i].upper() in _os.environ:
58
66
  parts[i] = _os.environ[parts[i].upper()]
59
- return ''.join(parts)
67
+ return "".join(parts)
68
+
60
69
  path = _os.path.normpath(expand_env_path(path))
61
70
  if _os.path.isabs(path):
62
71
  drive, rel_path = _os.path.splitdrive(path)
63
72
  rel_path = rel_path.lstrip(_os.sep)
64
- search_dirs = [drive + _os.sep] if drive else [_os.sep]
73
+ search_dirs = (drive + _os.sep) if drive else [_os.sep]
65
74
  else:
66
75
  rel_path = path.lstrip(_os.sep)
67
76
  base_dir = Path.get(base_dir=True)
68
- search_dirs = [_os.getcwd(), base_dir, _os.path.expanduser('~'), _tempfile.gettempdir()]
77
+ search_dirs = (
78
+ _os.getcwd(),
79
+ base_dir,
80
+ _os.path.expanduser("~"),
81
+ _tempfile.gettempdir(),
82
+ )
69
83
  if search_in:
70
84
  search_dirs.extend([search_in] if isinstance(search_in, str) else search_in)
71
85
  path_parts = rel_path.split(_os.sep)
@@ -74,13 +88,14 @@ class Path:
74
88
  if _os.path.exists(full_path):
75
89
  return full_path
76
90
  match = find_path(search_dir, path_parts) if correct_path else None
77
- if match: return match
91
+ if match:
92
+ return match
78
93
  if raise_error:
79
- raise FileNotFoundError(f'Path \'{path}\' not found in specified directories.')
94
+ raise FileNotFoundError(f"Path '{path}' not found in specified directories.")
80
95
  return _os.path.join(search_dirs[0], rel_path)
81
96
 
82
97
  @staticmethod
83
- def remove(path:str, only_content:bool = False) -> None:
98
+ def remove(path: str, only_content: bool = False) -> None:
84
99
  if not _os.path.exists(path):
85
100
  return None
86
101
  if not only_content:
@@ -94,4 +109,4 @@ class Path:
94
109
  elif _os.path.isdir(file_path):
95
110
  _shutil.rmtree(file_path)
96
111
  except Exception as e:
97
- raise Exception(f'Failed to delete {file_path}. Reason: {e}')
112
+ raise Exception(f"Failed to delete {file_path}. Reason: {e}")
xulbux/xx_regex.py CHANGED
@@ -9,12 +9,9 @@ Really long regex code presets:<br>
9
9
  `hsla_str` match a HSLA color
10
10
  """
11
11
 
12
-
13
12
  import re as _re
14
13
 
15
14
 
16
-
17
-
18
15
  class Regex:
19
16
 
20
17
  @staticmethod
@@ -25,42 +22,54 @@ class Regex:
25
22
  **`quote`** the quote type (single or double)<br>
26
23
  **`string`** everything inside the found quote pair\n
27
24
  ------------------------------------------------------------------------------------
28
- **Attention:** Requires non standard library `regex` not standard library `re`!"""
25
+ **Attention:** Requires non standard library `regex` not standard library `re`!
26
+ """
29
27
  return r'(?P<quote>[\'"])(?P<string>(?:\\.|(?!\g<quote>).)*?)\g<quote>'
30
28
 
31
29
  @staticmethod
32
- def brackets(bracket1:str = '(', bracket2:str = ')', is_group:bool = False) -> str:
30
+ def brackets(bracket1: str = "(", bracket2: str = ")", is_group: bool = False) -> str:
33
31
  """Matches everything inside brackets, including other nested brackets.\n
34
32
  ------------------------------------------------------------------------------------
35
- **Attention:** Requires non standard library `regex` not standard library `re`!"""
36
- g, b1, b2 = '' if is_group else '?:', _re.escape(bracket1) if len(bracket1) == 1 else bracket1, _re.escape(bracket2) if len(bracket2) == 1 else bracket2
33
+ **Attention:** Requires non standard library `regex` not standard library `re`!
34
+ """
35
+ g, b1, b2 = (
36
+ "" if is_group else "?:",
37
+ _re.escape(bracket1) if len(bracket1) == 1 else bracket1,
38
+ _re.escape(bracket2) if len(bracket2) == 1 else bracket2,
39
+ )
37
40
  return rf'{b1}\s*({g}(?:[^{b1}{b2}"\']|"(?:\\.|[^"\\])*"|\'(?:\\.|[^\'\\])*\'|{b1}(?:[^{b1}{b2}"\']|"(?:\\.|[^"\\])*"|\'(?:\\.|[^\'\\])*\'|(?R))*{b2})*)\s*{b2}'
38
41
 
39
42
  @staticmethod
40
- def outside_strings(pattern:str = r'.*') -> str:
43
+ def outside_strings(pattern: str = r".*") -> str:
41
44
  """Matches the `pattern` only when it is not found inside a string (`'...'` or `"..."`)."""
42
45
  return rf'(?<!["\'])(?:{pattern})(?!["\'])'
43
46
 
44
47
  @staticmethod
45
- def all_except(disallowed_pattern:str, ignore_pattern:str = '', is_group:bool = False) -> str:
48
+ def all_except(
49
+ disallowed_pattern: str,
50
+ ignore_pattern: str = "",
51
+ is_group: bool = False,
52
+ ) -> str:
46
53
  """Matches everything except `disallowed_pattern`, unless the `disallowed_pattern` is found inside a string (`'...'` or `"..."`).\n
47
54
  ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
48
55
  The `ignore_pattern` is just always ignored. For example if `disallowed_pattern` is `>` and `ignore_pattern` is `->`, the `->`-arrows will be allowed, even though they have `>` in them.<br>
49
- If `is_group` is `True`, you will be able to reference the matched content as a group (e.g. <code>match.group(<i>int</i>)</code> or <code>r'\\<i>int</i>'</code>)."""
56
+ If `is_group` is `True`, you will be able to reference the matched content as a group (e.g. <code>match.group(<i>int</i>)</code> or <code>r'\\<i>int</i>'</code>).
57
+ """
50
58
  return rf'({"" if is_group else "?:"}(?:(?!{ignore_pattern}).)*(?:(?!{Regex.outside_strings(disallowed_pattern)}).)*)'
51
59
 
52
60
  @staticmethod
53
- def func_call(func_name:str = None) -> str:
61
+ def func_call(func_name: str = None) -> str:
54
62
  """Match a function call<br>
55
63
  **`1`** function name<br>
56
64
  **`2`** the function's arguments\n
57
65
  If no `func_name` is given, it will match any function call.\n
58
66
  ------------------------------------------------------------------------------------
59
- **Attention:** Requires non standard library `regex` not standard library `re`!"""
60
- return r'(?<=\b)(' + (func_name if func_name else r'[\w_]+') + r')\s*' + Regex.brackets("(", ")", is_group=True)
67
+ **Attention:** Requires non standard library `regex` not standard library `re`!
68
+ """
69
+ return r"(?<=\b)(" + (func_name if func_name else r"[\w_]+") + r")\s*" + Regex.brackets("(", ")", is_group=True)
61
70
 
62
71
  @staticmethod
63
- def rgba_str(fix_sep:str = ',', allow_alpha:bool = False) -> str:
72
+ def rgba_str(fix_sep: str = ",", allow_alpha: bool = True) -> str:
64
73
  """Matches an RGBA color inside a string.\n
65
74
  --------------------------------------------------------------------------------
66
75
  The RGBA color can be in the formats (for `fix_sep = ','`):<br>
@@ -78,21 +87,25 @@ class Regex:
78
87
  `a` 0-1 (float: opacity)\n
79
88
  --------------------------------------------------------------------------------
80
89
  If the `fix_sep` is set to nothing, any char that is not a letter or number<br>
81
- can be used to separate the RGB values, including just a space."""
82
- if fix_sep in (None, ''):
83
- fix_sep = r'[^0-9A-Z]'
90
+ can be used to separate the RGBA values, including just a space."""
91
+ if fix_sep in (None, ""):
92
+ fix_sep = r"[^0-9A-Z]"
84
93
  else:
85
94
  fix_sep = _re.escape(fix_sep)
86
- rgb_part = rf'''((?:0*(?:25[0-5]|2[0-4][0-9]|1?[0-9]{{1,2}})))
95
+ rgb_part = rf"""((?:0*(?:25[0-5]|2[0-4][0-9]|1?[0-9]{{1,2}})))
87
96
  (?:\s*{fix_sep}\s*)((?:0*(?:25[0-5]|2[0-4][0-9]|1?[0-9]{{1,2}})))
88
- (?:\s*{fix_sep}\s*)((?:0*(?:25[0-5]|2[0-4][0-9]|1?[0-9]{{1,2}})))'''
89
- return rf'''(?ix)
97
+ (?:\s*{fix_sep}\s*)((?:0*(?:25[0-5]|2[0-4][0-9]|1?[0-9]{{1,2}})))"""
98
+ return (
99
+ rf"""(?ix)
90
100
  (?:rgb|rgba)?\s*(?:\(?\s*{rgb_part}
91
101
  (?:(?:\s*{fix_sep}\s*)((?:0*(?:0?\.[0-9]+|1\.0+|[0-9]+\.[0-9]+|[0-9]+))))?
92
- \s*\)?)''' if allow_alpha else rf'(?ix)(?:rgb|rgba)?\s*(?:\(?\s*{rgb_part}\s*\)?)'
102
+ \s*\)?)"""
103
+ if allow_alpha
104
+ else rf"(?ix)(?:rgb|rgba)?\s*(?:\(?\s*{rgb_part}\s*\)?)"
105
+ )
93
106
 
94
107
  @staticmethod
95
- def hsla_str(fix_sep:str = ',', allow_alpha:bool = False) -> str:
108
+ def hsla_str(fix_sep: str = ",", allow_alpha: bool = True) -> str:
96
109
  """Matches a HSLA color inside a string.\n
97
110
  --------------------------------------------------------------------------------
98
111
  The HSLA color can be in the formats (for `fix_sep = ','`):<br>
@@ -110,15 +123,37 @@ class Regex:
110
123
  `a` 0-1 (float: opacity)\n
111
124
  --------------------------------------------------------------------------------
112
125
  If the `fix_sep` is set to nothing, any char that is not a letter or number<br>
113
- can be used to separate the HSL values, including just a space."""
114
- if fix_sep in (None, ''):
115
- fix_sep = r'[^0-9A-Z]'
126
+ can be used to separate the HSLA values, including just a space."""
127
+ if fix_sep in (None, ""):
128
+ fix_sep = r"[^0-9A-Z]"
116
129
  else:
117
130
  fix_sep = _re.escape(fix_sep)
118
- hsl_part = rf'''((?:0*(?:360|3[0-5][0-9]|[12][0-9][0-9]|[1-9]?[0-9])))
131
+ hsl_part = rf"""((?:0*(?:360|3[0-5][0-9]|[12][0-9][0-9]|[1-9]?[0-9])))
119
132
  (?:\s*{fix_sep}\s*)((?:0*(?:100|[1-9][0-9]|[0-9])))
120
- (?:\s*{fix_sep}\s*)((?:0*(?:100|[1-9][0-9]|[0-9])))'''
121
- return rf'''(?ix)
133
+ (?:\s*{fix_sep}\s*)((?:0*(?:100|[1-9][0-9]|[0-9])))"""
134
+ return (
135
+ rf"""(?ix)
122
136
  (?:hsl|hsla)?\s*(?:\(?\s*{hsl_part}
123
137
  (?:(?:\s*{fix_sep}\s*)((?:0*(?:0?\.[0-9]+|1\.0+|[0-9]+\.[0-9]+|[0-9]+))))?
124
- \s*\)?)''' if allow_alpha else rf'(?ix)(?:hsl|hsla)?\s*(?:\(?\s*{hsl_part}\s*\)?)'
138
+ \s*\)?)"""
139
+ if allow_alpha
140
+ else rf"(?ix)(?:hsl|hsla)?\s*(?:\(?\s*{hsl_part}\s*\)?)"
141
+ )
142
+
143
+ @staticmethod
144
+ def hexa_str(allow_alpha: bool = True) -> str:
145
+ """Matches a HEXA color inside a string.\n
146
+ --------------------------------------------------------------------------
147
+ The HEXA color can be in the formats (prefix `#`, `0x` or no prefix):<br>
148
+ `RGB`<br>
149
+ `RGBA` (if `allow_alpha=True`)<br>
150
+ `RRGGBB`<br>
151
+ `RRGGBBAA` (if `allow_alpha=True`)\n
152
+ --------------------------------------------------------------------------
153
+ ### Valid ranges:<br>
154
+ each channel from 0-9 and A-F (*case insensitive*)"""
155
+ return (
156
+ r"(?i)^(?:#|0x)?[0-9A-F]{8}|[0-9A-F]{6}|[0-9A-F]{4}|[0-9A-F]{3}$"
157
+ if allow_alpha
158
+ else r"(?i)^(?:#|0x)?[0-9A-F]{6}|[0-9A-F]{3}$"
159
+ )
xulbux/xx_string.py CHANGED
@@ -1,64 +1,116 @@
1
1
  import re as _re
2
2
 
3
3
 
4
-
5
-
6
4
  class String:
7
5
 
8
6
  @staticmethod
9
- def to_type(value:str) -> any:
7
+ def to_type(string: str) -> any:
10
8
  """Will convert a string to a type."""
11
- if value.lower() in ['true', 'false']: # BOOLEAN
12
- return value.lower() == 'true'
13
- elif value.lower() in ['none', 'null', 'undefined']: # NONE
9
+ if string.lower() in ("true", "false"): # BOOLEAN
10
+ return string.lower() == "true"
11
+ elif string.lower() in ("none", "null", "undefined"): # NONE
14
12
  return None
15
- elif value.startswith('[') and value.endswith(']'): # LIST
16
- return [String.to_type(item.strip()) for item in value[1:-1].split(',') if item.strip()]
17
- elif value.startswith('(') and value.endswith(')'): # TUPLE
18
- return tuple(String.to_type(item.strip()) for item in value[1:-1].split(',') if item.strip())
19
- elif value.startswith('{') and value.endswith('}'): # SET
20
- return {String.to_type(item.strip()) for item in value[1:-1].split(',') if item.strip()}
21
- elif value.startswith('{') and value.endswith('}') and ':' in value: # DICTIONARY
22
- return {String.to_type(k.strip()): String.to_type(v.strip()) for k, v in [item.split(':') for item in value[1:-1].split(',') if item.strip()]}
13
+ elif string.startswith("[") and string.endswith("]"): # LIST
14
+ return [String.to_type(item.strip()) for item in string[1:-1].split(",") if item.strip()]
15
+ elif string.startswith("(") and string.endswith(")"): # TUPLE
16
+ return tuple(String.to_type(item.strip()) for item in string[1:-1].split(",") if item.strip())
17
+ elif string.startswith("{") and string.endswith("}"): # SET
18
+ return {String.to_type(item.strip()) for item in string[1:-1].split(",") if item.strip()}
19
+ elif string.startswith("{") and string.endswith("}") and ":" in string: # DICTIONARY
20
+ return {
21
+ String.to_type(k.strip()): String.to_type(v.strip())
22
+ for k, v in (item.split(":") for item in string[1:-1].split(",") if item.strip())
23
+ }
23
24
  try: # NUMBER (INT OR FLOAT)
24
- if '.' in value or 'e' in value.lower():
25
- return float(value)
25
+ if "." in string or "e" in string.lower():
26
+ return float(string)
26
27
  else:
27
- return int(value)
28
- except ValueError: pass
29
- if value.startswith(("'", '"')) and value.endswith(("'", '"')): # STRING (WITH OR WITHOUT QUOTES)
30
- return value[1:-1]
28
+ return int(string)
29
+ except ValueError:
30
+ pass
31
+ if string.startswith(("'", '"')) and string.endswith(("'", '"')): # STRING (WITH OR WITHOUT QUOTES)
32
+ return string[1:-1]
31
33
  try: # COMPLEX
32
- return complex(value)
33
- except ValueError: pass
34
- return value # IF NOTHING ELSE MATCHES, RETURN AS IS
34
+ return complex(string)
35
+ except ValueError:
36
+ pass
37
+ return string # IF NOTHING ELSE MATCHES, RETURN AS IS
38
+
39
+ @staticmethod
40
+ def normalize_spaces(string: str, tab_spaces: int = 4) -> str:
41
+ """Replaces all special space characters with normal spaces.<br>
42
+ Also replaces tab characters with `tab_spaces` spaces."""
43
+ return (
44
+ string.replace("\t", " " * tab_spaces)
45
+ .replace("\u2000", " ")
46
+ .replace("\u2001", " ")
47
+ .replace("\u2002", " ")
48
+ .replace("\u2003", " ")
49
+ .replace("\u2004", " ")
50
+ .replace("\u2005", " ")
51
+ .replace("\u2006", " ")
52
+ .replace("\u2007", " ")
53
+ .replace("\u2008", " ")
54
+ .replace("\u2009", " ")
55
+ .replace("\u200A", " ")
56
+ )
57
+
58
+ @staticmethod
59
+ def escape(string: str, str_quotes: str = '"') -> str:
60
+ """Escapes the special characters and quotes inside a string.\n
61
+ ----------------------------------------------------------------------------
62
+ `str_quotes` can be either `"` or `'` and should match the quotes,<br>
63
+ the string will be put inside of. So if your string will be `"string"`,<br>
64
+ you should pass `"` to the parameter `str_quotes`.<br>
65
+ That way, if the string includes the same quotes, they will be escaped."""
66
+ string = (
67
+ string.replace("\\", r"\\")
68
+ .replace("\n", r"\n")
69
+ .replace("\r", r"\r")
70
+ .replace("\t", r"\t")
71
+ .replace("\b", r"\b")
72
+ .replace("\f", r"\f")
73
+ .replace("\a", r"\a")
74
+ )
75
+ if str_quotes == '"':
76
+ string = string.replace(r"\\'", "'").replace(r'"', r"\"")
77
+ elif str_quotes == "'":
78
+ string = string.replace(r'\\"', '"').replace(r"'", r"\'")
79
+ return string
35
80
 
36
81
  @staticmethod
37
- def get_repeated_symbol(string:str, symbol:str) -> int|bool:
38
- """If the string consists of one repeating `symbol`, it returns the number of times it is repeated.<br>
39
- If the string doesn't consist of one repeating symbol, it returns `False`."""
40
- if len(string) == len(symbol) * string.count(symbol):
41
- return string.count(symbol)
82
+ def is_empty(string: str, spaces_are_empty: bool = False):
83
+ """Returns `True` if the string is empty and `False` otherwise.<br>
84
+ If `spaces_are_empty` is true, it will also return `True` if the string is only spaces."""
85
+ return (string in (None, "")) or (spaces_are_empty and isinstance(string, str) and not string.strip())
86
+
87
+ @staticmethod
88
+ def single_char_repeats(string: str, char: str) -> int | bool:
89
+ """If the string consists of only the same `char`, it returns the number of times it is present.<br>
90
+ If the string doesn't consist of only the same character, it returns `False`.
91
+ """
92
+ if len(string) == len(char) * string.count(char):
93
+ return string.count(char)
42
94
  else:
43
95
  return False
44
96
 
45
97
  @staticmethod
46
- def decompose(case_string:str, seps:str = '-_', lower_all:bool = True) -> list[str]:
98
+ def decompose(case_string: str, seps: str = "-_", lower_all: bool = True) -> list[str]:
47
99
  """Will decompose the string (*any type of casing, also mixed*) into parts."""
48
- return [(part.lower() if lower_all else part) for part in _re.split(rf'(?<=[a-z])(?=[A-Z])|[{seps}]', case_string)]
100
+ return [(part.lower() if lower_all else part) for part in _re.split(rf"(?<=[a-z])(?=[A-Z])|[{seps}]", case_string)]
49
101
 
50
102
  @staticmethod
51
- def to_camel_case(string:str) -> str:
103
+ def to_camel_case(string: str) -> str:
52
104
  """Will convert the string of any type of casing to camel case."""
53
- return ''.join(part.capitalize() for part in String.decompose(string))
105
+ return "".join(part.capitalize() for part in String.decompose(string))
54
106
 
55
107
  @staticmethod
56
- def to_snake_case(string:str, sep:str = '_', screaming:bool = False) -> str:
108
+ def to_snake_case(string: str, sep: str = "_", screaming: bool = False) -> str:
57
109
  """Will convert the string of any type of casing to snake case."""
58
110
  return sep.join(part.upper() if screaming else part for part in String.decompose(string))
59
111
 
60
112
  @staticmethod
61
- def get_string_lines(string:str, remove_empty_lines:bool = False) -> list[str]:
113
+ def get_string_lines(string: str, remove_empty_lines: bool = False) -> list[str]:
62
114
  """Will split the string into lines."""
63
115
  if not remove_empty_lines:
64
116
  return string.splitlines()
@@ -71,46 +123,51 @@ class String:
71
123
  return non_empty_lines
72
124
 
73
125
  @staticmethod
74
- def remove_consecutive_empty_lines(string:str, max_consecutive:int = 0) -> str:
126
+ def remove_consecutive_empty_lines(string: str, max_consecutive: int = 0) -> str:
75
127
  """Will remove consecutive empty lines from the string.\n
76
128
  ----------------------------------------------------------------------------------------------
77
129
  If `max_consecutive` is `0`, it will remove all consecutive empty lines.<br>
78
130
  If `max_consecutive` is bigger than `0`, it will only allow `max_consecutive` consecutive<br>
79
- empty lines and everything above it will be cut down to `max_consecutive` empty lines."""
80
- return _re.sub(r'(\n\s*){2,}', r'\1' * (max_consecutive + 1), string)
131
+ empty lines and everything above it will be cut down to `max_consecutive` empty lines.
132
+ """
133
+ return _re.sub(r"(\n\s*){2,}", r"\1" * (max_consecutive + 1), string)
81
134
 
82
135
  @staticmethod
83
- def split_every_chars(string:str, split:int) -> list[str]:
84
- """Will split the string every `split` characters."""
85
- return [string[i:i + split] for i in range(0, len(string), split)]
136
+ def split_count(string: str, count: int) -> list[str]:
137
+ """Will split the string every `count` characters."""
138
+ return [string[i : i + count] for i in range(0, len(string), count)]
86
139
 
87
140
  @staticmethod
88
- def multi_strip(string:str, strip_chars:str = ' _-') -> str:
141
+ def multi_strip(string: str, strip_chars: str = " _-") -> str:
89
142
  """Will remove all leading and trailing `strip_chars` from the string."""
90
143
  for char in string:
91
144
  if char in strip_chars:
92
145
  string = string[1:]
93
- else: break
146
+ else:
147
+ break
94
148
  for char in string[::-1]:
95
149
  if char in strip_chars:
96
150
  string = string[:-1]
97
- else: break
151
+ else:
152
+ break
98
153
  return string
99
154
 
100
155
  @staticmethod
101
- def multi_lstrip(string:str, strip_chars:str = ' _-') -> str:
156
+ def multi_lstrip(string: str, strip_chars: str = " _-") -> str:
102
157
  """Will remove all leading `strip_chars` from the string."""
103
158
  for char in string:
104
159
  if char in strip_chars:
105
160
  string = string[1:]
106
- else: break
161
+ else:
162
+ break
107
163
  return string
108
164
 
109
165
  @staticmethod
110
- def multi_rstrip(string:str, strip_chars:str = ' _-') -> str:
166
+ def multi_rstrip(string: str, strip_chars: str = " _-") -> str:
111
167
  """Will remove all trailing `strip_chars` from the string."""
112
168
  for char in string[::-1]:
113
169
  if char in strip_chars:
114
170
  string = string[:-1]
115
- else: break
171
+ else:
172
+ break
116
173
  return string
xulbux/xx_system.py CHANGED
@@ -5,71 +5,82 @@ import sys as _sys
5
5
  import os as _os
6
6
 
7
7
 
8
-
9
-
10
8
  class System:
11
9
 
12
10
  @staticmethod
13
- def restart(prompt:object = None, wait:int = 0, continue_program:bool = False, force:bool = False) -> None:
11
+ def restart(
12
+ prompt: object = None,
13
+ wait: int = 0,
14
+ continue_program: bool = False,
15
+ force: bool = False,
16
+ ) -> None:
14
17
  """Starts a system restart:<br>
15
18
  `prompt` is the message to be displayed in the systems restart notification.<br>
16
19
  `wait` is the time to wait until restarting in seconds.<br>
17
20
  `continue_program` is whether to continue the current Python program after calling this function.<br>
18
- `force` is whether to force a restart even if other processes are still running."""
21
+ `force` is whether to force a restart even if other processes are still running.
22
+ """
19
23
  system = _platform.system().lower()
20
- if system == 'windows':
24
+ if system == "windows":
21
25
  if not force:
22
- output = _subprocess.check_output('tasklist', shell=True).decode()
26
+ output = _subprocess.check_output("tasklist", shell=True).decode()
23
27
  processes = [line.split()[0] for line in output.splitlines()[3:] if line.strip()]
24
28
  if len(processes) > 2: # EXCLUDING THE PYTHON PROCESS AND CMD
25
- raise RuntimeError('Processes are still running. Use the parameter `force=True` to restart anyway.')
29
+ raise RuntimeError("Processes are still running. Use the parameter `force=True` to restart anyway.")
26
30
  if prompt:
27
31
  _os.system(f'shutdown /r /t {wait} /c "{prompt}"')
28
32
  else:
29
- _os.system('shutdown /r /t 0')
33
+ _os.system("shutdown /r /t 0")
30
34
  if continue_program:
31
- print(f'Restarting in {wait} seconds...')
35
+ print(f"Restarting in {wait} seconds...")
32
36
  _time.sleep(wait)
33
- elif system in ['linux', 'darwin']:
37
+ elif system in ("linux", "darwin"):
34
38
  if not force:
35
- output = _subprocess.check_output(['ps', '-A']).decode()
39
+ output = _subprocess.check_output(["ps", "-A"]).decode()
36
40
  processes = output.splitlines()[1:] # EXCLUDE HEADER
37
41
  if len(processes) > 2: # EXCLUDING THE PYTHON PROCESS AND PS
38
- raise RuntimeError('Processes are still running. Use the parameter `force=True` to restart anyway.')
42
+ raise RuntimeError("Processes are still running. Use the parameter `force=True` to restart anyway.")
39
43
  if prompt:
40
- _subprocess.Popen(['notify-send', 'System Restart', prompt])
44
+ _subprocess.Popen(["notify-send", "System Restart", prompt])
41
45
  _time.sleep(wait)
42
46
  try:
43
- _subprocess.run(['sudo', 'shutdown', '-r', 'now'])
47
+ _subprocess.run(["sudo", "shutdown", "-r", "now"])
44
48
  except _subprocess.CalledProcessError:
45
- raise PermissionError('Failed to restart: insufficient privileges. Ensure sudo permissions are granted.')
49
+ raise PermissionError("Failed to restart: insufficient privileges. Ensure sudo permissions are granted.")
46
50
  if continue_program:
47
- print(f'Restarting in {wait} seconds...')
51
+ print(f"Restarting in {wait} seconds...")
48
52
  _time.sleep(wait)
49
53
  else:
50
- raise NotImplementedError(f'Restart not implemented for `{system}`')
54
+ raise NotImplementedError(f"Restart not implemented for `{system}`")
51
55
 
52
56
  @staticmethod
53
- def check_libs(lib_names:list[str], install_missing:bool = False, confirm_install:bool = True) -> None|list[str]:
57
+ def check_libs(
58
+ lib_names: list[str],
59
+ install_missing: bool = False,
60
+ confirm_install: bool = True,
61
+ ) -> None | list[str]:
54
62
  """Checks if the given list of libraries are installed. If not:
55
63
  - If `install_missing` is `False` the missing libraries will be returned as a list.
56
- - If `install_missing` is `True` the missing libraries will be installed. If `confirm_install` is `True` the user will first be asked if they want to install the missing libraries."""
64
+ - If `install_missing` is `True` the missing libraries will be installed. If `confirm_install` is `True` the user will first be asked if they want to install the missing libraries.
65
+ """
57
66
  missing = []
58
67
  for lib in lib_names:
59
- try: __import__(lib)
60
- except ImportError: missing.append(lib)
68
+ try:
69
+ __import__(lib)
70
+ except ImportError:
71
+ missing.append(lib)
61
72
  if not missing:
62
73
  return None
63
74
  elif not install_missing:
64
75
  return missing
65
76
  if confirm_install:
66
- print('The following required libraries are missing:')
77
+ print("The following required libraries are missing:")
67
78
  for lib in missing:
68
- print(f'- {lib}')
69
- if input('Do you want to install them now (Y/n): ').strip().lower() not in ['', 'y', 'yes']:
70
- raise ImportError('Missing required libraries.')
79
+ print(f"- {lib}")
80
+ if input("Do you want to install them now (Y/n): ").strip().lower() not in ("", "y", "yes"):
81
+ raise ImportError("Missing required libraries.")
71
82
  try:
72
- _subprocess.check_call([_sys.executable, '-m', 'pip', 'install'] + missing)
83
+ _subprocess.check_call([_sys.executable, "-m", "pip", "install"] + missing)
73
84
  return None
74
85
  except _subprocess.CalledProcessError:
75
86
  return missing