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.
Files changed (67) hide show
  1. {arpakitlib-1.9.23 → arpakitlib-1.9.37}/PKG-INFO +4 -1
  2. {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_dict_util.py +4 -0
  3. arpakitlib-1.9.37/arpakitlib/ar_generate_difficult_password_util.py +36 -0
  4. arpakitlib-1.9.37/arpakitlib/ar_make_zip_with_passwd.py +20 -0
  5. {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_sqlalchemy_etc_util.py +5 -0
  6. {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_ssh_runner_util.py +20 -9
  7. {arpakitlib-1.9.23 → arpakitlib-1.9.37}/pyproject.toml +4 -1
  8. arpakitlib-1.9.23/arpakitlib/ar_generate_difficult_password_util.py +0 -41
  9. {arpakitlib-1.9.23 → arpakitlib-1.9.37}/LICENSE +0 -0
  10. {arpakitlib-1.9.23 → arpakitlib-1.9.37}/README.md +0 -0
  11. {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/__init__.py +0 -0
  12. {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_aiogram_as_tg_command_2_util.py +0 -0
  13. {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_aiogram_as_tg_command_util.py +0 -0
  14. {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_arpakit_project_template_util.py +0 -0
  15. {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_arpakitlib_module_util.py +0 -0
  16. {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_base64_util.py +0 -0
  17. {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_base_http_api_client_util.py +0 -0
  18. {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_base_worker_util.py +0 -0
  19. {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_blank_util.py +0 -0
  20. {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_cache_file_util.py +0 -0
  21. {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_class_util.py +0 -0
  22. {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_clone_pydantic_model_fields_util.py +0 -0
  23. {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_datetime_util.py +0 -0
  24. {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_dict_as_object.py +0 -0
  25. {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_encrypt_decrypt_util.py +0 -0
  26. {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_enumeration_util.py +0 -0
  27. {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_exception_util.py +0 -0
  28. {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_file_storage_in_dir_util.py +0 -0
  29. {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_file_util.py +0 -0
  30. {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_func_util.py +0 -0
  31. {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_generate_connection_url_util.py +0 -0
  32. {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_generate_simple_code_util.py +0 -0
  33. {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_hash_util.py +0 -0
  34. {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_http_request_util.py +0 -0
  35. {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_include_aiogram_routers_from_dir_util.py +0 -0
  36. {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_include_fastapi_routers_from_dir_util.py +0 -0
  37. {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_ip_util.py +0 -0
  38. {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_json_db_util.py +0 -0
  39. {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_json_util.py +0 -0
  40. {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_jwt_util.py +0 -0
  41. {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_list_util.py +0 -0
  42. {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_log_async_func_if_error_util.py +0 -0
  43. {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_logging_util.py +0 -0
  44. {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_need_type_util.py +0 -0
  45. {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_openai_api_client_util.py +0 -0
  46. {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_parse_command_util.py +0 -0
  47. {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_postgresql_util.py +0 -0
  48. {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_pydantic_schema_from_sqlalchemy_model_util.py +0 -0
  49. {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_raise_own_exception_if_exception_util.py +0 -0
  50. {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_rat_func_util.py +0 -0
  51. {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_really_validate_email_util.py +0 -0
  52. {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_really_validate_url_util.py +0 -0
  53. {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_retry_func_util.py +0 -0
  54. {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_run_cmd_util.py +0 -0
  55. {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_safe_func_util.py +0 -0
  56. {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_settings_util.py +0 -0
  57. {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_sleep_util.py +0 -0
  58. {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_sqladmin_util.py +0 -0
  59. {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_sqlalchemy_base_dbm_util.py +0 -0
  60. {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_sqlalchemy_drop_check_constraints_util.py +0 -0
  61. {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_sqlalchemy_ensure_check_constraints_util.py +0 -0
  62. {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_ssh_keys_util.py +0 -0
  63. {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_str_util.py +0 -0
  64. {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_type_util.py +0 -0
  65. {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_uppercase_env_keys_util.py +0 -0
  66. {arpakitlib-1.9.23 → arpakitlib-1.9.37}/arpakitlib/ar_yookassa_api_client_util.py +0 -0
  67. /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.23
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)
@@ -49,6 +49,10 @@ def get_typed_from_dict(
49
49
  return val
50
50
 
51
51
 
52
+ def sort_dict_by_keys(*, data: dict[str, Any]) -> dict[str, Any]:
53
+ return {k: data[k] for k in sorted(data)}
54
+
55
+
52
56
  def __example():
53
57
  pass
54
58
 
@@ -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=stdout,
322
- err=stderr,
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.23"
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