Trying to check if 2 values match in a file - python

this is a code from a chat bot, and it's purpose is to save into a file all information about an user. That will work fine as long as it's only in 1 room, but if i want to save information of the same user in 2 different rooms, i got a problem. The bot won't just update the information getting the user and the room, instead it will always create new and new lines of that user and that room.
It's getting annoying and i would really like to not break this code a lot, so i'd like to know where it fails and how to fix it in a proper way without using dicts. (You can read all the comments inside the code to understand how i think it works).
Thank you for your time.
#First of all it reads the file
leyendoestadisticas = open("listas\Estadisticas.txt", "r")
bufferestadisticas = leyendoestadisticas.read()
leyendoestadisticas.close()
if not '"'+user.name+'"' in bufferestadisticas: #If the name of the user is not there, it adds all the information.
escribiendoestadisticas = open("listas\Estadisticas.txt", 'a')
escribiendoestadisticas.write(json.dumps([user.name, palabrasdelafrase, letrasdelafrase,
"1", user.nameColor, user.fontColor, user.fontFace, user.fontSize,
message.body.replace('"', "'"), room.name, 0, "primermensajitodeesapersona", fixedrooms])+"\n")
escribiendoestadisticas.close()
else: #If the name it's there, it will do the next:
#First of all, get all rooms where the name is saved, to do that...
listadesalas = []
for line in open("listas\Estadisticas.txt", 'r'):
retrieved3 = json.loads(line)
if retrieved3[0] == user.name: #If the name is found
if not retrieved3[9] == room.name: #But room is diferent
listadesalas.append(retrieved3[9]) #Adds the room to a temporal list
#Now that we got a list with all different lines of that user based on rooms... we do the next code
data = []
hablaenunanuevasala = "no"
with open('listas\Estadisticas.txt', 'r+') as f:
for line in f:
data_line = json.loads(line)
if data_line[0] == user.name: #If name is there
if data_line[9] == room.name: #And the room matches with actual room, then update that line.
data_line[1] = int(data_line[1])+int(palabrasdelafrase)
data_line[2] = int(data_line[2])+int(letrasdelafrase)
data_line[3] = int(data_line[3])+1
data_line[4] = user.nameColor
data_line[5] = user.fontColor
data_line[6] = user.fontFace
data_line[7] = user.fontSize
data_line[11] = data_line[8]
data_line[8] = message.body.replace('"', "'")
data_line[9] = room.name
data_line[12] = fixedrooms
else: #but if the user is there and room NOT matches, we want to add a new line to the file with the same user but a new room.
if not room.name in listadesalas: #And here is where i believe is the problem of my code.
hablaenunanuevasala = "si" #needed since i didn't found a way to properly add a new line inside this loop, so must be done outside the loop later.
data.append(data_line)
f.seek(0)
f.writelines(["%s\n" % json.dumps(i) for i in data])
f.truncate()
#Outside the loop - This would work if the program noticed it's a room that is not saved yet in the file for that user.
if hablaenunanuevasala == "si":
escribiendoestadisticas2 = open("listas\Estadisticas.txt", 'a')
escribiendoestadisticas2.write(json.dumps([user.name, palabrasdelafrase, letrasdelafrase,
"1", user.nameColor, user.fontColor, user.fontFace, user.fontSize,
message.body.replace('"', "'"), room.name, 0, "primermensajitodeesapersona", fixedrooms])+"\n")
escribiendoestadisticas2.close()
So... that's what i tried, and it works perfect as long as it's 1 room, it updates the info all the time. When i speak in a second room, it adds me a new record with that second room (perfect). But then if i speak again in ANY of those 2 rooms, the bot will add 2 more lines of code to the file instead of updating the information of the room where i did speak.
Edit Let me summarize it:
Let's say I speak in "whenever" room, the file will save a record
["saelyth", "whenever", "more info"]
If i speak in another room, the file should save a record
["saelyth", "anotherroom", "more info"]
It works great... but then it doesn't update the info. If now i speak in any of those 2 rooms, instead of updating the proper line, the bot will add more new lines into the file, wich is the problem.

