mm-std 0.4.17__py3-none-any.whl → 0.5.0__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.
- mm_std/__init__.py +15 -56
- mm_std/{date.py → date_utils.py} +11 -18
- mm_std/dict_utils.py +63 -0
- mm_std/json_utils.py +112 -0
- mm_std/random_utils.py +72 -0
- mm_std-0.5.0.dist-info/METADATA +4 -0
- mm_std-0.5.0.dist-info/RECORD +9 -0
- mm_std/command.py +0 -35
- mm_std/concurrency/__init__.py +0 -0
- mm_std/concurrency/async_decorators.py +0 -54
- mm_std/concurrency/async_scheduler.py +0 -172
- mm_std/concurrency/async_task_runner.py +0 -126
- mm_std/concurrency/sync_decorators.py +0 -35
- mm_std/concurrency/sync_scheduler.py +0 -73
- mm_std/concurrency/sync_task_runner.py +0 -45
- mm_std/config.py +0 -81
- mm_std/crypto/__init__.py +0 -0
- mm_std/crypto/fernet.py +0 -13
- mm_std/crypto/openssl.py +0 -207
- mm_std/dict.py +0 -49
- mm_std/env.py +0 -9
- mm_std/fs.py +0 -13
- mm_std/http/__init__.py +0 -0
- mm_std/http/http_request.py +0 -126
- mm_std/http/http_request_sync.py +0 -63
- mm_std/http/http_response.py +0 -119
- mm_std/json_.py +0 -38
- mm_std/log.py +0 -85
- mm_std/net.py +0 -22
- mm_std/print_.py +0 -58
- mm_std/random_.py +0 -35
- mm_std/result.py +0 -315
- mm_std/str.py +0 -105
- mm_std/toml.py +0 -22
- mm_std/types_.py +0 -8
- mm_std/zip.py +0 -9
- mm_std-0.4.17.dist-info/METADATA +0 -14
- mm_std-0.4.17.dist-info/RECORD +0 -35
- {mm_std-0.4.17.dist-info → mm_std-0.5.0.dist-info}/WHEEL +0 -0
mm_std/http/http_request.py
DELETED
@@ -1,126 +0,0 @@
|
|
1
|
-
import aiohttp
|
2
|
-
from aiohttp import ClientHttpProxyError, InvalidUrlClientError
|
3
|
-
from aiohttp.typedefs import LooseCookies, Query
|
4
|
-
from aiohttp_socks import ProxyConnectionError, ProxyConnector
|
5
|
-
from multidict import CIMultiDictProxy
|
6
|
-
|
7
|
-
from mm_std.http.http_response import HttpError, HttpResponse
|
8
|
-
|
9
|
-
|
10
|
-
async def http_request(
|
11
|
-
url: str,
|
12
|
-
*,
|
13
|
-
method: str = "GET",
|
14
|
-
params: Query | None = None,
|
15
|
-
data: dict[str, object] | None = None,
|
16
|
-
json: dict[str, object] | None = None,
|
17
|
-
headers: dict[str, str] | None = None,
|
18
|
-
cookies: LooseCookies | None = None,
|
19
|
-
user_agent: str | None = None,
|
20
|
-
proxy: str | None = None,
|
21
|
-
timeout: float | None = 10.0,
|
22
|
-
) -> HttpResponse:
|
23
|
-
"""
|
24
|
-
Send an HTTP request and return the response.
|
25
|
-
"""
|
26
|
-
timeout_ = aiohttp.ClientTimeout(total=timeout) if timeout else None
|
27
|
-
if user_agent:
|
28
|
-
if not headers:
|
29
|
-
headers = {}
|
30
|
-
headers["user-agent"] = user_agent
|
31
|
-
|
32
|
-
try:
|
33
|
-
if proxy and proxy.startswith("socks"):
|
34
|
-
return await _request_with_socks_proxy(
|
35
|
-
url,
|
36
|
-
method=method,
|
37
|
-
params=params,
|
38
|
-
data=data,
|
39
|
-
json=json,
|
40
|
-
headers=headers,
|
41
|
-
cookies=cookies,
|
42
|
-
proxy=proxy,
|
43
|
-
timeout=timeout_,
|
44
|
-
)
|
45
|
-
return await _request_with_http_or_none_proxy(
|
46
|
-
url,
|
47
|
-
method=method,
|
48
|
-
params=params,
|
49
|
-
data=data,
|
50
|
-
json=json,
|
51
|
-
headers=headers,
|
52
|
-
cookies=cookies,
|
53
|
-
proxy=proxy,
|
54
|
-
timeout=timeout_,
|
55
|
-
)
|
56
|
-
except TimeoutError as err:
|
57
|
-
return HttpResponse(error=HttpError.TIMEOUT, error_message=str(err))
|
58
|
-
except (aiohttp.ClientProxyConnectionError, ProxyConnectionError, ClientHttpProxyError) as err:
|
59
|
-
return HttpResponse(error=HttpError.PROXY, error_message=str(err))
|
60
|
-
except InvalidUrlClientError as e:
|
61
|
-
return HttpResponse(error=HttpError.INVALID_URL, error_message=str(e))
|
62
|
-
except Exception as err:
|
63
|
-
return HttpResponse(error=HttpError.ERROR, error_message=str(err))
|
64
|
-
|
65
|
-
|
66
|
-
async def _request_with_http_or_none_proxy(
|
67
|
-
url: str,
|
68
|
-
*,
|
69
|
-
method: str = "GET",
|
70
|
-
params: Query | None = None,
|
71
|
-
data: dict[str, object] | None = None,
|
72
|
-
json: dict[str, object] | None = None,
|
73
|
-
headers: dict[str, str] | None = None,
|
74
|
-
cookies: LooseCookies | None = None,
|
75
|
-
proxy: str | None = None,
|
76
|
-
timeout: aiohttp.ClientTimeout | None,
|
77
|
-
) -> HttpResponse:
|
78
|
-
async with aiohttp.request(
|
79
|
-
method, url, params=params, data=data, json=json, headers=headers, cookies=cookies, proxy=proxy, timeout=timeout
|
80
|
-
) as res:
|
81
|
-
return HttpResponse(
|
82
|
-
status_code=res.status,
|
83
|
-
error=None,
|
84
|
-
error_message=None,
|
85
|
-
body=(await res.read()).decode(),
|
86
|
-
headers=headers_dict(res.headers),
|
87
|
-
)
|
88
|
-
|
89
|
-
|
90
|
-
async def _request_with_socks_proxy(
|
91
|
-
url: str,
|
92
|
-
*,
|
93
|
-
method: str = "GET",
|
94
|
-
proxy: str,
|
95
|
-
params: Query | None = None,
|
96
|
-
data: dict[str, object] | None = None,
|
97
|
-
json: dict[str, object] | None = None,
|
98
|
-
headers: dict[str, str] | None = None,
|
99
|
-
cookies: LooseCookies | None = None,
|
100
|
-
timeout: aiohttp.ClientTimeout | None,
|
101
|
-
) -> HttpResponse:
|
102
|
-
connector = ProxyConnector.from_url(proxy)
|
103
|
-
async with (
|
104
|
-
aiohttp.ClientSession(connector=connector) as session,
|
105
|
-
session.request(
|
106
|
-
method, url, params=params, data=data, json=json, headers=headers, cookies=cookies, timeout=timeout
|
107
|
-
) as res,
|
108
|
-
):
|
109
|
-
return HttpResponse(
|
110
|
-
status_code=res.status,
|
111
|
-
error=None,
|
112
|
-
error_message=None,
|
113
|
-
body=(await res.read()).decode(),
|
114
|
-
headers=headers_dict(res.headers),
|
115
|
-
)
|
116
|
-
|
117
|
-
|
118
|
-
def headers_dict(headers: CIMultiDictProxy[str]) -> dict[str, str]:
|
119
|
-
result: dict[str, str] = {}
|
120
|
-
for key in headers:
|
121
|
-
values = headers.getall(key)
|
122
|
-
if len(values) == 1:
|
123
|
-
result[key] = values[0]
|
124
|
-
else:
|
125
|
-
result[key] = ", ".join(values)
|
126
|
-
return result
|
mm_std/http/http_request_sync.py
DELETED
@@ -1,63 +0,0 @@
|
|
1
|
-
from typing import Any
|
2
|
-
|
3
|
-
import requests
|
4
|
-
from requests.exceptions import InvalidSchema, MissingSchema, ProxyError
|
5
|
-
|
6
|
-
from mm_std.http.http_response import HttpError, HttpResponse
|
7
|
-
|
8
|
-
|
9
|
-
def http_request_sync(
|
10
|
-
url: str,
|
11
|
-
*,
|
12
|
-
method: str = "GET",
|
13
|
-
params: dict[str, Any] | None = None,
|
14
|
-
data: dict[str, Any] | None = None,
|
15
|
-
json: dict[str, Any] | None = None,
|
16
|
-
headers: dict[str, Any] | None = None,
|
17
|
-
cookies: dict[str, Any] | None = None,
|
18
|
-
user_agent: str | None = None,
|
19
|
-
proxy: str | None = None,
|
20
|
-
timeout: float | None = 10.0,
|
21
|
-
) -> HttpResponse:
|
22
|
-
"""
|
23
|
-
Send a synchronous HTTP request and return the response.
|
24
|
-
"""
|
25
|
-
if user_agent:
|
26
|
-
if headers is None:
|
27
|
-
headers = {}
|
28
|
-
headers["User-Agent"] = user_agent
|
29
|
-
|
30
|
-
proxies: dict[str, str] | None = None
|
31
|
-
if proxy:
|
32
|
-
proxies = {
|
33
|
-
"http": proxy,
|
34
|
-
"https": proxy,
|
35
|
-
}
|
36
|
-
|
37
|
-
try:
|
38
|
-
res = requests.request(
|
39
|
-
method=method,
|
40
|
-
url=url,
|
41
|
-
params=params,
|
42
|
-
data=data,
|
43
|
-
json=json,
|
44
|
-
headers=headers,
|
45
|
-
cookies=cookies,
|
46
|
-
timeout=timeout,
|
47
|
-
proxies=proxies,
|
48
|
-
)
|
49
|
-
return HttpResponse(
|
50
|
-
status_code=res.status_code,
|
51
|
-
error=None,
|
52
|
-
error_message=None,
|
53
|
-
body=res.text,
|
54
|
-
headers=dict(res.headers),
|
55
|
-
)
|
56
|
-
except requests.Timeout as e:
|
57
|
-
return HttpResponse(error=HttpError.TIMEOUT, error_message=str(e))
|
58
|
-
except ProxyError as e:
|
59
|
-
return HttpResponse(error=HttpError.PROXY, error_message=str(e))
|
60
|
-
except (InvalidSchema, MissingSchema) as e:
|
61
|
-
return HttpResponse(error=HttpError.INVALID_URL, error_message=str(e))
|
62
|
-
except Exception as e:
|
63
|
-
return HttpResponse(error=HttpError.ERROR, error_message=str(e))
|
mm_std/http/http_response.py
DELETED
@@ -1,119 +0,0 @@
|
|
1
|
-
from __future__ import annotations
|
2
|
-
|
3
|
-
import enum
|
4
|
-
import json
|
5
|
-
from typing import Any
|
6
|
-
|
7
|
-
import pydash
|
8
|
-
from pydantic import GetCoreSchemaHandler
|
9
|
-
from pydantic_core import CoreSchema, core_schema
|
10
|
-
|
11
|
-
from mm_std.result import Result
|
12
|
-
|
13
|
-
|
14
|
-
@enum.unique
|
15
|
-
class HttpError(str, enum.Enum):
|
16
|
-
TIMEOUT = "timeout"
|
17
|
-
PROXY = "proxy"
|
18
|
-
INVALID_URL = "invalid_url"
|
19
|
-
CONNECTION = "connection"
|
20
|
-
ERROR = "error"
|
21
|
-
|
22
|
-
|
23
|
-
class HttpResponse:
|
24
|
-
status_code: int | None
|
25
|
-
error: HttpError | None
|
26
|
-
error_message: str | None
|
27
|
-
body: str | None
|
28
|
-
headers: dict[str, str] | None
|
29
|
-
|
30
|
-
def __init__(
|
31
|
-
self,
|
32
|
-
status_code: int | None = None,
|
33
|
-
error: HttpError | None = None,
|
34
|
-
error_message: str | None = None,
|
35
|
-
body: str | None = None,
|
36
|
-
headers: dict[str, str] | None = None,
|
37
|
-
) -> None:
|
38
|
-
self.status_code = status_code
|
39
|
-
self.error = error
|
40
|
-
self.error_message = error_message
|
41
|
-
self.body = body
|
42
|
-
self.headers = headers
|
43
|
-
|
44
|
-
def parse_json_body(self, path: str | None = None, none_on_error: bool = False) -> Any: # noqa: ANN401
|
45
|
-
if self.body is None:
|
46
|
-
if none_on_error:
|
47
|
-
return None
|
48
|
-
raise ValueError("Body is None")
|
49
|
-
|
50
|
-
try:
|
51
|
-
res = json.loads(self.body)
|
52
|
-
return pydash.get(res, path, None) if path else res
|
53
|
-
except json.JSONDecodeError:
|
54
|
-
if none_on_error:
|
55
|
-
return None
|
56
|
-
raise
|
57
|
-
|
58
|
-
def is_err(self) -> bool:
|
59
|
-
return self.error is not None or (self.status_code is not None and self.status_code >= 400)
|
60
|
-
|
61
|
-
def to_err[T](self, error: str | Exception | tuple[str, Exception] | None = None) -> Result[T]:
|
62
|
-
return Result.err(error or self.error or "error", extra=self.to_dict())
|
63
|
-
|
64
|
-
def to_ok[T](self, value: T) -> Result[T]:
|
65
|
-
return Result.ok(value, extra=self.to_dict())
|
66
|
-
|
67
|
-
def to_dict(self) -> dict[str, Any]:
|
68
|
-
return {
|
69
|
-
"status_code": self.status_code,
|
70
|
-
"error": self.error.value if self.error else None,
|
71
|
-
"error_message": self.error_message,
|
72
|
-
"body": self.body,
|
73
|
-
"headers": self.headers,
|
74
|
-
}
|
75
|
-
|
76
|
-
@property
|
77
|
-
def content_type(self) -> str | None:
|
78
|
-
if self.headers is None:
|
79
|
-
return None
|
80
|
-
for key in self.headers:
|
81
|
-
if key.lower() == "content-type":
|
82
|
-
return self.headers[key]
|
83
|
-
return None
|
84
|
-
|
85
|
-
def __repr__(self) -> str:
|
86
|
-
parts: list[str] = []
|
87
|
-
if self.status_code is not None:
|
88
|
-
parts.append(f"status_code={self.status_code!r}")
|
89
|
-
if self.error is not None:
|
90
|
-
parts.append(f"error={self.error!r}")
|
91
|
-
if self.error_message is not None:
|
92
|
-
parts.append(f"error_message={self.error_message!r}")
|
93
|
-
if self.body is not None:
|
94
|
-
parts.append(f"body={self.body!r}")
|
95
|
-
if self.headers is not None:
|
96
|
-
parts.append(f"headers={self.headers!r}")
|
97
|
-
return f"HttpResponse({', '.join(parts)})"
|
98
|
-
|
99
|
-
@classmethod
|
100
|
-
def __get_pydantic_core_schema__(cls, _source_type: type[Any], _handler: GetCoreSchemaHandler) -> CoreSchema:
|
101
|
-
return core_schema.no_info_after_validator_function(
|
102
|
-
cls._validate,
|
103
|
-
core_schema.any_schema(),
|
104
|
-
serialization=core_schema.plain_serializer_function_ser_schema(lambda x: x.to_dict()),
|
105
|
-
)
|
106
|
-
|
107
|
-
@classmethod
|
108
|
-
def _validate(cls, value: object) -> HttpResponse:
|
109
|
-
if isinstance(value, cls):
|
110
|
-
return value
|
111
|
-
if isinstance(value, dict):
|
112
|
-
return cls(
|
113
|
-
status_code=value.get("status_code"),
|
114
|
-
error=HttpError(value["error"]) if value.get("error") else None,
|
115
|
-
error_message=value.get("error_message"),
|
116
|
-
body=value.get("body"),
|
117
|
-
headers=value.get("headers"),
|
118
|
-
)
|
119
|
-
raise TypeError(f"Invalid value for HttpResponse: {value}")
|
mm_std/json_.py
DELETED
@@ -1,38 +0,0 @@
|
|
1
|
-
import json
|
2
|
-
from collections.abc import Callable
|
3
|
-
from dataclasses import asdict, is_dataclass
|
4
|
-
from datetime import date, datetime
|
5
|
-
from decimal import Decimal
|
6
|
-
from enum import Enum
|
7
|
-
from json import JSONEncoder
|
8
|
-
from pathlib import Path
|
9
|
-
|
10
|
-
from pydantic import BaseModel
|
11
|
-
|
12
|
-
from mm_std.result import Result
|
13
|
-
|
14
|
-
|
15
|
-
class CustomJSONEncoder(JSONEncoder):
|
16
|
-
def default(self, o: object) -> object:
|
17
|
-
if isinstance(o, Result):
|
18
|
-
return o.to_dict()
|
19
|
-
if isinstance(o, Decimal):
|
20
|
-
return str(o)
|
21
|
-
if isinstance(o, Path):
|
22
|
-
return str(o)
|
23
|
-
if isinstance(o, datetime | date):
|
24
|
-
return o.isoformat()
|
25
|
-
if is_dataclass(o) and not isinstance(o, type):
|
26
|
-
return asdict(o)
|
27
|
-
if isinstance(o, Enum):
|
28
|
-
return o.value
|
29
|
-
if isinstance(o, BaseModel):
|
30
|
-
return o.model_dump()
|
31
|
-
if isinstance(o, Exception):
|
32
|
-
return str(o)
|
33
|
-
|
34
|
-
return super().default(o)
|
35
|
-
|
36
|
-
|
37
|
-
def json_dumps(data: object, default_serializer: Callable[[object], str] | None = str) -> str:
|
38
|
-
return json.dumps(data, cls=CustomJSONEncoder, default=default_serializer)
|
mm_std/log.py
DELETED
@@ -1,85 +0,0 @@
|
|
1
|
-
import logging
|
2
|
-
from logging.handlers import RotatingFileHandler
|
3
|
-
from pathlib import Path
|
4
|
-
|
5
|
-
from rich.logging import RichHandler
|
6
|
-
|
7
|
-
|
8
|
-
class ExtraFormatter(logging.Formatter):
|
9
|
-
def format(self, record: logging.LogRecord) -> str:
|
10
|
-
base = super().format(record)
|
11
|
-
extras = {
|
12
|
-
key: value
|
13
|
-
for key, value in record.__dict__.items()
|
14
|
-
if key not in logging.LogRecord.__dict__
|
15
|
-
and key
|
16
|
-
not in (
|
17
|
-
"name",
|
18
|
-
"msg",
|
19
|
-
"args",
|
20
|
-
"levelname",
|
21
|
-
"levelno",
|
22
|
-
"pathname",
|
23
|
-
"filename",
|
24
|
-
"module",
|
25
|
-
"exc_info",
|
26
|
-
"exc_text",
|
27
|
-
"stack_info",
|
28
|
-
"lineno",
|
29
|
-
"funcName",
|
30
|
-
"created",
|
31
|
-
"msecs",
|
32
|
-
"relativeCreated",
|
33
|
-
"thread",
|
34
|
-
"threadName",
|
35
|
-
"processName",
|
36
|
-
"process",
|
37
|
-
"message",
|
38
|
-
"taskName",
|
39
|
-
"asctime",
|
40
|
-
)
|
41
|
-
}
|
42
|
-
if extras:
|
43
|
-
extras_str = " | " + " ".join(f"{k}={v}" for k, v in extras.items())
|
44
|
-
return base + extras_str
|
45
|
-
return base
|
46
|
-
|
47
|
-
|
48
|
-
def configure_logging(developer_console: bool = False, console_level: int = logging.INFO) -> None:
|
49
|
-
"""
|
50
|
-
Configure the root logger with a custom formatter that includes extra fields.
|
51
|
-
"""
|
52
|
-
logger = logging.getLogger()
|
53
|
-
logger.setLevel(console_level)
|
54
|
-
logger.handlers.clear()
|
55
|
-
|
56
|
-
console_handler: logging.Handler
|
57
|
-
|
58
|
-
if developer_console:
|
59
|
-
console_handler = RichHandler(rich_tracebacks=True, show_time=True, show_level=True, show_path=False)
|
60
|
-
formatter = ExtraFormatter("{message}", style="{")
|
61
|
-
else:
|
62
|
-
console_handler = logging.StreamHandler()
|
63
|
-
formatter = ExtraFormatter("{asctime} - {name} - {levelname} - {message}", datefmt="%Y-%m-%d %H:%M:%S", style="{")
|
64
|
-
console_handler.setFormatter(formatter)
|
65
|
-
|
66
|
-
logger.addHandler(console_handler)
|
67
|
-
|
68
|
-
|
69
|
-
def init_logger(name: str, file_path: str | None = None, file_mkdir: bool = True, level: int = logging.DEBUG) -> logging.Logger:
|
70
|
-
log = logging.getLogger(name)
|
71
|
-
log.setLevel(level)
|
72
|
-
log.propagate = False
|
73
|
-
fmt = logging.Formatter(fmt="%(asctime)s - %(name)s - %(levelname)s - %(message)s", datefmt="%Y-%m-%d %H:%M:%S")
|
74
|
-
console_handler = logging.StreamHandler()
|
75
|
-
console_handler.setLevel(logging.DEBUG)
|
76
|
-
console_handler.setFormatter(fmt)
|
77
|
-
log.addHandler(console_handler)
|
78
|
-
if file_path:
|
79
|
-
if file_mkdir:
|
80
|
-
Path(file_path).parent.mkdir(exist_ok=True)
|
81
|
-
file_handler = RotatingFileHandler(file_path, maxBytes=10 * 1024 * 1024, backupCount=1)
|
82
|
-
file_handler.setLevel(logging.INFO)
|
83
|
-
file_handler.setFormatter(fmt)
|
84
|
-
log.addHandler(file_handler)
|
85
|
-
return log
|
mm_std/net.py
DELETED
@@ -1,22 +0,0 @@
|
|
1
|
-
import socket
|
2
|
-
import time
|
3
|
-
from typing import cast
|
4
|
-
|
5
|
-
|
6
|
-
def check_port(ip: str, port: int, attempts: int = 3, sleep_seconds: float = 1, timeout: float = 1) -> bool:
|
7
|
-
for _ in range(attempts):
|
8
|
-
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
9
|
-
sock.settimeout(timeout)
|
10
|
-
res = sock.connect_ex((ip, port)) == 0
|
11
|
-
if res:
|
12
|
-
return True
|
13
|
-
time.sleep(sleep_seconds)
|
14
|
-
return False
|
15
|
-
|
16
|
-
|
17
|
-
def get_free_local_port() -> int:
|
18
|
-
sock = socket.socket()
|
19
|
-
sock.bind(("", 0))
|
20
|
-
port = sock.getsockname()[1]
|
21
|
-
sock.close()
|
22
|
-
return cast(int, port)
|
mm_std/print_.py
DELETED
@@ -1,58 +0,0 @@
|
|
1
|
-
import sys
|
2
|
-
from collections.abc import Callable
|
3
|
-
from enum import Enum, unique
|
4
|
-
from typing import Any, NoReturn
|
5
|
-
|
6
|
-
import rich
|
7
|
-
from rich.console import Console
|
8
|
-
from rich.syntax import Syntax
|
9
|
-
from rich.table import Table
|
10
|
-
|
11
|
-
from mm_std.json_ import json_dumps
|
12
|
-
|
13
|
-
|
14
|
-
@unique
|
15
|
-
class PrintFormat(str, Enum):
|
16
|
-
PLAIN = "plain"
|
17
|
-
TABLE = "table"
|
18
|
-
JSON = "json"
|
19
|
-
|
20
|
-
|
21
|
-
def fatal(message: str, code: int = 1) -> NoReturn:
|
22
|
-
print(message, file=sys.stderr) # noqa: T201
|
23
|
-
sys.exit(code)
|
24
|
-
|
25
|
-
|
26
|
-
def print_console(*messages: object, print_json: bool = False, default: Callable[[object], str] | None = str) -> None:
|
27
|
-
if len(messages) == 1:
|
28
|
-
message = messages[0]
|
29
|
-
if isinstance(message, str):
|
30
|
-
print(message) # noqa: T201
|
31
|
-
elif print_json:
|
32
|
-
rich.print_json(json_dumps(message, default_serializer=default))
|
33
|
-
else:
|
34
|
-
rich.print(message)
|
35
|
-
else:
|
36
|
-
rich.print(messages)
|
37
|
-
|
38
|
-
|
39
|
-
def print_plain(messages: object) -> None:
|
40
|
-
print(messages) # noqa: T201
|
41
|
-
|
42
|
-
|
43
|
-
def print_json(data: object, default_serializer: Callable[[object], str] | None = None) -> None:
|
44
|
-
rich.print_json(json_dumps(data, default_serializer=default_serializer))
|
45
|
-
|
46
|
-
|
47
|
-
def print_table(title: str, columns: list[str], rows: list[list[Any]]) -> None:
|
48
|
-
table = Table(*columns, title=title)
|
49
|
-
for row in rows:
|
50
|
-
table.add_row(*(str(cell) for cell in row))
|
51
|
-
console = Console()
|
52
|
-
console.print(table)
|
53
|
-
|
54
|
-
|
55
|
-
def pretty_print_toml(data: str, line_numbers: bool = False, theme: str = "monokai") -> None:
|
56
|
-
console = Console()
|
57
|
-
syntax = Syntax(data, "toml", theme=theme, line_numbers=line_numbers)
|
58
|
-
console.print(syntax)
|
mm_std/random_.py
DELETED
@@ -1,35 +0,0 @@
|
|
1
|
-
import random
|
2
|
-
from collections.abc import Sequence
|
3
|
-
from decimal import Decimal
|
4
|
-
|
5
|
-
|
6
|
-
def random_choice[T](source: Sequence[T] | T | None) -> T | None:
|
7
|
-
"""Deprecated, don't use it"""
|
8
|
-
if source is None:
|
9
|
-
return None
|
10
|
-
if isinstance(source, str):
|
11
|
-
return source # type: ignore[return-value]
|
12
|
-
if isinstance(source, Sequence):
|
13
|
-
if source:
|
14
|
-
return random.choice(source) # type:ignore[no-any-return]
|
15
|
-
return None
|
16
|
-
return source
|
17
|
-
|
18
|
-
|
19
|
-
def random_str_choice(source: Sequence[str] | str | None) -> str | None:
|
20
|
-
if source is None:
|
21
|
-
return None
|
22
|
-
if isinstance(source, str):
|
23
|
-
return source
|
24
|
-
if isinstance(source, Sequence):
|
25
|
-
if source:
|
26
|
-
return random.choice(source)
|
27
|
-
return None
|
28
|
-
return source
|
29
|
-
|
30
|
-
|
31
|
-
def random_decimal(from_: Decimal, to: Decimal) -> Decimal:
|
32
|
-
from_ndigits = abs(from_.as_tuple().exponent) # type:ignore[arg-type]
|
33
|
-
to_ndigits = abs(to.as_tuple().exponent) # type:ignore[arg-type]
|
34
|
-
ndigits = max(from_ndigits, to_ndigits)
|
35
|
-
return Decimal(str(round(random.uniform(float(from_), float(to)), ndigits)))
|