MainShortcuts2 2.3.2__tar.gz → 2.4.0__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.
Files changed (30) hide show
  1. {mainshortcuts2-2.3.2 → mainshortcuts2-2.4.0}/PKG-INFO +1 -1
  2. {mainshortcuts2-2.3.2 → mainshortcuts2-2.4.0}/pyproject.toml +2 -2
  3. mainshortcuts2-2.4.0/src/MainShortcuts2/__main__.py +172 -0
  4. mainshortcuts2-2.4.0/src/MainShortcuts2/_any2json_regs.py +136 -0
  5. {mainshortcuts2-2.3.2 → mainshortcuts2-2.4.0}/src/MainShortcuts2/_module_info.py +1 -1
  6. mainshortcuts2-2.4.0/src/MainShortcuts2/any2json.py +50 -0
  7. {mainshortcuts2-2.3.2 → mainshortcuts2-2.4.0}/src/MainShortcuts2/core.py +8 -0
  8. mainshortcuts2-2.3.2/src/MainShortcuts2/__main__.py +0 -128
  9. {mainshortcuts2-2.3.2 → mainshortcuts2-2.4.0}/README.md +0 -0
  10. {mainshortcuts2-2.3.2 → mainshortcuts2-2.4.0}/src/MainShortcuts2/__init__.py +0 -0
  11. {mainshortcuts2-2.3.2 → mainshortcuts2-2.4.0}/src/MainShortcuts2/advanced.py +0 -0
  12. {mainshortcuts2-2.3.2 → mainshortcuts2-2.4.0}/src/MainShortcuts2/api/base.py +0 -0
  13. {mainshortcuts2-2.3.2 → mainshortcuts2-2.4.0}/src/MainShortcuts2/api/gigachat.py +0 -0
  14. {mainshortcuts2-2.3.2 → mainshortcuts2-2.4.0}/src/MainShortcuts2/api/russian_trusted_root_ca_pem.crt +0 -0
  15. {mainshortcuts2-2.3.2 → mainshortcuts2-2.4.0}/src/MainShortcuts2/api/russian_trusted_sub_ca_pem.crt +0 -0
  16. {mainshortcuts2-2.3.2 → mainshortcuts2-2.4.0}/src/MainShortcuts2/cfg.py +0 -0
  17. {mainshortcuts2-2.3.2 → mainshortcuts2-2.4.0}/src/MainShortcuts2/dict.py +0 -0
  18. {mainshortcuts2-2.3.2 → mainshortcuts2-2.4.0}/src/MainShortcuts2/dir.py +0 -0
  19. {mainshortcuts2-2.3.2 → mainshortcuts2-2.4.0}/src/MainShortcuts2/file.py +0 -0
  20. {mainshortcuts2-2.3.2 → mainshortcuts2-2.4.0}/src/MainShortcuts2/json.py +0 -0
  21. {mainshortcuts2-2.3.2 → mainshortcuts2-2.4.0}/src/MainShortcuts2/list.py +0 -0
  22. {mainshortcuts2-2.3.2 → mainshortcuts2-2.4.0}/src/MainShortcuts2/path.py +0 -0
  23. {mainshortcuts2-2.3.2 → mainshortcuts2-2.4.0}/src/MainShortcuts2/proc.py +0 -0
  24. {mainshortcuts2-2.3.2 → mainshortcuts2-2.4.0}/src/MainShortcuts2/regex.py +0 -0
  25. {mainshortcuts2-2.3.2 → mainshortcuts2-2.4.0}/src/MainShortcuts2/special_chars.py +0 -0
  26. {mainshortcuts2-2.3.2 → mainshortcuts2-2.4.0}/src/MainShortcuts2/str.py +0 -0
  27. {mainshortcuts2-2.3.2 → mainshortcuts2-2.4.0}/src/MainShortcuts2/term.py +0 -0
  28. {mainshortcuts2-2.3.2 → mainshortcuts2-2.4.0}/src/MainShortcuts2/types.py +0 -0
  29. {mainshortcuts2-2.3.2 → mainshortcuts2-2.4.0}/src/MainShortcuts2/utils.py +0 -0
  30. {mainshortcuts2-2.3.2 → mainshortcuts2-2.4.0}/src/MainShortcuts2/win.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: MainShortcuts2
