I have Python 3.11.9 on Windows 10 Pro. My virtual env is activated. I’m trying to get some system information on my own to practice Python. My mini program works but my main program does not.
But when I run this in my main program, which has some class definitions, and other code, here’s what I get. Here’s part of the function to get the same information.
def printdetail(options):
procname = str(inspect.stack()[0][3]) + ":"
t = platform.platform() # Returns string
print(f"OS: {t}")
t = platform.release() # Returns string.
t = platform.system() # Returns string.
t = platform.version() # Returns string.
Error in the debugger:
-> t = platform.platform() # Returns string
(Pdb) t = str(platform.platform())
*** AttributeError: 'str' object has no attribute 'platform'
(Pdb) p platform.platform()
*** AttributeError: 'str' object has no attribute 'platform'
(Pdb) p str(platform.platform())
*** AttributeError: 'str' object has no attribute 'platform'
Do you assign anything to the platform name anywhere? Do you modify frames, globals, locals or builtins anywhere? Do you fiddle with sys.modules anywhere? Any of these could explain the error.
I fixed it. For some reason if I do the import in the actual function, it works. Perhaps importing the module initializes a class instance variable which is needed.
That is very strange. This should not be an issue. I imported platform at the top of the script and get no such error. Seems like something else is at play.
Since the variable is declared in the global scope, this function will work:
def find_variable_definition(variable_name):
# Read the current module file and search for the variable assignment
with open(__file__, 'r') as file:
lines = file.readlines()
# Find the line number where the variable is defined
for i, line in enumerate(lines, 1):
# Strip whitespace and check if the line starts with the variable name
stripped_line = line.strip()
if stripped_line.startswith(f"{variable_name}"):
print(f"Variable '{variable_name}' is defined at line {i}: {line.strip()}")
return i, line.strip()
# If the variable is not found, inform the user
print(f"Variable '{variable_name}' not found.")
return None, None
# Test the function
a = 42
b = "Hello, world!"
find_variable_definition("a") # This will find the definition of 'a'
find_variable_definition("b") # This will find the definition of 'b'
Yes I do add a path to sys.path(). Here’s my full code that has the trouble. The filename is sysinfo2.py.
NOTE:
Pycharm is not used for this. I simply run the code in cmd.exe with python sysinfo2.py -summary. For debugging I use python -m pdb sysinfo2.py -summary
I pass in the variable options as a habit to functions. It is not actually used in the functions in this program.
r'''
Get hardware and OS info for Windows or Linux systems.
Created: 5/17/24
Install these: python -m pip install psutil py-cpuinfo wmi
"wmi" is only for windows systems. It does not work with Linux.
import inspect
procname = str(inspect.stack()[0][3]) + ":"
===Documentation for modules
psutil: https://pypi.org/project/psutil/
py-cupinfo: https://github.com/workhorsy/py-cpuinfo https://pypi.org/project/py-cpuinfo/
wmi: https://pypi.org/project/WMI/
'''
import inspect
import platform # Core Python library
import psutil
import cpuinfo
import wmi # For windows only, will not work on Linux.
import sys
# Add my personal utilities library.
sys.path.append(r"c:/users/USER/Pycharmprojects/ggutil2024") # Required to use ggutil
try:
from ggutil import * # Custom utils. Must go last.
except ImportError as e:
print('ERROR: could not import ggutil.',e)
sys.exit()
SUBVER=1
VER = "2024-11-07." + str(f"{SUBVER:02d}")
APPTITLE = "Show hardware and OS info."
#####################################################
# Classes
# Option variables go here.
class clsOptions: # Command line options
r'''
This holds all command line options.
.overwrite = set to True to overwrite error logs and output files during testing. Source is -overwrite option.
'''
def __init__(self):
r'''These are class variables we need to use
with initial values.'''
self.adminemail = 'foo@bar.com'
self.datetoday = getdate_YYYY_MM_DD() # Used with filenames.
self.debug = False # Should we delete inventory?
self.debugprint = False # True to show debug messages.
self.dirsep = os.sep
self.mydate = getdate_YYYY_MM_DD() # Used for filenames
self.mydatetime = getdatetime_fn() # For filenames.
self.overwrite = False # True to overwrite output files, for testing.
self.progpath = __file__
self.progdir = os.path.dirname(__file__)
self.starttime = 0
self.starttime_human = ''
self.summary = False
def __repr__(self):
r'''Usage: in debugger p(options)
Print boolean variables first, then strings, then lists.
'''
procname = str(inspect.stack()[0][3]) + ":"
s = f"{procname} This holds command line options.\n"
s = s + f"adminemail={self.adminemail}\n"
s = s + f"datetoday={self.datetoday}\n"
s = s + f"debug={self.debug}\n"
s = s + f"debugprint={self.debugprint}\n"
s = s + f"dirsep={self.dirsep}\n"
s = s + f"mydate={self.mydate}\n"
s = s + f"mydatetime={self.mydatetime}\n"
s = s + f"overwrite={self.overwrite}\n"
s = s + f"progpath={self.progpath}\n"
s = s + f"progdir={self.progdir}\n"
s = s + f"starttime={self.starttime}\n"
s = s + f"starttime_human={self.starttime_human}\n"
s = s + f"summary={self.summary}\n"
return s
def __str__(self):
r'''Used with print(options)'''
s = f"This is __str__\n"
__repr__(self)
return s
def __sizeof__(self):
return "The sizeof method no worky."
options = clsOptions()
options.starttime = time.time()
options.donedir = os.path.join(options.progdir, r'done')
options.logfn = os.path.join(options.progdir, r'log.txt')
#################################################
#################################################
def argparseit(options):
procname = str(inspect.stack()[0][3]) + ":"
errorflag = False
maxargpos = len(sys.argv)
for i in range(1,maxargpos):
myarg = sys.argv[i]
alist = myarg.split(':')
alist[0] = alist[0].upper()
if myarg[0]=='-':
if alist[0] == '-DEBUG':
options.debug = True
elif alist[0] == '-DETAIL':
options.summary = False
elif alist[0] == '-OVERWRITE':
options.overwrite = True
elif alist[0] == '-SUMMARY':
options.summary = True
elif alist[0] == '-V': # Print version info.
# print(f"{APPTITLE} v{VER}")
print(f"{MODULEVER}")
sys.exit()
else:
print(f"{procname} ERROR: Invalid arg %s" % (myarg))
errorflag = True
else:
print(f"{procname} ERROR: Looks like a bad argument: %s" % (myarg))
sys.exit()
if errorflag: # Done with argparseit()
print(f"{procname} Please fix errors and try again.")
sys.exit()
#################################################
def printdetail(options):
procname = str(inspect.stack()[0][3]) + ":"
import platform
import cpuinfo
import psutil
import wmi
t = platform.platform() # Returns string
print(f"OS: {t}")
# t = platform.release() # Returns string.
# t = platform.system() # Returns string.
# t = platform.version() # Returns string.
# Error below: AttributeError: 'str' object has no attribute 'node'. Did you mean: 'encode'?
print(f"Network name/Computer name:", platform.node())
print(f"Processor:", platform.processor()) # Returns string.
t = platform.machine() # Returns string or empty string. Ex: "AMD64"
# Get python version.
ver = sys.version
print(f"Python version: {ver}")
cpuinfo = cpuinfo.get_cpu_info() # Returns a dictionary
#print(cpuinfo.keys()) # To print keys.
print(f"Full CPU name: {cpuinfo['brand_raw']}")
print(f"CPU speed: {cpuinfo['hz_actual_friendly']}")
t = cpuinfo['hz_advertised_friendly']
print(f"CPU speed advertised: {t}")
print(f"Total RAM: {human_storage(psutil.virtual_memory().total)}")
d = cpuinfo['l2_cache_size'] / 1024
print(f"L2 cache: {d} MB")
flags = cpuinfo['flags'] # List of strings.
print(f"CPU flags: {flags}")
print("")
pc = wmi.WMI() # For Windows systems only.
# print(os_info.status)
# os_info = pc.Win32_OperatingSystem()[0] # Very detailed OS info.
# print(f"OS Info: {os_info}")
# print(f"wmi CPU info: {pc.Win32_Processor()[0]}")
# Get GPU/video card info
vcard = pc.Win32_VideoController()[0] # Do print(vcard)
print(f"Video Card: {pc.Win32_VideoController()[0].Name}")
print(f"Video Card Driver Version: {pc.Win32_VideoController()[0].DriverVersion}")
t = pc.Win32_VideoController()[0].AdapterRAM
if t < 0:
t = t * -1
t = human_storage(t)
print(f"Video Card VRAM: {t}")
vres = pc.Win32_VideoController()[0].CurrentVerticalResolution
hres = pc.Win32_VideoController()[0].CurrentHorizontalResolution
print(f"Video resolution: {hres} x {vres}")
#################################################
def printsummary(options):
procname = str(inspect.stack()[0][3]) + ":"
import platform
import cpuinfo
import psutil
import wmi
# print(f"Architecture: {platform.architecture()}")
print(f"Network name/Computer name: {platform.node()}")
print(f"OS: {platform.platform()}")
print(f"Processor: {platform.processor()}")
# t = platform.system()
# Get python version.
ver = sys.version
print(f"Python version: {ver}")
cpuinfo = cpuinfo.get_cpu_info() # Returns a dictionary
#print(cpuinfo.keys()) # To print keys.
print(f"Full CPU name: {cpuinfo['brand_raw']}")
print(f"CPU speed: {cpuinfo['hz_actual_friendly']}")
print(f"CPU speed advertised: {cpuinfo['hz_advertised_friendly']}")
print(f"Total RAM: {human_storage(psutil.virtual_memory().total)}")
print(f"CPU Architecture: {cpuinfo['arch']}")
print("")
pc = wmi.WMI() # For Windows systems only.
# print(os_info.status)
# os_info = pc.Win32_OperatingSystem()[0] # Very detailed OS info.
# print(f"OS Info: {os_info}")
# print(f"wmi CPU info: {pc.Win32_Processor()[0]}")
# Get GPU/video card info
vcard = pc.Win32_VideoController()[0] # Do print(vcard)
print(f"Video Card: {pc.Win32_VideoController()[0].Name}")
print(f"Video Card Driver Version: {pc.Win32_VideoController()[0].DriverVersion}")
vram = pc.Win32_VideoController()[0].AdapterRAM
tvram = vram
if vram < 0:
vram = vram * -1
vram = human_storage(vram)
print(f"Video Card VRAM: {vram} ({tvram})")
vres = pc.Win32_VideoController()[0].CurrentVerticalResolution
hres = pc.Win32_VideoController()[0].CurrentHorizontalResolution
print(f"Video resolution: {hres} x {vres}")
#################################################
#################################################
# Main program
helpstr = f'''Syntax: Python {sys.argv[0]} OK
{APPTITLE} v{VER}
To send output to a file do: python {sys.argv[0]} OK > myfile.txt
OPTIONS:
-detail: print detailed info about OS and hardware.
-summary: Print a summary of features, ignoring features most people don't want to see.
'''
if len(sys.argv)<=1:
print(helpstr) # Print help screen and exit.
sys.exit() # Exit program
print("\n=====================================")
print(f"{APPTITLE} v{VER}\n")
argparseit(options)
if options.summary:
printsummary(options)
else:
printdetail(options)
Problem solved. I thought that variable would be scoped to that ggutil.py file but it isn’t?
The ggutil.py is a single file with 60+ functions in it that I commonly use in my programs. Whenever I write a program I never know how many functions from ggutil.py I will use.
Apparently I do not understand all the issues of scoping yet. So if I do this import on my own utilities file called ggutil.py, all those import are scoped to the main program that imports ggutil.py? Or am I missing something?
When I write a new program I don’t know how many functions I will need in that single ggutil.py file. I may need 10 or 20 of them. There must be 60+ functions in that single .py file.