2011-07-10 18 views
0

我是Python的新手,並開始編寫我的第一個模塊,它將對外部存儲(通常是一個或多個USB磁盤)執行備份。Python:在try/except/else塊中引發異常,處理順序問題

的期望的行爲是:

  1. 檢查如果目的地(備份磁盤)已經安裝。 destination_was_mounted變成True或False
  2. 如果destination_was_mounted = False,則裝入目標。
  3. 如果mountDestination失敗,引發異常並重新啓動循環。
  4. 如果mountDestination正常,請檢查目標是否存在checkfile(和backup_dir)。
  5. 如果check_destination失敗引發異常並重新啓動循環。
  6. 繼續處理(尚未編碼此)。
  7. 在任何情況下,如果destination_was_mounted = False,則卸載目標。

問題是,如果check_destination部分引發異常,它將無法卸載目標,即使我已經在最後一節。就好像destination_was_mounted變成True,即使它應該是False。或者就好像check_destination在mount_destination之前運行,即使它在它之後。

我引用(除了解一下Python文檔和我的Python入門書):

Python: How to tell the for loop to continue from a function?

How to retry after exception in python?

How to get back to the for loop after exception handling

#!/usr/bin/env python3.1 

import sys 
import os 
import os.path 
import subprocess 
import configparser 
CONFIGFILE = 'backup.ini' 
# do i need this? 
config = {} 

config = configparser.ConfigParser() 
config.read(CONFIGFILE) 
backup_sources = sorted(config.sections()[1:]) 

class NoCheckFile(Exception): 
    pass 

def mountDestination(destination): 
    return subprocess.check_call(['mount', destination]) 

def unMountDestination(destination): 
    return subprocess.check_call(['umount', destination]) 

def checkDestination(destination, backup_dir, checkfile): 
    return os.path.exists(destination + '/' + backup_dir + '/' + checkfile) 

''' exception handlers ''' 
# perhaps add another arg like 0 or 1 for success/failure 
def handleCalledProcessError(ex): 
    print('Exception: ' + str(ex)) 

def handleNoCheckFile(ex): 
    print('Exception: ' + str(ex)) 

# rename me once I work out logging 
def logExecute(result): 
    print('Info: ' + str(result)) 
# can I pass logging output here 

def main(): 
    for section in backup_sources: 
     item = dict(config.items(section)) 
     destination = item['destination'] 
     destination_was_mounted = os.path.ismount(destination) 
     backup_dir = item['backup_dir'] 
     checkfile = item['checkfile'] 
     try: 
      ''' check destination_was_mounted and mount destination if required ''' 
      mount_destination = None 
      unmount_destination = None 
      if not destination_was_mounted: 
       mount_destination = mountDestination(destination) 

      ''' check that checkfile exists in backup_dir ''' 
      check_destination = checkDestination(destination, backup_dir, checkfile) 
      if not check_destination: 
       raise NoCheckFile('no checkfile found') 

      ''' lvm snapshot, mount and source path update ''' 

      ''' backup engine code here ''' 

      ''' check destination_was_mounted and um-mount destination if required ''' 
      if not destination_was_mounted: 
       unmount_destination = unMountDestination(destination) 
     except subprocess.CalledProcessError as ex: 
      print(destination, 'mounted before loop start: ', destination_was_mounted) 
      handleCalledProcessError(ex) 
     except NoCheckFile as ex: 
      handleNoCheckFile(ex) 
     else: 
      print(destination, 'mounted before loop start: ', destination_was_mounted) 
      logExecute(mount_destination) 
      logExecute(check_destination) 
     finally: 
      print('should always see me') 
      logExecute(unmount_destination) 
      # return to say True or False 

    # this should be where email reports etc. go 

if __name__ == '__main__': 
    main() 

的backup.ini的相關部分文件是:

[general] 

[1] 
DESTINATION = /mnt/backup2 
BACKUP_DIR = BACKUP2 
CHECKFILE = .checkfile 

[2] 
DESTINATION = /mnt/backup1 
BACKUP_DIR = BACKUP1 
CHECKFILE = .checkfile 

輸出看起來像這樣 - 我在[1]和[2]中指定的掛載點處附加了2個備份磁盤,並且故意沒有爲[1]創建檢查文件來測試。

> umount /mnt/backup1 
umount: /mnt/backup1: not mounted 
> umount /mnt/backup2 
umount: /mnt/backup2: not mounted 
> mugsyback.py 
Exception: no checkfile found 
should always see me 
Info: None 
/mnt/backup1 mounted before loop start: False 
Info: 0 
Info: True 
should always see me 
Info: 0 
> mount 
... 
/dev/sdc1 on /mnt/backup2 type ext3 (rw) 
+2

你可以壓縮你的問題嗎?我完全失去了...... – Blender

+0

「並重新啓動循環」...爲什麼?如果第一次無法正常工作,你爲什麼會期待它再次工作? –

+0

@eryksun,感謝您的澄清,是的,這就是我的意思。 – jelloir

回答

0

您在try塊中有卸載代碼。最後,你只是在登錄。

+0

謝謝,這是正確的,並將卸載代碼移到最後:。我還添加了一個打印「除了NoCheckFile作爲前例:」這幫助我遵循該過程並將logExecute函數重命名爲logInfo。從我正在閱讀的內容中,我對try:部分是如何執行和想到其他方面感到困惑:在除了新手之外的錯誤之後,對象仍然被調用。 – jelloir