Python Killmail Class

From EVEDev
Jump to: navigation, search
Python Killmail Class
Maintainer:
Stable release:
Development release:
OS: Linux, Windows
License: Open-Source/Common-Use
Website:

A very simple and explicit KM parsing class in Python. It takes the raw mail loops through and assigns the information to a Kill object. Can easily be interfaced to an ORM layer for use in dynamic environments. Updated with Rev3 working example. Still parses Rev2 without issue.

 
'''
Python Killmail Parser
Killmail - Parse raw killmail, store in local kill object.
Kill - user friendly representation of a kill
 
Explicit is better; the data from the KMs in guaranteed
unless malformed so no need for regex magic.
Just a nice hard coded and very fast parser
'''
 
example_mail = '''2007.10.10 10:10
 
Victim: John Doe
Alliance: None
Corp: Pator Tech School
Destroyed: Armageddon
System: Pator
Security: 1.0
 
Involved parties:
 
Name: Minmatar Sentry Gun / Republic Fleet
 
Name: Some Guy (laid the final blow)
Security: -0.3
Alliance: Alliance One
Corp: Corp One
Ship: Cyclone
Weapon: 220mm Vulcan AutoCannon II
 
Name: Another Guy
Security: -1.3
Alliance: Alliance One
Corp: Corp Two
Ship: Scimitar
Weapon: Hobgoblin II
 
Name: Last Guy
Security: -1.7
Alliance: Alliance One
Corp: Corp Three
Ship: Falcon
Weapon: BZ-5 Neutralizing Spatial Destabilizer ECM
 
 
Destroyed items:
 
Mega Pulse Laser II, Qty: 4
Conflagration L, Qty: 4
Warp Disruptor II
X5 Prototype I Engine Enervator
Pseudoelectron Containment Field I
Extruded Heat Sink I, Qty: 3
1600mm Reinforced Rolled Tungsten Plates I, Qty: 3
Cap Booster 800, Qty: 9 (Cargo)
Scorch L, Qty: 4 (Cargo)
Acolyte II, Qty: 4 (Drone Bay)
 
Dropped items:
 
Mega Pulse Laser II, Qty: 4
Conflagration L, Qty: 4
Warp Disruptor II
X5 Prototype I Engine Enervator
Pseudoelectron Containment Field I
Extruded Heat Sink I, Qty: 3
1600mm Reinforced Rolled Tungsten Plates I, Qty: 3'''
 
class Kill(object):
    '''Used by Killmail for storing a clean interface for getting kill data
    date: simple datetime in CCYY.MM.DD HH:MM:SS format
    victim: dict - keys are (name, alliance, corp, faction, ship, system, security
    involved: list of dict - keys are (name, security, alliance, corp, faction, weapon, ship, fb)
    destroyed_fit: list of tuple - [(item, qty),]
    destroyed_cargo: list of tuple - [(item,qty),]
    destroyed_drone: list of tuple - [(item,qty),]
    '''
 
    def __init__(self):
        self.date = None
        self.victim = {'name':'', 'alliance':'',
                       'corp':'', 'faction':'',
                       'ship':'', 'system':'',
                       'security':'', 'damage':''}
 
        self.involved = []
        self.destroyed_fit = []
        self.destroyed_cargo = []
        self.destroyed_drone = []
        self.dropped = []
 
    def new_assailant(self):
        assailant = {'name':'', 'security':'',
                     'alliance':'', 'corp':'', 'faction':'',
                     'ship':'', 'weapon':'',
                     'damage':'','fb':False}
 
        self.involved.append(assailant)
 
 
 