Fix done... somehow.
I did choose to save info into different files for each room, that works.

Related

Filling form fields in Word automatically with pywin32

I have a little problem to solve, but I donĀ“t get an acceptable solution. I try to have a script that automaticcaly fills in FormFields in Word with entries of dictionaries. So far I used pywin32 for that task and somehow I managed to find a solution that works at all. At least as long as I update the word document.
The command that I use so far in a loop is "marks(i).Result = keyValue". Here "marks" is - as far as I understand - a formfields object, which I get by "marks = doc.FormFields".
As I said, all this works to some extent, but as soon as I update the document in Word, all entries disappear again.
Would be really great if someone could help me and knows how to make it that the entry remains permanent. Unfortunately I do not understand the documentation of pywin32 at all. Attached below is the whole function.
Thanks in advance!
def wordExport(window, excDict, docPath):
wordApp = win32com.client.Dispatch('Word.Application') #Word App Object
wordApp.Visible = False
doc = wordApp.Documents.Open(docPath) #Open .docx
marks = doc.FormFields # FormFields object
cMarks = marks.Count # FormField count
cMatches = 0 #Match counter
cOverwrt = 0 #Fields overwritten
for i in range(1, cMarks + 1):
fieldName = str(marks(i).Name) #String object of FormField
#Default Cases --------------------------------------------------------------------
if fieldName in excDict:
keyValue = excDict.get(fieldName) #Get value to key(FormField)
resultIsEmpty = not marks(i).Result #No text has been entered before
# No prior entry present
if keyValue != "None"
marks(i).Result = keyValue + " "
cMatches += 1
if not resultIsEmpty:
cOverwrt += 1
doc.Close()
wordApp.Visible = False

NameError: device is not defined

i know there are a lot of people asking a similar question and i also understand what the answers are trying to say but no matter what i try,it just doesnt work.
someone help!
here is my code (well a shorter version)
import random
##opening all the files and reading them line by line.
file_1 = open("devices.txt","r")
read_1 = file_1.readlines()
file_2 = open("phones.txt","r")
read_2 = file_2.readlines()
def choose_device():##creating function
device = input(read_1[0]).lower()##asking the user by printing a question from file_1
if device == "phone" or device == "phones" or device == "smartphone" or device == "smartphones" or device == "1":
brand = input(read_2[0])
if brand == "samsung":
version = input(read_2[1])
raw_memory = input(read_2[4])
solution_for_phones()
elif brand == "iphone":
version = input(read_2[2])
raw_memory = input(read_2[4])
solution_for_phones()
elif brand == "sony":
version = input(read_2[3])
raw_memory = input(read_2[4])
solution_for_phones()
else:
print(read_2[5])
do_again()##restart
def solution_for_phones():
datadict = {} ##creating a dictionary
with open('phonesolution.txt') as file: ##opening file
for rec in file: ##looping through every line
rec = rec.split(':') ##delimiter is :
problem = rec[0] ##first values before the delimiter are saved as problems
answer = rec[1] ##second values after the delimiter are saved as answers
problem = problem.split(" ") ##problems is further split by the delimiter "space"
for item in problem: ##every word in the problem section is assigned to an answer
datadict[item] = answer
user_problem = input('What is the problem?: ')##asking the user where the problem is
split_answer = user_problem.split(" ")##splitting the users answer into separate words
for option in datadict.keys():
if option in split_answer:##mathcing the users answer to keywords in the problem
print(datadict[option])
else:
CaseNo = (random.randrange(100000,999999))
print (CaseNo)
ReportFile = open('not_found.txt', 'a')
ReportFile.write ("\n"+"-------------------------------------------")
ReportFile.write ("\n"+"Case No is : "+str(CaseNo))
ReportFile.write ("\n"+"Case No is : "+(device))
ReportFile.close
do_again()
and here is the error message. anybody knows how to fix it?
welcome to our trouble shooting system
what device do you have a problem with? (these are the options:1.smartphones, 2.laptops, 3.game consoles)
smartphones
what brand is your phone? (eg: samsung, iphone)
samsung
what version is your samsung? (eg:J3, S7 edge)
J3
what is the memory size? (eg:8g, 16gb)
8
What is the problem?: vZrfvSZ
109451
Traceback (most recent call last):
File "C:\Users\hp\Downloads\A453\task 3\mine\task 3 just for practice.py", line 156, in <module>
choose_device()##calling the function
File "C:\Users\hp\Downloads\A453\task 3\mine\task 3 just for practice.py", line 110, in choose_device
solution_for_phones()
File "C:\Users\hp\Downloads\A453\task 3\mine\task 3 just for practice.py", line 58, in solution_for_phones
ReportFile.write ("\n"+"Case No is : "+(device))
NameError: name 'device' is not defined
Zwol's comment is the correct answer:
device is a local variable within choose_device. To make it accessible
from inside solution_for_phones you will have to pass it there as an
argument.
Here is how that works in code, since from your last comment it seems like you're still confused.
You define solution_for_phones with def solution_for_phones():. But it needs a value for device to work, since it uses device. So first change your function definition to:
def solution_for_phones(device):
Now solution_for_phones requires a value for device to be passed to it to run.
Next you need to make sure that everytime you call solution_for_phones, you pass a value for device. Everywhere in choose_device() where you have solution_for_phones(), you need to replace that with solution_for_phones(device).
You should also probably google something like "python passing values between functions" and read up some more on this, such as the difference between "positional" vs "keyword" parameters of functions.

