mm-std 0.3.21__py3-none-any.whl → 0.3.22__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 CHANGED
@@ -29,7 +29,7 @@ from .http_ import hrequest as hrequest
29
29
  from .http_ import hrequest_async as hrequest_async
30
30
  from .json_ import CustomJSONEncoder as CustomJSONEncoder
31
31
  from .json_ import json_dumps as json_dumps
32
- from .log import configure_structlog as configure_structlog
32
+ from .log import configure_logging as configure_logging
33
33
  from .log import init_logger as init_logger
34
34
  from .net import check_port as check_port
35
35
  from .net import get_free_local_port as get_free_local_port
@@ -1,18 +1,17 @@
1
1
  import asyncio
2
+ import logging
2
3
  from collections.abc import Awaitable, Callable
3
4
  from dataclasses import dataclass, field
4
5
  from datetime import datetime
5
6
  from typing import Any
6
7
 
7
- import structlog
8
-
9
8
  from mm_std.date import utc_now
10
9
 
11
10
  type AsyncFunc = Callable[..., Awaitable[object]]
12
11
  type Args = tuple[object, ...]
13
12
  type Kwargs = dict[str, object]
14
13
 
15
- logger = structlog.stdlib.get_logger()
14
+ logger = logging.getLogger(__name__)
16
15
 
17
16
 
18
17
  class AsyncScheduler:
@@ -75,6 +74,7 @@ class AsyncScheduler:
75
74
  task = self.tasks[task_id]
76
75
  task.running = True
77
76
 
77
+ elapsed = 0.0
78
78
  try:
79
79
  while self._running:
80
80
  task.last_run = utc_now()
@@ -83,11 +83,11 @@ class AsyncScheduler:
83
83
  await task.func(*task.args, **task.kwargs)
84
84
  except Exception:
85
85
  task.error_count += 1
86
- logger.exception("Error in task", task_id=task_id, error=task.error_count)
86
+ logger.exception("Error in task", extra={"task_id": task_id, "error_count": task.error_count})
87
87
 
88
88
  # Calculate elapsed time and sleep if needed
89
89
  elapsed = (utc_now() - task.last_run).total_seconds()
90
- sleep_time = max(0, task.interval - elapsed)
90
+ sleep_time = max(0.0, task.interval - elapsed)
91
91
  if sleep_time > 0:
92
92
  try:
93
93
  await asyncio.sleep(sleep_time)
@@ -95,7 +95,7 @@ class AsyncScheduler:
95
95
  break
96
96
  finally:
97
97
  task.running = False
98
- logger.debug("Finished task", task_id=task_id, elapsed=elapsed)
98
+ logger.debug("Finished task", extra={"task_id": task_id, "elapsed": elapsed})
99
99
 
100
100
  async def _start_all_tasks(self) -> None:
101
101
  """Starts all tasks concurrently using asyncio tasks."""
@@ -1,13 +1,12 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import asyncio
4
+ import logging
4
5
  from collections.abc import Awaitable
5
6
  from dataclasses import dataclass
6
7
  from typing import Any
7
8
 
8
- import structlog
9
-
10
- logger = structlog.stdlib.get_logger()
9
+ logger = logging.getLogger(__name__)
11
10
 
12
11
 
13
12
  class AsyncTaskRunner:
@@ -101,7 +100,7 @@ class AsyncTaskRunner:
101
100
  results[task.task_id] = res
102
101
  except Exception as e:
103
102
  if not self.no_logging:
104
- logger.exception("Task raised an exception", task_id=task.task_id)
103
+ logger.exception("Task raised an exception", extra={"task_id": task.task_id})
105
104
  exceptions[task.task_id] = e
106
105
 
107
106
  # Create asyncio tasks for all runner tasks
mm_std/log.py CHANGED
@@ -2,8 +2,68 @@ import logging
2
2
  from logging.handlers import RotatingFileHandler
3
3
  from pathlib import Path
4
4
 
5
- import structlog
6
- from structlog.typing import Processor
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)
7
67
 
