File Writing Python, How to print variable to txt file - python

I am trying to print a variable of a score and name to a .txt file using python.
import random
import csv
import operator
import datetime
now = datetime.datetime.now() ## gets the exact time of when the user begins the test.
def main():
global myRecord
myRecord = []
name = getNames()
myRecord.append(name)
record = quiz()
def getNames(): ## this function grabs first and lastname of the user
firstName = input ("Please enter your first name") ## asks for users name
surName = input("Please enter your surname") ## asks for users suername
space = " "
fullName = firstName + space +surName ## puts data of name together to make full name
print("Hello")
print (fullName)
myRecord.append(fullName)
return fullName ## this is a variable returned to main
def quiz():
print('Welcome. This is a 10 question math quiz\n')
score = 0 ## sets score to 0.
for i in range(10): ## repeats question 10 times
correct = askQuestion()## if the statement above if correct the program asks a question.
if correct:
score += 1## adds one to the score
print('Correct!\n')## prints correct if the user gets a question correct.
else:
print('Incorrect!\n') ## prints incorrect if the user gets a question wrong.
return 'Your score was {}/10'.format(score)
def randomCalc():
ops = {'+':operator.add, ## selects one of the three operators
'-':operator.sub, ## selects one of the three operators
'*':operator.mul,} ## selects one of the three operators
num1 = random.randint(0,12) ## samples a number between 0 and 12
num2 = random.randint(1,10) ## zero are not used to stop diving by zero
op = random.choice(list(ops.keys()))
answer = ops.get(op)(num1,num2)
print('What is {} {} {}?\n'.format(num1, op, num2)) ## puts together the num1, the operator and num2 to form question
return answer
def askQuestion():
answer = randomCalc()
guess = float(input())
return guess == answer
def myfileWrite (myrecord):
with open('Namescore.txt', 'w') as score:
score.write(fullName + '\n')
main()
here is the full code it should ask the users name, print 10 maths questions and then save the time name and score to a txt file
if you can help please do
many thanks

Your indentation is incorrect and you never actually call the function:
with open('Namescore.txt', 'w') as score:
score.write(fullName + '\n')

the code you wrote would IIRC re-make the file each time you ran the code. I believe this is the correct way to do it:
with open("Namescore.txt", "a") as file:
file.write(name, score, "\n") # I don't know what your vars are called
This will append to the file rather than rewrite :)
If you want to do it your way, the correct way would be:
def writeScore(name, score):
file = open("Namescore.txt", "a")
file.write(name, score, "\n")
file.close()
writeScore("Example Examlpus", 201)

Related

How do I get a python quiz to randomize questions?

My task is to make a quiz using python, with questions being stored in an external file. However, I can not figure out how to get my questions to randomize and only display 10 at a time out of the 20 possible
I have tried using import random however the syntax random.shuffle(question) does not seem to be valid. I am not sure what to do now.
The question.txt file is laid out as:
Category
Question
Answer
Answer
Answer
Answer
Correct Answer
Explanation
My code:
#allows program to know how file should be read
def open_file(file_name, mode):
"""Open a file."""
try:
the_file = open(file_name, mode)
except IOError as e:
print("Unable to open the file", file_name, "Ending program.\n", e)
input("\n\nPress the enter key to exit.")
sys.exit()
else:
return the_file
def next_line(the_file):
"""Return next line from the trivia file, formatted."""
line = the_file.readline()
line = line.replace("/", "\n")
return line
#defines block of data
def next_block(the_file):
"""Return the next block of data from the trivia file."""
category = next_line(the_file)
question = next_line(the_file)
answers = []
for i in range(4):
answers.append(next_line(the_file))
correct = next_line(the_file)
if correct:
correct = correct[0]
explanation = next_line(the_file)
time.sleep(1.5)
#beginning of quiz questions
def main():
trivia_file = open_file("trivia.txt", "r")
title = next_line(trivia_file)
welcome(title)
score = 0
# get first block
category, question, answers, correct, explanation = next_block(trivia_file)
while category:
# ask a question
print(category)
print(question)
for i in range(4):
print("\t", i + 1, "-", answers[i])
# get answer
answer = input("What's your answer?: ")
# check answer
if answer == correct:
print("\nCorrect!", end=" ")
score += 1
else:
print("\nWrong.", end=" ")
print(explanation)
print("Score:", score, "\n\n")
# get next block
category, question, answers, correct, explanation = next_block(trivia_file)
trivia_file.close()
print("That was the last question!")
print("Your final score is", score)
main()
That is most of the code associated with the program. I will be very grateful for any support available.
You can read the file and group its contents into blocks of eight. To generate unique random questions, you can use random.shuffle and then list slicing to create the groups of questions. Also, it is cleaner to use a collections.namedtuple to form the attributes of the question for use later:
import random, collections
data = [i.strip('\n') for i in open('filename.txt')]
questions = [data[i:i+8] for i in range(0, len(data), 8)]
random.shuffle(questions)
question = collections.namedtuple('question', ['category', 'question', 'answers', 'correct', 'explanation'])
final_questions = [question(*i[:2], i[2:6], *i[6:]) for i in questions]
Now, to create the groups of 10:
group_questions = [final_questions[i:i+10] for i in range(0, len(final_questions), 10)]
The result will be a list of lists containing the namedtuple objects:
[[question(category='Category', question='Question', answers=['Answer', 'Answer', 'Answer', 'Answer'], correct='Correct Answer', explanation='Explanation ')]]
To get the desired values from each namedtuple, you can lookup the attributes:
category, question = question.category, question.question
Etc.