class Killmail(object):
    def __init__(self, raw_killmail):
        self.raw_mail = raw_killmail
 
        self.kill = Kill()
        self.parse()
 
    def parse(self):
        lines = self.raw_mail.split('\n')
        lines = filter(self.notEmpty, lines)
 
        self.kill.date = lines[0] # get the datetime
 
        list_pos = 1 # move down position on the KM, we will use this to
                     # to keep track of our position in the KM as we parse it
 
        # first up, the vic-
        for line in lines[list_pos:]:
            field,value = line.split(':')
            value = value.strip(' ')
 
            if field == 'Victim':
                self.kill.victim['name'] = value
            elif field == 'Alliance':
                self.kill.victim['alliance'] = value
            elif field == 'Corp':
                self.kill.victim['corp'] = value
            elif field == 'Destroyed':
                self.kill.victim['ship']= value
            elif field == 'Damage Taken':
                self.kill.victim['damage'] = value
            elif field == 'System':
                self.kill.victim['system'] = value
            elif field == 'Security':
                self.kill.victim['security'] = value
            elif field == 'Faction':
                self.kill.victim['faction'] = value
            else:
                break
            list_pos += 1
 
        # ok, now for the assailants
        for line in lines[list_pos:]:
            field,value = line.split(':')
            value = value.lstrip(' ')
 
            if field == 'Name':
                self.kill.new_assailant()
 
                # little hack to deal with things like gate guns
                isNpc = False
                if '/' in value:
                    isNpc = True
 
                try:
                    name, fb = value.split('(')
                    self.kill.involved[-1]['fb'] = True
 
                    if isNpc == True:
                        npc,corp = name.split('/')
                        self.kill.involved[-1]['name'] = npc
                        self.kill.involved[-1]['corp'] = corp
                    else:
                        self.kill.involved[-1]['name'] = name.strip(' ')
                except ValueError:
                    # well can't split and unpack to name and fb, but not be the fb
                    if isNpc == True:
                        npc,corp = value.split('/')
                        self.kill.involved[-1]['name'] = npc
                        self.kill.involved[-1]['corp'] = corp
                    else:
                        self.kill.involved[-1]['name'] = value
 
            elif field == 'Security':
                self.kill.involved[-1]['security'] = value
            elif field == 'Alliance':
                self.kill.involved[-1]['alliance'] = value
            elif field == 'Corp':
                self.kill.involved[-1]['corp'] = value
            elif field == 'Ship':
                self.kill.involved[-1]['ship'] = value
            elif field == 'Weapon':
                self.kill.involved[-1]['weapon'] = value
            elif field == 'Damage Done':
                self.kill.involved[-1]['damage'] = value
            elif field == 'Faction':
                self.kill.involved[-1]['faction'] = value
            elif field == 'Destroyed items' or field == 'Dropped items':
                # trigger a break, destroyed/dropped items happens at the end of the involved list
                list_pos += 1
                break
 
            list_pos += 1
 
        # lets see what he lost .. tough break
        for line in lines[list_pos:]:
            if line.split(':')[0] == 'Dropped items':
                # ok, done with what got blow up, lets see what we got!
                list_pos += 1
                break
 
            try:
                item,qty = line.split(',')
                if '(Cargo)' in qty \
                   or '(Drone Bay)' in qty:
                    qty = int(qty.split(':')[1].split('(')[0].strip(' '))
                else:
                    qty = int(qty.split(':')[1].strip(' '))
            except ValueError:
                # we tried to unpack too few values, which means a qty of 1
                item = line
                qty = 1
 
            if '(Cargo)' in line:
                self.kill.destroyed_cargo.append((item,qty))
            elif '(Drone Bay)' in line:
                self.kill.destroyed_drone.append((item,qty))
            else:
                self.kill.destroyed_fit.append((item,qty))
 
            list_pos += 1
 
        # lets see what he dropped .. hooray for us
        for line in lines[list_pos+1:]:
            try:
                item,qty = line.split(',')
                if '(Cargo)' in qty \
                   or '(Drone Bay)' in qty:
                    qty = int(qty.split(':')[1].split('(')[0].strip(' '))
                else:
                    qty = int(qty.split(':')[1].strip(' '))
            except ValueError:
                # we tried to unpack too few values, which means a qty of 1
                item = line
                qty = 1
 
            if '(Cargo)' in line:
                self.kill.dropped.append((item,qty))
            elif '(Drone Bay)' in line:
                self.kill.dropped.append((item,qty))
            else:
                self.kill.dropped.append((item,qty))
 
            list_pos += 1
 
    def notEmpty(self, c):
        return len(c.strip()) > 0
 
 
if __name__ == '__main__':
    km = Killmail(example_mail)
 
    print 'Victim',km.kill.victim
    print 'Involved',km.kill.involved
 
    print 'Items Fit',km.kill.destroyed_fit
    print 'Items Cargo',km.kill.destroyed_cargo
 
    print 'Items Dronebay',km.kill.destroyed_drone
    print 'Items Dropped',km.kill.dropped
 
Personal tools