8
68
 
9
69
  def init_logger(name: str, file_path: str | None = None, file_mkdir: bool = True, level: int = logging.DEBUG) -> logging.Logger:
@@ -23,54 +83,3 @@ def init_logger(name: str, file_path: str | None = None, file_mkdir: bool = True
23
83
  file_handler.setFormatter(fmt)
24
84
  log.addHandler(file_handler)
25
85
  return log
26
-
27
-
28
- def configure_structlog(json_logs: bool = False, log_level: str = "DEBUG", compact: bool = False) -> None:
29
- timestamper: Processor = structlog.processors.TimeStamper(fmt="%H:%M:%S" if compact else "[%Y-%m-%d %H:%M:%S.%f]")
30
-
31
- shared_processors: list[Processor] = [
32
- structlog.contextvars.merge_contextvars,
33
- structlog.stdlib.add_logger_name,
34
- structlog.stdlib.add_log_level,
35
- structlog.stdlib.PositionalArgumentsFormatter(),
36
- structlog.stdlib.ExtraAdder(),
37
- timestamper,
38
- structlog.processors.StackInfoRenderer(),
39
- ]
40
-
41
- if json_logs:
42
- # Format the exception only for JSON logs, as we want to pretty-print them when
43
- # using the ConsoleRenderer
44
- shared_processors.append(structlog.processors.format_exc_info)
45
-
46
- structlog.configure(
47
- processors=shared_processors # noqa: RUF005
48
- + [
49
- # Prepare event dict for `ProcessorFormatter`.
50
- structlog.stdlib.ProcessorFormatter.wrap_for_formatter,
51
- ],
52
- logger_factory=structlog.stdlib.LoggerFactory(),
53
- cache_logger_on_first_use=True,
54
- )
55
-
56
- log_renderer: Processor
57
- log_renderer = structlog.processors.JSONRenderer() if json_logs else structlog.dev.ConsoleRenderer()
58
-
59
- formatter: structlog.stdlib.ProcessorFormatter = structlog.stdlib.ProcessorFormatter(
60
- # These run ONLY on `logging` entries that do NOT originate within
61
- # structlog.
62
- foreign_pre_chain=shared_processors,
63
- # These run on ALL entries after the pre_chain is done.
64
- processors=[
65
- # Remove _record & _from_structlog.
66
- structlog.stdlib.ProcessorFormatter.remove_processors_meta,
67
- log_renderer,
68
- ],
69
- )
70
-
71
- handler = logging.StreamHandler()
72
- # Use OUR `ProcessorFormatter` to format all `logging` entries.
73
- handler.setFormatter(formatter)
74
- root_logger: logging.Logger = logging.getLogger()
75
- root_logger.addHandler(handler)
76
- root_logger.setLevel(log_level.upper())
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mm-std
3
- Version: 0.3.21
3
+ Version: 0.3.22
4
4
  Requires-Python: >=3.12
5
5
  Requires-Dist: aiohttp-socks~=0.10.1
6
6
  Requires-Dist: aiohttp~=3.11.16
@@ -11,5 +11,4 @@ Requires-Dist: pydash~=8.0.5
11
11
  Requires-Dist: python-dotenv~=1.1.0
12
12
  Requires-Dist: requests[socks]~=2.32.3
13
13
  Requires-Dist: rich>=13.9.0
14
- Requires-Dist: structlog>=25.2.0
15
14
  Requires-Dist: tomlkit~=0.13.2
@@ -1,4 +1,4 @@
1
- mm_std/__init__.py,sha256=ATaZN6AzmRUJIc8IE4PichCbh45pNncbBidUG7V1m0Q,3044
1
+ mm_std/__init__.py,sha256=ETGLXQW17ZnV5i6kdhoNA-1MulHZixpzGIOLlYpiYx0,3040
2
2
  mm_std/command.py,sha256=ze286wjUjg0QSTgIu-2WZks53_Vclg69UaYYgPpQvCU,1283
3
3
  mm_std/config.py,sha256=4ox4D2CgGR76bvZ2n2vGQOYUDagFnlKEDb87to5zpxE,1871
4
4
  mm_std/crypto.py,sha256=jdk0_TCmeU0pPXMyz9xH6kQHSjjZ9GcGClBwQps5vBo,340
@@ -8,7 +8,7 @@ mm_std/env.py,sha256=5zaR9VeIfObN-4yfgxoFeU5IM1GDeZZj9SuYf7t9sOA,125
8
8
  mm_std/fs.py,sha256=RwarNRJq3tIMG6LVX_g03hasfYpjYFh_O27oVDt5IPQ,291
9
9
  mm_std/http_.py,sha256=cozBUGZcbKp9sZuEnu7bklwa6lTE0RxEUVo_aNt1_kE,7468
10
10
  mm_std/json_.py,sha256=Naa6mBE4D0yiQGkPNRrFvndnUH3R7ovw3FeaejWV60o,1196
11
- mm_std/log.py,sha256=vQzNJ0oenvuHF9sXDI6CUZDR12BcDURUZVwkpdNle4Q,2983
11
+ mm_std/log.py,sha256=0TkTsAlUTt00gjgukvsvnZRIAGELq0MI6Lv8mKP-Wz4,2887
12
12
  mm_std/net.py,sha256=qdRCBIDneip6FaPNe5mx31UtYVmzqam_AoUF7ydEyjA,590
13
13
  mm_std/print_.py,sha256=zB7sVbSSF8RffMxvnOdbKCXjCKtKzKV3R68pBri4NkQ,1638
14
14
  mm_std/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -20,11 +20,11 @@ mm_std/types_.py,sha256=9FGd2q47a8M9QQgsWJR1Kq34jLxBAkYSoJuwih4PPqg,257
20
20
  mm_std/zip.py,sha256=axzF1BwcIygtfNNTefZH7hXKaQqwe-ZH3ChuRWr9dnk,396
21
21
  mm_std/concurrency/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
22
22
  mm_std/concurrency/async_decorators.py,sha256=xEpyipzp3ZhaPHtdeTE-Ikrt67SUTFKBE6LQPeoeh6Q,1735
23
- mm_std/concurrency/async_scheduler.py,sha256=cTsEY0FJKqlA94Ap-5Yx4KFOc-0QP5lRocn4P2n3cdE,5526
24
- mm_std/concurrency/async_task_runner.py,sha256=JpofaXCSqQDgQTh1FvaCWxsUsFWNPJGfXpuTlkF7hS0,4988
23
+ mm_std/concurrency/async_scheduler.py,sha256=TSu2WDJ8vfKZ4-saM3iZdcpGz8yPpSmud-7jJ4XKdJs,5579
24
+ mm_std/concurrency/async_task_runner.py,sha256=EN7tN2enkVYVgDbhSiAr-_W4o9m9wBXCveXGT8aVXII,4994
25
25
  mm_std/concurrency/sync_decorators.py,sha256=syCQBOmN7qPO55yzgJB2rbkh10CVww376hmyvs6e5tA,1080
26
26
  mm_std/concurrency/sync_scheduler.py,sha256=j4tBL_cBI1spr0cZplTA7N2CoYsznuORMeRN8rpR6gY,2407
27
27
  mm_std/concurrency/sync_task_runner.py,sha256=s5JPlLYLGQGHIxy4oDS-PN7O9gcy-yPZFoNm8RQwzcw,1780
28
- mm_std-0.3.21.dist-info/METADATA,sha256=_VWt4WbyHA-fN5KkHKXpSyu1evey3AtLnrJR4Sbdprs,448
29
- mm_std-0.3.21.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
30
- mm_std-0.3.21.dist-info/RECORD,,
28
+ mm_std-0.3.22.dist-info/METADATA,sha256=BN3U-377sfY6l7yYDzLyW3RRkYqAU581moSJAfIDU8c,415
29
+ mm_std-0.3.22.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
30
+ mm_std-0.3.22.dist-info/RECORD,,