Skip to content

Commit 46f65f3

Browse files
committed
fix(build): update build arguments and version
- Changed BASE_IMAGE in BUILD_ARGS from python:3.9.21-slim-bookworm to python:3.10.16-slim-bookworm. - Updated BUILD_DATE to 2025-04-01T23:04:43UTC. - Modified LOCAL_SERVER IP address from 100.65.0.17 to 20.20.5.172. - Bumped version in BUILD_ARGS from 2.1.7 to 2.1.12. - Enhanced timestamp logging in convert_timestamp.py to include UTC time zone. - Improved CPU time statistics gathering in server.py with better error handling and validation. - Updated timestamp_to_string function in date_utils.py to support timezone conversion. - Added timezone setup in test_typing_time.py for consistent test results.
1 parent 60f2c3e commit 46f65f3

5 files changed

Lines changed: 106 additions & 49 deletions

File tree

‎BUILD_ARGS‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11

2-
--build-arg BASE_IMAGE=python:3.9.21-slim-bookworm
3-
--build-arg BUILD_DATE=2025-03-04T23:47:58UTC
2+
--build-arg BASE_IMAGE=python:3.10.16-slim-bookworm
3+
--build-arg BUILD_DATE=2025-04-01T23:04:43UTC
44
--build-arg DOCKER_BUILD_OPTION=--no-cache --rm=true
55
--build-arg ECHO_OPTION=
66
--build-arg GIT_USER=JINWOO-J
77
--build-arg IS_MULTI_ARCH=false
8-
--build-arg LOCAL_SERVER=100.65.0.17
8+
--build-arg LOCAL_SERVER=20.20.5.172
99
--build-arg NAME=pawnlib
1010
--build-arg PRIMARY_BRANCH=master
1111
--build-arg REPO_HUB=jinwoo
1212
--build-arg SED_OPTION=''
1313
--build-arg UNAME_S=Darwin
14-
--build-arg VERSION=2.1.7
14+
--build-arg VERSION=2.1.12

‎examples/converter/convert_timestamp.py‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,5 @@
1212
number_list = []
1313

1414
for unixtime_stamp in [1646060400000000, 1646060400]:
15-
pawn.console.log(timestamp_to_string(unixtime_stamp))
15+
pawn.console.log(f"Local Time Zone: {timestamp_to_string(unixtime_stamp)}")
16+
pawn.console.log(f"UTC Time Zone: {timestamp_to_string(unixtime_stamp, tz='UTC')}")

‎pawnlib/resource/server.py‎

Lines changed: 66 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1470,46 +1470,83 @@ def convert_values_to_unit(data, convert_unit):
14701470
return data
14711471

14721472

1473-
def get_cpu_time():
1473+
def get_cpu_time() -> Dict[str, Dict[str, float]]:
1474+
"""
1475+
Reads /proc/stat to gather CPU time statistics for each CPU core.
1476+
Returns a dictionary with CPU IDs and their respective time metrics.
1477+
"""
14741478
cpu_infos = {}
1475-
if os.path.exists('/proc/stat'):
1476-
with open('/proc/stat', 'r') as file_stat:
1477-
cpu_lines = []
1478-
for lines in file_stat.readlines():
1479-
for line in lines.split('\n'):
1480-
if line.startswith('cpu'):
1481-
cpu_lines.append(line.split(' '))
1482-
for cpu_line in cpu_lines:
1483-
if '' in cpu_line:
1484-
cpu_line.remove('') # First row(cpu) exist '' and Remove ''
1485-
cpu_id = cpu_line[0]
1486-
cpu_line = [float(item) for item in cpu_line[1:]]
1487-
user, nice, system, idle, iowait, irq, softirq, steal, guest, guest_nice = cpu_line
1488-
1489-
idle_time = idle + iowait
1490-
non_idle_time = user + nice + system + irq + softirq + steal
1491-
total = idle_time + non_idle_time
1492-
1493-
cpu_infos.update({cpu_id: {'total': total, 'idle': idle_time, 'iowait': iowait}})
1479+
if not os.path.exists('/proc/stat'):
1480+
return cpu_infos # Return empty dict if /proc/stat is unavailable
1481+
1482+
with open('/proc/stat', 'r') as file_stat:
1483+
for line in file_stat:
1484+
if not line.startswith('cpu'):
1485+
continue
1486+
fields = [field for field in line.split() if field] # Remove empty strings
1487+
if len(fields) < 5: # Basic validation for expected fields
1488+
continue
1489+
1490+
cpu_id = fields[0]
1491+
times = [float(t) for t in fields[1:]] # Convert to floats
1492+
user, nice, system, idle, iowait = times[:5] # Core fields
1493+
# Optional fields (irq, softirq, etc.) may not always be present
1494+
irq = times[5] if len(times) > 5 else 0
1495+
softirq = times[6] if len(times) > 6 else 0
1496+
steal = times[7] if len(times) > 7 else 0
1497+
1498+
idle_time = idle + iowait
1499+
non_idle_time = user + nice + system + irq + softirq + steal
1500+
total_time = idle_time + non_idle_time
1501+
1502+
cpu_infos[cpu_id] = {
1503+
'total': total_time,
1504+
'idle': idle_time,
1505+
'iowait': iowait
1506+
}
14941507
return cpu_infos
14951508