3
- Version: 2.3.2
3
+ Version: 2.4.0
4
4
  Summary: Сокращение и улучшение функций + консольные утилиты
5
5
  Home-page: https://github.com/MainPlay-TG/MainShortcuts2.py
6
6
  Author: MainPlay TG
@@ -1,12 +1,12 @@
1
1
  [tool.poetry]
2
- version = "2.3.2"
2
+ version = "2.4.0"
3
3
  name = "MainShortcuts2"
4
4
  description = "Сокращение и улучшение функций + консольные утилиты"
5
5
  authors = [ "MainPlay TG <xbox.roman6666666666@gmail.com>",]
6
6
  readme = "README.md"
7
7
  repository = "https://github.com/MainPlay-TG/MainShortcuts2.py"
8
8
  packages = [
9
- { include = "MainShortcuts2", from = "src" },
9
+ { include = "MainShortcuts2", from = "src" },
10
10
  ]
11
11
 
12
12
  [tool.poetry.scripts]
@@ -0,0 +1,172 @@
1
+ import argparse
2
+ import sys
3
+ from MainShortcuts2 import ms
4
+ HASH_SUFFIX = ".MS2_hash"
5
+ HASH_TYPES = ["blake2b", "blake2s", "md5", "sha1", "sha224", "sha256", "sha384", "sha3_224", "sha3_256", "sha3_384", "sha3_512", "sha512"]
6
+
7
+
8
+ def import_example():
9
+ argp = argparse.ArgumentParser("ms2-import_example", description="код для импорта MainShortcuts2")
10
+ argp.parse_args()
11
+ print("from MainShortcuts2 import ms")
12
+
13
+
14
+ def nano_json():
15
+ ms.utils.check_programs("nano")
16
+ import subprocess
17
+ argp = argparse.ArgumentParser("nano-json", description="форматирование JSON файлов и редактирование в GNU NANO")
18
+ argp.add_argument("files", nargs="+", help="пути к файлам JSON")
19
+ argp.add_argument("--encoding", default="utf-8", help="кодировка файлов"
20
+ argp.add_argument("--nano-help", action="store_true", help="показать помощь nano")
21
+ argp.add_argument("--no-escape", action="store_false", help="не использовать Unicode Escape")
22
+ argp.add_argument("-f", "--rcfile", help="использовать только этот файл для настройки nano")
23
+ argp.add_argument("-m", "--mode", choices=ms.json.MODES, default="p", help="режим сохранения редактирования")
24
+ args=argp.parse_args()
25
+ if args.nano_help:
26
+ return subprocess.call(["nano", "--help"])
27
+ nano_args=["nano"]
28
+ if args.rcfile:
29
+ nano_args += ["--rcfile", args.rcfile]
30
+ nano_args += args.files
31
+ for i in args.files:
32
+ try:
33
+ data=ms.json.read(i, encoding=args.encoding)
34
+ ms.json.write(i + ms.file.TMP_SUFFIX, data, encoding=args.encoding, ensure_ascii=False, mode="p")
35
+ ms.file.delete(i)
36
+ ms.file.move(i + ms.file.TMP_SUFFIX, i)
37
+ except Exception as err:
38
+ print(err, file=sys.stderr)
39
+ subprocess.call(nano_args)
40
+ for i in args.files:
41
+ try:
42
+ data=ms.json.read(i, encoding=args.encoding)
43
+ ms.json.write(i + ms.file.TMP_SUFFIX, data, encoding=args.encoding, ensure_ascii=args.no_escape, mode=args.mode)
44
+ ms.file.delete(i)
45
+ ms.file.move(i + ms.file.TMP_SUFFIX, i)
46
+ except Exception as err:
47
+ print(err, file=sys.stderr)
48
+
49
+
50
+ def _check_nginx() -> int:
51
+ import subprocess
52
+ with subprocess.Popen(["nginx", "-t"], stderr=subprocess.PIPE) as p:
53
+ code=p.wait()
54
+ if code != 0:
55
+ sys.stderr.buffer.write(p.stderr.read())
56
+ return code
57
+
58
+
59
+ def nginx_reload():
60
+ ms.utils.check_programs("nginx")
61
+ import subprocess
62
+ argp=argparse.ArgumentParser("nginx-reload", description="проверка конфига и перезагрузка Nginx")
63
+ argp.parse_args()
64
+ code=_check_nginx()
65
+ if code != 0:
66
+ sys.exit(code)
67
+ sys.exit(subprocess.call(["nginx", "-s", "reload"]))
68
+
69
+
70
+ def nginx_restart():
71
+ ms.utils.check_programs("nginx", "systemctl")
72
+ import subprocess
73
+ argp=argparse.ArgumentParser("nginx-reload", description="проверка конфига и перезапуск Nginx через systemctl")
74
+ argp.parse_args()
75
+ code=_check_nginx()
76
+ if code != 0:
77
+ sys.exit(code)
78
+ sys.exit(subprocess.call(["systemctl", "restart", "nginx"]))
79
+
80
+
81
+ def hash_gen():
82
+ import os
83
+ import hashlib
84
+ argp=argparse.ArgumentParser("ms2-hash-gen", description="создание контрольной суммы для файла")
85
+ argp.add_argument("files", nargs="+", help="пути к файлам")
86
+ argp.add_argument("-b", "--bar", action="store_true", help="показывать прогрессбар (нужен модуль progressbar2)")
87
+ argp.add_argument("-t", "--type", choices=HASH_TYPES, default="sha512", help="тип контрольной суммы")
88
+ args=argp.parse_args()
89
+ if args.bar:
90
+ import progressbar
91
+ pbar_w=[
92
+ progressbar.Percentage(),
93
+ progressbar.GranularBar(left="(", right=")"),
94
+ progressbar.FileTransferSpeed(),
95
+ progressbar.ETA(format="%(eta)8s", format_finished="%(elapsed)8s", format_na=" N/A", format_not_started="--:--:--", format_zero="00:00:00"),
96
+ ]
97
+ data={}
98
+ data["format"]="MainShortcuts2_hash_v1"
99
+ data["file"]={}
100
+ data["hash"]={}
101
+ data["hash"]["type"]=args.type
102
+ Hash=getattr(hashlib, args.type)
103
+ for file in args.files:
104
+ hash=Hash()
105
+ data["file"]["size"]=os.path.getsize(file)
106
+ if args.bar:
107
+ pbar=progressbar.ProgressBar(
108
+ max_error=False,
109
+ max_value=data["file"]["size"],
110
+ min_value=0,
111
+ widgets=[ms.path.Path(file).full_name] + pbar_w,
112
+ )
113
+ c=0
114
+ pbar.start()
115
+ with open(file, "rb") as f:
116
+ for chunk in f:
117
+ hash.update(chunk)
118
+ if args.bar:
119
+ c += len(chunk)
120
+ pbar.update(c)
121
+ if args.bar:
122
+ pbar.finish(dirty=True)
123
+ data["hash"]["hex"]=hash.hexdigest()
124
+ ms.json.write(file + HASH_SUFFIX, data)
125
+ def hash_check():
126
+ import hashlib
127
+ import os
128
+ import shlex
129
+ argp=argparse.ArgumentParser("ms2-hash-check", description="проверка размера и контрольной суммы файла")
130
+ argp.add_argument("-b", "--bar", action="store_true", help="показывать прогрессбар (нужен модуль progressbar2)")
131
+ argp.add_argument("files", nargs="+", help="пути к файлам")
132
+ args=argp.parse_args()
133
+ if args.bar:
134
+ import progressbar
135
+ pbar_w=[
136
+ progressbar.Percentage(),
137
+ progressbar.GranularBar(left="(", right=")"),
138
+ progressbar.FileTransferSpeed(),
139
+ progressbar.ETA(format="%(eta)8s", format_finished="%(elapsed)8s", format_na=" N/A", format_not_started="--:--:--", format_zero="00:00:00"),
140
+ ]
141
+ for file in args.files:
142
+ if file.lower().endswith(HASH_SUFFIX.lower()):
143
+ file=file[:0 - len(HASH_SUFFIX)]
144
+ if not os.path.exists(file + HASH_SUFFIX):
145
+ print("Ошибка: не найден файл " + shlex.quote(file + HASH_SUFFIX), file=sys.stderr)
146
+ continue
147
+ data=ms.json.read(file + HASH_SUFFIX)
148
+ if data["file"]["size"] != os.path.getsize(file):
149
+ print("Ошибка: размер файла " + shlex.quote(file) + " не совпадает")
150
+ continue
151
+ hash=getattr(hashlib, data["hash"]["type"])()
152
+ if args.bar:
153
+ pbar=progressbar.ProgressBar(
154
+ max_error=False,
155
+ max_value=data["file"]["size"],
156
+ min_value=0,
157
+ widgets=[ms.path.Path(file).full_name] + pbar_w,
158
+ )
159
+ c=0
160
+ pbar.start()
161
+ with open(file, "rb") as f:
162
+ for chunk in f:
163
+ hash.update(chunk)
164
+ if args.bar:
165
+ c += len(chunk)
166
+ pbar.update()
167
+ if args.bar:
168
+ pbar.finish(dirty=True)
169
+ if data["hash"]["hex"] == hash.hexdigest():
170
+ print("Успех: файл " + shlex.quote(file) + " не изменён")
171
+ else:
172
+ print("Ошибка: файл " + shlex.quote(file) + " изменён")
@@ -0,0 +1,136 @@
1
+ import builtins
2
+ from .core import ms
3
+ decoders = {}
4
+ encoders = {}
5
+
6
+
7
+ def reg_decoder(type: str):
8
+ if builtins.type(type) != str:
9
+ type = type.__module__ + "." + type.__name__
10
+
11
+ def deco(func):
12
+ decoders[type] = func
13
+ return func
14
+ return deco
15
+
16
+
17
+ def reg_encoder(type: str):
18
+ if builtins.type(type) != str:
19
+ type = type.__module__ + "." + type.__name__
20
+
21
+ def deco(func):
22
+ encoders[type] = func
23
+ return func
24
+ return deco
25
+
26
+
27
+ @reg_decoder(type(None))
28
+ def _(obj):
29
+ return None
30
+
31
+
32
+ @reg_decoder(bool)
33
+ def _(obj):
34
+ return obj
35
+
36
+
37
+ @reg_decoder(bytes)
38
+ def _(obj):
39
+ import base64
40
+ if obj[0] == "base64":
41
+ return base64.b64decode(obj[1].encode("utf-8"))
42
+
43
+
44
+ @reg_decoder(dict)
45
+ def _(obj):
46
+ result = {}
47
+ for k, v in obj:
48
+ result[ms.any2json._decode_obj(k)] = ms.any2json._decode_obj(v)
49
+ return result
50
+
51
+
52
+ @reg_decoder(float)
53
+ def _(obj):
54
+ return obj
55
+
56
+
57
+ @reg_decoder(int)
58
+ def _(obj):
59
+ return obj
60
+
61
+
62
+ @reg_decoder(list)
63
+ def _(obj):
64
+ return [ms.any2json._decode_obj(i) for i in obj]
65
+
66
+
67
+ @reg_decoder(str)
68
+ def _(obj):
69
+ return obj
70
+
71
+
72
+ @reg_decoder(tuple)
73
+ def _(obj):
74
+ return tuple([ms.any2json._decode_obj(i) for i in obj])
75
+
76
+
77
+ @reg_encoder(type(None))
78
+ def _(obj):
79
+ if obj is None:
80
+ return 0
81
+
82
+
83
+ @reg_encoder(bool)
84
+ def _(obj):
85
+ if isinstance(obj, bool):
86
+ return bool(obj)
87
+
88
+
89
+ @reg_encoder(bytes)
90
+ def _(obj):
91
+ if isinstance(obj, bytes):
92
+ from base64 import b64encode
93
+ result = [
94
+ "base64",
95
+ b64encode(obj).decode("utf-8"),
96
+ ]
97
+ return result
98
+
99
+
100
+ @reg_encoder(dict)
101
+ def _(obj):
102
+ if isinstance(obj, dict):
103
+ result = []
104
+ for k, v in obj.items():
105
+ result.append([ms.any2json._encode_obj(k), ms.any2json._encode_obj(v)])
106
+ return result
107
+
108
+
109
+ @reg_encoder(float)
110
+ def _(obj):
111
+ if isinstance(obj, float):
112
+ return float(obj)
113
+
114
+
115
+ @reg_encoder(int)
116
+ def _(obj):
117
+ if isinstance(obj, int):
118
+ return int(obj)
119
+
120
+
121
+ @reg_encoder(list)
122
+ def _(obj):
123
+ if isinstance(obj, list):
124
+ return [ms.any2json._encode_obj(i) for i in obj]
125
+
126
+
127
+ @reg_encoder(str)
128
+ def _(obj):
129
+ if isinstance(obj, str):
130
+ return str(obj)
131
+
132
+
133
+ @reg_encoder(tuple)
134
+ def _(obj):
135
+ if isinstance(obj, tuple):
136
+ return [ms.any2json._encode_obj(i) for i in obj]
@@ -1,2 +1,2 @@
1
1
  name = "MainShortcuts2"
2
- version = "2.3.2"
2
+ version = "2.4.0"
@@ -0,0 +1,50 @@
1
+ import builtins
2
+ from .core import ms
3
+ from ._any2json_regs import decoders, encoders, reg_decoder, reg_encoder
4
+
5
+
6
+ def _decode_obj(obj: dict):
7
+ return decoders[obj["type"]](obj["data"])
8
+
9
+
10
+ def _encode_obj(obj) -> dict:
11
+ result = {}
12
+ obj_type = builtins.type(obj)
13
+ if hasattr(obj_type, "__module__"):
14
+ if hasattr(obj_type, "__name__"):
15
+ type = obj_type.__module__ + "." + obj_type.__name__
16
+ if type in encoders:
17
+ result["data"] = encoders[type](obj)
18
+ result["type"] = type
19
+ return result
20
+ for type, func in encoders.items():
21
+ try:
22
+ encoded = func(obj)
23
+ if not encoded is None:
24
+ result["data"] = encoded
25
+ result["type"] = type
26
+ return result
27
+ except Exception:
28
+ pass
29
+ raise ValueError("failed to encode object " + repr(obj))
30
+
31
+
32
+ def decode(text, **kw):
33
+ kw["text"] = text
34
+ return _decode_obj(ms.json.decode(**kw))
35
+
36
+
37
+ def encode(data, **kw) -> str:
38
+ kw["data"] = _encode_obj(data)
39
+ return ms.json.encode(**kw)
40
+
41
+
42
+ def read(path: str, **kw):
43
+ kw["path"] = path
44
+ return _decode_obj(ms.json.read(**kw))
45
+
46
+
47
+ def write(path: str, data, **kw):
48
+ kw["data"] = _encode_obj(data)
49
+ kw["path"] = path
50
+ return ms.json.write(**kw)
@@ -33,6 +33,7 @@ class MS2:
33
33
  logger: Logger = None,
34
34
  **kw):
