Why is my dictionary not updating in this while loop? - python

Running: Python 3.9.9 and Django 4
I'm trying to put together a loop that waits for a users input and then appends that input to an existing dictionary. See code below:
def calculator(request):
loop_int = 1
numbers = [str(x) for x in range(0,10)]
i = "1"
current_nums = {'1':[],'2':[]}
if request.GET: #wait for request.GET to return True before starting while loop
while loop_int < 10:
r = request.GET #store request.GET object as r
if r: #this is here to stop the loop and wait for request.GET to return True
print(r)
if list(r.values())[0] in numbers:
digit = list(r.values())[0] #grab the value from request.GET
current_nums[i].append(digit) #append that value to the list at "1" in current_nums dictionary
print(f'digit = {digit}')
print(f'current_nums = {current_nums}')
loop_int += 1 #increment the loop_int
request.GET = None
return render(request, 'calculator/calculator.html')
The last print statement print(f'current_nums={current_nums}') displays the updated dictionary that I expect, but the appended digits don't persist through the next iteration of the loop. Code output below:
<QueryDict: {'1': ['1']}>
digit = 1
current_nums = {'1': ['1'], '2': []}
<QueryDict: {'2': ['2']}>
digit = 2
current_nums = {'1': ['2'], '2': []}
This file is a views.py file for a Django project. I'm having no issues (as far as I can tell) getting the information from the front end using request.GET.
One odd thing I discovered is that if I remove the statement request.GET = None at the end of the loop, which allows the loop to run uninterrupted with the same value for request.GET, then the program works as intended for the next 9 iterations and the dictionary updates persist. However, as soon as I try to set request.GET = None to pause the loop and wait for a legitimate user input, the dictionary updates stop persisting.
Am I making a simple scope error? Or is there a nuance to request.GET that I'm missing?

Your problem is that you put current_nums in the view function, and every time a request comes in, it will be initialized.
You can put it outside the view function, like below, and it will save the data added with each request.
class Data:
loop_int = 1
current_nums = {'1':[],'2':[]}
numbers = [str(x) for x in range(0,10)]
def calculator(request):
i = "1"
if request.GET and Data.loop_int < 10: #wait for request.GET to return True before starting while loop
r = request.GET #store request.GET object as r
print(r)
if list(r.values())[0] in Data.numbers:
digit = list(r.values())[0] #grab the value from request.GET
Data.current_nums[i].append(digit) #append that value to the list at "1" in current_nums dictionary
print(f'digit = {digit}')
print(f'current_nums = {Data.current_nums}')
Data.loop_int += 1 #increment the loop_int
return render(request, 'calculator/calculator.html')
You can still use it for a single person to test locally. If it involves multiple concurrency, you need to lock it.

Related

Inconsistent Behaviour while executing a Background Task in Flask Web App

I am creating a flask web app which has a background task of making an API Calls every x seconds.The interval is decided based on a value coming from the API,if the value is True then and if the database don't have any data for counter it will insert a counter value 1.If it has a counter value it will increment the counter and update it on the database and the next call for this task will be after 40 seconds but if it is false the the next call will be in 10 seconds.Here is my code
import time
import threading
def writemotiondata():
processing = False
while True:
deviceid = 'eb4f7839b63063bdec3ikc'
openapi = authorization()
openapi.connect()
response = openapi.get("/v1.0/devices/{}".format(deviceid))
result = response['result']
status = result['status']
value = status[0]['value']
print(value)
if (value == True):
tempdata = motiondata.find()
previousdata = [{item: key[item] for item in key if item != '_id'} for key in tempdata]
if len(previousdata) == 0:
data = {"sensorname": "pir",
"numberofpeople": 1}
motiondata.insert_one(data).inserted_id
else:
count = previousdata[0]['numberofpeople']
count += 1
filter = {"sensorname": "pir"}
updateddata = {"$set": {"numberofpeople": count}}
motiondata.update_one(filter, updateddata)
time.sleep(40)
else:
time.sleep(10)
if __name__ == '__main__':
t1 = threading.Thread(target=writemotiondata)
t1.start()
app.run(debug=True)
Here the expected output is if the value is True the task should increment the counter and update the database.For example if the previous count was 1,after completing the task the new count should be 2 and the task should be called to execute again in 40 seconds. If the value is false the task will be called again in 10 seconds.
However The output I am getting is the counter in my database gets incremented inconsistently,sometimes it gets incremented by 1 ,sometimes it gets incremented by 2 or 3.I have printed out the value and saw in 40 seconds sometimes the value true is being printed 2/3 times instead of one,same goes for false.Basically the task is being executed more than once,in that time interval.Can anyone please help me figure out why is this happening and what I am doing wrong.
I am using a single thread,no more threads has been used in the code.