14961509

1497-
def get_cpu_usage_percentage():
1510+
def get_cpu_usage_percentage(interval: float = 1.0) -> Dict[str, float]:
1511+
"""
1512+
Calculates CPU usage percentage over a given interval.
1513+
Returns a dictionary with CPU usage percentages per core, average, and iowait.
1514+
"""
14981515
start = get_cpu_time()
1499-
time.sleep(1)
1516+
if not start:
1517+
return {}
1518+
1519+
time.sleep(interval)
15001520
end = get_cpu_time()
1521+
if not end:
1522+
return {}
1523+
15011524
cpu_usages = {}
15021525
iowait_usages = []
1526+
15031527
for cpu in start:
1504-
diff_total = end[cpu]['total'] - start[cpu]['total']
1505-
diff_idle = end[cpu]['idle'] - start[cpu]['idle']
1506-
diff_iowait = end[cpu].get('iowait', 0) - start[cpu].get('iowait', 0)
1507-
iowait_usages.append(diff_iowait)
1508-
cpu_usage_percentage = (diff_total - diff_idle) / diff_total * 100
1509-
cpu_usages.update({cpu: round(cpu_usage_percentage, 2)})
1528+
if cpu not in end:
1529+
continue # Skip if CPU data is missing in end snapshot
1530+
try:
1531+
diff_total = end[cpu]['total'] - start[cpu]['total']
1532+
diff_idle = end[cpu]['idle'] - start[cpu]['idle']
1533+
diff_iowait = end[cpu]['iowait'] - start[cpu]['iowait']
1534+
1535+
if diff_total <= 0: # Avoid division by zero or negative time
1536+
cpu_usage_percentage = 0.0
1537+
else:
1538+
cpu_usage_percentage = (diff_total - diff_idle) / diff_total * 100
1539+
1540+
cpu_usages[cpu] = round(cpu_usage_percentage, 2)
1541+
iowait_usages.append(diff_iowait)
1542+
except KeyError as e:
1543+
print(f"Warning: Missing data for {cpu}: {e}")
1544+
continue
1545+
15101546
if cpu_usages:
1511-
cpu_usages['avg'] = round(sum(cpu_usages.values()) / len(cpu_usages.values()), 2)
1547+
cpu_usages['avg'] = round(sum(cpu_usages.values()) / len(cpu_usages), 2)
15121548
cpu_usages['iowait'] = round(sum(iowait_usages) / len(iowait_usages), 2)
1549+
15131550
return cpu_usages
15141551

15151552

‎pawnlib/typing/date_utils.py‎

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from functools import lru_cache
1212

1313
if sys.version_info >= (3, 9):
14-
from zoneinfo import ZoneInfo
14+
from zoneinfo import ZoneInfo, ZoneInfoNotFoundError
1515
USE_ZONEINFO = True
1616
else:
1717
USE_ZONEINFO = False
@@ -317,26 +317,30 @@ def format_seconds_to_hhmmss(seconds: int = 0):
317317
return seconds
318318

