Frage

def leopardRemoveWireless(networkName):
  plistPath = '/Library/Preferences/SystemConfiguration/preferences.plist'
  # Sanity checks for the plist
  if os.path.exists(plistPath):
    try:
      pl = NSMutableDictionary.dictionaryWithContentsOfFile_(plistPath)
    except:
      print 'Unable to parse file at path: %s' % plistPath
      sys.exit(1)
  else:
    print 'File does not exist at path: %s' % plistPath
    sys.exit(1)
  # Create a copy of the dictionary due to emuration
  copy = NSDictionary.dictionaryWithDictionary_(pl)
  # Iterate through network sets
  for Set in copy['Sets']:
    UserDefinedName = copy['Sets'][Set]['UserDefinedName']
    print 'Processing location: %s' % UserDefinedName

    for enX in copy['Sets'][Set]['Network']['Interface']:
      print 'Processing interface: %s' % enX
      # I think this will always be a single key but this works either way
      for key in copy['Sets'][Set]['Network']['Interface'][enX]:
        print 'Processing Service: %s' % key
        # Try to grab the PreferredNetworks key if any
        try:
          # Iterate through preferred network sets
          index = 0
          for PreferredNetwork in copy['Sets'][Set]['Network']['Interface'][enX][key]['PreferredNetworks']:
            SSID_STR = PreferredNetwork['SSID_STR']
            print 'Processing SSID: %s' % SSID_STR
            # If the preferred network matches our removal SSID
            if SSID_STR == networkName:
              print 'Found SSID %s to remove' % SSID_STR
              # Delete our in ram copy
              print 'Processing Set: %s' % Set
              print 'Processing enX: %s' % enX
              print 'Processing key: %s' % key
              del pl['Sets'][Set]['Network']['Interface'][enX][key]['PreferredNetworks'][index]
            index += 1
        except KeyError:
           print 'Skipping interface without PreferredNetworks'

I am editing a fairly complex (dictionary) plist and then writing the changes back to the file after I find a specific key value pair. The issue is that even though I am making a copy of the Property lists dictionary:

copy = NSDictionary.dictionaryWithDictionary_(pl)

It is giving me the standard "mutated while enumerated" error when I edit the original, just the loop keys as stand ins (notice the lack of quotes).

del pl['Sets'][Set]['Network']['Interface'][enX][key]['PreferredNetworks'][index]

Is my syntax somehow causing it to try and edit the pl dictionary rather then the copy? Here is the output:

... Processing Set: D5C0A0F4-613A-4121-B6AE-4CBA6E2635FF Processing enX: en1 Processing key: AirPort Traceback (most recent call last): File "/Users/tester/Desktop/wifiutil", line 1164, in sys.exit(main()) File "/Users/tester/Desktop/wifiutil", line 1135, in main removeWireless(osVersion,network) File "/Users/tester/Desktop/wifiutil", line 1051, in removeWireless leopardRemoveWireless(network)
File "/Users/tester/Desktop/wifiutil", line 528, in leopardRemoveWireless for PreferredNetwork in copy['Sets'][Set]['Network']['Interface'][enX][key]['PreferredNetworks']: File "/System/Library/Frameworks/Python.framework/Versions/2.5/Extras/lib/python/PyObjC/objc/_convenience.py", line 431, in enumeratorGenerator yield container_unwrap(anEnumerator.nextObject(), StopIteration) objc.error: NSGenericException - * Collection was mutated while being enumerated.

War es hilfreich?

Lösung

I believe that the issue is the nested nature of the dictionary. dictionaryWithDictionary_() doesn't do anything like a deep copy; all it does is create a new NSDictionary and copy the pointers for the values (it does copy the keys themselves, since that is the nature of NSDictionary).

This means that, although you have a new top-level which you can use for enumeration, the inner dictionaries and arrays are the exact same objects as are in the original.

Your last loop:

for PreferredNetwork in copy['Sets'][Set]['Network']['Interface'][enX][key]['PreferredNetworks']:

is enumerating one of those inner arrays, which you then try to mutate with a del statement:

del pl['Sets'][Set]['Network']['Interface'][enX][key]['PreferredNetworks'][index]

This wasn't copied; it is the same array object that you are using in the for, which causes an exception. You can test this by passing the two expressions to id().

You'll have to either do a full-depth copy of the original dictionary, or (probably better) take a copy of the last level before you enumerate it.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top