Further improved and simplified class definitions
2 files changed, 79 insertions(+), 84 deletions(-)

M common.py
M fixed.py
M common.py +30 -4
@@ 7,13 7,39 @@ import struct
 class PlanetsData(object):
     """Base class for all Planets data objects"""
     COUNT = None # Default number of objects in a data file
-    PACK_LENGTH = None # Length of binary data fo single object
-    id = None # Every object needs an id (if not set, generated automatically)
+    PACK_LENGTH = None # Length of binary data for single object
+    PACK_FORMAT = None # Format of binary data for single object
+    FIELDS = ()
+
+    def __init__(self):
+        for field in self.FIELDS:
+            # Dictionary field: see EngSpec class in fixed.py for an example
+            if isinstance(field, tuple):
+                setattr(self, str(field[0])+'['+str(field[1])+']', None)
+            else:
+                setattr(self, field, None)
+        self.id = None
     
+    def __setattr__(self, name, value):
+        """__setattr__() is modified to rstrip() space padded BASIC strings"""
+        if isinstance(value, str):
+            value = value.rstrip()
+        object.__setattr__(self, name, value)
+
     def unpack(self, data):
         """Unpacks binary data into class instance variables"""
-        raise NotImplementedError
-    
+        if len(data) is not self.PACK_LENGTH:
+            raise ValueError('Binary data passed has incorrect length')
+        values = struct.unpack(self.PACK_FORMAT, data)
+        if len(self.FIELDS) is not len(values):
+            raise ValueError('Incorrect number of variables in pack format')
+        for name, value in zip(self.FIELDS, values):
+            # Dictionary field: see EngSpec class in fixed.py for an example
+            if isinstance(name, tuple):
+                setattr(self, str(name[0])+'['+str(name[1])+']', value)
+            else:
+                setattr(self, name, value)
+
     @classmethod
     def load(cls, data, count=None):
         """Unpacks binary data into a list of object instances"""

          
M fixed.py +49 -80
@@ 3,103 3,72 @@ Classes for reading files that are const
 such as the "spec" and name lists, which are used by both client and host.
 """
 
-import struct
 from common import PlanetsData
 
 class BeamSpec(PlanetsData):
     """List of starship beam weapons"""
     COUNT = 10
     PACK_LENGTH = 36
-    name = ''
-    cost = 0
-    tritanium = 0
-    duranium = 0
-    molybdenum = 0
-    mass = 0
-    tech = 0 
-    kill = 0
-    damage = 0
-    
-    def unpack(self, data):
-        (self.name, self.cost, self.tritanium, self.duranium, self.molybdenum,
-         self.mass, self.tech, self.kill, self.damage) = struct.unpack(
-            '< 20s h h h h h h h h', data)
-        self.name = self.name.rstrip()
+    PACK_FORMAT = '< 20s h h h h h h h h'
+    FIELDS = ('name',
+              'cost',
+              'tritanium',
+              'duranium',
+              'molybdenum',
+              'mass',
+              'tech',
+              'kill',
+              'damage')
     
 class EngSpec(PlanetsData):
     """List of starship engines"""
     COUNT = 9
     PACK_LENGTH = 66
-    name = ''
-    cost = 0
-    tritanium = 0
-    duranium = 0
-    molybdenum = 0
-    tech = 0
-    mileage = {1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0, 7: 0, 8: 0, 9: 0}
-    
-    def unpack(self, data):
-        if len(data) is not self.PACK_LENGTH:
-            raise ValueError('Binary data passed has incorrect length')
-        # Reinitialize mileage dict or it will not be seen as instance variable
-        self.mileage = {}
-        (self.name, self.cost, self.tritanium, self.duranium, self.molybdenum,
-         self.tech, self.mileage[1], self.mileage[2], self.mileage[3],
-         self.mileage[4], self.mileage[5], self.mileage[6],
-         self.mileage[7], self.mileage[8], self.mileage[9]) = struct.unpack(
-            '< 20s h h h h h i i i i i i i i i', data)
-        self.name = self.name.rstrip()
+    PACK_FORMAT = '< 20s h h h h h i i i i i i i i i'
+    FIELDS = ('name',
+              'cost',
+              'tritanium',
+              'duranium',
+              'molybdenum',
+              'tech',
+              ('mileage', 1,), ('mileage', 2,), ('mileage', 3,),
+              ('mileage', 4,), ('mileage', 5,), ('mileage', 6,),
+              ('mileage', 7,), ('mileage', 8,), ('mileage', 9,))
         
 class HullSpec(PlanetsData):
     """List of starship hulls"""
     # No COUNT, but typically 105 objects in default HULLSPEC.DAT
     PACK_LENGTH = 60
-    name = ''
-    picture = 0
-    damaged = 0 # Unused field for picture of damaged ship
-    tritanium = 0
-    duranium = 0
-    molybdenum = 0
-    fueltank = 0
-    crew = 0
-    engines = 0
-    mass = 0
-    tech = 0
-    cargo = 0
-    fighterbays = 0
-    torpedolaunchers = 0
-    beams = 0
-    cost = 0
-    
-    def unpack(self, data):
-        if len(data) is not self.PACK_LENGTH:
-            raise ValueError('Binary data passed has incorrect length')
-        (self.name, self.picture, self.damaged, self.tritanium, self.duranium,
-         self.molybdenum, self.fueltank, self.crew, self.engines, self.mass,
-         self.tech, self.cargo, self.fighterbays, self.torpedolaunchers,
-         self.beams, self.cost) = struct.unpack(
-            '< 30s h h h h h h h h h h h h h h h', data)
-        self.name = self.name.rstrip()
-        
+    PACK_FORMAT = '< 30s h h h h h h h h h h h h h h h'
+    FIELDS = ('name',
+              'picture',
+              'damaged', # Unused field for picture of damaged ship
+              'tritanium',
+              'duranium',
+              'molybdenum',
+              'fueltank',
+              'crew',
+              'engines',
+              'mass',
+              'tech',
+              'cargo',
+              'fighterbays',
+              'torpedolaunchers',
+              'beams',
+              'cost')
+
 class TorpSpec(PlanetsData):
     """List of starship torpedo weapons"""
     COUNT = 10
     PACK_LENGTH = 38
-    name = ''
-    torpedo_cost = 0
-    launcher_cost = 0
-    tritanium = 0
-    duranium = 0
-    molybdenum = 0
-    mass = 0
-    tech = 0
-    kill = 0
-    damage = 0
-
-    def unpack(self, data):
-        if len(data) is not self.PACK_LENGTH:
-            raise ValueError('Binary data passed has incorrect length')
-        (self.name, self.torpedo_cost, self.launcher_cost, self.tritanium,
-         self.duranium, self.molybdenum, self.mass, self.tech, self.kill,
-         self.damage) = struct.unpack('< 20s h h h h h h h h h', data)
-        self.name = self.name.rstrip()
  No newline at end of file
+    PACK_FORMAT = '< 20s h h h h h h h h h'
+    FIELDS = ('name',
+              'torpedo_cost',
+              'launcher_cost',
+              'tritanium',
+              'duranium',
+              'molybdenum',
+              'mass',
+              'tech',
+              'kill',
+              'damage')
  No newline at end of file