Getting my Python program to run Power Shell Script

Hello please forgive me if my question duplicate, I've searched previous questions and nothing seems to be quite the same. I'm working on a program that will scan a specific folder and search for specific file types to create a menu for a user to select. Once the user select the menu option the the corresponding file which is a power shell script. Currently My program does everything but run even a simple power shell script. I've attempted several configuration and it's not working. It would be great if someone can see what I may be doing wrong or provide me with some pointers. Code below.
##Text Menu Dynamic test
##version 1
## Created By Dragonshadow
## Code produce in Notpad++ For python v3.4.4
import os
import subprocess
import time
import pathlib
import logging
import fnmatch
import re
## Directory Enumerator
fileFolderLocationFilter = fnmatch.filter(os.listdir('C:\\Users\\myfolder\\Documents\\Automation_Scripts\\ENScripts\\'),"*.ps1")
selectedFile=""
## Menu defined setting veriables
def ENOC_menu():
files = fileFolderLocationFilter
counter = 1
print (20 * "=" , "Enoc Quick Menu" , 20 * "=")
enumFiles = list(enumerate(files))
for counter, value in enumFiles:
str = repr(counter) + ") " + repr(value);
print(str)
str = repr(counter+1) + ") Exit";
print(str)
print (57 * "_")
str = "Enter your choice [1 - " + repr((counter+1)) + "]:"
choice = int(input("Please Enter a Selection: "))
selectedFiles = enumFiles[choice]
return(selectedFiles[1])
if choice > counter :
choice = -1
elif choice != counter :
print("Please selecte a valid choice")
else:
selectedFiles = enumFiles[choice]
print(selectedFiles[1])
##selectedFiles = selectedFiles[1]
return choice
def you_sure():
opt = input("Are you sure Yes or No: ")
if opt=="Yes":
print("Continuing please wait this may take a moment...")
elif opt=="No":
print("returnig to Enoc Menu")
else: ##Stays in loop
print ("Please choose yes or no")
##count_down
def count_down ():
count_down = 10
while (count_down >= 0):
print(count_down)
count_down -= 1
if count_down == 0:
print("Task will continue")
break
##initiating loop
loop = True
while loop:
choice = ENOC_menu()
print ("\n" +"You selected "+ choice +"\n")
subprocess.call("C:\\WINDOWS\\system32\\WindowsPowerShell\\v1.0\\powershell.exe" + choice, shell=True)
##print ("---" +str(selectedFile))
You have probably already figured this out, but I the problem is in the subprocess.call() line. You are concatenating the powershell.exe path and the target file name together. See here:
>>> scriptToRun = "c:\\users\\Username\\Documents\\WindowsPowerShell\\classtestscript.ps1"
>>> powershellExe = "c:\\windows\\system32\\windowspowershell\\v1.0\\powershell.exe"
>>> print(powershellExe + scriptToRun)
c:\windows\system32\windowspowershell\v1.0\powershell.exec:\users\Username\Documents\WindowsPowerShell\classtestscript.ps1
Above, the two strings are stuck together without a space between them. Windows can't make sense of what you're trying to execute.
Put a space between the two two and subprocess.call() will understand what you're trying to do:
>>> print(powershellExe + ' ' + scriptToRun)
c:\windows\system32\windowspowershell\v1.0\powershell.exe c:\users\Username\Documents\WindowsPowerShell\classtestscript.ps1