TypeError: 'DictWriter' object is not iterable

I'm working on creating a short simple program for a nonprofit fundraiser to validate ticket numbers as guests check in to make sure no duplicate tickets are redeemed. I'm running Python 3.4.3 on a Windows 10 machine. Once the program is finalized it will be used on a Raspberry Pi with touchscreen at the fundraiser.
I've tried a couple different methods to build the list, save it, and search for duplicates. Ideally the list will be stored in a CSV file, but a plain text or other format is ok too.
Can you help me with the traceback error (TypeError: 'DictWriter' object is not iterable) due to the looping function to check ticket #'s against a list stored in a file to make sure no duplicate tickets are redeemed?
Thank you in advance for your help!
version = "v1.4"
fname="tickets.csv"
import csv
import datetime
import os.path
print("\nWelcome to TicketCheck", version)
extant = os.path.isfile(fname)
with open(fname, 'a', newline='') as csvfile:
fieldnames = ['ticketid', 'timestamp']
ticketwriter = csv.DictWriter(csvfile, fieldnames=fieldnames)
if extant == False:
ticketwriter.writeheader()
while True:
ticket = ""
print("Please enter a ticket # to continue or type exit to exit:")
ticket = str(input())
if ticket == "":
continue
if ticket == "exit":
break
print("You entered ticket # %s." % (ticket))
print("Validating ticket...")
for row in ticketwriter:
if row[0] == ticket:
print("\n\n\n===== ERROR!!! TICKET # %s ALREADY CHECKED IN =====\n\n\n" % (ticket))
continue
time = datetime.datetime.now()
print("Thank you for checking in ticket # %s at %s \n\n\n" % (ticket, time))
print("Ticket is now validated.")
ticketwriter.writerow({'ticketid': ticket, 'timestamp': time})
csvfile.flush()
continue
csvfile.close()
print("All your work has been saved in %s.\n Thank you for using TicketCheck %s \n" % (fname, version))
Hmm, I think you might be over-complicating this a bit! For something like that there's really no need to go to all that trouble. This is a great spot to use a dictionary, and for something with only two inputs, the id and the check-in time, you can easily just make a .txt log. I get the feeling this might be more of what you are looking for.
import time
go = True
while go:
the_guestlist = {}
the_ticket = input().strip()
file = open('somefile.txt', 'r')
for line in file:
my_items = line.split(',')
the_guestlist[my_items[0]] = my_items[1]
file.close()
if the_ticket in the_guestlist.keys():
print("Sorry, that ticket has been entered at {}".format(the_guestlist[the_ticket]))
elif the_ticket == 'exit':
go = False
print('Exiting...')
else:
the_guestlist[the_ticket] = '{}'.format(time.asctime())
file = open('somefile.txt', 'a')
file.write(the_ticket +','+the_guestlist[the_ticket]+'\n')
file.close()
Objects of the csv.DictWriter class are not iterable, i.e. you cannot iterate over them like you would a dictionary, list, or even string, hence your error message. It does not store the data you have previously written to file, only the file you wrote to stores that data.
To achieve your goal, you could do two things: either open your CSV file every time a new ticket needs to be validated, and check if the ticket number is present, or - since you are using relatively small amounts of data - store a dictionary in memory, and only write it out at the end of use, checking from that if the ticket is valid.