Trying to produce correct recursion

Didn't know who to ask at this time of night. But I'm trying to implement recursion for the first time with not much background knowledge. I am getting some result on the right track but the program is now in an infinite loop.
def url_open(url, count, position):
for i in range(count):
newURL = 0
html = urlopen(url, context=ctx).read()
soup = BeautifulSoup(html, "html.parser")
tags = soup.find_all("a")
newURL = dict_populate(tags, position)
url_open(newURL, count - 1, position)
def dict_populate(tags, position):
workingCOUNT = 0
workingDICT = {}
newURL = 0
for tag in tags:
workingCOUNT += 1
for key,value in tag.attrs.items():
workingDICT[workingCOUNT] = value
new = workingDICT[position]
return new
url = input("Enter - ")
var1 = input("Enter count - ")
var2 = input("Enter position - ")
searchCOUNT = int(var1)
urlPOSI = int(var2)
url_open(url, searchCOUNT, urlPOSI)
print("The last url retrieved: ", url)
It works with low values of count 1, 2, 3, but over that it gets into an infinite loop.
Any suggestions?
EDIT:
I have posted the whole program.
This program parses webpage for a URL. The website that I'm asked to use is a website that contains links to other websites of the same links but in different order. I need to find the url in position n and that repeat the process for n other websites until I find the last one.
Have a look at while statement.
While Loops is used to execute a block of statements repeatedly until a given condition is satisfied.
# assign a default value to a variable called "count"
count = 0
# iterate until test expression is False
while (count < 5):
count += 1;
# print results
print("count is :" + str(count) )
Output:
count is :1
count is :2
count is :3
count is :4
count is :5
Obviously, you can manage while statements inside a for loop.
for item in my_items_list:
while some_conditions:
# do something here

Find_between function with indexed output?

I'd like to use the find_between function to retrieve index-able values from a specific web server.
I'm using the requests module to gather some source code from a specific website seen on line 18:
response = requests.get("https://www.shodan.io/search?query=Server%3A+SQ-WEBCAM")
and I'd like to call the find_between function to retrieve all the values (all items on page each item represented by the incrementing value of 'n') with the specified find_between parameters:
x = find_between(response.content,'/></a><a href="/host/','">---')
Anyone know how to pull this off?
import sys
import requests
from time import sleep
# Find between page tags on page.
def find_between( s, tag1, tag2 ):
try:
start = s.index( tag1 ) + len( tag1 )
end = s.index( tag2, start )
return s[start:end]
except ValueError:
return ""
def main():
# Default value for 'n' index value (item on page) is 0
n = 0
# Enter the command 'go' to start
cmd = raw_input("Enter Command: ")
if cmd == "go":
print "go!"
# Go to this page for page item gathering.
response = requests.get("https://www.shodan.io/search?query=Server%3A+SQ-WEBCAM")
# Initial source output...
print response.content
# Find between value of 'x' sources between two tags
x = find_between(response.content,'/></a><a href="/host/','">---')
while(True):
# Wait one second before continuing...
sleep(1)
n = n + 1
# Display find_between data in 'x'
print "\nindex: %s\n\n%s\n" % (n, x)
# Enter 'exit' to exit script
if cmd == "exit":
sys.exit()
# Recursive function call
while(True):
main()
A few things in your code appear to need addressing:
The value of x is set outside (before) your while loop, so the loop increments the index n but prints the same text over and over because x never changes.
find_between() returns only a single match, and you want all matches.
Your while loop never ends.
Suggestions:
Put the call to find_between() inside the while loop.
Each successive time you call find_between(), pass it only the portion of the text following the previous match.
Exit the while loop when find_between() finds no match.
Something like this:
text_to_search = response.content
while(True):
# Find between value of 'x' sources between two tags
x = find_between(text_to_search, '/></a><a href="/host/', '">---')
if not x:
break
# Wait one second before continuing...
sleep(1)
# Increment 'n' for index value of item on page
n = n + 1
# Display find_between data in 'x'
print "\nindex: %s\n\n%s\n" % (n, x)
# Remove text already searched
found_text_pos = text_to_search.index(x) + len(x)
text_to_search = text_to_search[found_text_pos:]

if statement only executes else block

