Recipe10.17.Gathering Detailed System Informationon Mac OS X


Recipe 10.17. Gathering Detailed System Informationon Mac OS X

Credit: Brian Quinlan

Problem

You want to retrieve detailed information about a Mac OS X system. You want either complete information about the system or information about particular keys in the system-information database.

Solution

Mac OS X's system_profiler command can provide system information as an XML stream that we can parse and examine:

#!/usr/bin/env python from xml import dom from xml.dom.xmlbuilder import DOMInputSource, DOMBuilder import datetime, time, os def group(seq, n):     """group([0, 3, 4, 10, 2, 3, 1], 3) => [(0, 3, 4), (10, 2, 3)]        Group a sequence into n-subseqs, discarding incomplete subseqs.     """     return [ seq[i:i+n] for i in xrange(0, len(seq)-n+1, n) ] def remove_whitespace_nodes(node):     """Removes all of the whitespace-only text descendants of a DOM node."""     remove_list = [  ]     for child in node.childNodes:         if child.nodeType == dom.Node.TEXT_NODE and not child.data.strip( ):             remove_list.append(child)         elif child.hasChildNodes( ):             remove_whitespace_nodes(child)     for child in remove_list:         node.removeChild(child)         child.unlink( ) class POpenInputSource(DOMInputSource):     "Use stdout from an external program as a DOMInputSource"     def _ _init_ _(self, command):         super(DOMInputSource, self)._ _init_ _( )         self.byteStream = os.popen(command) class OSXSystemProfiler(object):     "Provide information from the Mac OS X System Profiler"     def _ _init_ _(self, detail=-1):         """detail can range from -2 to +1.  Larger numbers return more info.            Beware of +1, can take many minutes to get all info!"""         b = DOMBuilder( )         self.document = b.parse(             POpenInputSource('system_profiler -xml -detailLevel %d' % detail))         remove_whitespace_nodes(self.document)     def _content(self, node):         "Get the text node content of an element, or an empty string"         if node.firstChild:             return node.firstChild.nodeValue         else:             return ''     def _convert_value_node(self, node):         """Convert a 'value' node (i.e. anything but 'key') into a Python data            structure"""         if node.tagName == 'string':             return self._content(node)         elif node.tagName == 'integer':             return int(self._content(node))         elif node.tagName == 'real':             return float(self._content(node))         elif node.tagName == 'date': #  <date>2004-07-05T13:29:29Z</date>             return datetime.datetime(                 *time.strptime(self._content(node), '%Y-%m-%dT%H:%M:%SZ')[:5])         elif node.tagName == 'array':             return [self._convert_value_node(n) for n in node.childNodes]         elif node.tagName == 'dict':             return dict([(self._content(n), self._convert_value_node(m))                           for n, m in group(node.childNodes, 2)])         else:             raise ValueError, 'Unknown tag %r' % node.tagName     def _ _getitem_ _(self, key):         from xml import xpath         # pyxml's xpath does not support /element1[...]/element2...         nodes = xpath.Evaluate('//dict[key=%r]' % key, self.document)         results = [  ]         for node in nodes:             v = self._convert_value_node(node)[key]             if isinstance(v, dict) and '_order' in v:                 # this is just information for display                 pass             else:                 results.append(v)         return results     def all(self):         """Return the complete information from the system profiler            as a Python data structure"""         return self._convert_value_node(             self.document.documentElement.firstChild) def main( ):     from optparse import OptionParser     from pprint import pprint     info = OSXSystemProfiler( )     parser = OptionParser( )     parser.add_option("-f", "--field", action="store", dest="field",                       help="display the value of the specified field")     options, args = parser.parse_args( )     if args:         parser.error("no arguments are allowed")     if options.field is not None:         pprint(info[options.field])     else:         # print some keys known to exist in only one important dict         for k in ['cpu_type', 'current_processor_speed', 'l2_cache_size',                   'physical_memory', 'user_name', 'os_version', 'ip_address']:             print '%s: %s' % (k, info[k][0]) if _ _name_ _ == '_ _main_ _':     main( )

Discussion

Mac OS X puts at your disposal a wealth of information about your system through the system_profiler application. This recipe shows how to access that information from your Python code. First, you have to instantiate class OSXSystemProfiler, for example, via a statement such as info = OSXSystemProfiler( ); once you have done that, you can obtain all available information by calling info.all( ), or information for one specific key by indexing info[thekey]. The main function in the recipe, which executes when you run this module as a main script, emits information to standard outputeither a specific key, requested by using switch -f when invoking the script, or, by default, a small set of keys known to be generally useful.

For example, when run on the old Apple iBook belonging to one of this book's editors (no prize for guessing which one), the script in this recipe emits the following output:

cpu_type: PowerPC G4  (3.3) current_processor_speed: 800 MHz l2_cache_size: 256 KB physical_memory: 640 MB user_name: Alex (alex) os_version: Mac OS X 10.3.6 (7R28) ip_address: [u'192.168.0.190']

system_profiler returns XML data in pinfo format, so this recipe implements a partial pinfo parser, using Python's standard library XML-parsing facilities, and the xpath implementation from the PyXML extensions. More information about Python's facilities that help you deal with XML can be found in Chapter 12.

See Also

Documentation of the standard Python library support for XML in the Library Reference and Python in a Nutshell; PyXML docs at http://pyxml.sourceforge.net/; Mac OS X system_profiler docs at http://developer.apple.com/documentation/Darwin/Reference/ManPages/man8/system_profiler.8.html; Chapter 12.



Python Cookbook
Python Cookbook
ISBN: 0596007973
EAN: 2147483647
Year: 2004
Pages: 420

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net