arpakitlib 1.9.23__tar.gz → 1.9.37__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.
- {arpakitlib-1.9.23 → arpakitlib-1.9.37}/PKG-INFO +4 -1
- {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_dict_util.py +4 -0
- arpakitlib-1.9.37/arpakitlib/ar_generate_difficult_password_util.py +36 -0
- arpakitlib-1.9.37/arpakitlib/ar_make_zip_with_passwd.py +20 -0
- {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_sqlalchemy_etc_util.py +5 -0
- {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_ssh_runner_util.py +20 -9
- {arpakitlib-1.9.23 → arpakitlib-1.9.37}/pyproject.toml +4 -1
- arpakitlib-1.9.23/arpakitlib/ar_generate_difficult_password_util.py +0 -41
- {arpakitlib-1.9.23 → arpakitlib-1.9.37}/LICENSE +0 -0
- {arpakitlib-1.9.23 → arpakitlib-1.9.37}/README.md +0 -0
- {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/__init__.py +0 -0
- {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_aiogram_as_tg_command_2_util.py +0 -0
- {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_aiogram_as_tg_command_util.py +0 -0
- {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_arpakit_project_template_util.py +0 -0
- {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_arpakitlib_module_util.py +0 -0
- {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_base64_util.py +0 -0
- {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_base_http_api_client_util.py +0 -0
- {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_base_worker_util.py +0 -0
- {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_blank_util.py +0 -0
- {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_cache_file_util.py +0 -0
- {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_class_util.py +0 -0
- {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_clone_pydantic_model_fields_util.py +0 -0
- {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_datetime_util.py +0 -0
- {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_dict_as_object.py +0 -0
- {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_encrypt_decrypt_util.py +0 -0
- {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_enumeration_util.py +0 -0
- {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_exception_util.py +0 -0
- {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_file_storage_in_dir_util.py +0 -0
- {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_file_util.py +0 -0
- {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_func_util.py +0 -0
- {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_generate_connection_url_util.py +0 -0
- {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_generate_simple_code_util.py +0 -0
- {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_hash_util.py +0 -0
- {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_http_request_util.py +0 -0
- {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_include_aiogram_routers_from_dir_util.py +0 -0
- {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_include_fastapi_routers_from_dir_util.py +0 -0
- {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_ip_util.py +0 -0
- {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_json_db_util.py +0 -0
- {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_json_util.py +0 -0
- {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_jwt_util.py +0 -0
- {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_list_util.py +0 -0
- {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_log_async_func_if_error_util.py +0 -0
- {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_logging_util.py +0 -0
- {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_need_type_util.py +0 -0
- {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_openai_api_client_util.py +0 -0
- {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_parse_command_util.py +0 -0
- {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_postgresql_util.py +0 -0
- {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_pydantic_schema_from_sqlalchemy_model_util.py +0 -0
- {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_raise_own_exception_if_exception_util.py +0 -0
- {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_rat_func_util.py +0 -0
- {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_really_validate_email_util.py +0 -0
- {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_really_validate_url_util.py +0 -0
- {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_retry_func_util.py +0 -0
- {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_run_cmd_util.py +0 -0
- {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_safe_func_util.py +0 -0
- {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_settings_util.py +0 -0
- {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_sleep_util.py +0 -0
- {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_sqladmin_util.py +0 -0
- {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_sqlalchemy_base_dbm_util.py +0 -0
- {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_sqlalchemy_drop_check_constraints_util.py +0 -0
- {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_sqlalchemy_ensure_check_constraints_util.py +0 -0
- {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_ssh_keys_util.py +0 -0
- {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_str_util.py +0 -0
- {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_type_util.py +0 -0
- {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_uppercase_env_keys_util.py +0 -0
- {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_yookassa_api_client_util.py +0 -0
- /arpakitlib-1.9.23/arpakitlib/ar_list_of_dicts_to_xlsx_util.py → /arpakitlib-1.9.37/arpakitlib/list_of_dicts_to_xlsx_util.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: arpakitlib
|
|
3
|
-
Version: 1.9.
|
|
3
|
+
Version: 1.9.37
|
|
4
4
|
Summary: arpakitlib
|
|
5
5
|
License-Expression: Apache-2.0
|
|
6
6
|
License-File: LICENSE
|
|
@@ -37,6 +37,7 @@ Requires-Dist: markdown (>=3.7,<4.0)
|
|
|
37
37
|
Requires-Dist: openai (>=2.6.1,<3.0.0)
|
|
38
38
|
Requires-Dist: openpyxl (>=3.1.5,<4.0.0)
|
|
39
39
|
Requires-Dist: orjson (>=3.10.15,<4.0.0)
|
|
40
|
+
Requires-Dist: pandas (>=2.3.3,<3.0.0)
|
|
40
41
|
Requires-Dist: paramiko (>=4.0.0,<5.0.0)
|
|
41
42
|
Requires-Dist: pika (>=1.3.2,<2.0.0)
|
|
42
43
|
Requires-Dist: poetry (>=2.0.1,<3.0.0)
|
|
@@ -46,6 +47,8 @@ Requires-Dist: pulp (>=2.9.0,<3.0.0)
|
|
|
46
47
|
Requires-Dist: pydantic (>=2.10.5,<3.0.0)
|
|
47
48
|
Requires-Dist: pydantic-settings (>=2.7.1,<3.0.0)
|
|
48
49
|
Requires-Dist: pyjwt (>=2.10.1,<3.0.0)
|
|
50
|
+
Requires-Dist: pyminizip (>=0.2.6,<0.3.0)
|
|
51
|
+
Requires-Dist: pymongo (>=4.15.5,<5.0.0)
|
|
49
52
|
Requires-Dist: pytelegrambotapi (>=4.29.1,<5.0.0)
|
|
50
53
|
Requires-Dist: pytest (>=8.4.2,<9.0.0)
|
|
51
54
|
Requires-Dist: pytz (>=2024.2,<2025.0)
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import random
|
|
2
|
+
import secrets
|
|
3
|
+
import string
|
|
4
|
+
import uuid
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def generate_difficult_password(*, difficult: int = 1):
|
|
8
|
+
# динамический диапазон длины
|
|
9
|
+
base = 32 + difficult * 16
|
|
10
|
+
variance = 64 + difficult * 32
|
|
11
|
+
target_len = random.randint(base, base + variance)
|
|
12
|
+
|
|
13
|
+
# ТОЛЬКО английские буквы и цифры
|
|
14
|
+
alphabet = string.ascii_letters + string.digits
|
|
15
|
+
|
|
16
|
+
password = []
|
|
17
|
+
|
|
18
|
+
# UUID-шум (hex = 0-9 + a-f)
|
|
19
|
+
for _ in range(difficult * 2):
|
|
20
|
+
password.append(uuid.uuid4().hex)
|
|
21
|
+
|
|
22
|
+
# основная часть
|
|
23
|
+
for _ in range(target_len):
|
|
24
|
+
password.append(secrets.choice(alphabet))
|
|
25
|
+
|
|
26
|
+
secrets.SystemRandom().shuffle(password)
|
|
27
|
+
|
|
28
|
+
return "".join(password)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def __example():
|
|
32
|
+
print(generate_difficult_password(difficult=2))
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
if __name__ == '__main__':
|
|
36
|
+
__example()
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# arpakit
|
|
2
|
+
|
|
3
|
+
import pyminizip
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def make_zip_with_passwd(
|
|
7
|
+
*,
|
|
8
|
+
input_filepath: str,
|
|
9
|
+
output_filename: str = "archive.zip",
|
|
10
|
+
passwd: str = "123"
|
|
11
|
+
) -> str:
|
|
12
|
+
pyminizip.compress(
|
|
13
|
+
input_filepath, # исходный файл
|
|
14
|
+
None,
|
|
15
|
+
output_filename, # архив
|
|
16
|
+
passwd, # пароль
|
|
17
|
+
5 # уровень сжатия (1–9)
|
|
18
|
+
)
|
|
19
|
+
return output_filename
|
|
20
|
+
|
|
@@ -5,6 +5,10 @@ def _str_no_self(v: str) -> str:
|
|
|
5
5
|
return v.replace("self.", "").strip()
|
|
6
6
|
|
|
7
7
|
|
|
8
|
+
def _str_no_dbm(v: str) -> str:
|
|
9
|
+
return v.replace("dbm.", "").strip()
|
|
10
|
+
|
|
11
|
+
|
|
8
12
|
def generate_sqlalchemy_model_repr(*, title: str, parts: list[Any]):
|
|
9
13
|
res = []
|
|
10
14
|
for part in parts:
|
|
@@ -16,6 +20,7 @@ def generate_sqlalchemy_model_repr(*, title: str, parts: list[Any]):
|
|
|
16
20
|
part = str(part)
|
|
17
21
|
elif isinstance(part, str):
|
|
18
22
|
part = _str_no_self(part)
|
|
23
|
+
part = _str_no_dbm(part)
|
|
19
24
|
part = part.strip()
|
|
20
25
|
if not part:
|
|
21
26
|
continue
|
|
@@ -10,9 +10,8 @@ from typing import Any
|
|
|
10
10
|
|
|
11
11
|
import asyncssh
|
|
12
12
|
import paramiko
|
|
13
|
-
from pydantic import BaseModel, ConfigDict
|
|
14
|
-
|
|
15
13
|
from arpakitlib.ar_json_util import transfer_data_to_json_str
|
|
14
|
+
from pydantic import BaseModel, ConfigDict
|
|
16
15
|
|
|
17
16
|
|
|
18
17
|
class BaseSSHException(Exception):
|
|
@@ -20,9 +19,11 @@ class BaseSSHException(Exception):
|
|
|
20
19
|
|
|
21
20
|
|
|
22
21
|
class ConnectionSSHException(BaseSSHException):
|
|
23
|
-
def __init__(self, ssh_runner: SSHRunner, base_exception: Exception | None = None
|
|
22
|
+
def __init__(self, ssh_runner: SSHRunner, base_exception: Exception | None = None,
|
|
23
|
+
error_message: str | None = None):
|
|
24
24
|
self.ssh_runner = ssh_runner
|
|
25
25
|
self.base_exception = base_exception
|
|
26
|
+
self.error_message = error_message
|
|
26
27
|
|
|
27
28
|
def format_message(self) -> str:
|
|
28
29
|
parts = [
|
|
@@ -266,7 +267,7 @@ class SSHRunner:
|
|
|
266
267
|
self.sync_client.connect(**connect_kwargs)
|
|
267
268
|
except Exception as exception:
|
|
268
269
|
self.sync_close()
|
|
269
|
-
raise ConnectionSSHException(ssh_runner=self, base_exception=exception)
|
|
270
|
+
raise ConnectionSSHException(ssh_runner=self, base_exception=exception, error_message=f"{exception=}")
|
|
270
271
|
|
|
271
272
|
self._logger.info("connected")
|
|
272
273
|
|
|
@@ -289,7 +290,8 @@ class SSHRunner:
|
|
|
289
290
|
command: str,
|
|
290
291
|
*,
|
|
291
292
|
timeout: float | None = timedelta(seconds=10).total_seconds(),
|
|
292
|
-
raise_for_bad_return_code: bool = True
|
|
293
|
+
raise_for_bad_return_code: bool = True,
|
|
294
|
+
stdin_data: str | bytes | None = None,
|
|
293
295
|
) -> SSHRunResult:
|
|
294
296
|
if not command or not command.strip():
|
|
295
297
|
raise ValueError("command must be a non-empty string")
|
|
@@ -306,9 +308,18 @@ class SSHRunner:
|
|
|
306
308
|
command=command,
|
|
307
309
|
timeout=timeout
|
|
308
310
|
)
|
|
311
|
+
|
|
312
|
+
if stdin_data is not None:
|
|
313
|
+
if isinstance(stdin_data, str):
|
|
314
|
+
stdin_data = stdin_data.encode()
|
|
315
|
+
stdin.write(stdin_data)
|
|
316
|
+
stdin.flush()
|
|
317
|
+
stdin.channel.shutdown_write()
|
|
318
|
+
stdin.close()
|
|
319
|
+
|
|
320
|
+
out = stdout.read().decode(errors="replace")
|
|
321
|
+
err = stderr.read().decode(errors="replace")
|
|
309
322
|
return_code = stdout.channel.recv_exit_status()
|
|
310
|
-
stdout = stdout.read().decode()
|
|
311
|
-
stderr = stderr.read().decode()
|
|
312
323
|
except Exception as exception:
|
|
313
324
|
if self.auto_close_after_run:
|
|
314
325
|
self.sync_close()
|
|
@@ -318,8 +329,8 @@ class SSHRunner:
|
|
|
318
329
|
self.sync_close()
|
|
319
330
|
|
|
320
331
|
ssh_run_result = SSHRunResult(
|
|
321
|
-
out=
|
|
322
|
-
err=
|
|
332
|
+
out=out,
|
|
333
|
+
err=err,
|
|
323
334
|
return_code=return_code,
|
|
324
335
|
ssh_runner=self
|
|
325
336
|
)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "arpakitlib"
|
|
3
|
-
version = "1.9.
|
|
3
|
+
version = "1.9.37"
|
|
4
4
|
description = "arpakitlib"
|
|
5
5
|
authors = [
|
|
6
6
|
{ name = "arpakit_company", email = "support@arpakit.com" }
|
|
@@ -65,6 +65,9 @@ dependencies = [
|
|
|
65
65
|
"paramiko (>=4.0.0,<5.0.0)",
|
|
66
66
|
"openai (>=2.6.1,<3.0.0)",
|
|
67
67
|
"asyncssh (>=2.21.1,<3.0.0)",
|
|
68
|
+
"pymongo (>=4.15.5,<5.0.0)",
|
|
69
|
+
"pandas (>=2.3.3,<3.0.0)",
|
|
70
|
+
"pyminizip (>=0.2.6,<0.3.0)",
|
|
68
71
|
]
|
|
69
72
|
|
|
70
73
|
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import random
|
|
2
|
-
import secrets
|
|
3
|
-
import string
|
|
4
|
-
import uuid
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
def generate_difficult_password(*, difficult: int = 1):
|
|
8
|
-
# динамический диапазон длины
|
|
9
|
-
base = 32 + difficult * 16 # минимальная длина
|
|
10
|
-
variance = 64 + difficult * 32 # насколько может "гулять"
|
|
11
|
-
target_len = random.randint(base, base + variance)
|
|
12
|
-
|
|
13
|
-
alphabet = (
|
|
14
|
-
string.ascii_letters +
|
|
15
|
-
string.digits +
|
|
16
|
-
string.punctuation
|
|
17
|
-
)
|
|
18
|
-
|
|
19
|
-
password = []
|
|
20
|
-
|
|
21
|
-
# добавляем случайный шум из UUID блоков
|
|
22
|
-
for _ in range(difficult * 2):
|
|
23
|
-
noise_block = uuid.uuid4().hex
|
|
24
|
-
password.append(noise_block)
|
|
25
|
-
|
|
26
|
-
# основная часть пароля — криптостойкие символы
|
|
27
|
-
for _ in range(target_len):
|
|
28
|
-
password.append(secrets.choice(alphabet))
|
|
29
|
-
|
|
30
|
-
# финальная перемешка обеспечивает нерегулярность структуры
|
|
31
|
-
secrets.SystemRandom().shuffle(password)
|
|
32
|
-
|
|
33
|
-
return "".join(password)
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
def __example():
|
|
37
|
-
pass
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
if __name__ == '__main__':
|
|
41
|
-
__example()
|
|
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
|
|
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
|
{arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_include_aiogram_routers_from_dir_util.py
RENAMED
|
File without changes
|
{arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_include_fastapi_routers_from_dir_util.py
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
|
{arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_pydantic_schema_from_sqlalchemy_model_util.py
RENAMED
|
File without changes
|
{arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_raise_own_exception_if_exception_util.py
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
|
{arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_sqlalchemy_drop_check_constraints_util.py
RENAMED
|
File without changes
|
{arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_sqlalchemy_ensure_check_constraints_util.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|