1

I'm getting a keyerror exception when I input a player name here that is not in the records list. I can search it and get back any valid name, but if I input anything else, i get a keyerror. I'm not really sure how to go about handling this since it's kindof confusing already dealing with like 3 sets of data created from parsing my file.

I know this code is bad I'm new to python so please excuse the mess - also note that this is a sortof test file to get this functionality working, which I will then write into functions in my real main file. Kindof a testbed here, if that makes any sense.

This is what my data file, stats4.txt, has in it:

[00000] Cho'Gath - 12/16/3 - Loss - 2012-11-22
[00001] Fizz - 12/5/16 - Win - 2012-11-22
[00002] Caitlyn - 13/4/6 - Win - 2012-11-22
[00003] Sona - 4/5/9 - Loss - 2012-11-23
[00004] Sona - 2/1/20 - Win - 2012-11-23
[00005] Sona - 6/3/17 - Loss - 2012-11-23
[00006] Caitlyn - 14/2/16 - Win - 2012-11-24
[00007] Lux - 10/2/14 - Win - 2012-11-24
[00008] Sona - 8/1/22 - Win - 2012-11-27

Here's my code:

import re

info = {}
records = []
search = []
with open('stats4.txt') as data:
    for line in data:
        gameid = [item.strip('[') for item in line.split(']')]
        del gameid[-1]
        gameidstr = ''.join(gameid)
        gameid = gameidstr
        line = line[7:]
        player, stats, outcome, date = [item.strip() for item in line.split('-', 3)]
        stats = dict(zip(('kills', 'deaths', 'assists'), map(int, stats.split('/'))))
        date = tuple(map(int, date.split('-')))
        info[player] = dict(zip(('gameid', 'player', 'stats', 'outcome', 'date'), (gameid, player, stats, outcome, date)))
        records.append(tuple((gameid, info[player])))

print "\n\n", info, "\n\n" #print the info dictionary just to see 
champ = raw_input() #get champion name
#print info[champ].get('stats').get('kills'), "\n\n"
#print "[%s] %s - %s/%s/%s - %s-%s-%s" % (info[champ].get('gameid'), champ, info[champ].get('stats').get('kills'), info[champ].get('stats').get('deaths'), info[champ].get('stats').get('assists'), info[champ].get('date')[0], info[champ].get('date')[1], info[champ].get('date')[2])
#print "\n\n"
#print info[champ].values()

i = 0
for item in records: #this prints out all records
    print "\n", "[%s] %s - %s/%s/%s - %s - %s-%s-%s" % (records[i][0], records[i][1]['player'], records[i][1]['stats']['kills'], records[i][1]['stats']['deaths'], records[i][1]['stats']['assists'], records[i][1]['outcome'], records[i][1]['date'][0], records[i][1]['date'][1], records[i][1]['date'][2])
    i = i + 1

print "\n" + "*" * 50
i = 0
for item in records:
    if champ in records[i][1]['player']:
        search.append(records[i][1])
    else:
        pass
    i = i + 1

s = 0

if not search:
    print "no availble records" #how can I get this to print even if nothing is inputted in raw_input above for champ?


print "****"
for item in search:
        print "\n[%s] %s - %s/%s/%s - %s - %s-%s-%s" % (search[s]['gameid'], search[s]['player'], search[s]['stats']['kills'], search[s]['stats']['deaths'], search[s]['stats']['assists'], search[s]['outcome'], search[s]['date'][0], search[s]['date'][1], search[s]['date'][2])
        s = s + 1

I tried setting up a Try; Except sort of thing but I couldn't get any different result when entering an invalid player name. I think I could probably set something up with a function and returning different things if the name is present or not but I think I've just gotten myself a bit confused. Also notice that no match does indeed print for the 8 records that aren't matches, though thats not quite how I want it to work. Basically I need to get something like that for any invalid input name, not just a valid input that happens to not be in a record in the loop.

Valid input names for this data are: Cho'Gath, Fizz, Caitlyn, Sona, or Lux - anything else gives a keyerror, thats what I need to handle so it doesn't raise an error and instead just prints something like "no records available for that champion" (and prints that only once, rather then 8 times)

Thanks for any help!