I am making a program which makes a mark list with a letter grade in python.
But the problem is the if-else statements to decide letter grade is only executing else statement when given inputs. But the if statement for 'A+' grade is working if maximum marks are given. I am a newbie and I can't understand where the bug is, please help. Below is my python code, here datails.html collects information from the user and mark list is displayed in the results.html page.
from flask import Flask, render_template, request
app=Flask(__name__)
#app.route("/")
def index():
return render_template('details.html')
#app.route("/send",methods=['POST','GET'])
def send():
if(request.method=='POST'):
getname=request.form['name']
getregno=request.form['regno']
getcollege=request.form['college']
getsem=request.form['sem']
getsub1=request.form['sub1']
getsub1m=request.form['sub1m']
getsub2=request.form['sub2']
getsub2m=request.form['sub2m']
getsub3=request.form['sub3']
getsub3m=request.form['sub3m']
getsub4=request.form['sub4']
getsub4m=request.form['sub4m']
malayalam_mark = int(getsub1)
malayalam_maxmark = int(getsub1m)
english_mark = int(getsub2)
english_maxmark = int(getsub2m)
maths_mark = int(getsub3)
maths_maxmark = int(getsub3m)
computer_mark = int(getsub4)
computer_maxmark = int(getsub4m)
percent_malayalam = malayalam_mark/malayalam_maxmark*100
percent_english = english_mark/english_maxmark*100
percent_maths = maths_mark/maths_maxmark*100
percent_computer = computer_mark/computer_maxmark*100
slist= [percent_malayalam,percent_english,percent_maths,percent_computer]
result_list=[]
for i in slist:
if i>=50 and i<58:
grade='D+'
result='pass'
elif i>=58 and i<65:
grade='C'
result='Pass'
elif i>=65 and i<72:
grade='C+'
result='Pass'
elif i>=72 and i<79:
grade='B'
result='Pass'
elif i>=79 and i<86:
grade='B+'
result='Pass'
elif i>=86 and i<93:
grade='A'
result='Pass'
elif i>=93 and i<=100:
grade='A+'
result='Pass'
else:
grade='D'
result='Fail'
result_list.append(grade)
result_list.append(result)
return render_template('/results.html',list=result_list,a=getname,b=getregno,c=getsem,d=getcollege,e=getsub1,e1=getsub1m,f=getsub2,f1=getsub2m,g=getsub3,g1=getsub3m,h=getsub4,h1=getsub4m)
if(__name__=='__main__'):
app.run(debug=True)
I am including a result page, here I included the final list in the bottom for reference, you can find that every input gives grade 'D' and result 'Fail' except maximum marks.
I guess this is being run in Python 2 which doesn't automatically promote integer division. If you rearrange your calculations like:
percent_malayalam = malayalam_mark * 100 / malayalam_maxmark
you might get the right answer… Previously all non-100% results were being (implicitly) rounded to 0%. 2 / 3 in Python 2 will be 0, not ~0.6. The defaults have been changed in Python 3 so it tends to do the right thing more often.
You could then read about integer division in Python 2 from various places, here's one at this site: What is the difference between '/' and '//' when used for division?

Django Views Incrementing Variables

When I increment one of my variables, it only goes up to 2 instead of 3. The default value is 1. I am not sure what I am missing. Any help is appreciated.
def unanswered(request, template ='unanswered.html'):
phone_number = Pool.objects.order_by('?')[0]
pool = Pool.objects.order_by('?')[0]
pool_list = Pool.objects.all()
number_attempts = Pool.objects.filter(phone_number=phone_number).count()
# unanswer number action
if pool_list:
if number_attempts > 3:
return number_attempts
else:
x = number_attempts
x += 1
print x 'returns 2'
store = Pool(id=phone_number.id,
phone_number = phone_number.phone_number,
un_answered=x, answered=0)
store.save()
payload = {'pool':pool,}
return render_to_response(template, payload, context_instance=RequestContext(request))
There is no any for loop or while loop in your code, so if initial number_attempts is 1, it will incremented to 2 and complete the flow.
I see you want to store attempts in the DB, but the way you are doing is not correct. You are passing id=phone_number.id to Store(...), which will try to update existing record if exists with given id. So Pool.objects.filter(phone_number=phone_number).count() always returns 1.
You may want to change it to
store = Pool(phone_number = phone_number.phone_number,
un_answered=x, answered=0)
So for the next request, Pool.objects.filter(phone_number=phone_number).count() will give you 2.
Update after the comment:
All I want is to update the un_answered field from 1,2,3.
In that case, don't use .count() to get number of failed attempts use the field from object that has that counter.
So instead of
number_attempts = Pool.objects.filter(phone_number=phone_number).count()
you can do this
try:
store = Pool.objects.get(phone_number=phone_number)
number_attempts = store.un_answered
# FIX : the original code used a bare except clause.
# Bare except clauses are EVIL. DONT use bare except clauses. NEVER.
# Or thou shall burn in the flames of hell for your eternal death....
except Pool.DoesNotExist:
store = Pool(phone_number = phone_number.phone_number,
un_answered=1, answered=0)
store.save()
number_attempts = 1
...
if pool_list:
if number_attempts > 3:
return number_attempts
else:
x = number_attempts
x += 1
print x 'returns 2'
store.un_answered = x
store.save()

Categories