Creating a leaderboard for offline game in Python

For a school project, I'm creating a game that has a score system, and I would like to create some sort of leaderboard. Once finished, the teachers will upload it to a shared server where other students can download a copy of the game, but unfortunately students can't save to that server; if we could, leaderboards would be a piece of cake. There would at most be a few hundred scores to keep track of, and all the computers have access to the internet.
I don't know much about servers or hosting, and I don't know java, html, or any other language commonly used in web development, so other related questions don't really help. My game prints the scoring information to a text file, and from there I don't know how to get it somewhere online that everyone can access.
Is there a way to accomplish such a task with just python?
Here I have the code for updating a leaderboard file (assuming it would just be a text file) once I have the scores. This would assume that I had a copy of the leaderboard and the score file in the same place.
This is the format of my mock-leaderboard (Leaderboards.txt):
Leaderboards
1) JOE 10001
2) ANA 10000
3) JAK 8400
4) AAA 4000
5) ABC 3999
This is what the log-file would print - the initials and score (log.txt):
ABC
3999
Code (works for both python 2.7 and 3.3):
def extract_log_info(log_file = "log.txt"):
with open(log_file, 'r') as log_info:
new_name, new_score = [i.strip('\n') for i in log_info.readlines()[:2]]
new_score = int(new_score)
return new_name, new_score
def update_leaderboards(new_name, new_score, lb_file = "Leaderboards.txt"):
cur_index = None
with open(lb_file, 'r') as lb_info:
lb_lines = lb_info.readlines()
lb_lines_cp = list(lb_lines) # Make a copy for iterating over
for line in lb_lines_cp:
if 'Leaderboards' in line or line == '\n':
continue
# Now we're at the numbers
position, name, score = [ i for i in line.split() ]
if new_score > int(score):
cur_index = lb_lines.index(line)
cur_place = int(position.strip(')'))
break
# If you have reached the bottom of the leaderboard, and there
# are no scores lower than yours
if cur_index is None:
# last_place essentially gets the number of entries thus far
last_place = int(lb_lines[-1].split()[0].strip(')'))
entry = "{}) {}\t{}\n".format((last_place+1), new_name, new_score)
lb_lines.append(entry)
else: # You've found a score you've beaten
entry = "{}) {}\t{}\n".format(cur_place, new_name, new_score)
lb_lines.insert(cur_index, entry)
lb_lines_cp = list(lb_lines) # Make a copy for iterating over
for line in lb_lines_cp[cur_index+1:]:
position, entry_info = line.split(')', 1)
new_entry_info = str(int(position)+1) + ')' + entry_info
lb_lines[lb_lines.index(line)] = new_entry_info
with open(lb_file, 'w') as lb_file_o:
lb_file_o.writelines(lb_lines)
if __name__ == '__main__':
name, score = extract_log_info()
update_leaderboards(name, score)
Some more info:
The score would be less than 1 000 000
Ideally, the solution would just be some code external to the game, so that I would just make an executable that the user would run after they've finished
I know it doesn't sound very secure - and it isn't - but that's ok, it's doesn't need to be hackproof
The easiest is probably to just use MongoDB or something (MongoDB is a NoSQL type database that allows you to save dictionary data easily...)
You can use the free account at https://mongolab.com (that should give you plenty of space).
You will need pymongo as well pip install pymongo.
Then you can simply save records there:
from pymongo import MongoClient, DESCENDING
uri = "mongodb://test1:test1#ds051990.mongolab.com:51990/joran1"
my_db_cli = MongoClient(uri)
db = my_db_cli.joran1 # select the database ...
my_scores = db.scores # this will be created if it doesn't exist!
# add a new score
my_scores.insert({"user_name": "Leeeeroy Jenkins", "score": 124, "time": "11/24/2014 13:43:22"})
my_scores.insert({"user_name": "bob smith", "score": 88, "time": "11/24/2014 13:43:22"})
# get a list of high scores (from best to worst)
print(list(my_scores.find().sort("score", DESCENDING)))
Those credentials will actually work if you want to test the system (keep in mind I added leeroy a few times).

