pam-python 0.1.40__tar.gz → 0.1.41__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 (41) hide show
  1. {pam_python-0.1.40/pam_python.egg-info → pam_python-0.1.41}/PKG-INFO +1 -1
  2. pam_python-0.1.41/pam/logger.py +96 -0
  3. {pam_python-0.1.40 → pam_python-0.1.41}/pam/models/request_command.py +5 -0
  4. {pam_python-0.1.40 → pam_python-0.1.41}/pam/utils.py +2 -3
  5. {pam_python-0.1.40 → pam_python-0.1.41/pam_python.egg-info}/PKG-INFO +1 -1
  6. {pam_python-0.1.40 → pam_python-0.1.41}/pam_python.egg-info/SOURCES.txt +1 -0
  7. {pam_python-0.1.40 → pam_python-0.1.41}/setup.py +1 -1
  8. {pam_python-0.1.40 → pam_python-0.1.41}/LICENSE.txt +0 -0
  9. {pam_python-0.1.40 → pam_python-0.1.41}/README.md +0 -0
  10. {pam_python-0.1.40 → pam_python-0.1.41}/pam/__init__.py +0 -0
  11. {pam_python-0.1.40 → pam_python-0.1.41}/pam/api.py +0 -0
  12. {pam_python-0.1.40 → pam_python-0.1.41}/pam/cli.py +0 -0
  13. {pam_python-0.1.40 → pam_python-0.1.41}/pam/interface_task_manager.py +0 -0
  14. {pam_python-0.1.40 → pam_python-0.1.41}/pam/models/__init__.py +0 -0
  15. {pam_python-0.1.40 → pam_python-0.1.41}/pam/request_file_format.py +0 -0
  16. {pam_python-0.1.40 → pam_python-0.1.41}/pam/server.py +0 -0
  17. {pam_python-0.1.40 → pam_python-0.1.41}/pam/service.py +0 -0
  18. {pam_python-0.1.40 → pam_python-0.1.41}/pam/sqlite.py +0 -0
  19. {pam_python-0.1.40 → pam_python-0.1.41}/pam/task_manager.py +0 -0
  20. {pam_python-0.1.40 → pam_python-0.1.41}/pam/temp_file_utils.py +0 -0
  21. {pam_python-0.1.40 → pam_python-0.1.41}/pam/templates/buildcmd/pamb +0 -0
  22. {pam_python-0.1.40 → pam_python-0.1.41}/pam/templates/buildcmd/pamb-base.sh +0 -0
  23. {pam_python-0.1.40 → pam_python-0.1.41}/pam/templates/docker/Dockerfile +0 -0
  24. {pam_python-0.1.40 → pam_python-0.1.41}/pam/templates/init/AGENT.md +0 -0
  25. {pam_python-0.1.40 → pam_python-0.1.41}/pam/templates/init/dockerignore.tmpl +0 -0
  26. {pam_python-0.1.40 → pam_python-0.1.41}/pam/templates/init/gitignore.tmpl +0 -0
  27. {pam_python-0.1.40 → pam_python-0.1.41}/pam/templates/init/main.tmpl +0 -0
  28. {pam_python-0.1.40 → pam_python-0.1.41}/pam/templates/init/pylintrc.tmpl +0 -0
  29. {pam_python-0.1.40 → pam_python-0.1.41}/pam/templates/init/run_unit_test.bat +0 -0
  30. {pam_python-0.1.40 → pam_python-0.1.41}/pam/templates/init/run_unit_test.ps1 +0 -0
  31. {pam_python-0.1.40 → pam_python-0.1.41}/pam/templates/init/run_unit_test.sh +0 -0
  32. {pam_python-0.1.40 → pam_python-0.1.41}/pam/templates/service/functions.tmpl +0 -0
  33. {pam_python-0.1.40 → pam_python-0.1.41}/pam/templates/service/service.test.tmpl +0 -0
  34. {pam_python-0.1.40 → pam_python-0.1.41}/pam/templates/service/service.yaml +0 -0
  35. {pam_python-0.1.40 → pam_python-0.1.41}/pam/templates/service/service_class.tmpl +0 -0
  36. {pam_python-0.1.40 → pam_python-0.1.41}/pam/tester_task.py +0 -0
  37. {pam_python-0.1.40 → pam_python-0.1.41}/pam_python.egg-info/dependency_links.txt +0 -0
  38. {pam_python-0.1.40 → pam_python-0.1.41}/pam_python.egg-info/entry_points.txt +0 -0
  39. {pam_python-0.1.40 → pam_python-0.1.41}/pam_python.egg-info/requires.txt +0 -0
  40. {pam_python-0.1.40 → pam_python-0.1.41}/pam_python.egg-info/top_level.txt +0 -0
  41. {pam_python-0.1.40 → pam_python-0.1.41}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pam-python
3
- Version: 0.1.40
3
+ Version: 0.1.41
4
4
  Summary: Pam Python Library
5
5
  Home-page: https://github.com/heart/pam-python
6
6
  Author: Narongrit Kanhanoi