319319

320-
def timestamp_to_string(unix_timestamp: int, str_format='%Y-%m-%d %H:%M:%S'):
320+
def timestamp_to_string(unix_timestamp: int, str_format: str = '%Y-%m-%d %H:%M:%S', tz: Optional[Union[str, datetime.tzinfo]] = None) -> str:
321321
"""
322+
Converts a Unix timestamp to a formatted string based on local timezone or specified timezone.
322323
323-
This functions will be returned unix timestamp to hh:mm:ss format
324-
325-
:param unix_timestamp: unix_timestamp
326-
:param str_format: string format
327-
:return:
324+
:param unix_timestamp: Unix timestamp (seconds, milliseconds, or microseconds)
325+
:param str_format: Output string format (default: '%Y-%m-%d %H:%M:%S')
326+
:param tz: Timezone as string (e.g., 'UTC', 'Asia/Seoul') or tzinfo object (default: None, uses local timezone)
327+
:return: Formatted datetime string
328328
329329
Example:
330-
331330
.. code-block:: python
332-
333331
from pawnlib.typing import date_utils
334332
333+
# Local timezone (default)
335334
date_utils.timestamp_to_string(12323232323)
335+
# >> '2360-07-05 09:05:23' (local timezone, e.g., KST)
336336
337-
# >> '2360-07-05 09:05:23'
338-
337+
# UTC timezone
338+
date_utils.timestamp_to_string(12323232323, tz='UTC')
339+
# >> '2360-07-05 00:05:23' (UTC)
339340
341+
# Asia/Seoul timezone
342+
date_utils.timestamp_to_string(12323232323, tz='Asia/Seoul')
343+
# >> '2360-07-05 09:05:23' (Asia/Seoul)
340344
"""
341345
if isinstance(unix_timestamp, str):
342346
unix_timestamp = unix_timestamp.strip()
@@ -346,15 +350,25 @@ def timestamp_to_string(unix_timestamp: int, str_format='%Y-%m-%d %H:%M:%S'):
346350
ts_length = len(str(unix_timestamp))
347351

348352
if ts_length == const.SECONDS_DIGITS:
349-
timestamp_in_seconds = unix_timestamp
353+
timestamp_in_seconds = int(unix_timestamp)
350354
elif ts_length == const.MILLI_SECONDS_DIGITS:
351-
timestamp_in_seconds = unix_timestamp / 1_000
355+
timestamp_in_seconds = int(unix_timestamp) / 1_000
352356
elif ts_length == const.MICRO_SECONDS_DIGITS:
353-
timestamp_in_seconds = unix_timestamp / 1_000_000
357+
timestamp_in_seconds = int(unix_timestamp) / 1_000_000
354358
else:
355359
raise ValueError(f'Invalid timestamp length - length={ts_length}, timestamp={unix_timestamp}')
356360

357-
return datetime.datetime.fromtimestamp(timestamp_in_seconds).strftime(str_format)
361+
362+
if isinstance(tz, str):
363+
try:
364+
timezone = get_timezone(tz)
365+
except ZoneInfoNotFoundError as e:
366+
raise ValueError(f"Unsupported timezone: {tz} ({e})")
367+
else:
368+
timezone = tz
369+
370+
dt = datetime.datetime.fromtimestamp(timestamp_in_seconds, tz=timezone)
371+
return dt.strftime(str_format)
358372

359373

360374
def second_to_dayhhmm(seconds: int = 0):

‎tests/test_typing_time.py‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@
88
import datetime
99
from pawnlib.typing.date_utils import convert_unix_timestamp, get_range_day_of_month, timestamp_to_string, TimeCalculator, todaydate
1010
from pawnlib.output import cprint
11+
import time
12+
import os
13+
os.environ['TZ'] = 'Asia/Seoul'
14+
time.tzset()
15+
1116

1217

1318
class TestMethodRequest(unittest.TestCase):

0 commit comments

Comments
 (0)