Python 3 Unit tests with user input

I'm absolutely brand new to Python unit test. I need to use it for a project I have to submit. I sort of have an idea of where to begin, it looks like we basically put in test parameters to functions we have defined in our program and we enter the expected result. If the expected result is output, we get OK, otherwise we will get Failure, or an error.
So my problem is that I have multiple user inputs stored into variables that are within for loops or while loops. I don't know where to even begin with this to set test values in for them.
Here is all of my code:
studentTripExpenses = {}
def dictCreate(studentAmount):
for i in range(0, studentAmount):
studentName = input("What is the name of the student? ")
expenseList = []
print("Enter 'done' to move to the next student.")
while True:
expense = input("What is the cost of this expense? ")
if expense.lower() == 'done':
break
elif (float(expense) >= 0) or (float(expense) < 0):
expenseList.append(float(expense))
elif not expense.isdigit():
print("Please enter a number or enter 'done' to move on.")
studentTripExpenses[studentName] = expenseList
return studentTripExpenses
def studentCost(dct):
for i in dct:
#Variable for individual costs of student
personalCost = 0
#Determines the total cost for each student
for x in dct[i]:
personalCost = personalCost + x
#Sets each students value to their total cost to two decimal places
dct[i] = float("%.2f" % personalCost)
return dct
def amountsDue(expenseLst, studentAvgPrice):
#Runs through the dictionary of students and individual total trip costs
for key in expenseLst:
maxPerson = max(expenseLst, key=expenseLst.get)
costDifference = 0
#Determines who owes who how much money
if max(expenseLst.values()) > expenseLst[key]:
costDifference = studentAvgPrice-expenseLst[key]
if (costDifference < 0):
costDifference = costDifference * -1
print("%s owes %s $%.2f" % (key, maxPerson, costDifference))
def main():
numOfStudents = int(input("How many students are going on the trip? "))
studentCostDict = dictCreate(numOfStudents)
studentTripExpenses = studentCost(studentCostDict)
totalCost = 0
#Gets the total cost for all students
for key in (studentTripExpenses):
totalCost = totalCost + studentTripExpenses[key]
#Changes the total cost to 2 decimal places
totalCost = float("%.2f" % totalCost)
#Determines the average amount spent per student
avgCost = float("%.2f" % (totalCost/len(studentTripExpenses)))
amountsDue(studentTripExpenses, avgCost)
main()
You can use mocking, where you replace a function or class with a test-supplied version. You can do this with the unittest.mock() module.
In this case, you can patch the input() name in your module; instead of the built-in function, the mock object will be called:
from unittest import mock
from unittest import TestCase
import module_under_test
class DictCreateTests(TestCase):
#mock.patch('module_under_test.input', create=True)
def testdictCreateSimple(self, mocked_input):
mocked_input.side_effect = ['Albert Einstein', '42.81', 'done']
result = dictCreate(1)
self.assertEqual(result, {'Albert Einstein': [42.81]})
Because input doesn't exist in your module (it is a built-in function), I told the mock.patch() decorator to create the name; now this input will be used instead of the built-in function.
The side_effect attribute lets you state multiple results; each time the mock is called, it'll return the next value in that list. So the first time 'Albert Einstein' is returned, the next time '42.81', etc.
Together, this lets you simulate actual user inputs.
If you do your test right, you'll notice that there is a bug in your function; the float() call will throw a ValueError exception when anything other than done or a valid numeric value is entered. You need to rework your code to account for that. Try with mocked_input.side_effect = ['Albert Einstein', 'Not an expense', '42.81', 'done'] to trigger the bug.
In case we do not have classes.
In the names.py file, we have the get_names function.
def get_names() -> list:
names = [str(input("Enter name: "))]
while str(input("Do you want to add another name")) == "Y":
names.append(str(input("Enter name: ")))
return categories
In the test_names.py file, we can write test like the following
import numpy as np
from unittest import mock
from src.main.names import get_names
#mock.patch('src.main.names.input', create=True)
def test_should_get_names_from_users(mocked_input):
mocked_input.side_effect = ["John", "Y", "Robert", "N"]
actual_names = get_names()
expected_names = ['John', "Robert"]
assert actual_names == expected_names

