comparison python/storage.py @ 708:a37c565f4b68

merged dev
author Nicolas Saunier <nicolas.saunier@polymtl.ca>
date Wed, 22 Jul 2015 14:17:44 -0400
parents f83d125d0c55
children 523eda2fafd4
comparison
equal deleted inserted replaced
707:7efa36b9bcfd 708:a37c565f4b68
4 4
5 import utils, moving, events, indicators 5 import utils, moving, events, indicators
6 from base import VideoFilenameAddable 6 from base import VideoFilenameAddable
7 7
8 import sqlite3, logging 8 import sqlite3, logging
9 from numpy import log, min as npmin, max as npmax, round as npround, array, sum as npsum, loadtxt
9 10
10 11
11 commentChar = '#' 12 commentChar = '#'
12 13
13 delimiterChar = '%'; 14 delimiterChar = '%';
287 matched_indexes.append((row[0],row[1])) 288 matched_indexes.append((row[0],row[1]))
288 289
289 connection.close() 290 connection.close()
290 return matched_indexes 291 return matched_indexes
291 292
292 def getTrajectoryIdQuery(objectNumbers, trajectoryType): 293 def getObjectCriteria(objectNumbers):
293 if trajectoryType == 'feature':
294 statementBeginning = 'where trajectory_id '
295 elif trajectoryType == 'object':
296 statementBeginning = 'and OF.object_id '
297 elif trajectoryType == 'bbtop' or 'bbbottom':
298 statementBeginning = 'where object_id '
299 else:
300 print('no trajectory type was chosen')
301
302 if objectNumbers is None: 294 if objectNumbers is None:
303 query = '' 295 query = ''
304 elif type(objectNumbers) == int: 296 elif type(objectNumbers) == int:
305 query = statementBeginning+'between 0 and {0} '.format(objectNumbers) 297 query = 'between 0 and {0}'.format(objectNumbers-1)
306 elif type(objectNumbers) == list: 298 elif type(objectNumbers) == list:
307 query = statementBeginning+'in ('+', '.join([str(n) for n in objectNumbers])+') ' 299 query = 'in ('+', '.join([str(n) for n in objectNumbers])+')'
300 else:
301 print('objectNumbers {} are not a known type ({})'.format(objectNumbers, type(objectNumbers)))
302 query = ''
308 return query 303 return query
309 304
310 def loadTrajectoriesFromTable(connection, tableName, trajectoryType, objectNumbers = None): 305 def loadTrajectoriesFromTable(connection, tableName, trajectoryType, objectNumbers = None):
311 '''Loads trajectories (in the general sense) from the given table 306 '''Loads trajectories (in the general sense) from the given table
312 can be positions or velocities 307 can be positions or velocities
313 308
314 returns a moving object''' 309 returns a moving object'''
315 cursor = connection.cursor() 310 cursor = connection.cursor()
316 311
317 try: 312 try:
318 idQuery = getTrajectoryIdQuery(objectNumbers, trajectoryType) 313 objectCriteria = getObjectCriteria(objectNumbers)
319 if trajectoryType == 'feature': 314 if trajectoryType == 'feature':
320 queryStatement = 'SELECT * from '+tableName+' '+idQuery+'ORDER BY trajectory_id, frame_number' 315 queryStatement = 'SELECT * from '+tableName
316 if objectNumbers is not None:
317 queryStatement += ' where trajectory_id '+objectCriteria
318 queryStatement += ' ORDER BY trajectory_id, frame_number'
321 cursor.execute(queryStatement) 319 cursor.execute(queryStatement)
322 logging.debug(queryStatement) 320 logging.debug(queryStatement)
323 elif trajectoryType == 'object': 321 elif trajectoryType == 'object':
324 queryStatement = 'SELECT OF.object_id, P.frame_number, avg(P.x_coordinate), avg(P.y_coordinate) from '+tableName+' P, objects_features OF where P.trajectory_id = OF.trajectory_id '+idQuery+'group by OF.object_id, P.frame_number ORDER BY OF.object_id, P.frame_number' 322 queryStatement = 'SELECT OF.object_id, P.frame_number, avg(P.x_coordinate), avg(P.y_coordinate) from '+tableName+' P, objects_features OF where P.trajectory_id = OF.trajectory_id'
323 if objectNumbers is not None:
324 queryStatement += ' and OF.object_id '+objectCriteria
325 queryStatement += ' group by OF.object_id, P.frame_number ORDER BY OF.object_id, P.frame_number'
325 cursor.execute(queryStatement) 326 cursor.execute(queryStatement)
326 logging.debug(queryStatement) 327 logging.debug(queryStatement)
327 elif trajectoryType in ['bbtop', 'bbbottom']: 328 elif trajectoryType in ['bbtop', 'bbbottom']:
328 if trajectoryType == 'bbtop': 329 if trajectoryType == 'bbtop':
329 corner = 'top_left' 330 corner = 'top_left'
330 elif trajectoryType == 'bbbottom': 331 elif trajectoryType == 'bbbottom':
331 corner = 'bottom_right' 332 corner = 'bottom_right'
332 queryStatement = 'SELECT object_id, frame_number, x_'+corner+', y_'+corner+' FROM '+tableName+' '+idQuery+'ORDER BY object_id, frame_number' 333 queryStatement = 'SELECT object_id, frame_number, x_'+corner+', y_'+corner+' FROM '+tableName
334 if objectNumbers is not None:
335 queryStatement += ' where object_id '+objectCriteria
336 queryStatement += ' ORDER BY object_id, frame_number'
333 cursor.execute(queryStatement) 337 cursor.execute(queryStatement)
334 logging.debug(queryStatement) 338 logging.debug(queryStatement)
335 else: 339 else:
336 print('no trajectory type was chosen') 340 print('no trajectory type was chosen')
337 except sqlite3.OperationalError as error: 341 except sqlite3.OperationalError as error:
359 print('Object {} is missing {} positions'.format(obj.getNum(), int(obj.length())-obj.positions.length())) 363 print('Object {} is missing {} positions'.format(obj.getNum(), int(obj.length())-obj.positions.length()))
360 364
361 return objects 365 return objects
362 366
363 def loadUserTypesFromTable(cursor, trajectoryType, objectNumbers): 367 def loadUserTypesFromTable(cursor, trajectoryType, objectNumbers):
364 objectIdQuery = getTrajectoryIdQuery(objectNumbers, trajectoryType) 368 objectCriteria = getObjectCriteria(objectNumbers)
365 if objectIdQuery == '': 369 queryStatement = 'SELECT object_id, road_user_type from objects'
366 cursor.execute('SELECT object_id, road_user_type from objects') 370 if objectNumbers is not None:
367 else: 371 queryStatement += ' where object_id '+objectCriteria
368 cursor.execute('SELECT object_id, road_user_type from objects where '+objectIdQuery[7:]) 372 cursor.execute(queryStatement)
369 userTypes = {} 373 userTypes = {}
370 for row in cursor: 374 for row in cursor:
371 userTypes[row[0]] = row[1] 375 userTypes[row[0]] = row[1]
372 return userTypes 376 return userTypes
373 377
374 def loadTrajectoriesFromSqlite(filename, trajectoryType, objectNumbers = None): 378 def loadTrajectoriesFromSqlite(filename, trajectoryType, objectNumbers = None, withFeatures = False):
375 '''Loads the first objectNumbers objects or the indices in objectNumbers from the database''' 379 '''Loads the first objectNumbers objects or the indices in objectNumbers from the database'''
376 connection = sqlite3.connect(filename) 380 connection = sqlite3.connect(filename)
377 381
378 objects = loadTrajectoriesFromTable(connection, 'positions', trajectoryType, objectNumbers) 382 objects = loadTrajectoriesFromTable(connection, 'positions', trajectoryType, objectNumbers)
379 objectVelocities = loadTrajectoriesFromTable(connection, 'velocities', trajectoryType, objectNumbers) 383 objectVelocities = loadTrajectoriesFromTable(connection, 'velocities', trajectoryType, objectNumbers)
388 392
389 if trajectoryType == 'object': 393 if trajectoryType == 'object':
390 cursor = connection.cursor() 394 cursor = connection.cursor()
391 try: 395 try:
392 # attribute feature numbers to objects 396 # attribute feature numbers to objects
393 objectIdQuery = getTrajectoryIdQuery(objectNumbers, trajectoryType) 397 objectCriteria = getObjectCriteria(objectNumbers)
394 queryStatement = 'SELECT P.trajectory_id, OF.object_id from positions P, objects_features OF where P.trajectory_id = OF.trajectory_id '+objectIdQuery+'group by P.trajectory_id order by OF.object_id' # order is important to group all features per object 398 queryStatement = 'SELECT P.trajectory_id, OF.object_id from positions P, objects_features OF where P.trajectory_id = OF.trajectory_id'
399 if objectNumbers is not None:
400 queryStatement += ' and OF.object_id '+objectCriteria
401 queryStatement += ' group by P.trajectory_id order by OF.object_id' # order is important to group all features per object
395 cursor.execute(queryStatement) 402 cursor.execute(queryStatement)
396 logging.debug(queryStatement) 403 logging.debug(queryStatement)
397 404
398 featureNumbers = {} 405 featureNumbers = {}
399 for row in cursor: 406 for row in cursor:
408 415
409 # load userType 416 # load userType
410 userTypes = loadUserTypesFromTable(cursor, trajectoryType, objectNumbers) 417 userTypes = loadUserTypesFromTable(cursor, trajectoryType, objectNumbers)
411 for obj in objects: 418 for obj in objects:
412 obj.userType = userTypes[obj.getNum()] 419 obj.userType = userTypes[obj.getNum()]
420
421 if withFeatures:
422 nFeatures = 0
423 for obj in objects:
424 nFeatures = max(nFeatures, max(obj.featureNumbers))
425 features = loadTrajectoriesFromSqlite(filename, 'feature', nFeatures+1)
426 for obj in objects:
427 obj.setFeatures(features)
413 428
414 except sqlite3.OperationalError as error: 429 except sqlite3.OperationalError as error:
415 printDBError(error) 430 printDBError(error)
416 objects = [] 431 objects = []
417 432
510 TODO choose the interactions to load''' 525 TODO choose the interactions to load'''
511 interactions = [] 526 interactions = []
512 connection = sqlite3.connect(filename) 527 connection = sqlite3.connect(filename)
513 cursor = connection.cursor() 528 cursor = connection.cursor()
514 try: 529 try:
515 cursor.execute('select INT.id, INT.object_id1, INT.object_id2, INT.first_frame_number, INT.last_frame_number, IND.indicator_type, IND.frame_number, IND.value from interactions INT, indicators IND where INT.id = IND.interaction_id ORDER BY INT.id, IND.indicator_type') 530 cursor.execute('select INT.id, INT.object_id1, INT.object_id2, INT.first_frame_number, INT.last_frame_number, IND.indicator_type, IND.frame_number, IND.value from interactions INT, indicators IND where INT.id = IND.interaction_id ORDER BY INT.id, IND.indicator_type, IND.frame_number')
516 interactionNum = -1 531 interactionNum = -1
517 indicatorTypeNum = -1 532 indicatorTypeNum = -1
518 tmpIndicators = {} 533 tmpIndicators = {}
519 for row in cursor: 534 for row in cursor:
520 if row[0] != interactionNum: 535 if row[0] != interactionNum:
521 interactionNum = row[0] 536 interactionNum = row[0]
522 interactions.append(events.Interaction(interactionNum, moving.TimeInterval(row[3],row[4]), row[1], row[2])) 537 interactions.append(events.Interaction(interactionNum, moving.TimeInterval(row[3],row[4]), row[1], row[2]))
523 interactions[-1].indicators = {} 538 interactions[-1].indicators = {}
524 if indicatorTypeNum != row[5]: 539 if indicatorTypeNum != row[5] or row[0] != interactionNum:
540 indicatorTypeNum = row[5]
525 indicatorName = events.Interaction.indicatorNames[indicatorTypeNum] 541 indicatorName = events.Interaction.indicatorNames[indicatorTypeNum]
526 indicatorValues = {row[6]:row[7]} 542 indicatorValues = {row[6]:row[7]}
527 interactions[-1].indicators[indicatorName] = indicators.SeverityIndicator(indicatorName, indicatorValues) 543 interactions[-1].indicators[indicatorName] = indicators.SeverityIndicator(indicatorName, indicatorValues, mostSevereIsMax = not indicatorName in events.Interaction.timeIndicators)
528 indicatorTypeNum = row[5]
529 else: 544 else:
530 indicatorValues[row[6]] = row[7] 545 indicatorValues[row[6]] = row[7]
546 interactions[-1].indicators[indicatorName].timeInterval.last = row[6]
531 except sqlite3.OperationalError as error: 547 except sqlite3.OperationalError as error:
532 printDBError(error) 548 printDBError(error)
533 return [] 549 return []
534 connection.close() 550 connection.close()
535 return interactions 551 return interactions
654 Assumed to be sorted over time''' 670 Assumed to be sorted over time'''
655 objects = {} # dictionary of objects index by their id 671 objects = {} # dictionary of objects index by their id
656 672
657 if usePandas: 673 if usePandas:
658 from pandas import read_csv 674 from pandas import read_csv
659 from numpy import min, max, round
660 data = read_csv(filename, delimiter=';', comment='*', header=0, skiprows = 1) 675 data = read_csv(filename, delimiter=';', comment='*', header=0, skiprows = 1)
661 generatePDLaneColumn(data) 676 generatePDLaneColumn(data)
662 data['TIME'] = data['$VEHICLE:SIMSEC']*simulationStepsPerTimeUnit 677 data['TIME'] = data['$VEHICLE:SIMSEC']*simulationStepsPerTimeUnit
663 if warmUpLastInstant is not None: 678 if warmUpLastInstant is not None:
664 data = data[data['TIME']>=warmUpLastInstant] 679 data = data[data['TIME']>=warmUpLastInstant]
665 grouped = data.loc[:,['NO','TIME']].groupby(['NO'], as_index = False) 680 grouped = data.loc[:,['NO','TIME']].groupby(['NO'], as_index = False)
666 instants = grouped['TIME'].agg({'first': min, 'last': max}) 681 instants = grouped['TIME'].agg({'first': npmin, 'last': npmax})
667 for row_index, row in instants.iterrows(): 682 for row_index, row in instants.iterrows():
668 objNum = int(row['NO']) 683 objNum = int(row['NO'])
669 tmp = data[data['NO'] == objNum] 684 tmp = data[data['NO'] == objNum]
670 objects[objNum] = moving.MovingObject(num = objNum, timeInterval = moving.TimeInterval(row['first'], row['last'])) 685 objects[objNum] = moving.MovingObject(num = objNum, timeInterval = moving.TimeInterval(row['first'], row['last']))
671 # positions should be rounded to nDecimals decimals only 686 # positions should be rounded to nDecimals decimals only
672 objects[objNum].curvilinearPositions = moving.CurvilinearTrajectory(S = round(tmp['POS'].tolist(), nDecimals), Y = round(tmp['POSLAT'].tolist(), nDecimals), lanes = tmp['LANE'].tolist()) 687 objects[objNum].curvilinearPositions = moving.CurvilinearTrajectory(S = npround(tmp['POS'].tolist(), nDecimals), Y = npround(tmp['POSLAT'].tolist(), nDecimals), lanes = tmp['LANE'].tolist())
688 if nObjects > 0 and len(objects) >= nObjects:
689 break
673 return objects.values() 690 return objects.values()
674 else: 691 else:
675 inputfile = openCheck(filename, quitting = True) 692 inputfile = openCheck(filename, quitting = True)
676 # data = pd.read_csv(filename, skiprows=15, delimiter=';') 693 # data = pd.read_csv(filename, skiprows=15, delimiter=';')
677 # skip header: 15 lines + 1 694 # skip header: 15 lines + 1
716 Vehicles are considered finally stationary 733 Vehicles are considered finally stationary
717 if more than proportionStationaryTime of their total time 734 if more than proportionStationaryTime of their total time
718 If lanes is not None, only the data for the selected lanes will be provided 735 If lanes is not None, only the data for the selected lanes will be provided
719 (format as string x_y where x is link index and y is lane index)''' 736 (format as string x_y where x is link index and y is lane index)'''
720 from pandas import read_csv 737 from pandas import read_csv
721 from numpy import array, sum as npsum
722 columns = ['NO', '$VEHICLE:SIMSEC', 'POS'] 738 columns = ['NO', '$VEHICLE:SIMSEC', 'POS']
723 if lanes is not None: 739 if lanes is not None:
724 columns += ['LANE\LINK\NO', 'LANE\INDEX'] 740 columns += ['LANE\LINK\NO', 'LANE\INDEX']
725 data = read_csv(filename, delimiter=';', comment='*', header=0, skiprows = 1, usecols = columns) 741 data = read_csv(filename, delimiter=';', comment='*', header=0, skiprows = 1, usecols = columns)
726 data = selectPDLanes(data, lanes) 742 data = selectPDLanes(data, lanes)
727 data.sort(['$VEHICLE:SIMSEC'], inplace = True) 743 data.sort(['$VEHICLE:SIMSEC'], inplace = True)
728 744
729 nStationary = 0 745 nStationary = 0
730 from matplotlib.pyplot import plot, figure
731 nVehicles = 0 746 nVehicles = 0
732 for name, group in data.groupby(['NO'], sort = False): 747 for name, group in data.groupby(['NO'], sort = False):
733 nVehicles += 1 748 nVehicles += 1
734 positions = array(group['POS']) 749 positions = array(group['POS'])
735 diff = positions[1:]-positions[:-1] 750 diff = positions[1:]-positions[:-1]
752 merged = merge(data, data, how='inner', left_on=['LANE\LINK\NO', 'LANE\INDEX', '$VEHICLE:SIMSEC'], right_on=['LANE\LINK\NO', 'LANE\INDEX', '$VEHICLE:SIMSEC'], sort = False) 767 merged = merge(data, data, how='inner', left_on=['LANE\LINK\NO', 'LANE\INDEX', '$VEHICLE:SIMSEC'], right_on=['LANE\LINK\NO', 'LANE\INDEX', '$VEHICLE:SIMSEC'], sort = False)
753 merged = merged[merged['NO_x']>merged['NO_y']] 768 merged = merged[merged['NO_x']>merged['NO_y']]
754 769
755 nCollisions = 0 770 nCollisions = 0
756 for name, group in merged.groupby(['LANE\LINK\NO', 'LANE\INDEX', 'NO_x', 'NO_y']): 771 for name, group in merged.groupby(['LANE\LINK\NO', 'LANE\INDEX', 'NO_x', 'NO_y']):
757 diff = group['POS_x']-group['POS_y'] 772 diff = group['POS_x'].convert_objects(convert_numeric=True)-group['POS_y'].convert_objects(convert_numeric=True)
758 if len(diff) >= 2 and min(diff) < 0 and max(diff) > 0: 773 # diff = group['POS_x']-group['POS_y'] # to check the impact of convert_objects and the possibility of using type conversion in read_csv or function to convert strings if any
774 if len(diff) >= 2 and npmin(diff) < 0 and npmax(diff) > 0:
759 xidx = diff[diff < 0].argmax() 775 xidx = diff[diff < 0].argmax()
760 yidx = diff[diff > 0].argmin() 776 yidx = diff[diff > 0].argmin()
761 if abs(group.loc[xidx, '$VEHICLE:SIMSEC'] - group.loc[yidx, '$VEHICLE:SIMSEC']) <= collisionTimeDifference: 777 if abs(group.loc[xidx, '$VEHICLE:SIMSEC'] - group.loc[yidx, '$VEHICLE:SIMSEC']) <= collisionTimeDifference:
762 nCollisions += 1 778 nCollisions += 1
763 return nCollisions 779 return nCollisions
872 888
873 Note: framerate is already taken into account''' 889 Note: framerate is already taken into account'''
874 890
875 def loadConfigFile(self, filename): 891 def loadConfigFile(self, filename):
876 from ConfigParser import ConfigParser 892 from ConfigParser import ConfigParser
877 from numpy import loadtxt
878 from os import path 893 from os import path
879 894
880 config = ConfigParser() 895 config = ConfigParser()
881 config.readfp(FakeSecHead(openCheck(filename))) 896 config.readfp(FakeSecHead(openCheck(filename)))
882 self.sectionHeader = config.sections()[0] 897 self.sectionHeader = config.sections()[0]
899 self.undistort = config.getboolean(self.sectionHeader, 'undistort') 914 self.undistort = config.getboolean(self.sectionHeader, 'undistort')
900 self.firstFrameNum = config.getint(self.sectionHeader, 'frame1') 915 self.firstFrameNum = config.getint(self.sectionHeader, 'frame1')
901 self.videoFrameRate = config.getfloat(self.sectionHeader, 'video-fps') 916 self.videoFrameRate = config.getfloat(self.sectionHeader, 'video-fps')
902 917
903 # Classification parameters 918 # Classification parameters
904 919 self.speedAggregationMethod = config.get(self.sectionHeader, 'speed-aggregation-method')
920 self.nFramesIgnoreAtEnds = config.getint(self.sectionHeader, 'nframes-ignore-at-ends')
921 self.speedAggregationQuantile = config.getint(self.sectionHeader, 'speed-aggregation-quantile')
922 self.minSpeedEquiprobable = config.getfloat(self.sectionHeader, 'min-speed-equiprobable')
923 self.minNPixels = config.getint(self.sectionHeader, 'min-npixels-crop')
924 self.pedBikeCarSVMFilename = config.get(self.sectionHeader, 'pbv-svm-filename')
925 self.bikeCarSVMFilename = config.get(self.sectionHeader, 'bv-svm-filename')
926 self.maxPedestrianSpeed = config.getfloat(self.sectionHeader, 'max-ped-speed')
927 self.maxCyclistSpeed = config.getfloat(self.sectionHeader, 'max-cyc-speed')
928 self.meanPedestrianSpeed = config.getfloat(self.sectionHeader, 'mean-ped-speed')
929 self.stdPedestrianSpeed = config.getfloat(self.sectionHeader, 'std-ped-speed')
930 self.locationCyclistSpeed = config.getfloat(self.sectionHeader, 'cyc-speed-loc')
931 self.scaleCyclistSpeed = config.getfloat(self.sectionHeader, 'cyc-speed-scale')
932 self.meanVehicleSpeed = config.getfloat(self.sectionHeader, 'mean-veh-speed')
933 self.stdVehicleSpeed = config.getfloat(self.sectionHeader, 'std-veh-speed')
905 934
906 # Safety parameters 935 # Safety parameters
907 self.maxPredictedSpeed = config.getfloat(self.sectionHeader, 'max-predicted-speed')/3.6/self.videoFrameRate 936 self.maxPredictedSpeed = config.getfloat(self.sectionHeader, 'max-predicted-speed')/3.6/self.videoFrameRate
908 self.predictionTimeHorizon = config.getfloat(self.sectionHeader, 'prediction-time-horizon')*self.videoFrameRate 937 self.predictionTimeHorizon = config.getfloat(self.sectionHeader, 'prediction-time-horizon')*self.videoFrameRate
909 self.collisionDistance = config.getfloat(self.sectionHeader, 'collision-distance') 938 self.collisionDistance = config.getfloat(self.sectionHeader, 'collision-distance')
918 self.useFeaturesForPrediction = config.getboolean(self.sectionHeader, 'use-features-prediction') 947 self.useFeaturesForPrediction = config.getboolean(self.sectionHeader, 'use-features-prediction')
919 948
920 def __init__(self, filename = None): 949 def __init__(self, filename = None):
921 if filename is not None: 950 if filename is not None:
922 self.loadConfigFile(filename) 951 self.loadConfigFile(filename)
952
953 def convertToFrames(self, speedRatio = 3.6):
954 '''Converts parameters with a relationship to time in 'native' frame time
955 speedRatio is the conversion from the speed unit in the config file
956 to the distance per second
957
958 ie param(config file) = speedRatio x fps x param(used in program)
959 eg km/h = 3.6 (m/s to km/h) x frame/s x m/frame'''
960 denominator = self.videoFrameRate*speedRatio
961 denominator2 = denominator**2
962 self.minSpeedEquiprobable = self.minSpeedEquiprobable/denominator
963 self.maxPedestrianSpeed = self.maxPedestrianSpeed/denominator
964 self.maxCyclistSpeed = self.maxCyclistSpeed/denominator
965 self.meanPedestrianSpeed = self.meanPedestrianSpeed/denominator
966 self.stdPedestrianSpeed = self.stdPedestrianSpeed/denominator
967 self.meanVehicleSpeed = self.meanVehicleSpeed/denominator
968 self.stdVehicleSpeed = self.stdVehicleSpeed/denominator
969 # special case for the lognormal distribution
970 self.locationCyclistSpeed = self.locationCyclistSpeed-log(denominator)
971 #self.scaleCyclistSpeed = self.scaleCyclistSpeed
923 972
924 class SceneParameters(object): 973 class SceneParameters(object):
925 def __init__(self, config, sectionName): 974 def __init__(self, config, sectionName):
926 from ConfigParser import NoOptionError 975 from ConfigParser import NoOptionError
927 from ast import literal_eval 976 from ast import literal_eval