cgse-tools 0.11.5__tar.gz → 0.12.0__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.
@@ -1,12 +1,12 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cgse-tools
3
- Version: 0.11.5
3
+ Version: 0.12.0
4
4
  Summary: Tools for CGSE
5
5
  Author: IvS KU Leuven
6
6
  Maintainer-email: Rik Huygen <rik.huygen@kuleuven.be>, Sara Regibo <sara.regibo@kuleuven.be>
7
7
  License-Expression: MIT
8
8
  Keywords: CGSE,Common-EGSE,hardware testing,software framework
9
- Requires-Python: >=3.9
9
+ Requires-Python: >=3.10
10
10
  Requires-Dist: cgse-common
11
11
  Requires-Dist: textual>=2.0.0
12
12
  Description-Content-Type: text/markdown
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "cgse-tools"
3
- version = "0.11.5"
3
+ version = "0.12.0"
4
4
  description = "Tools for CGSE"
5
5
  authors = [
6
6
  {name = "IvS KU Leuven"}
@@ -10,7 +10,7 @@ maintainers = [
10
10
  {name = "Sara Regibo", email = "sara.regibo@kuleuven.be"}
11
11
  ]
12
12
  readme = {"file" = "README.md", "content-type" = "text/markdown"}
13
- requires-python = ">=3.9"
13
+ requires-python = ">=3.10"
14
14
  license = "MIT"
15
15
  keywords = [
16
16
  "CGSE",
@@ -54,7 +54,7 @@ class ClockApp(App):
54
54
 
55
55
  @app.command()
56
56
  def clock(utc: bool = False):
57
- """Showcase for running an in-line Textual App. """
57
+ """Showcase for running an in-line Textual App."""
58
58
 
59
59
  ClockApp(utc).run(inline=True)
60
60
 
@@ -9,9 +9,15 @@ from typing import Annotated
9
9
 
10
10
  import rich
11
11
  import typer
12
+ from rich.console import Console
13
+ from rich.table import Table
12
14
 
13
15
  from cgse_common import AppState
16
+ from egse.config import find_files
17
+ from egse.env import get_conf_data_location
18
+ from egse.env import get_site_id
14
19
  from egse.plugin import entry_points
20
+ from egse.process import ProcessInfo
15
21
  from egse.setup import Setup
16
22
  from egse.system import format_datetime
17
23
 
@@ -39,7 +45,7 @@ def init(project: str = ""):
39
45
  project = project.upper()
40
46
  site_id = None
41
47
 
42
- rich.print("[light_steel_blue]Please note default values are given between \[brackets].[/]")
48
+ rich.print(r"[light_steel_blue]Please note default values are given between \[brackets].[/]")
43
49
 
44
50
  answer = Prompt.ask(f"What is the name of the project [{project}] ?")
45
51
  if answer:
@@ -80,7 +86,7 @@ def init(project: str = ""):
80
86
  Path(log_file_location).expanduser().mkdir(exist_ok=True, parents=True)
81
87
 
82
88
  if not Path(local_settings_path).expanduser().exists():
83
- with open(Path(local_settings_path).expanduser(), 'w') as fd:
89
+ with open(Path(local_settings_path).expanduser(), "w") as fd:
84
90
  fd.write(
85
91
  textwrap.dedent(
86
92
  f"""\
@@ -92,7 +98,7 @@ def init(project: str = ""):
92
98
 
93
99
  answer = Confirm.ask("Shall I add the environment to your ~/bash_profile ?")
94
100
  if answer:
95
- with open(Path("~/.bash_profile").expanduser(), 'a') as fd:
101
+ with open(Path("~/.bash_profile").expanduser(), "a") as fd:
96
102
  fd.write(
97
103
  textwrap.dedent(
98
104
  f"""
@@ -120,7 +126,6 @@ def init(project: str = ""):
120
126
  export {project}_LOCAL_SETTINGS={local_settings_path}
121
127
  """
122
128
  )
123
-
124
129
  )
125
130
 
126
131
 
@@ -130,22 +135,18 @@ show = typer.Typer(help="Show information about settings, environment, setup, ..
130
135
  @show.command(name="settings")
131
136
  def show_settings():
132
137
  """Show the settings that are defined by the installed packages."""
133
- proc = subprocess.Popen(
134
- [sys.executable, "-m", "egse.settings"],
135
- stdout=subprocess.PIPE,
136
- stderr=subprocess.PIPE
137
- )
138
+ proc = subprocess.Popen([sys.executable, "-m", "egse.settings"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
138
139
  stdout, stderr = proc.communicate()
139
- rich.print(stdout.decode(), end='')
140
+ rich.print(stdout.decode(), end="")
140
141
  if stderr:
141
142
  rich.print(f"[red]{stderr.decode()}[/]")
142
143
 
143
144
 
144
145
  @show.command(name="env")
145
146
  def show_env(
146
- mkdir: Annotated[bool, typer.Option(help="Create the missing folder")] = None,
147
- full: Annotated[bool, typer.Option(help="Provide additional info")] = None,
148
- doc: Annotated[bool, typer.Option(help="Provide documentation on environment variables")] = None,
147
+ mkdir: Annotated[bool, typer.Option(help="Create the missing folder")] = None,
148
+ full: Annotated[bool, typer.Option(help="Provide additional info")] = None,
149
+ doc: Annotated[bool, typer.Option(help="Provide documentation on environment variables")] = None,
149
150
  ):
150
151
  """Show the environment variables that are defined for the project."""
151
152
  options = [opt for opt, flag in [("--mkdir", mkdir), ("--full", full), ("--doc", doc)] if flag]
@@ -153,13 +154,9 @@ def show_env(
153
154
  cmd = [sys.executable, "-m", "egse.env"]
154
155
  cmd += options if options else []
155
156
 
156
- proc = subprocess.Popen(
157
- cmd,
158
- stdout=subprocess.PIPE,
159
- stderr=subprocess.PIPE
160
- )
157
+ proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
161
158
  stdout, stderr = proc.communicate()
162
- rich.print(stdout.decode(), end='')
159
+ rich.print(stdout.decode(), end="")
163
160
  if stderr:
164
161
  rich.print(f"[red]{stderr.decode()}[/]")
165
162
 
@@ -167,13 +164,95 @@ def show_env(
167
164
  @show.command(name="procs")
168
165
  def show_processes():
169
166
  """Show the processes that are running for the installed packages."""
167
+ processes: list[ProcessInfo] = []
168
+
170
169
  for ep in entry_points("cgse.explore"):
171
170
  # print(f"{ep.name = }, {ep.module = }, {ep.load() = }, {ep.extras = }")
172
171
  explore = ep.load()
173
172
  with contextlib.suppress(AttributeError):
174
173
  show_procs = getattr(explore, "show_processes")
175
- for line in show_procs():
176
- rich.print(line)
174
+ processes.extend(show_procs())
175
+
176
+ console = Console()
177
+ console.print(create_rich_table(processes))
178
+
179
+
180
+ def create_rich_table(processes: list[ProcessInfo]):
181
+ """Create a rich table with the processes from all registered packages."""
182
+
183
+ table = Table(title="Process Information")
184
+
185
+ table.add_column("PID", style="cyan", no_wrap=True)
186
+ table.add_column("Name", style="magenta")
187
+ table.add_column("User", style="green")
188
+ table.add_column("CPU%", justify="right", style="yellow")
189
+ # table.add_column("Memory%", justify="right", style="blue")
190
+ table.add_column("Memory MB", justify="right", style="blue")
191
+ table.add_column("Status", style="red")
192
+ table.add_column("Command", style="white")
193
+
194
+ # Sort by CPU usage
195
+ processes.sort(key=lambda x: x.cpu_percent, reverse=True)
196
+
197
+ for proc in processes:
198
+ proc = proc.as_dict()
199
+ cmd = re.sub(r"^.*/?python(?:\d+\.\d+)?\s+(?:-m)?\s*", "python -m ", proc["command"])
200
+ table.add_row(
201
+ str(proc["pid"]),
202
+ proc["name"],
203
+ proc.get("username", "N/A"),
204
+ f"{proc.get('cpu_percent', 0):.1f}",
205
+ # f"{proc.get('memory_percent', 0):.1f}",
206
+ f"{proc.get('memory_mb', 0):.1f}",
207
+ proc.get("status", "unknown"),
208
+ cmd[:100] + "..." if len(cmd) > 100 else cmd,
209
+ )
210
+
211
+ return table
212
+
213
+
214
+ @show.command(name="setup")
215
+ def show_setup(
216
+ use_cm: Annotated[bool, typer.Option(help="Get the current setup from the configuration manager")] = True,
217
+ list_all: Annotated[bool, typer.Option(help="Print a list of all available setups")] = False,
218
+ setup_id: Annotated[int, typer.Option(help="Show the setup with this id")] = -1,
219
+ ):
220
+ if use_cm:
221
+ try:
222
+ from egse.confman import ConfigurationManagerProxy
223
+ except ImportError:
224
+ rich.print("[dark_orange3]WARNING: package 'cgse-core' is not installed, service not available.[/]")
225
+ return
226
+
227
+ with ConfigurationManagerProxy() as cm:
228
+ if list_all:
229
+ rich.print(cm.list_setups())
230
+ else:
231
+ rich.print(cm.get_setup())
232
+ return
233
+
234
+ location = get_conf_data_location()
235
+ site_id = get_site_id()
236
+
237
+ if list_all:
238
+ files = find_files(f"SETUP_{site_id}_*_*.yaml", root=location)
239
+ files = list(files)
240
+ if files:
241
+ location = files[0].parent.resolve()
242
+ rich.print(sorted([f.name for f in files]))
243
+ rich.print(f"Loaded from [purple]{location}.")
244
+ else:
245
+ if setup_id == -1:
246
+ setup_files = find_files(f"SETUP_{site_id}_*_*.yaml", root=location)
247
+ else:
248
+ setup_files = find_files(f"SETUP_{site_id}_{setup_id:05d}_*.yaml", root=location)
249
+ setup_files = list(setup_files)
250
+ if len(setup_files) > 0:
251
+ setup_file = sorted(setup_files)[-1]
252
+ setup = Setup.from_yaml_file(setup_file)
253
+ rich.print(setup)
254
+ else:
255
+ rich.print("[red]No setup files were found.[/]")
177
256
 
178
257
 
179
258
  check = typer.Typer(help="Check installation, settings, required files, etc.", no_args_is_help=True)
@@ -229,9 +308,7 @@ def check_setups(verbose: bool = False):
229
308
  )
230
309
  elif not Path(conf_data_location).exists():
231
310
  any_errors += 1
232
- error_messages.append(
233
- f"[red]The location of the configuration data doesn't exist: {conf_data_location!s}[/]"
234
- )
311
+ error_messages.append(f"[red]The location of the configuration data doesn't exist: {conf_data_location!s}[/]")
235
312
 
236
313
  if any_errors:
237
314
  print_error_messages(error_messages)
@@ -245,9 +322,7 @@ def check_setups(verbose: bool = False):
245
322
 
246
323
  if not files:
247
324
  any_errors += 1
248
- error_messages.append(
249
- f"[red]No SETUP files were found at {conf_data_location}[/]"
250
- )
325
+ error_messages.append(f"[red]No SETUP files were found at {conf_data_location}[/]")
251
326
  else:
252
327
  verbose and rich.print(f":arrow_forward: Found {len(files)} Setup files.")
253
328
 
@@ -255,9 +330,7 @@ def check_setups(verbose: bool = False):
255
330
 
256
331
  if not any(True for file in files if regex.search(str(file))):
257
332
  any_errors += 1
258
- error_messages.append(
259
- f"[red]There is no 'Zero' SETUP for {site_id} in {conf_data_location}[/]"
260
- )
333
+ error_messages.append(f"[red]There is no 'Zero' SETUP for {site_id} in {conf_data_location}[/]")
261
334
  else:
262
335
  verbose and rich.print(f":arrow_forward: Found the 'Zero' Setup file: SETUP_{site_id}_00000_*.yaml")
263
336
 
@@ -4,9 +4,7 @@ import rich
4
4
  import typer
5
5
 
6
6
  dev_x = typer.Typer(
7
- name="dev-x",
8
- help="device-x is an imaginary device that serves as an example",
9
- no_args_is_help=True
7
+ name="dev-x", help="device-x is an imaginary device that serves as an example", no_args_is_help=True
10
8
  )
11
9
 
12
10
 
@@ -26,7 +26,6 @@ class StatusApp(App):
26
26
 
27
27
 
28
28
  def get_log_cs_status():
29
-
30
29
  from egse.logger import send_request
31
30
 
32
31
  response = send_request("status")
@@ -36,9 +35,9 @@ def get_log_cs_status():
36
35
  f"""\
37
36
  Log Manager:
38
37
  Status: [green]active[/]
39
- Level [grey50](file)[/]: {response.get('file_logger_level')}
40
- Level [grey50](stdout)[/]: {response.get('stream_logger_level')}
41
- Log file location: {response.get('file_logger_location')}
38
+ Level [grey50](file)[/]: {response.get("file_logger_level")}
39
+ Level [grey50](stdout)[/]: {response.get("stream_logger_level")}
40
+ Log file location: {response.get("file_logger_location")}
42
41
  """
43
42
  )
44
43
  else:
@@ -48,14 +47,14 @@ def get_log_cs_status():
48
47
 
49
48
 
50
49
  def get_cm_cs_status():
51
-
52
50
  from egse.confman import get_status
51
+
53
52
  return Text.from_markup(get_status())
54
53
 
55
54
 
56
55
  def get_sm_cs_status():
57
-
58
56
  from egse.storage import get_status
57
+
59
58
  return Text.from_markup(get_status())
60
59
 
61
60
 
@@ -75,12 +74,14 @@ def main():
75
74
  installed in the Python environment you are running this tool from.
76
75
  """
77
76
  ),
78
- flush=True)
77
+ flush=True,
78
+ )
79
79
  print(exc)
80
80
  return
81
81
 
82
82
  app = StatusApp()
83
83
  app.run()
84
84
 
85
+
85
86
  if __name__ == "__main__":
86
87
  main()
File without changes
File without changes