Parsing chat messages as config

I'm trying write a function that would be able to parse out a file with defined messages for a set of replies but am at loss on how to do so.
For example the config file would look:
[Message 1]
1: Hey
How are you?
2: Good, today is a good day.
3: What do you have planned?
Anything special?
4: I am busy working, so nothing in particular.
My calendar is full.
Each new line without a number preceding it is considered part of the reply, just another message in the conversation without waiting for a response.
Thanks
Edit: The config file will contain multiple messages and I would like to have the ability to randomly select from them all. Maybe store each reply from a conversation as a list, then the replies with extra messages can carry the newline then just split them by the newline. I'm not really sure what would be the best operation.
Update:
I've got for the most part this coded up so far:
def parseMessages(filename):
messages = {}
begin_message = lambda x: re.match(r'^(\d)\: (.+)', x)
with open(filename) as f:
for line in f:
m = re.match(r'^\[(.+)\]$', line)
if m:
index = m.group(1)
elif begin_message(line):
begin = begin_message(line).group(2)
else:
cont = line.strip()
else:
# ??
return messages
But now I am stuck on being able to store them into the dict the way I'd like..
How would I get this to store a dict like:
{'Message 1':
{'1': 'How are you?\nHow are you?',
'2': 'Good, today is a good day.',
'3': 'What do you have planned?\nAnything special?',
'4': 'I am busy working, so nothing in particular.\nMy calendar is full'
}
}
Or if anyone has a better idea, I'm open for suggestions.
Once again, thanks.
Update Two
Here is my final code:
import re
def parseMessages(filename):
all_messages = {}
num = None
begin_message = lambda x: re.match(r'^(\d)\: (.+)', x)
with open(filename) as f:
messages = {}
message = []
for line in f:
m = re.match(r'^\[(.+)\]$', line)
if m:
index = m.group(1)
elif begin_message(line):
if num:
messages.update({num: '\n'.join(message)})
all_messages.update({index: messages})
del message[:]
num = int(begin_message(line).group(1))
begin = begin_message(line).group(2)
message.append(begin)
else:
cont = line.strip()
if cont:
message.append(cont)
return all_messages
Doesn't sound too difficult. Almost-Python pseudocode:
for line in configFile:
strip comments from line
if line looks like a section separator:
section = matched section
elsif line looks like the beginning of a reply:
append line to replies[section]
else:
append line to last reply in replies[section][-1]
You may want to use the re module for the "looks like" operation. :)
If you have a relatively small number of strings, why not just supply them as string literals in a dict?
{'How are you?' : 'Good, today is a good day.'}

Categories

Resources