forked from platypush/platypush
Converted system.processes
to the new data model.
This commit is contained in:
parent
387616ea96
commit
27b1048789
8 changed files with 183 additions and 133 deletions
|
@ -1,77 +0,0 @@
|
|||
from datetime import datetime
|
||||
from typing import Optional, List
|
||||
|
||||
from platypush.message.response import Response
|
||||
|
||||
|
||||
class SystemResponse(Response):
|
||||
pass
|
||||
|
||||
|
||||
class ProcessResponse(SystemResponse):
|
||||
def __init__(
|
||||
self,
|
||||
pid: int,
|
||||
name: str,
|
||||
started: datetime,
|
||||
ppid: Optional[int],
|
||||
children: Optional[List[int]] = None,
|
||||
exe: Optional[List[str]] = None,
|
||||
status: Optional[str] = None,
|
||||
username: Optional[str] = None,
|
||||
terminal: Optional[str] = None,
|
||||
cpu_user_time: Optional[float] = None,
|
||||
cpu_system_time: Optional[float] = None,
|
||||
cpu_children_user_time: Optional[float] = None,
|
||||
cpu_children_system_time: Optional[float] = None,
|
||||
mem_rss: Optional[int] = None,
|
||||
mem_vms: Optional[int] = None,
|
||||
mem_shared: Optional[int] = None,
|
||||
mem_text: Optional[int] = None,
|
||||
mem_data: Optional[int] = None,
|
||||
mem_lib: Optional[int] = None,
|
||||
mem_dirty: Optional[int] = None,
|
||||
mem_percent: Optional[float] = None,
|
||||
*args,
|
||||
**kwargs
|
||||
):
|
||||
super().__init__(
|
||||
*args,
|
||||
output={
|
||||
'pid': pid,
|
||||
'name': name,
|
||||
'started': started,
|
||||
'ppid': ppid,
|
||||
'exe': exe,
|
||||
'status': status,
|
||||
'username': username,
|
||||
'terminal': terminal,
|
||||
'cpu_user_time': cpu_user_time,
|
||||
'cpu_system_time': cpu_system_time,
|
||||
'cpu_children_user_time': cpu_children_user_time,
|
||||
'cpu_children_system_time': cpu_children_system_time,
|
||||
'mem_rss': mem_rss,
|
||||
'mem_vms': mem_vms,
|
||||
'mem_shared': mem_shared,
|
||||
'mem_text': mem_text,
|
||||
'mem_data': mem_data,
|
||||
'mem_lib': mem_lib,
|
||||
'mem_dirty': mem_dirty,
|
||||
'mem_percent': mem_percent,
|
||||
'children': children or [],
|
||||
},
|
||||
**kwargs
|
||||
)
|
||||
|
||||
|
||||
class SystemResponseList(SystemResponse):
|
||||
def __init__(self, responses: List[SystemResponse], *args, **kwargs):
|
||||
super().__init__(output=[r.output for r in responses], *args, **kwargs)
|
||||
|
||||
|
||||
class ProcessResponseList(SystemResponseList):
|
||||
def __init__(self, responses: List[ProcessResponse], *args, **kwargs):
|
||||
super().__init__(responses=responses, *args, **kwargs)
|
||||
|
||||
|
||||
# vim:sw=4:ts=4:et:
|
|
@ -1,6 +1,5 @@
|
|||
import os
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Tuple, Union, List, Optional
|
||||
from typing_extensions import override
|
||||
|
||||
|
@ -23,10 +22,6 @@ from platypush.entities.system import (
|
|||
SystemFan,
|
||||
SystemTemperature,
|
||||
)
|
||||
from platypush.message.response.system import (
|
||||
ProcessResponseList,
|
||||
ProcessResponse,
|
||||
)
|
||||
from platypush.plugins import action
|
||||
from platypush.plugins.sensor import SensorPlugin
|
||||
from platypush.schemas.system import (
|
||||
|
@ -49,6 +44,8 @@ from platypush.schemas.system import (
|
|||
MemoryStatsSchema,
|
||||
NetworkInterface,
|
||||
NetworkInterfaceSchema,
|
||||
Process,
|
||||
ProcessSchema,
|
||||
SwapStats,
|
||||
SwapStatsSchema,
|
||||
SystemInfoSchema,
|
||||
|
@ -366,7 +363,8 @@ class SystemPlugin(SensorPlugin, EntityManager):
|
|||
"""
|
||||
return TemperatureSchema().dump(self._sensors_temperature(), many=True)
|
||||
|
||||
def _sensors_fan(self) -> List[Fan]:
|
||||
@staticmethod
|
||||
def _sensors_fan() -> List[Fan]:
|
||||
return FanSchema().load( # type: ignore
|
||||
[
|
||||
{
|
||||
|
@ -389,7 +387,8 @@ class SystemPlugin(SensorPlugin, EntityManager):
|
|||
"""
|
||||
return FanSchema().dump(self._sensors_fan(), many=True)
|
||||
|
||||
def _sensors_battery(self) -> Optional[Battery]:
|
||||
@staticmethod
|
||||
def _sensors_battery() -> Optional[Battery]:
|
||||
battery = psutil.sensors_battery()
|
||||
return BatterySchema().load(battery) if battery else None # type: ignore
|
||||
|
||||
|
@ -403,7 +402,8 @@ class SystemPlugin(SensorPlugin, EntityManager):
|
|||
battery = self._sensors_battery()
|
||||
return BatterySchema().dump(battery) if battery else None # type: ignore
|
||||
|
||||
def _connected_users(self) -> List[User]:
|
||||
@staticmethod
|
||||
def _connected_users() -> List[User]:
|
||||
return UserSchema().load(psutil.users(), many=True) # type: ignore
|
||||
|
||||
@action
|
||||
|
@ -415,64 +415,40 @@ class SystemPlugin(SensorPlugin, EntityManager):
|
|||
"""
|
||||
return UserSchema().dump(self._connected_users(), many=True)
|
||||
|
||||
@action
|
||||
def processes(self, filter: Optional[str] = '') -> ProcessResponseList:
|
||||
@classmethod
|
||||
def _processes(cls) -> List[Process]:
|
||||
"""
|
||||
Get the list of running processes.
|
||||
|
||||
:param filter: Filter the list by name.
|
||||
:return: List of :class:`platypush.message.response.system.ProcessResponse`.
|
||||
"""
|
||||
processes = [psutil.Process(pid) for pid in psutil.pids()]
|
||||
p_list = []
|
||||
return ProcessSchema().load( # type: ignore
|
||||
filter( # type: ignore
|
||||
lambda proc: proc is not None,
|
||||
[cls._get_process_if_exists(pid) for pid in psutil.pids()],
|
||||
),
|
||||
many=True,
|
||||
)
|
||||
|
||||
for p in processes:
|
||||
if filter and filter not in p.name():
|
||||
continue
|
||||
@action
|
||||
def processes(self) -> List[dict]:
|
||||
"""
|
||||
Get the list of running processes.
|
||||
|
||||
args = {}
|
||||
:return: .. schema:: system.ProcessSchema
|
||||
"""
|
||||
return ProcessSchema().dump(self._processes(), many=True)
|
||||
|
||||
try:
|
||||
mem = p.memory_info()
|
||||
times = p.cpu_times()
|
||||
args.update(
|
||||
pid=p.pid,
|
||||
name=p.name(),
|
||||
started=datetime.fromtimestamp(p.create_time()),
|
||||
ppid=p.ppid(),
|
||||
children=[pp.pid for pp in p.children()],
|
||||
status=p.status(),
|
||||
username=p.username(),
|
||||
terminal=p.terminal(),
|
||||
cpu_user_time=times.user,
|
||||
cpu_system_time=times.system,
|
||||
cpu_children_user_time=times.children_user,
|
||||
cpu_children_system_time=times.children_system,
|
||||
mem_rss=mem.rss,
|
||||
mem_vms=mem.vms,
|
||||
mem_shared=mem.shared,
|
||||
mem_text=mem.text,
|
||||
mem_data=mem.data,
|
||||
mem_lib=mem.lib,
|
||||
mem_dirty=mem.dirty,
|
||||
mem_percent=p.memory_percent(),
|
||||
)
|
||||
except psutil.Error:
|
||||
continue
|
||||
|
||||
try:
|
||||
args.update(
|
||||
exe=p.exe(),
|
||||
)
|
||||
except psutil.Error:
|
||||
pass
|
||||
|
||||
p_list.append(ProcessResponse(**args))
|
||||
|
||||
return ProcessResponseList(p_list)
|
||||
@classmethod
|
||||
def _get_process_if_exists(cls, pid: int) -> Optional[psutil.Process]:
|
||||
try:
|
||||
return cls._get_process(pid)
|
||||
except psutil.NoSuchProcess:
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def _get_process(pid: int):
|
||||
def _get_process(pid: int) -> psutil.Process:
|
||||
return psutil.Process(pid)
|
||||
|
||||
@action
|
||||
|
|
|
@ -16,6 +16,7 @@ from ._fan import Fan, FanSchema
|
|||
from ._memory import MemoryStats, MemoryStatsSchema, SwapStats, SwapStatsSchema
|
||||
from ._model import SystemInfo
|
||||
from ._network import NetworkInterface, NetworkInterfaceSchema
|
||||
from ._process import Process, ProcessSchema
|
||||
from ._schemas import SystemInfoSchema
|
||||
from ._temperature import Temperature, TemperatureSchema
|
||||
from ._user import User, UserSchema
|
||||
|
@ -41,6 +42,8 @@ __all__ = [
|
|||
"FanSchema",
|
||||
"MemoryStats",
|
||||
"MemoryStatsSchema",
|
||||
"Process",
|
||||
"ProcessSchema",
|
||||
"SwapStats",
|
||||
"SwapStatsSchema",
|
||||
"NetworkInterface",
|
||||
|
|
4
platypush/schemas/system/_process/__init__.py
Normal file
4
platypush/schemas/system/_process/__init__.py
Normal file
|
@ -0,0 +1,4 @@
|
|||
from ._model import Process
|
||||
from ._schemas import ProcessSchema
|
||||
|
||||
__all__ = ['Process', 'ProcessSchema']
|
28
platypush/schemas/system/_process/_base.py
Normal file
28
platypush/schemas/system/_process/_base.py
Normal file
|
@ -0,0 +1,28 @@
|
|||
from datetime import datetime
|
||||
|
||||
from dateutil.tz import gettz
|
||||
from marshmallow import pre_load
|
||||
|
||||
from .._base import SystemBaseSchema
|
||||
|
||||
|
||||
class ProcessBaseSchema(SystemBaseSchema):
|
||||
"""
|
||||
Base schema for system processes.
|
||||
"""
|
||||
|
||||
@pre_load
|
||||
def pre_load(self, data, **_) -> dict:
|
||||
if hasattr(data, 'as_dict'):
|
||||
data = data.as_dict()
|
||||
|
||||
started_ts = data.pop('create_time', None)
|
||||
if started_ts is not None:
|
||||
data['started'] = datetime.fromtimestamp(started_ts).replace(tzinfo=gettz())
|
||||
|
||||
data['command_line'] = data.pop('cmdline', None)
|
||||
data['cpu_percent'] = data.pop('cpu_percent') / 100
|
||||
data['current_directory'] = data.pop('cwd', None)
|
||||
data['memory_percent'] = data.pop('memory_percent') / 100
|
||||
data['parent_pid'] = data.pop('ppid', None)
|
||||
return data
|
110
platypush/schemas/system/_process/_model.py
Normal file
110
platypush/schemas/system/_process/_model.py
Normal file
|
@ -0,0 +1,110 @@
|
|||
from dataclasses import dataclass, field
|
||||
from datetime import datetime
|
||||
from typing import List, Optional
|
||||
|
||||
from platypush.schemas.dataclasses import percent_field
|
||||
|
||||
|
||||
@dataclass
|
||||
class Process:
|
||||
"""
|
||||
System process data class.
|
||||
"""
|
||||
|
||||
pid: int = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Process PID',
|
||||
'example': 12345,
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
name: str = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Process name',
|
||||
'example': 'python',
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
parent_pid: Optional[int] = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'PID of the parent process',
|
||||
'example': 1000,
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
username: str = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Username that owns the process',
|
||||
'example': 'root',
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
command_line: List[str] = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Command line of the process',
|
||||
'example': ['/usr/bin/python', '-m', 'platypush'],
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
status: str = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Process status',
|
||||
'example': 'running',
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
terminal: Optional[str] = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Terminal the process is running on',
|
||||
'example': 'pts/1',
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
current_directory: Optional[str] = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Current directory of the process',
|
||||
'example': '/root',
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
started: Optional[datetime] = field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'When the process started',
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
cpu_percent: float = percent_field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Percentage of CPU used by the process, between 0 and 1',
|
||||
'example': 0.1,
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
memory_percent: float = percent_field(
|
||||
metadata={
|
||||
'metadata': {
|
||||
'description': 'Percentage of memory used by the process, between 0 and 1',
|
||||
'example': 0.05,
|
||||
}
|
||||
}
|
||||
)
|
7
platypush/schemas/system/_process/_schemas.py
Normal file
7
platypush/schemas/system/_process/_schemas.py
Normal file
|
@ -0,0 +1,7 @@
|
|||
from marshmallow_dataclass import class_schema
|
||||
|
||||
from ._base import ProcessBaseSchema
|
||||
from ._model import Process
|
||||
|
||||
|
||||
ProcessSchema = class_schema(Process, base_schema=ProcessBaseSchema)
|
|
@ -31,7 +31,6 @@ class User:
|
|||
metadata={
|
||||
'metadata': {
|
||||
'description': 'When the user session started',
|
||||
'example': 'pts/1',
|
||||
}
|
||||
}
|
||||
)
|
||||
|
|
Loading…
Reference in a new issue