MainShortcuts2 2.4.2__tar.gz → 2.4.3__tar.gz
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.
- {mainshortcuts2-2.4.2 → mainshortcuts2-2.4.3}/PKG-INFO +2 -3
- {mainshortcuts2-2.4.2 → mainshortcuts2-2.4.3}/README.md +1 -2
- {mainshortcuts2-2.4.2 → mainshortcuts2-2.4.3}/pyproject.toml +2 -2
- {mainshortcuts2-2.4.2 → mainshortcuts2-2.4.3}/src/MainShortcuts2/__main__.py +33 -23
- {mainshortcuts2-2.4.2 → mainshortcuts2-2.4.3}/src/MainShortcuts2/_module_info.py +1 -1
- {mainshortcuts2-2.4.2 → mainshortcuts2-2.4.3}/src/MainShortcuts2/advanced.py +2 -2
- {mainshortcuts2-2.4.2 → mainshortcuts2-2.4.3}/src/MainShortcuts2/api/base.py +18 -3
- {mainshortcuts2-2.4.2 → mainshortcuts2-2.4.3}/src/MainShortcuts2/api/gigachat.py +1 -1
- {mainshortcuts2-2.4.2 → mainshortcuts2-2.4.3}/src/MainShortcuts2/term.py +1 -1
- mainshortcuts2-2.4.3/src/MainShortcuts2/types.py +408 -0
- mainshortcuts2-2.4.2/src/MainShortcuts2/types.py +0 -147
- {mainshortcuts2-2.4.2 → mainshortcuts2-2.4.3}/src/MainShortcuts2/__init__.py +0 -0
- {mainshortcuts2-2.4.2 → mainshortcuts2-2.4.3}/src/MainShortcuts2/_any2json_regs.py +0 -0
- {mainshortcuts2-2.4.2 → mainshortcuts2-2.4.3}/src/MainShortcuts2/any2json.py +0 -0
- {mainshortcuts2-2.4.2 → mainshortcuts2-2.4.3}/src/MainShortcuts2/api/russian_trusted_root_ca_pem.crt +0 -0
- {mainshortcuts2-2.4.2 → mainshortcuts2-2.4.3}/src/MainShortcuts2/api/russian_trusted_sub_ca_pem.crt +0 -0
- {mainshortcuts2-2.4.2 → mainshortcuts2-2.4.3}/src/MainShortcuts2/cfg.py +0 -0
- {mainshortcuts2-2.4.2 → mainshortcuts2-2.4.3}/src/MainShortcuts2/core.py +0 -0
- {mainshortcuts2-2.4.2 → mainshortcuts2-2.4.3}/src/MainShortcuts2/dict.py +0 -0
- {mainshortcuts2-2.4.2 → mainshortcuts2-2.4.3}/src/MainShortcuts2/dir.py +0 -0
- {mainshortcuts2-2.4.2 → mainshortcuts2-2.4.3}/src/MainShortcuts2/file.py +0 -0
- {mainshortcuts2-2.4.2 → mainshortcuts2-2.4.3}/src/MainShortcuts2/json.py +0 -0
- {mainshortcuts2-2.4.2 → mainshortcuts2-2.4.3}/src/MainShortcuts2/list.py +0 -0
- {mainshortcuts2-2.4.2 → mainshortcuts2-2.4.3}/src/MainShortcuts2/path.py +0 -0
- {mainshortcuts2-2.4.2 → mainshortcuts2-2.4.3}/src/MainShortcuts2/proc.py +0 -0
- {mainshortcuts2-2.4.2 → mainshortcuts2-2.4.3}/src/MainShortcuts2/regex.py +0 -0
- {mainshortcuts2-2.4.2 → mainshortcuts2-2.4.3}/src/MainShortcuts2/special_chars.py +0 -0
- {mainshortcuts2-2.4.2 → mainshortcuts2-2.4.3}/src/MainShortcuts2/str.py +0 -0
- {mainshortcuts2-2.4.2 → mainshortcuts2-2.4.3}/src/MainShortcuts2/utils.py +0 -0
- {mainshortcuts2-2.4.2 → mainshortcuts2-2.4.3}/src/MainShortcuts2/win.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: MainShortcuts2
|
|
3
|
-
Version: 2.4.
|
|
3
|
+
Version: 2.4.3
|
|
4
4
|
Summary: Сокращение и улучшение функций + консольные утилиты
|
|
5
5
|
Home-page: https://github.com/MainPlay-TG/MainShortcuts2.py
|
|
6
6
|
Author: MainPlay TG
|
|
@@ -17,7 +17,7 @@ Classifier: Programming Language :: Python :: 3.12
|
|
|
17
17
|
Project-URL: Repository, https://github.com/MainPlay-TG/MainShortcuts2.py
|
|
18
18
|
Description-Content-Type: text/markdown
|
|
19
19
|
|
|
20
|
-
#
|
|
20
|
+
# MainShortcuts2
|
|
21
21
|
## Описание
|
|
22
22
|
Сокращение и улучшение функций
|
|
23
23
|
## Установка
|
|
@@ -29,7 +29,6 @@ python3 -m pip install -U MainShortcuts2
|
|
|
29
29
|
Импорт модуля
|
|
30
30
|
```python
|
|
31
31
|
from MainShortcuts2 import ms
|
|
32
|
-
exec(ms.import_code)
|
|
33
32
|
```
|
|
34
33
|
Встроенная информация о модуле
|
|
35
34
|
```python
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#
|
|
1
|
+
# MainShortcuts2
|
|
2
2
|
## Описание
|
|
3
3
|
Сокращение и улучшение функций
|
|
4
4
|
## Установка
|
|
@@ -10,7 +10,6 @@ python3 -m pip install -U MainShortcuts2
|
|
|
10
10
|
Импорт модуля
|
|
11
11
|
```python
|
|
12
12
|
from MainShortcuts2 import ms
|
|
13
|
-
exec(ms.import_code)
|
|
14
13
|
```
|
|
15
14
|
Встроенная информация о модуле
|
|
16
15
|
```python
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
|
-
version = "2.4.
|
|
2
|
+
version = "2.4.3"
|
|
3
3
|
name = "MainShortcuts2"
|
|
4
4
|
description = "Сокращение и улучшение функций + консольные утилиты"
|
|
5
5
|
authors = [ "MainPlay TG <xbox.roman6666666666@gmail.com>",]
|
|
@@ -21,5 +21,5 @@ nginx-restart = "MainShortcuts2.__main__:nginx_restart"
|
|
|
21
21
|
python = "^3.6"
|
|
22
22
|
|
|
23
23
|
[build-system]
|
|
24
|
-
requires = [ "poetry-core",]
|
|
25
24
|
build-backend = "poetry.core.masonry.api"
|
|
25
|
+
requires = [ "poetry-core",]
|
|
@@ -11,17 +11,19 @@ def import_example():
|
|
|
11
11
|
print("from MainShortcuts2 import ms")
|
|
12
12
|
|
|
13
13
|
|
|
14
|
-
def nano_json():
|
|
14
|
+
def nano_json(args: argparse.Namespace = None):
|
|
15
15
|
ms.utils.check_programs("nano")
|
|
16
16
|
import subprocess
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
17
|
+
if args is None:
|
|
18
|
+
argp = argparse.ArgumentParser("nano-json", description="форматирование JSON файлов и редактирование в GNU NANO")
|
|
19
|
+
argp.add_argument("files", nargs="+", help="пути к файлам JSON")
|
|
20
|
+
argp.add_argument("--nano-help", action="store_true", help="показать помощь nano")
|
|
21
|
+
argp.add_argument("-e", "--encoding", default="utf-8", help="кодировка файлов")
|
|
22
|
+
argp.add_argument("-f", "--rcfile", help="использовать только этот файл для настройки nano")
|
|
23
|
+
argp.add_argument("-m", "--mode", choices=ms.json.MODES, default="p", help="режим сохранения редактирования")
|
|
24
|
+
argp.add_argument("-s", "--sort", action="store_true", help="сортировать ключи словаря")
|
|
25
|
+
argp.add_argument("-u", "--no-escape", action="store_false", help="не использовать Unicode Escape")
|
|
26
|
+
args = argp.parse_args()
|
|
25
27
|
if args.nano_help:
|
|
26
28
|
return subprocess.call(["nano", "--help"])
|
|
27
29
|
nano_args = ["nano"]
|
|
@@ -78,20 +80,22 @@ def nginx_restart():
|
|
|
78
80
|
sys.exit(subprocess.call(["systemctl", "restart", "nginx"]))
|
|
79
81
|
|
|
80
82
|
|
|
81
|
-
def hash_gen():
|
|
83
|
+
def hash_gen(args: argparse.Namespace = None):
|
|
82
84
|
import os
|
|
83
85
|
import hashlib
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
86
|
+
if args is None:
|
|
87
|
+
argp = argparse.ArgumentParser("ms2-hash-gen", description="создание контрольной суммы для файла")
|
|
88
|
+
argp.add_argument("files", nargs="+", help="пути к файлам")
|
|
89
|
+
argp.add_argument("-b", "--bar", action="store_true", help="показывать прогрессбар (нужен модуль progressbar2)")
|
|
90
|
+
argp.add_argument("-t", "--type", choices=HASH_TYPES, default="sha512", help="тип контрольной суммы")
|
|
91
|
+
args = argp.parse_args()
|
|
89
92
|
if args.bar:
|
|
90
93
|
import progressbar
|
|
91
94
|
pbar_w = [
|
|
92
95
|
progressbar.Percentage(),
|
|
93
96
|
progressbar.GranularBar(left="(", right=")"),
|
|
94
97
|
progressbar.FileTransferSpeed(),
|
|
98
|
+
" ",
|
|
95
99
|
progressbar.ETA(format="%(eta)8s", format_finished="%(elapsed)8s", format_na=" N/A", format_not_started="--:--:--", format_zero="00:00:00"),
|
|
96
100
|
]
|
|
97
101
|
data = {}
|
|
@@ -119,30 +123,35 @@ def hash_gen():
|
|
|
119
123
|
c += len(chunk)
|
|
120
124
|
pbar.update(c)
|
|
121
125
|
if args.bar:
|
|
122
|
-
pbar.finish(
|
|
126
|
+
pbar.finish()
|
|
123
127
|
data["hash"]["hex"] = hash.hexdigest()
|
|
124
128
|
ms.json.write(file + HASH_SUFFIX, data)
|
|
125
129
|
|
|
126
130
|
|
|
127
|
-
def hash_check():
|
|
131
|
+
def hash_check(args: argparse.Namespace = None):
|
|
128
132
|
import hashlib
|
|
129
133
|
import os
|
|
130
134
|
import shlex
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
+
if args is None:
|
|
136
|
+
argp = argparse.ArgumentParser("ms2-hash-check", description="проверка размера и контрольной суммы файла")
|
|
137
|
+
argp.add_argument("-b", "--bar", action="store_true", help="показывать прогрессбар (нужен модуль progressbar2)")
|
|
138
|
+
argp.add_argument("files", nargs="+", help="пути к файлам")
|
|
139
|
+
args = argp.parse_args()
|
|
135
140
|
if args.bar:
|
|
136
141
|
import progressbar
|
|
137
142
|
pbar_w = [
|
|
138
143
|
progressbar.Percentage(),
|
|
139
144
|
progressbar.GranularBar(left="(", right=")"),
|
|
140
145
|
progressbar.FileTransferSpeed(),
|
|
146
|
+
" ",
|
|
141
147
|
progressbar.ETA(format="%(eta)8s", format_finished="%(elapsed)8s", format_na=" N/A", format_not_started="--:--:--", format_zero="00:00:00"),
|
|
142
148
|
]
|
|
149
|
+
completed = []
|
|
143
150
|
for file in args.files:
|
|
144
151
|
if file.lower().endswith(HASH_SUFFIX.lower()):
|
|
145
152
|
file = file[:0 - len(HASH_SUFFIX)]
|
|
153
|
+
if file in completed:
|
|
154
|
+
continue
|
|
146
155
|
if not os.path.exists(file + HASH_SUFFIX):
|
|
147
156
|
print("Ошибка: не найден файл " + shlex.quote(file + HASH_SUFFIX), file=sys.stderr)
|
|
148
157
|
continue
|
|
@@ -165,10 +174,11 @@ def hash_check():
|
|
|
165
174
|
hash.update(chunk)
|
|
166
175
|
if args.bar:
|
|
167
176
|
c += len(chunk)
|
|
168
|
-
pbar.update()
|
|
177
|
+
pbar.update(c)
|
|
169
178
|
if args.bar:
|
|
170
|
-
pbar.finish(
|
|
179
|
+
pbar.finish()
|
|
171
180
|
if data["hash"]["hex"] == hash.hexdigest():
|
|
172
181
|
print("Успех: файл " + shlex.quote(file) + " не изменён")
|
|
173
182
|
else:
|
|
174
183
|
print("Ошибка: файл " + shlex.quote(file) + " изменён")
|
|
184
|
+
completed.append(file)
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
name = "MainShortcuts2"
|
|
2
|
-
version = "2.4.
|
|
2
|
+
version = "2.4.3"
|
|
@@ -320,10 +320,10 @@ class DictScriptRunner:
|
|
|
320
320
|
|
|
321
321
|
def reg_class(self, name: str = None, overwrite: bool = False):
|
|
322
322
|
def deco(cls: type):
|
|
323
|
-
if name is None:
|
|
323
|
+
if name is None:
|
|
324
324
|
name = cls.__module__ + "." + cls.__name__
|
|
325
325
|
if callable(cls):
|
|
326
|
-
self.reg_function(name, overwrite=overwrite)(cls)
|
|
326
|
+
self.reg_function(name, overwrite=overwrite)(cls)
|
|
327
327
|
for k in dir(cls):
|
|
328
328
|
v = getattr(cls, k)
|
|
329
329
|
if callable(v):
|
|
@@ -2,15 +2,30 @@ import requests
|
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
class Base:
|
|
5
|
-
def __init__(self,
|
|
5
|
+
def __init__(self, **kw):
|
|
6
|
+
self._init(**kw)
|
|
7
|
+
|
|
8
|
+
def _init(self, session: requests.Session = None):
|
|
6
9
|
self._headers = {}
|
|
7
|
-
self._http =
|
|
10
|
+
self._http = session
|
|
8
11
|
self._params = {}
|
|
9
|
-
self._url_data = {}
|
|
10
12
|
self._url = "https://example.com/api/{method}"
|
|
13
|
+
self._url_data = {}
|
|
14
|
+
|
|
15
|
+
def __enter__(self):
|
|
16
|
+
return self
|
|
17
|
+
|
|
18
|
+
def __exit__(self, *a):
|
|
19
|
+
self.http.close()
|
|
20
|
+
|
|
21
|
+
def __repr__(self) -> str:
|
|
22
|
+
cls = type(self)
|
|
23
|
+
return "%s.%s(...)" % (cls.__module__, cls.__name__)
|
|
11
24
|
|
|
12
25
|
@property
|
|
13
26
|
def http(self) -> requests.Session:
|
|
27
|
+
if self._http is None:
|
|
28
|
+
self._http = requests.Session()
|
|
14
29
|
return self._http
|
|
15
30
|
|
|
16
31
|
def _request(self, http_method: str, api_method: str, *, headers: dict[str, str] = None, params: dict[str, str] = None, raise_for_status: bool = True, url_data: dict[str, str] = None, **kw):
|
|
@@ -9,7 +9,7 @@ class GigaChat(Base):
|
|
|
9
9
|
def __init__(self, auth_data: str, client_id: str, *,
|
|
10
10
|
cert_path: str = None,
|
|
11
11
|
**kw):
|
|
12
|
-
|
|
12
|
+
self._init(**kw)
|
|
13
13
|
self._access_token = {"expire_at": 0, "kw": None, "token": None}
|
|
14
14
|
self._auth_data: str = auth_data
|
|
15
15
|
self._client_id: str = client_id
|
|
@@ -95,7 +95,7 @@ def color_test(colors: list[str] = None):
|
|
|
95
95
|
cprint("$COLOR_RESET%s: $COLOR_%sEXAMPLE \u2591\u2592\u2593 \u2588\u2588\u2588" % (i, i))
|
|
96
96
|
|
|
97
97
|
|
|
98
|
-
def _clear():
|
|
98
|
+
def _clear(): # type: ignore
|
|
99
99
|
"""Если функция недоступна для ОС, дать ошибку"""
|
|
100
100
|
raise OSError("The function is not available on %s" % sys.platform)
|
|
101
101
|
|
|
@@ -0,0 +1,408 @@
|
|
|
1
|
+
"""Различные объекты и исключения"""
|
|
2
|
+
from typing import Union
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class Base:
|
|
6
|
+
def __init__(self, *args, **kwargs):
|
|
7
|
+
self.args = args
|
|
8
|
+
self.kwargs = kwargs
|
|
9
|
+
self.type = type(self)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class UserError(Exception):
|
|
13
|
+
pass
|
|
14
|
+
"""Ошибка, которую допустил пользователь. Например неправильно указал входные данные"""
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class AccessDeniedError(UserError):
|
|
18
|
+
pass
|
|
19
|
+
"""Ошибка доступа"""
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class Empty(Base):
|
|
23
|
+
pass
|
|
24
|
+
"""Пустота (не равно `None`)"""
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class Infinity(Base):
|
|
28
|
+
pass
|
|
29
|
+
"""Бесконечное число"""
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class NotAFileError(Exception):
|
|
33
|
+
pass
|
|
34
|
+
"""Ошибка 'это не файл'"""
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class NotANumber(Base):
|
|
38
|
+
pass
|
|
39
|
+
"""Не число"""
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class NotFound(Base):
|
|
43
|
+
pass
|
|
44
|
+
"""Не найдено"""
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class NotFoundError(Exception):
|
|
48
|
+
pass
|
|
49
|
+
"""Ошибка 'не найдено'"""
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class Action:
|
|
53
|
+
def __init__(self, func, *args, **kwargs):
|
|
54
|
+
self._closed = False
|
|
55
|
+
self._completed = False
|
|
56
|
+
self._error = None
|
|
57
|
+
self._launched = False
|
|
58
|
+
self._result = None
|
|
59
|
+
self.args: tuple = args
|
|
60
|
+
self.func = func
|
|
61
|
+
self.kwargs: dict = kwargs
|
|
62
|
+
|
|
63
|
+
def __enter__(self):
|
|
64
|
+
return self
|
|
65
|
+
|
|
66
|
+
def __exit__(self, a, b, c):
|
|
67
|
+
self.close()
|
|
68
|
+
|
|
69
|
+
def _check(self, launched: bool = None, completed: bool = None, closed: bool = None):
|
|
70
|
+
if not launched is None:
|
|
71
|
+
if launched:
|
|
72
|
+
if not self.launched:
|
|
73
|
+
raise RuntimeError("The action has not yet been launched")
|
|
74
|
+
else:
|
|
75
|
+
if self.launched:
|
|
76
|
+
raise RuntimeError("The action has already been launched")
|
|
77
|
+
if not completed is None:
|
|
78
|
+
if completed:
|
|
79
|
+
if not self.completed:
|
|
80
|
+
raise RuntimeError("The action has not yet been completed")
|
|
81
|
+
else:
|
|
82
|
+
if self.completed:
|
|
83
|
+
raise RuntimeError("The action has already been completed")
|
|
84
|
+
if not closed is None:
|
|
85
|
+
if closed:
|
|
86
|
+
if not self.closed:
|
|
87
|
+
raise RuntimeError("The action has not yet been closed")
|
|
88
|
+
else:
|
|
89
|
+
if self.closed:
|
|
90
|
+
raise RuntimeError("The action has already been closed")
|
|
91
|
+
|
|
92
|
+
def close(self):
|
|
93
|
+
self._closed = True
|
|
94
|
+
self._error = None
|
|
95
|
+
self._result = None
|
|
96
|
+
self.args = None
|
|
97
|
+
self.func = None
|
|
98
|
+
self.kwargs = None
|
|
99
|
+
|
|
100
|
+
@property
|
|
101
|
+
def launched(self) -> bool:
|
|
102
|
+
return self._launched
|
|
103
|
+
|
|
104
|
+
@property
|
|
105
|
+
def completed(self) -> bool:
|
|
106
|
+
return self._completed
|
|
107
|
+
|
|
108
|
+
@property
|
|
109
|
+
def exception(self) -> Union[None, Exception]:
|
|
110
|
+
self._check(launched=True, completed=True, closed=False)
|
|
111
|
+
return self._error
|
|
112
|
+
|
|
113
|
+
@property
|
|
114
|
+
def result(self):
|
|
115
|
+
self._check(launched=True, completed=True, closed=False)
|
|
116
|
+
if not self._error is None:
|
|
117
|
+
raise self._error # type: ignore
|
|
118
|
+
return self._result
|
|
119
|
+
|
|
120
|
+
@property
|
|
121
|
+
def closed(self) -> bool:
|
|
122
|
+
return self._closed
|
|
123
|
+
|
|
124
|
+
def run(self):
|
|
125
|
+
self._check(launched=False, completed=False, closed=False)
|
|
126
|
+
self._launched = True
|
|
127
|
+
try:
|
|
128
|
+
self._result = self.func(*self.args, **self.kwargs) # type: ignore
|
|
129
|
+
except Exception as err:
|
|
130
|
+
self._error = err
|
|
131
|
+
self._completed = True
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
class OnlyOneInstanceError(BaseException):
|
|
135
|
+
"""Ошибка для `.utils.OnlyOneInstance`"""
|
|
136
|
+
|
|
137
|
+
def __init__(self, *args):
|
|
138
|
+
if len(args) == 0:
|
|
139
|
+
args = ("Another instance is already running",)
|
|
140
|
+
BaseException.__init__(self, *args)
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
class DotDict:
|
|
144
|
+
def __init__(self, data: dict = None):
|
|
145
|
+
self._data = {}
|
|
146
|
+
for k in data:
|
|
147
|
+
self[k] = data[k]
|
|
148
|
+
|
|
149
|
+
def __delattr__(self, k: str):
|
|
150
|
+
if k.startswith("_"):
|
|
151
|
+
return object.__delattr__(self, k)
|
|
152
|
+
del self.data[k]
|
|
153
|
+
|
|
154
|
+
def __getattr__(self, k: str):
|
|
155
|
+
if k.startswith("_"):
|
|
156
|
+
return object.__getattr__(self, k)
|
|
157
|
+
return self[k]
|
|
158
|
+
|
|
159
|
+
def __setattr__(self, k: str, v):
|
|
160
|
+
if k.startswith("_"):
|
|
161
|
+
return object.__setattr__(self, k, v)
|
|
162
|
+
self[k] = v
|
|
163
|
+
|
|
164
|
+
def __contains__(self, k: str):
|
|
165
|
+
return k in self._data
|
|
166
|
+
|
|
167
|
+
def __delitem__(self, k: str):
|
|
168
|
+
del self._data[k]
|
|
169
|
+
|
|
170
|
+
def __getitem__(self, k: str):
|
|
171
|
+
return self._data[k]
|
|
172
|
+
|
|
173
|
+
def __setitem__(self, k: str, v):
|
|
174
|
+
if "." in k:
|
|
175
|
+
k, subk = k.split(".", 1)
|
|
176
|
+
v = {subk: v}
|
|
177
|
+
if isinstance(v, dict):
|
|
178
|
+
v = type(self)(v)
|
|
179
|
+
self._data[k] = v
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
class Color:
|
|
183
|
+
"""Значение цвета"""
|
|
184
|
+
|
|
185
|
+
def __init__(self, *args,
|
|
186
|
+
ahex: str = None,
|
|
187
|
+
hex: str = None,
|
|
188
|
+
hexa: str = None,
|
|
189
|
+
rgb: tuple[int, int, int] = None,
|
|
190
|
+
rgba: tuple[int, int, int, int] = None,
|
|
191
|
+
):
|
|
192
|
+
self._init_complete = False
|
|
193
|
+
self._readonly = False
|
|
194
|
+
self._red = None
|
|
195
|
+
self._green = None
|
|
196
|
+
self._blue = None
|
|
197
|
+
self._alpha = 255
|
|
198
|
+
largs = len(args)
|
|
199
|
+
if largs == 0:
|
|
200
|
+
pass
|
|
201
|
+
elif largs == 3:
|
|
202
|
+
self._check_init()
|
|
203
|
+
self.rgb = args
|
|
204
|
+
elif largs == 4:
|
|
205
|
+
self._check_init()
|
|
206
|
+
self.rgba = args
|
|
207
|
+
else:
|
|
208
|
+
raise TypeError("Give from 3 to 4 positional arguments or 1 keyword argument")
|
|
209
|
+
if not ahex is None:
|
|
210
|
+
self._check_init()
|
|
211
|
+
self.ahex = ahex
|
|
212
|
+
if not hex is None:
|
|
213
|
+
self._check_init()
|
|
214
|
+
self.hex = hex
|
|
215
|
+
if not hexa is None:
|
|
216
|
+
self._check_init()
|
|
217
|
+
self.hexa = hexa
|
|
218
|
+
if not rgb is None:
|
|
219
|
+
self._check_init()
|
|
220
|
+
self.rgb = rgb
|
|
221
|
+
if not rgba is None:
|
|
222
|
+
self._check_init()
|
|
223
|
+
self.rgba = rgba
|
|
224
|
+
if not self._init_complete:
|
|
225
|
+
raise TypeError("Give from 3 to 4 positional arguments or 1 keyword argument")
|
|
226
|
+
|
|
227
|
+
def __repr__(self):
|
|
228
|
+
cls = type(self)
|
|
229
|
+
return "%s.%s(rgba=%r)" % (cls.__module__, cls.__name__, self.rgba)
|
|
230
|
+
|
|
231
|
+
@property
|
|
232
|
+
def red(self) -> int:
|
|
233
|
+
"""Уровень красного от 0 до 255"""
|
|
234
|
+
return self._red
|
|
235
|
+
|
|
236
|
+
@red.setter
|
|
237
|
+
def red(self, v):
|
|
238
|
+
self._check_ro()
|
|
239
|
+
self._red = self._check_num(v)
|
|
240
|
+
self._reset()
|
|
241
|
+
|
|
242
|
+
@property
|
|
243
|
+
def green(self) -> int:
|
|
244
|
+
"""Уровень зелёного от 0 до 255"""
|
|
245
|
+
return self._green
|
|
246
|
+
|
|
247
|
+
@green.setter
|
|
248
|
+
def green(self, v):
|
|
249
|
+
self._check_ro()
|
|
250
|
+
self._green = self._check_num(v)
|
|
251
|
+
self._reset()
|
|
252
|
+
|
|
253
|
+
@property
|
|
254
|
+
def blue(self) -> int:
|
|
255
|
+
"""Уровень синего от 0 до 255"""
|
|
256
|
+
return self._blue
|
|
257
|
+
|
|
258
|
+
@blue.setter
|
|
259
|
+
def blue(self, v):
|
|
260
|
+
self._check_ro()
|
|
261
|
+
self._blue = self._check_num(v)
|
|
262
|
+
self._reset()
|
|
263
|
+
|
|
264
|
+
@property
|
|
265
|
+
def alpha(self) -> int:
|
|
266
|
+
"""Уровень прозрачности от 0 до 255"""
|
|
267
|
+
return self._alpha
|
|
268
|
+
|
|
269
|
+
@alpha.setter
|
|
270
|
+
def alpha(self, v):
|
|
271
|
+
self._check_ro()
|
|
272
|
+
self._alpha = self._check_num(v)
|
|
273
|
+
self._reset()
|
|
274
|
+
|
|
275
|
+
@property
|
|
276
|
+
def ahex(self) -> str:
|
|
277
|
+
"""Цвет в формате AHEX (`aarrggbb`)"""
|
|
278
|
+
if self._ahex is None:
|
|
279
|
+
self._ahex = ("%02x" % self.alpha) + self.hex
|
|
280
|
+
return self._ahex
|
|
281
|
+
|
|
282
|
+
@ahex.setter
|
|
283
|
+
def ahex(self, v):
|
|
284
|
+
self.alpha, self.red, self.green, self.blue = self._split_hex(v, 4)
|
|
285
|
+
|
|
286
|
+
@property
|
|
287
|
+
def hex(self) -> str:
|
|
288
|
+
"""Цвет в формате HEX (`rrggbb`). **Без прозрачности**"""
|
|
289
|
+
if self._hex is None:
|
|
290
|
+
self._hex = "%02x%02x%02x" % self.rgb
|
|
291
|
+
return self._hex
|
|
292
|
+
|
|
293
|
+
@hex.setter
|
|
294
|
+
def hex(self, v):
|
|
295
|
+
self.rgb = self._split_hex(v, 3)
|
|
296
|
+
|
|
297
|
+
@property
|
|
298
|
+
def hexa(self) -> str:
|
|
299
|
+
"""Цвет в формате HEXA (`rrggbbaa`)"""
|
|
300
|
+
if self._hexa is None:
|
|
301
|
+
self._hexa = self.hex + ("%02x" % self.alpha)
|
|
302
|
+
return self._hexa
|
|
303
|
+
|
|
304
|
+
@hexa.setter
|
|
305
|
+
def hexa(self, v):
|
|
306
|
+
self.rgba = self._split_hex(v, 4)
|
|
307
|
+
|
|
308
|
+
@property
|
|
309
|
+
def rgb(self) -> tuple[int, int, int]:
|
|
310
|
+
"""Цвет в формате RGB. **Без прозрачности**"""
|
|
311
|
+
if self._rgb is None:
|
|
312
|
+
self._rgb = (self.red, self.green, self.blue)
|
|
313
|
+
return self._rgb
|
|
314
|
+
|
|
315
|
+
@rgb.setter
|
|
316
|
+
def rgb(self, v):
|
|
317
|
+
self.red, self.green, self.blue = v
|
|
318
|
+
|
|
319
|
+
@property
|
|
320
|
+
def rgba(self) -> tuple[int, int, int, int]:
|
|
321
|
+
"""Цвет в формате RGBA"""
|
|
322
|
+
if self._rgba is None:
|
|
323
|
+
self._rgba = (self.red, self.green, self.blue, self.alpha)
|
|
324
|
+
return self._rgba
|
|
325
|
+
|
|
326
|
+
@rgba.setter
|
|
327
|
+
def rgba(self, v):
|
|
328
|
+
self.red, self.green, self.blue, self.alpha = v
|
|
329
|
+
|
|
330
|
+
def _check_init(self):
|
|
331
|
+
if self._init_complete:
|
|
332
|
+
raise TypeError("Give from 3 to 4 positional arguments or 1 keyword argument")
|
|
333
|
+
self._init_complete = True
|
|
334
|
+
|
|
335
|
+
def _check_num(self, num: int):
|
|
336
|
+
if not isinstance(num, int):
|
|
337
|
+
raise TypeError(type(num), int)
|
|
338
|
+
if (num < 0) or (num > 255):
|
|
339
|
+
raise ValueError("The number should be in the range from 0 to 255, not %i" % num)
|
|
340
|
+
return num
|
|
341
|
+
|
|
342
|
+
def _check_ro(self):
|
|
343
|
+
if self._readonly:
|
|
344
|
+
raise RuntimeError("Read-only object")
|
|
345
|
+
|
|
346
|
+
def _reset(self):
|
|
347
|
+
self._ahex = None
|
|
348
|
+
self._hex = None
|
|
349
|
+
self._hexa = None
|
|
350
|
+
self._rgb = None
|
|
351
|
+
self._rgba = None
|
|
352
|
+
|
|
353
|
+
def _split_hex(self, hex: str, n: int) -> list[int]:
|
|
354
|
+
if hex[0] == "#":
|
|
355
|
+
hex = hex[1:]
|
|
356
|
+
lhex = len(hex)
|
|
357
|
+
if lhex != n * 2:
|
|
358
|
+
raise ValueError("Invalid HEX string")
|
|
359
|
+
nums = [int(num, 16) for num in [hex[i:i + 2] for i in range(0, lhex, 2)]]
|
|
360
|
+
return nums
|
|
361
|
+
|
|
362
|
+
@classmethod
|
|
363
|
+
def from_random(cls, red: int | range | slice = None, green: int | range | slice = None, blue: int | range | slice = None, alpha: int | range | slice = 255):
|
|
364
|
+
"""Случайный цвет"""
|
|
365
|
+
from random import randint, randrange
|
|
366
|
+
|
|
367
|
+
def random(num: int | range | slice):
|
|
368
|
+
if num is None:
|
|
369
|
+
return randint(0, 255)
|
|
370
|
+
if isinstance(num, range) or isinstance(num, slice):
|
|
371
|
+
return randrange(num.start, num.stop, num.step)
|
|
372
|
+
return num
|
|
373
|
+
return cls(random(red), random(green), random(blue), random(alpha))
|
|
374
|
+
|
|
375
|
+
|
|
376
|
+
class _COLORS:
|
|
377
|
+
BLACK = 0, 0, 0
|
|
378
|
+
BLUE = 0, 0, 255
|
|
379
|
+
CYAN = 0, 255, 255
|
|
380
|
+
GREEN = 0, 255, 0
|
|
381
|
+
NULL = 0, 0, 0, 0
|
|
382
|
+
RED = 255, 0, 0
|
|
383
|
+
VIOLET = 255, 0, 255
|
|
384
|
+
WHITE = 255, 255, 255
|
|
385
|
+
YELLOW = 255, 255, 0
|
|
386
|
+
|
|
387
|
+
def __init__(self):
|
|
388
|
+
self._colors = {}
|
|
389
|
+
for name in dir(self):
|
|
390
|
+
if name[0] != "_":
|
|
391
|
+
color = Color(*getattr(self, name))
|
|
392
|
+
color._readonly = True
|
|
393
|
+
self._colors[name] = color
|
|
394
|
+
setattr(self, name, color)
|
|
395
|
+
|
|
396
|
+
def __contains__(self, k) -> bool:
|
|
397
|
+
return k.upper() in self._colors
|
|
398
|
+
|
|
399
|
+
def __getitem__(self, k) -> Color:
|
|
400
|
+
return self._colors[k.upper()]
|
|
401
|
+
|
|
402
|
+
|
|
403
|
+
COLORS = _COLORS()
|
|
404
|
+
Error401 = AccessDeniedError
|
|
405
|
+
Error403 = AccessDeniedError
|
|
406
|
+
Error404 = NotFoundError
|
|
407
|
+
Inf = Infinity
|
|
408
|
+
NaN = NotANumber
|
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
"""Различные объекты и исключения"""
|
|
2
|
-
from typing import Union
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
class Base:
|
|
6
|
-
def __init__(self, *args, **kwargs):
|
|
7
|
-
self.args = args
|
|
8
|
-
self.kwargs = kwargs
|
|
9
|
-
self.type = type(self)
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
class UserError(Exception):
|
|
13
|
-
pass
|
|
14
|
-
"""Ошибка, которую допустил пользователь. Например неправильно указал входные данные"""
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
class AccessDeniedError(UserError):
|
|
18
|
-
pass
|
|
19
|
-
"""Ошибка доступа"""
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
class Empty(Base):
|
|
23
|
-
pass
|
|
24
|
-
"""Пустота (не равно `None`)"""
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
class Infinity(Base):
|
|
28
|
-
pass
|
|
29
|
-
"""Бесконечное число"""
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
class NotAFileError(Exception):
|
|
33
|
-
pass
|
|
34
|
-
"""Ошибка 'это не файл'"""
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
class NotANumber(Base):
|
|
38
|
-
pass
|
|
39
|
-
"""Не число"""
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
class NotFound(Base):
|
|
43
|
-
pass
|
|
44
|
-
"""Не найдено"""
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
class NotFoundError(Exception):
|
|
48
|
-
pass
|
|
49
|
-
"""Ошибка 'не найдено'"""
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
class Action:
|
|
53
|
-
def __init__(self, func, *args, **kwargs):
|
|
54
|
-
self._closed = False
|
|
55
|
-
self._completed = False
|
|
56
|
-
self._error = None
|
|
57
|
-
self._launched = False
|
|
58
|
-
self._result = None
|
|
59
|
-
self.args: tuple = args
|
|
60
|
-
self.func = func
|
|
61
|
-
self.kwargs: dict = kwargs
|
|
62
|
-
|
|
63
|
-
def __enter__(self):
|
|
64
|
-
return self
|
|
65
|
-
|
|
66
|
-
def __exit__(self, a, b, c):
|
|
67
|
-
self.close()
|
|
68
|
-
|
|
69
|
-
def _check(self, launched: bool = None, completed: bool = None, closed: bool = None):
|
|
70
|
-
if not launched is None:
|
|
71
|
-
if launched:
|
|
72
|
-
if not self.launched:
|
|
73
|
-
raise RuntimeError("The action has not yet been launched")
|
|
74
|
-
else:
|
|
75
|
-
if self.launched:
|
|
76
|
-
raise RuntimeError("The action has already been launched")
|
|
77
|
-
if not completed is None:
|
|
78
|
-
if completed:
|
|
79
|
-
if not self.completed:
|
|
80
|
-
raise RuntimeError("The action has not yet been completed")
|
|
81
|
-
else:
|
|
82
|
-
if self.completed:
|
|
83
|
-
raise RuntimeError("The action has already been completed")
|
|
84
|
-
if not closed is None:
|
|
85
|
-
if closed:
|
|
86
|
-
if not self.closed:
|
|
87
|
-
raise RuntimeError("The action has not yet been closed")
|
|
88
|
-
else:
|
|
89
|
-
if self.closed:
|
|
90
|
-
raise RuntimeError("The action has already been closed")
|
|
91
|
-
|
|
92
|
-
def close(self):
|
|
93
|
-
self._closed = True
|
|
94
|
-
self._error = None
|
|
95
|
-
self._result = None
|
|
96
|
-
self.args = None
|
|
97
|
-
self.func = None
|
|
98
|
-
self.kwargs = None
|
|
99
|
-
|
|
100
|
-
@property
|
|
101
|
-
def launched(self) -> bool:
|
|
102
|
-
return self._launched
|
|
103
|
-
|
|
104
|
-
@property
|
|
105
|
-
def completed(self) -> bool:
|
|
106
|
-
return self._completed
|
|
107
|
-
|
|
108
|
-
@property
|
|
109
|
-
def exception(self) -> Union[None, Exception]:
|
|
110
|
-
self._check(launched=True, completed=True, closed=False)
|
|
111
|
-
return self._error
|
|
112
|
-
|
|
113
|
-
@property
|
|
114
|
-
def result(self):
|
|
115
|
-
self._check(launched=True, completed=True, closed=False)
|
|
116
|
-
if not self._error is None:
|
|
117
|
-
raise self._error # type: ignore
|
|
118
|
-
return self._result
|
|
119
|
-
|
|
120
|
-
@property
|
|
121
|
-
def closed(self) -> bool:
|
|
122
|
-
return self._closed
|
|
123
|
-
|
|
124
|
-
def run(self):
|
|
125
|
-
self._check(launched=False, completed=False, closed=False)
|
|
126
|
-
self._launched = True
|
|
127
|
-
try:
|
|
128
|
-
self._result = self.func(*self.args, **self.kwargs) # type: ignore
|
|
129
|
-
except Exception as err:
|
|
130
|
-
self._error = err
|
|
131
|
-
self._completed = True
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
class OnlyOneInstanceError(BaseException):
|
|
135
|
-
"""Ошибка для `.utils.OnlyOneInstance`"""
|
|
136
|
-
|
|
137
|
-
def __init__(self, *args):
|
|
138
|
-
if len(args) == 0:
|
|
139
|
-
args = ("Another instance is already running",)
|
|
140
|
-
BaseException.__init__(self, *args)
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
Error401 = AccessDeniedError
|
|
144
|
-
Error403 = AccessDeniedError
|
|
145
|
-
Error404 = NotFoundError
|
|
146
|
-
Inf = Infinity
|
|
147
|
-
NaN = NotANumber
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mainshortcuts2-2.4.2 → mainshortcuts2-2.4.3}/src/MainShortcuts2/api/russian_trusted_root_ca_pem.crt
RENAMED
|
File without changes
|
{mainshortcuts2-2.4.2 → mainshortcuts2-2.4.3}/src/MainShortcuts2/api/russian_trusted_sub_ca_pem.crt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|