I have a script that works fine when in a .pyw, but when converted to an .exe, (EDIT: actually, when I use pyinstaller with the arguments -w
or --windowed
or --noconsole
it doesn't work, but without them it works) I've found that this one single line seems to crash the program:
firstplan = subprocess.check_output(["powercfg", "-list"], shell=True ).split('\n')[3]
Does anybody have any idea why? If I comment it out the program doesn't crash. I have two other very similar lines.
EDIT:
Maybe it'd be a good idea to put the script here...
from __future__ import print_function
import os
# os.system('cls')
import psutil
import subprocess
loop = 1
while loop == (1):
CPUload = (psutil.cpu_percent(interval=4)) # CPU load
RAMload = (psutil.virtual_memory().percent) # RAM load
# os.system('cls')
print("CPU Load: ", end="") # Display CPU Load:
print(CPUload, "%") # Display CPUload
print("RAM Load: ", end="") # Display CPU Load:
print(str(RAMload) + " %") # Display RAMload
firstplan = subprocess.check_output(["powercfg", "-list"], shell=True ).split('\n')[3] # Selects a line
secondplan = subprocess.check_output(["powercfg", "-list"], shell=True ).split('\n')[4]
thirdplan = subprocess.check_output(["powercfg", "-list"], shell=True ).split('\n')[5]
firstplanID = ((firstplan.split(": "))[1].split(" (")[0]) # Extract XplanID from Xplan
secondplanID = ((secondplan.split(": "))[1].split(" (")[0])
thirdplanID = ((thirdplan.split(": "))[1].split(" (")[0])
activeplan = subprocess.check_output(["powercfg", "/getactivescheme"]) # Find the currently active plan
activeplanNAME = ((activeplan.split("("))[1].split(")")[0]) # Extract activeplanNAME from activeplan
firstplanNAME = ((firstplan.split("("))[1].split(")")[0]) # Extract XplanNAME from Xplan
secondplanNAME = ((secondplan.split("("))[1].split(")")[0])
thirdplanNAME = ((thirdplan.split("("))[1].split(")")[0])
if "High performance" in firstplanNAME: # Identify which plan is High performance
HighPerformance = firstplanNAME
HighPerformanceID = firstplanID
if "High performance" in secondplanNAME:
HighPerformance = secondplanNAME
HighPerformanceID = secondplanID
if "High performance" in thirdplanNAME:
HighPerformance = thirdplanNAME
HighPerformanceID = thirdplanID
if "Power saver" in firstplanNAME: # Identify which plan is Power saver
PowerSaver = firstplanNAME
PowerSaverID = firstplanID
if "Power saver" in secondplanNAME:
PowerSaver = secondplanNAME
PowerSaverID = secondplanID
if "Power saver" in thirdplanNAME:
PowerSaver = thirdplanNAME
PowerSaverID = thirdplanID
if activeplanNAME == PowerSaver: # Checks current plan name
print("Active plan: Power saver")
else:
if activeplanNAME == HighPerformance:
print("Active plan: High Performance")
else:
subprocess.check_output(["powercfg", "/s", HighPerformanceID])
if CPUload < 44:
if RAMload > 90:
if activeplanNAME == PowerSaver:
subprocess.check_output(["powercfg", "/s", HighPerformanceID])
print("Switching to High Performance by RAM load...")
if CPUload < 44:
if RAMload < 90:
if activeplanNAME == HighPerformance:
subprocess.check_output(["powercfg", "/s", PowerSaverID])
print("Switching to Power saver...")
if CPUload > 55:
if activeplanNAME == PowerSaver:
subprocess.check_output(["powercfg", "/s", HighPerformanceID])
print("Switching to High Performance...")
The troubled lines are lines 21-23.
For further info, scroll down to comments and answers.
I'm not sure if this will solve your problem, but here is a refactoring which addresses the problems which were pointed out in comments, as well as some other issues with your code.
shell=True
/list
over -list
for consistency and possibly correctness.I have removed your comments and inlined comments of mine explaining what exactly was changed.
# Only necessary in Python 2, you really should be using Python 3 now
#from __future__ import print_function
# Only used in os.system('cls') which was commented out (for good reasons I presume)
#import os
import psutil
import subprocess
from time import sleep # see below
# Simply loop forever; break when done
while True:
# Remove gratuitous parentheses
CPUload = psutil.cpu_percent(interval=4)
RAMload = psutil.virtual_memory().percent
# Use .format() to inline a string
print("CPU Load: {}%".format(CPUload)))
print("RAM Load: {}%".format(RAMload))
# Only run subprocess once; use /list pro -list; don't use shell=True
pcfg = subprocess.check_output(["powercfg", "/list"], shell=False).split('\n')
# Additional refactoring below ########
firstplan = pcfg[3]
secondplan = pcfg[4]
thirdplan = pcfg[5]
# Get rid of wacky parentheses
firstplanID = firstplan.split(": ")[1].split(" (")[0]
secondplanID = secondplan.split(": ")[1].split(" (")[0]
thirdplanID = thirdplan.split(": ")[1].split(" (")[0]
activeplan = subprocess.check_output(["powercfg", "/getactivescheme"])
# Get rid of wacky parentheses
activeplanNAME = activeplan.split("(")[1].split(")")[0]
firstplanNAME = firstplan.split("(")[1].split(")")[0]
secondplanNAME = secondplan.split("(")[1].split(")")[0]
thirdplanNAME = thirdplan.split("(")[1].split(")")[0]
if "High performance" in firstplanNAME:
HighPerformance = firstplanNAME
HighPerformanceID = firstplanID
if "High performance" in secondplanNAME:
HighPerformance = secondplanNAME
HighPerformanceID = secondplanID
if "High performance" in thirdplanNAME:
HighPerformance = thirdplanNAME
HighPerformanceID = thirdplanID
if "Power saver" in firstplanNAME:
PowerSaver = firstplanNAME
PowerSaverID = firstplanID
if "Power saver" in secondplanNAME:
PowerSaver = secondplanNAME
PowerSaverID = secondplanID
if "Power saver" in thirdplanNAME:
PowerSaver = thirdplanNAME
PowerSaverID = thirdplanID
# Additional refactoring ends
if activeplanNAME == PowerSaver:
print("Active plan: Power saver")
# prefer if / elif / else over nested if
elif activeplanNAME == HighPerformance:
print("Active plan: High Performance")
else:
# What's this supposed to do? You are capturing, then discarding the output.
# Perhaps you are looking for subprocess.check_call()?
subprocess.check_output(["powercfg", "/s", HighPerformanceID])
if CPUload < 44:
# Combine conditions rather than nesting conditionals
if RAMload > 90 and activeplanNAME == PowerSaver:
# subprocess.check_call() here too?
subprocess.check_output(["powercfg", "/s", HighPerformanceID])
print("Switching to High Performance by RAM load...")
# Don't check if CPUload < 44: again
# Instead, just stay within this indented block
# Combine conditions
elif RAMload < 90 and activeplanNAME == HighPerformance:
# subprocess.check_call() here too?
subprocess.check_output(["powercfg", "/s", PowerSaverID])
print("Switching to Power saver...")
# What if RAMload == 90?
# Combine conditions
if CPUload > 55 and activeplanNAME == PowerSaver:
# subprocess.check_call() here too?
subprocess.check_output(["powercfg", "/s", HighPerformanceID])
print("Switching to High Performance...")
# Maybe sleep between iterations?
#sleep(1)
The script currently runs a rather tight loop, you might want to uncomment the last line.
There is still a lot of repetitive code. You might want to consider further refactoring to collect the three plans into an array where each object is a dict with member names identifying different properties you have extracted.
# Additional refactoring below ########
activeplan = subprocess.check_output(["powercfg", "/getactivescheme"])
activeplanNAME = activeplan.split("(")[1].split(")")[0]
plan = []
for idx in range(3):
raw = pcfg[3+idx]
thisplan = {'raw': raw}
thisplan['id'] = raw.split(": ")[1].split(" (")[0]
thisplan['name'] = raw.split("(")[1].split(")")[0]
if "High performance" in thisplan['name']:
HighPerformance = thisplan['name']
HighPerformanceID = thisplan['id']
if "Power saver" in thisplan['name']:
PowerSaver = thisplan['name']
PowerSaverID = thisplan['id']
plan[idx] = thisplan
Now you could actually change the HighPerformance
and PowerSaver
variables to just remember the idx
and then if you want to, you can pull out the name from the list of dicts with plan[PowerSaverIdx]['name']
and ID with plan[PowerSaverIdx]['id']
.