35
35
  self._advanced = None
36
+ self._any2json = None
36
37
  self._cfg = None
37
38
  self._dict = None
38
39
  self._dir = None
@@ -98,6 +99,13 @@ class MS2:
98
99
  self._advanced = advanced
99
100
  return self._advanced
100
101
 
102
+ @property
103
+ def any2json(self):
104
+ if self._any2json is None:
105
+ from . import any2json
106
+ self._any2json = any2json
107
+ return self._any2json
108
+
101
109
  @property
102
110
  def cfg(self):
103
111
  if self._cfg is None:
@@ -1,128 +0,0 @@
1
- import argparse
2
- import sys
3
- from MainShortcuts2 import ms
4
- HASH_SUFFIX = ".MS2_hash"
5
- HASH_TYPES = ["sha1", "sha256", "sha512"]
6
-
7
-
8
- def import_example():
9
- argp = argparse.ArgumentParser("ms2-import_example", description="код для импорта MainShortcuts2")
10
- argp.parse_args()
11
- print("from MainShortcuts2 import ms")
12
-
13
-
14
- def nano_json():
15
- ms.utils.check_programs("nano")
16
- import subprocess
17
- argp = argparse.ArgumentParser("nano-json", description="форматирование JSON файлов и редактирование в GNU NANO")
18
- argp.add_argument("files", nargs="+", help="пути к файлам JSON")
19
- argp.add_argument("--nano-help", action="store_true", help="показать помощь nano")
20
- argp.add_argument("-f", "--rcfile", help="использовать только этот файл для настройки nano")
21
- argp.add_argument("-m", "--mode", choices=ms.json.MODES, default="p", help="режим сохранения редактирования")
22
- args = argp.parse_args()
23
- if args.nano_help:
24
- return subprocess.call(["nano", "--help"])
25
- nano_args = ["nano"]
26
- if args.rcfile:
27
- nano_args += ["--rcfile", args.rcfile]
28
- nano_args += args.files
29
- for i in args.files:
30
- try:
31
- data = ms.json.read(i)
32
- ms.json.write(i + ms.file.TMP_SUFFIX, data, ensure_ascii=False, mode="p")
33
- ms.file.delete(i)
34
- ms.file.move(i + ms.file.TMP_SUFFIX, i)
35
- except Exception as err:
36
- print(err, file=sys.stderr)
37
- subprocess.call(nano_args)
38
- for i in args.files:
39
- try:
40
- data = ms.json.read(i)
41
- ms.json.write(i + ms.file.TMP_SUFFIX, data, mode=args.mode)
42
- ms.file.delete(i)
43
- ms.file.move(i + ms.file.TMP_SUFFIX, i)
44
- except Exception as err:
45
- print(err, file=sys.stderr)
46
-
47
-
48
- def _check_nginx() -> int:
49
- import subprocess
50
- with subprocess.Popen(["nginx", "-t"], stderr=subprocess.PIPE) as p:
51
- code = p.wait()
52
- if code != 0:
53
- sys.stderr.buffer.write(p.stderr.read())
54
- return code
55
-
56
-
57
- def nginx_reload():
58
- ms.utils.check_programs("nginx")
59
- import subprocess
60
- argp = argparse.ArgumentParser("nginx-reload", description="проверка конфига и перезагрузка Nginx")
61
- argp.parse_args()
62
- code = _check_nginx()
63
- if code != 0:
64
- sys.exit(code)
65
- sys.exit(subprocess.call(["nginx", "-s", "reload"]))
66
-
67
-
68
- def nginx_restart():
69
- ms.utils.check_programs("nginx", "systemctl")
70
- import subprocess
71
- argp = argparse.ArgumentParser("nginx-reload", description="проверка конфига и перезапуск Nginx через systemctl")
72
- argp.parse_args()
73
- code = _check_nginx()
74
- if code != 0:
75
- sys.exit(code)
76
- sys.exit(subprocess.call(["systemctl", "restart", "nginx"]))
77
-
78
-
79
- def hash_gen():
80
- import os
81
- import hashlib
82
- argp = argparse.ArgumentParser("ms2-hash-gen", description="создание контрольной суммы для файла")
83
- argp.add_argument("files", nargs="+", help="пути к файлам")
84
- argp.add_argument("-t", "--type", choices=HASH_TYPES, default="sha512", help="тип контрольной суммы")
85
- args = argp.parse_args()
86
- data = {}
87
- data["format"] = "MainShortcuts2_hash_v1"
88
- data["file"] = {}
89
- data["hash"] = {}
90
- data["hash"]["type"] = args.type
91
- Hash = getattr(hashlib, args.type)
92
- for file in args.files:
93
- hash = Hash()
94
- data["file"]["size"] = os.path.getsize(file)
95
- with open(file, "rb") as f:
96
- for chunk in f:
97
- hash.update(chunk)
98
- data["hash"]["hex"] = hash.hexdigest()
99
- ms.json.write(file + HASH_SUFFIX, data)
100
-
101
-
102
- def hash_check()
103
-
104
-
105
- import hashlib
106
- import os
107
- import shlex
108
- argp = argparse.ArgumentParser("ms2-hash-check", description="проверка размера и контрольной суммы файла")
109
- argp.add_argument("files", nargs="+", help="пути к файлам")
110
- args = argp.parse_args()
111
- for file in args.files:
112
- if file.lower().endswith(HASH_SUFFIX.lower()):
113
- file = file[:0 - len(HASH_SUFFIX)]
114
- if not os.path.exists(file + HASH_SUFFIX):
115
- print("Ошибка: не найден файл " + shlex.quote(file + HASH_SUFFIX), file=sys.stderr)
116
- continue
117
- data = ms.json.read(file + HASH_SUFFIX)
118
- if data["file"]["size"] != os.path.getsize(file):
119
- print("Ошибка: размер файла " + shlex.quote(file) + " не совпадает")
120
- continue
121
- hash = getattr(hashlib, data["hash"]["type"])()
122
- with open(file, "rb") as f:
123
- for chunk in f:
124
- hash.update(chunk)
125
- if data["hash"]["hex"] == hash.hexdigest():
126
- print("Успех: файл " + shlex.quote(file) + " не изменён")
127
- else:
128
- print("Ошибка: файл " + shlex.quote(file) + " изменён")
File without changes