Saving of Information in Python Along with Retrieving It

The purpose of the two programs is to have twitter.py manage tweet.py by having the 5 most recent tweets that are saved in the program twitter.py to show up once you search and find it. There are four options, make a tweet, view recents tweets, search a tweet and quit. I'm having trouble saving because it keeps saying no recent tweets are found. Also I'm having trouble with the fact that I can't search for my tweets but that is probably the same reason as my first problem because they aren't being saved correctly. Thank you please help!!
tweet.py
import time
class tweet:
def __init__(self, author, text):
self.__author = author
self.__text = text
self.__age = time.time()
def get_author(self):
return self.__author
def get_text(self):
return self.__text
def get_age(self):
now = time.time()
difference = now - self.__time
hours = difference // 3600
difference = difference % 3600
minutes = difference // 60
seconds = difference % 60
# Truncate units of time and convert them to strings for output
hours = str(int(hours))
minutes = str(int(minutes))
seconds = str(int(seconds))
# Return formatted units of time
return hours + ":" + minutes + ":" + seconds
twitter.py
import tweet
import pickle
MAKE=1
VIEW=2
SEARCH=3
QUIT=4
FILENAME = 'tweets.dat'
def main():
mytweets = load_tweets()
choice = 0
while choice != QUIT:
choice = get_menu_choice()
if choice == MAKE:
add(mytweets)
elif choice == VIEW:
recent(mytweets)
elif choice == SEARCH:
find(mytweets)
else:
print("\nThanks for using the Twitter manager!")
save_tweets(mytweets)
def load_tweets():
try:
input_file = open(FILENAME, 'rb')
tweet_dct = pickle.load(input_file)
input_file.close()
except IOError:
tweet_dct = {}
return tweet_dct
def get_menu_choice():
print()
print('Tweet Menu')
print("----------")
print("1. Make a Tweet")
print("2. View Recent Tweets")
print("3. Search Tweets")
print("4. Quit")
print()
try:
choice = int(input("What would you like to do? "))
if choice < MAKE or choice > QUIT:
print("\nPlease select a valid option.")
except ValueError:
print("\nPlease enter a numeric value.")
return choice
def add(mytweets):
author = input("\nWhat is your name? ")
while True:
text = input("what would you like to tweet? ")
if len(text) > 140:
print("\ntweets can only be 140 characters!")
continue
else:
break
entry = tweet.tweet(author, text)
print("\nYour tweet has been saved!")
def recent(mytweets):
print("\nRecent Tweets")
print("-------------")
if len(mytweets) == 0:
print("There are no recent tweets. \n")
else:
for tweets in mytweets[-5]:
print(tweets.get_author, "-", tweets.get_age)
print(tweets.get_text, "\n")
def find(mytweets):
author = input("What would you like to search for? ")
if author in mytweets:
print("\nSearch Results")
print("----------------")
print(tweet.tweet.get_author(), - tweet.tweet.get_age())
print(tweet.tweet.get_text())
else:
print("\nSearch Results")
print("--------------")
print("No tweets contained ", author)
def save_tweets(mytweets):
output_file = open(FILENAME, 'wb')
pickle.dump(mytweets, output_file)
output_file.close()
main()
In twitter.py:add_tweets, mytweets is passed into the function and entry is created, but it is never added to mytweets. The created entry is lost after the function returns.
Your question was:
I'm having trouble saving because it keeps saying no recent tweets are
found.
Function add does not seem to be adding tweets anywhere. It creates a tweet.tweet instance, but it does not do anything with it.
You probably want to add the tweet to mytweets?
Another problem:
You initialize mytweets as a dicionary (tweet_dct = {}), but later you use it as a list (mytweets[-5]). It should be a list from start. And you probably want last five tweets (mytweets[-5:]), not just the fifth from the end.
On the sidenotes:
What you have here is not "two programs" - it is one program in two python files, or "modules"
Although there is nothing wrong with having getters (functions like get_author), there is no need for them in Python (see How does the #property decorator work?). Do youself a favour and keep it simple, e.g.:
class Tweet:
def __init__(self, author, text):
self.author = author
self.text = text
self.creation_time = time.time()
def get_age_as_string(self):
# your code from get_age
There will be time when you need private variables. When that happens, use a single leading underscore (self._author) until you fully understand what double underscore does and why.
Pickle is probably not the best way to store information here, but it is a good start for learning.

How do I allow only the latest inputs to be saved - Python

How do I implement a simple code that will only save the student's latest 3 scores? If the test is repeated later, the old score should be replaced.
Thank you.
This is the code that asks the user the questions and saves the results in the txt. files.
import random
import math
import operator as op
correct_answers = 0
def test():
num1 = random.randint(1, 10)
num2 = random.randint(1, 10)
ops = {
'+': op.add,
'-': op.sub,
'*': op.mul,
}
keys = list(ops.keys())
rand_key = random.choice(keys)
operation = ops[rand_key]
correct_result = operation(num1, num2)
print ("What is {} {} {}?".format(num1, rand_key, num2))
user_answer= int(input("Your answer: "))
if user_answer != correct_result:
print ("Incorrect. The right answer is {}".format(correct_result))
return False
else:
print("Correct!")
return True
username = input("What is your name? ")
print("Hi {}! Welcome to the Arithmetic quiz...".format(username))
class_name = input("Are you in class 1, 2 or 3? ")
correct_answers = 0
num_questions = 10
for i in range(num_questions):
if test():
correct_answers +=1
print("{}: You got {}/{} questions correct.".format(
username,
correct_answers,
num_questions,
))
class_name = class_name + ".txt" #creates a txt file called the class that the user entered earlier on in the quiz.
file = open(class_name , 'a') #These few lines open and then write the username and the marks of the student into the txt file.
name = (username)
file.write(str(username + " : " ))
file.write(str(correct_answers))
file.write('\n') #This puts each different entry on a different line.
file.close() #This closes the file once the infrmation has been written.
A much better solution would be to store the data in a different format that made everything easy. For example, if you used a shelve database that mapped each username to a deque of answers, the whole thing would be this simple:
with shelve.open(class_name) as db:
answers = db.get(username, collections.deque(maxlen=3))
answers.append(correct_answers)
db[username] = answers
But if you can't change the data format, and you need to just append new lines to the end of a human-readable text file, then the only want to find out if there are already 3 answers is to read through every line in the file to see how many are already there. For example:
past_answers = []
with open(class_name) as f:
for i, line in enumerate(f):
# rsplit(…,1) instead of split so users who call
# themselves 'I Rock : 99999' can't cheat the system
name, answers = line.rsplit(' : ', 1)
if name == username:
past_answers.append(i)
And if there were 3 past answers, you have to rewrite the file, skipping line #i. This is the really fun part; text files aren't random-access-editable, so the best you can do is either read it all into memory and write it back out, or copy it all to a temporary file and move it over the original. Like this:
excess_answers = set(past_answers[:-2])
if excess_answers:
with open(class_name) as fin, tempfile.NamedTemporaryFile() as fout:
for i, line in enumerate(fin):
if i not in excess_answers:
fout.write(line)
os.replace(fout.name, fin)
That part is untested. And it requires Python 3.3+; if you have an earlier version and are on Mac or Linux you can just use os.rename instead of replace, but if you're on Windows… you need to do some research, because it's ugly and no fun.
And now, you can finally just append the new answer, as you're already doing.

Categories

Resources