Skip to content

Commit 81eece1

Browse files
Click fixes, Windows support, README and docs
- CPULoadGenerator: BadOptionUsage(message=, option_name=), _ctx/_param in validators, typing.cast for entry point; docstrings include Windows; --plot help mentions PNG - README: supported platforms (Linux, macOS, Windows), plot/PNG note - Remove README.rst (replaced by README.md) Made-with: Cursor
1 parent 02bec1d commit 81eece1

3 files changed

Lines changed: 22 additions & 97 deletions

File tree

CPULoadGenerator.py

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import multiprocessing
88
import os
99
import signal
10+
from typing import cast, Callable
1011

1112
import click
1213
import psutil
@@ -18,7 +19,7 @@
1819

1920

2021
def _available_cores():
21-
"""Return list of available CPU core indices. Works on Linux, macOS, Windows."""
22+
"""Return list of available CPU core indices. Works on Linux, macOS, and Windows."""
2223
try:
2324
p = psutil.Process(os.getpid())
2425
return list(p.cpu_affinity())
@@ -97,28 +98,29 @@ def load_core(target_core, target_load,
9798
control.join()
9899

99100

100-
def __validate_cpu_load(ctx, param, value):
101+
def __validate_cpu_load(_ctx, _param, value):
101102
for v in value:
102103
if not 0. <= v <= 1.:
103-
raise click.BadOptionUsage(f'CPU load {v} out of range [0, 1]')
104+
msg = f'CPU load {v} out of range [0, 1]'
105+
raise click.BadOptionUsage(message=msg, option_name='cpu_load')
104106
return value
105107

106108

107-
def __validate_cpu_core(ctx, param, value):
109+
def __validate_cpu_core(_ctx, _param, value):
108110
available_cores = _available_cores()
109111

110112
for v in value:
111113
if v not in available_cores:
112-
raise click.BadOptionUsage(
113-
f'Target core ({v}) is not one of the available cores: '
114-
f'{available_cores}')
114+
msg = (f'Target core ({v}) is not one of the available cores: '
115+
f'{available_cores}')
116+
raise click.BadOptionUsage(message=msg, option_name='core')
115117
return value
116118

117119

118-
def __validate_sampling_interval(ctx, param, value):
120+
def __validate_sampling_interval(_ctx, _param, value):
119121
if value < 0:
120-
raise click.BadOptionUsage(
121-
f'Sampling interval cannot be negative ({value}).')
122+
msg = f'Sampling interval cannot be negative ({value}).'
123+
raise click.BadOptionUsage(message=msg, option_name='sampling_interval')
122124
return value
123125

124126

@@ -143,21 +145,23 @@ def __validate_sampling_interval(ctx, param, value):
143145
'program will run until a SIGINT or SIGTERM is received.')
144146
@click.option('--plot', '-p',
145147
is_flag=True, default=False, show_default=True,
146-
help='Plot the resulting CPU load. '
148+
help='Plot the resulting CPU load (and save a PNG at the end). '
147149
'Can only be used with a fixed duration.')
148150
@click.option('--sampling_interval', '-s',
149151
type=float, default=0.1, show_default=True,
150152
help='Sampling interval, in seconds, '
151153
'for the internal PI controller. '
152154
'Changing this value is strongly discouraged!',
153155
callback=__validate_sampling_interval)
156+
154157
def __main(core, cpu_load, duration, plot, sampling_interval):
155158
if plot and duration < 0:
156-
raise click.BadOptionUsage(
157-
'Plot option can only be used with a fixed duration.')
159+
msg = 'Plot option can only be used with a fixed duration.'
160+
raise click.BadOptionUsage(message=msg, option_name='plot')
158161

159162
if len(cpu_load) > 1 and len(cpu_load) != len(core):
160-
raise click.BadOptionUsage('Number of cores and loads does not match.')
163+
msg = 'Number of cores and loads does not match.'
164+
raise click.BadOptionUsage(message=msg, option_name='cpu_load')
161165
elif len(cpu_load) == 1:
162166
cpu_load = itertools.repeat(cpu_load[0], len(core))
163167

@@ -169,7 +173,7 @@ def __main(core, cpu_load, duration, plot, sampling_interval):
169173
print('Plot disabled when using multiple cores (use -c 0 for single-core plot).')
170174
plot = False
171175

172-
# Single core + plot: run in main process so the live plot window works (e.g. on macOS)
176+
# Single core + plot: run in main process so the live plot window works
173177
if len(core) == 1 and plot:
174178
load_core(core[0], next(cpu_load), duration, plot, sampling_interval)
175179
return
@@ -190,4 +194,4 @@ def __main(core, cpu_load, duration, plot, sampling_interval):
190194

191195

192196
if __name__ == '__main__':
193-
__main()
197+
cast(Callable[[], None], __main)()

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ This script generates a fixed CPU load for a finite or indefinite time period, o
88

99
You provide the desired CPU load and the CPU core(s) to load. The controller and the CPU monitor run in separate threads.
1010

11+
**Supported platforms:** Linux, macOS, and Windows (Windows is less tested; `psutil` supports CPU affinity on all three).
12+
1113
## Theoretical insight
1214

1315
- **Project homepage:** [https://gaetanocarlucci.github.io/CPULoadGenerator/](https://gaetanocarlucci.github.io/CPULoadGenerator/) — more details on the tool.

README.rst

Lines changed: 0 additions & 81 deletions
This file was deleted.

0 commit comments

Comments
 (0)