@@ -0,0 +1,96 @@
1
+ from __future__ import annotations
2
+
3
+ from datetime import datetime, timezone
4
+ from threading import Lock
5
+ from typing import Any
6
+
7
+ from pam.utils import log as stdout_log
8
+ from service import Service
9
+
10
+
11
+ class Logger:
12
+ def __init__(self, service: Service, buffer_size: int = 20, source: str = "worker"):
13
+ self.service = service
14
+ self.log_api = service.request.log_api
15
+ self.token = service.request.token
16
+ self.source = source
17
+ self.buffer_size = max(1, int(buffer_size))
18
+ self._buffer: list[dict[str, Any]] = []
19
+ self._lock = Lock()
20
+
21
+ def debug(self, message: Any, stage: str = "") -> None:
22
+ self.log(message, level="debug", stage=stage)
23
+
24
+ def info(self, message: Any, stage: str = "") -> None:
25
+ self.log(message, level="info", stage=stage)
26
+
27
+ def warning(self, message: Any, stage: str = "") -> None:
28
+ self.log(message, level="warning", stage=stage)
29
+
30
+ def error(self, message: Any, stage: str = "") -> None:
31
+ self.log(message, level="error", stage=stage)
32
+
33
+ def log(self, message: Any, level: str = "info", stage: str = "") -> None:
34
+ message_str = self._stringify(message)
35
+ self._write_stdout(message_str, level)
36
+ should_flush = self._enqueue(self._build_log_item(message_str, level, stage))
37
+
38
+ if should_flush:
39
+ self.flush()
40
+
41
+ def flush(self) -> bool:
42
+ if not self.log_api or not self.token:
43
+ return False
44
+
45
+ with self._lock:
46
+ if not self._buffer:
47
+ return True
48
+ logs = list(self._buffer)
49
+
50
+ payload = {
51
+ "token": self.token,
52
+ "logs": logs,
53
+ }
54
+ response = self.service.task_manager.api.http_post(self.log_api, payload)
55
+ if response is None:
56
+ return False
57
+
58
+ with self._lock:
59
+ if self._buffer[:len(logs)] == logs:
60
+ del self._buffer[:len(logs)]
61
+ else:
62
+ self._buffer = self._buffer[len(logs):]
63
+ return True
64
+
65
+ def pending_count(self) -> int:
66
+ with self._lock:
67
+ return len(self._buffer)
68
+
69
+ def _write_stdout(self, message: str, level: str) -> None:
70
+ stdout_log(f"[{level}] {message}")
71
+
72
+ def _build_log_item(self, message: str, level: str, stage: str) -> dict[str, Any]:
73
+ log_item = {
74
+ "message": message,
75
+ "level": level,
76
+ "source": self.source,
77
+ "logged_at": self._utc_now(),
78
+ }
79
+ if stage:
80
+ log_item["stage"] = stage
81
+ return log_item
82
+
83
+ def _enqueue(self, log_item: dict[str, Any]) -> bool:
84
+ with self._lock:
85
+ self._buffer.append(log_item)
86
+ return len(self._buffer) >= self.buffer_size
87
+
88
+ @staticmethod
89
+ def _stringify(message: Any) -> str:
90
+ if isinstance(message, str):
91
+ return message
92
+ return str(message)
93
+
94
+ @staticmethod
95
+ def _utc_now() -> str:
96
+ return datetime.now(timezone.utc).isoformat(timespec="milliseconds")
@@ -43,6 +43,7 @@ class RequestCommand:
43
43
  next: str
44
44
  input_files: list[str]
45
45
  service_name: str
46
+ log_api: str
46
47
 
47
48
  def is_start_command(self):
48
49
  """Determine if this command is a start command."""
@@ -138,6 +139,9 @@ class RequestCommand:
138
139
  sqlite_download = params.pop("sqlite_download", "")
139
140
 
140
141
  response_api = params.pop("response", "")
142
+
143
+ log_api = params.pop("log", "")
144
+
141
145
  is_end = RequestCommand.__safe_str_to_bool(params.pop("is_end", "true"))
142
146
  next_page = params.pop("next", "")
143
147
 
@@ -167,4 +171,5 @@ class RequestCommand:
167
171
  next=next_page,
168
172
  input_files=input_files,
169
173
  service_name=service_name,
174
+ log_api=log_api
170
175
  ), error_message
@@ -5,7 +5,6 @@ import re
5
5
  import pytz
6
6
  from typing import Any
7
7
 
8
-
9
8
  def get_adapter_id(url: str) -> str:
10
9
  """
11
10
  Extracts the adapter ID from a given URL.
@@ -55,6 +54,6 @@ def log(msg: str, level: str = "INFO"):
55
54
  tz = pytz.timezone('Asia/Bangkok')
56
55
  bangkok_time = utc_dt.astimezone(tz) # Convert UTC time to Bangkok time
57
56
  date_str = bangkok_time.strftime("%m/%d/%Y %H:%M:%S")
58
- print(f"[{date_str}] [{level}]: {msg}")
57
+ print(f"[{date_str}] [{level}]: {msg}", flush=True)
59
58
  except Exception as e:
60
- print(f"Failed to log message: {msg}. Error: {e}")
59
+ print(f"Failed to log message: {msg}. Error: {e}", flush=True)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pam-python
3
- Version: 0.1.40
3
+ Version: 0.1.41
4
4
  Summary: Pam Python Library
5
5
  Home-page: https://github.com/heart/pam-python
6
6
  Author: Narongrit Kanhanoi
@@ -5,6 +5,7 @@ pam/__init__.py
5
5
  pam/api.py
6
6
  pam/cli.py
7
7
  pam/interface_task_manager.py
8
+ pam/logger.py
8
9
  pam/request_file_format.py
9
10
  pam/server.py
10
11
  pam/service.py
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
2
2
 
3
3
  setup(
4
4
  name="pam-python",
5
- version="0.1.40",
5
+ version="0.1.41",
6
6
  author="Narongrit Kanhanoi",
7
7
  author_email="narongrit@pams.ai",
8
8
  description="Pam Python Library",
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