hohav / py-slippi

Python library for parsing SSBM replay files
MIT License
56 stars 25 forks source link

Cannot access frames when no items are present #22

Closed davidtjones closed 3 years ago

davidtjones commented 3 years ago

When loading a game, trying to access game.frames throws an Index out of range exception. The code I was trying to run:

game = Game("file.slp")
print(len(game.frames))
print(game.frames[0])

I expected this to print out the data for this frame, instead I was given an index out of range exception, which crashed the program. I was able to confirm that there were 8000 or so frames to view from the previous line. Below is the trace provided by python:

20200129 - HNC 2 - PM 0745 - Captain Falcon (Blue) vs Falco (Default) - Dream Land N64.slp
11638

---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
<ipython-input-5-ccb64f3d4e4d> in <module>
      4     game = Game(str(training_files[i]))
      5     print(len(game.frames))
----> 6     print(game.frames[0])
      7     break

~/.conda/envs/melee/lib/python3.6/site-packages/slippi/util.py in __repr__(self)
     71             # uppercase names are nested classes
     72             if not (attr.startswith('_') or attr[0].isupper()):
---> 73                 s = self._attr_repr(attr)
     74                 if s:
     75                     attrs.append(_indent(s))

~/.conda/envs/melee/lib/python3.6/site-packages/slippi/util.py in _attr_repr(self, attr)
     62 
     63     def _attr_repr(self, attr):
---> 64         return attr + '=' + _format(getattr(self, attr))
     65 
     66     def __repr__(self):

~/.conda/envs/melee/lib/python3.6/site-packages/slippi/util.py in _format(obj)
     26         return '%.02f' % obj
     27     elif isinstance(obj, tuple):
---> 28         return _format_collection(obj, '(', ')')
     29     elif isinstance(obj, list):
     30         return _format_collection(obj, '[', ']')

~/.conda/envs/melee/lib/python3.6/site-packages/slippi/util.py in _format_collection(coll, delim_open, delim_close)
     14     elements = [_format(x) for x in coll]
     15 #    if len(elements):
---> 16     if '\n' in elements[0]:
     17         return delim_open + '\n' + ',\n'.join(_indent(e) for e in elements) + delim_close
     18     else:

IndexError: list index out of range

After tracing through the issue, I discovered that there is no code in _format_collection that handles an empty collection:

def _format_collection(coll, delim_open, delim_close):    
    elements = [_format(x) for x in coll]    
    if '\n' in elements[0]:    
        return delim_open + '\n' + ',\n'.join(_indent(e) for e in elements) + delim_close    
    else:       
        return delim_open + ', '.join(elements) + delim_close    

if coll is empty, then trying to access elements[0] in the third line throws an index out of range exception. I was able to fix this by simply handling the failing condition, namely, when len(elements) is 0 :

def _format_collection(coll, delim_open, delim_close):    
    elements = [_format(x) for x in coll]    
    if len(elements):    
        if '\n' in elements[0]:    
            return delim_open + '\n' + ',\n'.join(_indent(e) for e in elements) + delim_close    
        else:       
            return delim_open + ', '.join(elements) + delim_close    
    else:    
        return delim_open + ' ' + delim_close   

For reference, I am on python 3.6.9. I am not exactly sure if this is the intended behavior, but this workaround did resolve my issues.

hohav commented 3 years ago

Thanks for the report. This will be fixed by #20 (sorry for the duplicate effort; my fault for being slow to respond).

davidtjones commented 3 years ago

No worries! Glad it's covered.