[edit] I was finally able to update this code in the post (thank you martineau for getting it added in, for some reason backticks aren't working to block code and it was showing up as bold normal text when i pasted. Anyways, look at if not search, how can I get that to print even if nothing is entered at all? just pressing return on raw_input, currently it prints all records after **** even though i didn't give it any search champ

3
  • Backticks are mainly for formatting small sections of code, like this. To do a block of code, indent each line four spaces either before you paste it in or afterwards. Alternatively, you can paste it all in unindented, then select it all and click the {} tool above the edit window to format it (which means indent it in this case). Commented Nov 28, 2012 at 14:51
  • ah okay, i know about the 4 spaces but that is so tedious to do for 100ish lines, and since it wordwraps on paste it gets confusing, ill try to remember the {} for next time i'm sure that would be easier, thanks for fixing my post :) Commented Nov 28, 2012 at 14:53
  • I either do the indenting in my text editor where it's very easy but tends to mess it up as far as running it goes, or in the edit window as I described. BTW, I didn't do the formatting of your question just for you, but you're welcome. Commented Nov 28, 2012 at 14:58

2 Answers 2

3

where is your exact error occurring?

i'm just assuming it is when champ = raw_input() #get champion name

and then info[champ]

you can either check if the key exists first

if champ not in info:
  print 'no records avaialble'

or use get

if info.get(champ)

or you can just try and access the key

try:
  info[champ] 
  # do stuff
except KeyError:
  print 'no records available'

the more specific you can be in your question the better, although you explained your problem you really didn't include any specifics Please always include a traceback if available, and post the relevant code IN your post not on a link.

Sign up to request clarification or add additional context in comments.

8 Comments

what... for some reason it's suddenly not keyerroring, maybe in cleaning up the file a bit before posting here i made some slight change, i'll do some more testing
this seems to do the trick: i = 0 for item in records: if champ in records[i][1]['player']: search.append(records[i][1]) else: pass i = i + 1 print "no match" - though this is printing "no match" at least once no matter what
@Kassandra is this self-learning or some course you're attending with a specific assignment?
@Jon self learning, i'm very new to all this and have never been good at it but decided to give python another try
@dm03514 I think what I need to do now is get it to print "no records available" only once, and only if the there is no match
|
1

Here's some modifications that I think address your problem. I also reformatted the code to make it a little more readable. In Python it's possible to continue long lines onto the next either by ending with a \ or just going to the next line if there's an unpaired '(' or '[' on the previous line.

Also, the way I put code in my questions or answer here is by cutting it out of my text editor and then pasting it into the edit window, after that I make sure it's all selected and then just use the {} tool at the top of edit window to format it all.

import re
from pprint import pprint

info = {}
records = []
with open('stats4.txt') as data:
    for line in data:
        gameid = [item.strip('[') for item in line.split(']')]
        del gameid[-1]
        gameidstr = ''.join(gameid)
        gameid = gameidstr
        line = line[7:]
        player, stats, outcome, date = [item.strip() for item in line.split('-', 3)]
        stats = dict(zip(('kills', 'deaths', 'assists'), map(int, stats.split('/'))))
        date = tuple(map(int, date.split('-')))
        info[player] = dict(zip(('gameid', 'player', 'stats', 'outcome', 'date'),
                                (gameid, player, stats, outcome, date)))
        records.append(tuple((gameid, info[player])))

#print "\n\n", info, "\n\n" #print the info dictionary just to see
pprint(info)
champ = raw_input("Champ's name: ") #get champion name
#print info[champ].get('stats').get('kills'), "\n\n"
#print "[%s] %s - %s/%s/%s - %s-%s-%s" % (
#       info[champ].get('gameid'), champ, info[champ].get('stats').get('kills'),
#       info[champ].get('stats').get('deaths'), info[champ].get('stats').get('assists'),
#       info[champ].get('date')[0], info[champ].get('date')[1],
#       info[champ].get('date')[2])
#print "\n\n"
#print info[champ].values()

i = 0
for item in records: #this prints out all records
    print "\n", "[%s] %s - %s/%s/%s - %s - %s-%s-%s" % (
                 records[i][0], records[i][1]['player'], records[i][1]['stats']['kills'],
                 records[i][1]['stats']['deaths'], records[i][1]['stats']['assists'],
                 records[i][1]['outcome'], records[i][1]['date'][0],
                 records[i][1]['date'][1], records[i][1]['date'][2])
    i = i + 1

print "\n" + "*" * 50
i = 0
search = []
for item in records:
    if champ in records[i][1]['player']:
        search.append(records[i][1])
    i = i + 1
if not search:
    print "no match"
    exit()

s = 0
for item in search:
        print "\n[%s] %s - %s/%s/%s - %s - %s-%s-%s" % (search[s]['gameid'],
              search[s]['player'], search[s]['stats']['kills'],
              search[s]['stats']['deaths'], search[s]['stats']['assists'],
              search[s]['outcome'], search[s]['date'][0], search[s]['date'][1],
              search[s]['date'][2])
        s = s + 1

6 Comments

Thank you very much that seems to work just fine :) I had seen lots of code with the cleaner alignment like you have here, I just wasn't sure how to be sure mine would work. Your code there will still print all records if the user enters nothing for champ name, but I found a solution by changing the search if statement to be within a lower one that does if champ:<search append stuff>else: champ = "poop", causing it to print, only once, the error "no match", because champ is not valid (None was always True because any name is > None, so "" would add all recs to search, printing all
Seems like you could check champ right after the raw_input() with a if champ not in info:, print 'no match', exit().
BTW, you could obtain the gameid more easily with these statements: import re, match = re.search(r'\[(\d+)\]', line), then gameid = match.group(1) if match else None.
that would work too, however I've encountered a small problem with my method and i think it would affect that too;, something i overlooked: if I enter "l", it matches Caitlyn, if i enter "z" it matches Fizz, because those letters are in those names - is there any way I can get if champ in records[i][1]['player'] to only match a full match? I'm sure this wouldn't be a problem with my other code to validate champion names you helped me with before but is there any way to handle that here?
Yeah, I was wondering what happened to that validation code. I think you need if champ == records[i][1]['player'].
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.