I'm quite new to Python/Flask and am writing a little script for some home automation I'm playing with.
At the moment, there's a route in my script that gets run by a cron job. This sniffs for bluetooth packets to see who's in and who's out of the house so I can control the heating. There's a row in my table for each person and a status which is either In or Out.
This works perfectly.
I've got another route to read the values back and display either a green or red bar on my dashboard depending on if they're in or out.
It's reading the values and doing some logic that I'm having problems with.
If I get the status for a person and display it on my dashboard (created with an HTML template), the value it displays is:
('In',)
In the MySQL table it's just In - no quotes or parentheses.
In my Python script I have:
conn = MySQLdb.connect(host="localhost", user = "*****", passwd = "*****", db = "mydb")
cursor = conn.cursor()
cursor.execute("select status from occupants WHERE id = '1'")
data = cursor.fetchone()
result = data
#result = str(result)
if (result == "In"):
result = "In"
else:
result = "Out"
This always returns Out.
I've tried various things in my if statement but I obviously haven't hit the right one. I've even tried:
if (result == "('In',)")
But even this returns Out.
Starting to tear my hair out now as I've been searching and playing for about 2 days just on this.
Any ideas gratefully received!
You need to get the value by index.
Python returns tuples for the rows.You need to get the first column.
Just get the value by index, data[0]
Then you go on with comparison.
Edit: when you use the "in" operators, you are just looping through the tuple.
It works buts not a good idea, when you already know for sure, the data you are looking for is at index 0.
You are using cursor.fetchone(), which returns a tuple or None(if element not found). So what you are receiving after executing the command is a tuple with only one element, which makes lesser sense in this context, but that is how this Python API returns data. So even after using fetchone() you need to access the first element explicitly, which can be done as lst[0]. So you need to change the line as:
result = ""
if data is not None:
result = data[0]
print result
You have more Data in "result" then just "In". For example:
a = ["yes", "hello"]
b = "no"
if "yes" == a:
print("yes yes yes")
else:
print("Something is wrong")
This gives you "Something is wrong" as output, but if you do:
a = ["yes", "hello"]
b = "no"
if "yes" in a:
print("yes yes yes")
else:
print("Something is wrong")
Now you get "yes yes yes" as output. Hope this helps a bit :)
Agree with Abhijith; indexing would be a better idea.
It's likely the result of you database query should look like this:
database_query_result = [('In',)]
If that's the case, you could just grab the occupants status like the below to get the answer you desire without a logical comparison.
result = database_query_result[0][0]
print(result)
Why this works:
database_query_result[0] gives you the tuple -> ('In', )
database_query_result[0][0] gives you the tuple's value. -> 'In'
Ok, as always, 5 minutes after posting, I try something different and get it working. However, I'm not sure if this is a fudge or if it's a valid thing to do:
if 'In' in result:
This now works.
For the purposes of this exercise, it doesn't really matter if it's a dirty workround but I'd like to know if there's a more elegant/conventional solution just for my learning.
Related
I'm trying to make a registration module to use in a larger login/authentication program and I need to make a function that can check if a username already exists in a collection.
I haven't tried much more than this, this is my first real programming project and I'm stuck on this part. I realize I could use in-line dictionary databases, but I want to learn how to integrate 3rd party databases with my programming.
from pymongo import MongoClient
import time
client = MongoClient('localhost', 27017)
loginDB = client["loginDB"]
userCol = loginDB["userCol"]
##Username##
print('Choose A Unique Username')
time.sleep(1.2)
unameInput = input("Enter Username: ")
unameList = {'Username': unameInput}
unameQuery = {}
unameQuery2 = userCol.find_one({'Username.Username': {'$gt': 'a'}})
if unameInput != unameQuery2:
print('Name is Available | Accepted!')
allList = {'Username': unameList}
userCol.insert_one(allList)
else:
print('Sorry, Please Try Again.')`
The expected result is to search the database for everything that starts with the letter "a", forward. If the input (unameInput) does not equal anything in the query result (unameQuery2), then print "Username is available". If anything in the query matches the input, then print "Please try again", however, it's accepting everything that is input and exiting the code.
You are using find_one() to find one entry in Username and then checking if unameInput is equal to it. If it's not an exact match, it will execute the code for name is available.
Try find() instead as this will iterate over all the documents in the collection.
unameQuery2 = userCol.find()
if unameInput not in unameQuery2:
# do something
I figured it out, I was putting dictionaries inside of dictionaries inside of documents, as well as not iterating "allList".
I recently started to develop with odoo8 and I've met a problem.
My problem is that I have two classes : 'helpdesk' and 'res_partner' and I don't know why my code stuck for a long time when I create a new record in 'res_partner' but when I comment this block of codes (below) my code works great.
self.env['res.partner'].create({
'name': nameFmt,
'firstname': self.firstNameOfUser.strip().lower().title(),
'lastname': self.lastNameOfUser.strip().upper(),
'birthdate': newDateFmt,
'birth_place': self.pBirthOfUser,
'is_company': False
})
'helpdesk' class has several fields and methods to get information, and computes them from the user inputs. Once the information computed, I create my record which is a new partner.
How I tried to solve my problem, I :
Launched odoo in shell mode with '--debug' option and a pdb where the code is stuck (it's stuck at the 'create' method as I said)
Read some threads and documentations about my problem, but most are in v7 for the create method and anybody has been stuck like this for the creation of a record
Checked each value that I sent to create my new record
Saw the behavior of records and how they are stored with phpPgAdmin
For more information, this is my entire method definition :
#api.one
def addPartnerInDB(self):
if (not self.firstNameOfUser or
not self.lastNameOfUser or
not self.dobOfUser or
not self.pBirthOfUser):
raise ValidationError(u"Tous les champs sp\u00E9cifi\u00E9s pour "
u"cette demande doivent \u00EAtre remplis !")
# Avoid concurrent drop-down
self.dropDownList1 = False
self.dropDownList3 = False
# Get every partners
listOfPartners = self.env['res.partner'].search(
[
('is_company', '=', False)
]
)
# Avoid useless compute for each iteration
newDateFmt = u"".join(datetime.datetime\
.strptime(str(self.dobOfUser), "%Y-%m-%d")\
.strftime("%d/%m/%Y"))
newFNameFmt = self.firstNameOfUser.strip().replace(" ", "-").lower()
newLNameFmt = self.lastNameOfUser.strip().replace(" ", "-").lower()
newBPFmt = self.pBirthOfUser.strip().replace(" ", "-").lower()
matchedPartners = []
# Fetch partner specified by the user
for p in listOfPartners:
if (newFNameFmt == p.firstname.strip().replace(" ", "-").lower() and
newLNameFmt == p.lastname.strip().replace(" ", "-").lower()):
matchedPartners.append(p)
partnerAlreadyExist = False
# If the list is not empty, then the fetch is enhance
if (matchedPartners):
for m in matchedPartners:
partnerDOB = False
partnerBP = False
if (not isinstance(m.birthdate, bool)):
if (newDateFmt == m.birthdate):
partnerDOB = True
if (not isinstance(m.birth_place, bool)):
if ((newBPFmt
== m.birth_place.strip().replace(" ", "-").lower())):
partnerBP = True
# If one of them it's true, the user already exist
if (partnerDOB or partnerBP):
partnerAlreadyExist = True
# Avoid useless iteration
break
# If the user specified doesn't exist he's created
if (not partnerAlreadyExist):
# Encode the string to avoid UnicodeError and further string errors
nameFmt = (self.lastNameOfUser.strip().upper(),
+ u" "
+ self.firstNameOfUser.strip().lower().title())
self.env['res.partner'].create(
{
'name': nameFmt,
'firstname': self.firstNameOfUser.strip().lower().title(),
'lastname': self.lastNameOfUser.strip().upper(),
'birthdate': newDateFmt,
'birth_place': self.pBirthOfUser,
'is_company': False
}
)
else:
raise ValidationError(u"L'utilisateur renseign\u00E9 "
u"existe d\u00E9j\u00E0 !")
EDIT
After several attempts to debug my code with pdb, I noticed that something went wrong in the for statement when I compare firstnames and lastnames :
for p in listOfPartners:
if (newFNameFmt == p.firstname.strip().replace(" ", "-").lower()
and newLNameFmt == p.lastname.strip().replace(" ", "-").lower()):
# Append element
Indeed, pdb blocks (2/3 sec) for each start of for statement before it gives me the hand back.
For example :
(pdb) ->if (newFNameFmt == p.firstname.strip().replace(" ", "-").lower() and
# stuck 2-3 seconds
(pdb) -> newLNameFmt == p.lastname.strip().replace(" ", "-").lower()):
This behavior continues for about the first iterations of the for statement, after this amount of iterations, this behavior is no longer adopted for the rest of the iterations. Once I arrived at the create statement (with pdb), the creation record is miraculously unlocked and the code works.
I still don't know why this problem occurs and I still don't know how to solve it.
you got that issue because maybe you have compare 2 different type! In your case, you maybe try to compare between res_partner object and string type or another! That should be res.partner(2973,).id or res.partner(2973,).name ....
I've found an answer for my question, and I think to know where the problem came from.
Where was my problem
So the problem came from my first for statement which is :
listOfPartners = self.env['res.partner'].search(
[
('is_company', '=', False)
]
)
for p in listOfPartners:
if (newFNameFmt == p.firstname.strip().replace(" ", "-").lower()
and newLNameFmt == p.lastname.strip().replace(" ", "-").lower()):
matchedPartners.append(p)
Theoretically nothing could be wrong with the for and search statements since they do what I want to do. But the problem is that each iteration that the program did in this for was 'n' queries sent to the PostgresSQL server (where n corresponds to the number of time that p is used in each iteration. In my case n = 2). This issue escalated quickly since search returned me about a thousand of partners (which are represented by id of each record saved in res.partner that matched the search query). So in the for this corresponds to thousands of queries that I sent in a very short time to the PostgreSQL server, and it seems that this server couldn't handle this amount of requests in a very short time.
So the problem was not the code in himself, but the behavior that I gave to him. The result of that behavior gave another behavior to the PostgreSQL for the further queries that I will give via Odoo, like create.
How I solved it
The solution for me was to use the psycopg2 module. This module allowing communication with the postgreSQL server. The main difference between both in my case was that Odoo stayed in communication with the PostgreSQL server even if I used search to get only values that I wanted. While psycopg2 gived me a list (of tuples) that only contains "real" values and not an id like Odoo gave me with search.
Once again, I don't know if the solution that I choosed was the best or if the issue came from there like I said above but this solution works well for me and I hope it will help others users stuck in a problem with the same behavior.
I am having the following python block where i want to check if a change doesnt exist in invalid_change and changes_not_in_manifest lists,the problem I am facing is as soon as the try loop is entered and checked for
invalid_change.index(change) it goes to except,how do I check if a change is not present in both "invalid_change" and "changes_not_in_manifest" lists?
try: # check if invalid change is present
invalid_change.index(change)
changes_not_in_manifest.index(change)
print "invalid list"
ifvalid = False
break
except:
print "except"
pass
Normally this kind of test is done using the in keyword:
if change not in invalid_change and change not in changes_not_in_manifest:
print "invalid list"
However, I think you are overlooking a good use case for sets. I have written a pretty detailed breakdown of a problem similar to this in this answer.
Basically, you would write a set comprehension like:
invalid_changes = {c for c in changes if c not in invalid_change or c not in manifest}
which you would later check using:
if change in invalid_changes:
# do something
I am trying to use a fetcher method to retrieve items from my datastore. If I use the following
def getItem(item_id):
q = Item.all()
q.filter("itemid = ", item_id)
It fails because nothing is returned. If I hard code in an item like
def getItem(item_id):
q = Item.all()
q.filter("itemid = ", 9000)
it fetches just fine, and sings merrily along. I have tried every which way to get this to work. I have used
result = db.GqlQuery("SELECT * FROM Item WHERE item_id = :1 LIMIT 1",
title).fetch(1)
to the same effect. If I hard code in a number, works fine. I have tried setting the select statement as a local string, assembling it that way, casting the int as a string, and nothing. When I output the SELECT statement to the screen, looks fine. I can cut ans paste the output into the string, and whammo, it works. Any help would be appreciated.
Does it make any difference if you do this:
def getItem(item_id):
q = Item.all()
q.filter("itemid = ", int(item_id))
The most likely cause of the problem that I can see is that the item_id parameter may be a string even though it is holding a numerical value. Coerce it to an int, and see if that makes any difference.
I'm learning Python as my second programming language (my first real one if you don't count HTML/CSS/Javascript). I'm trying to build something useful as my first real application - an IRC bot that alerts people via SMS when certain things happen in the channel. Per a request by someone, I'm (trying) to build in scheduling preferences where people can choose not to get alerts from between hours X and Y of the day.
Anyways, here's the code I'm having trouble with:
db = open("db.csv")
for line in db:
row = line.split(",") # storing stuff in a CSV, reading out of it
recipient = row[0] # who the SMS is going to
s = row[1] # gets the first hour of the "no alert" time range
f = row[2] # gets last hour of above
nrt = [] # empty array that will store hours
curtime = time.strftime("%H") # current hour
if s == "no":
print "They always want alerts, sending email" # start time will = "no" if they always want alerts
# send mail code goes here
else:
for hour in range(int(s), int(f)): #takes start, end hours, loops through to get hours in between, stores them in the above list
nrt.append(hour)
if curtime in nrt: # best way I could find of doing this, probably a better way, like I said I'm new
print "They don't want an alert during the current hour, not sending" # <== what it says
else:
# they do want an alert during the current hour, send an email
# send mail code here
The only problem I'm having is somehow the script only ends up looping through one of the lines (or something like that) because I only get one result every time, even if I have more than one entry in the CSV file.
If this is a regular CSV file you should not try to parse it yourself. Use the standard library csv module.
Here is a short example from the docs:
import csv
reader = csv.reader(open("some.csv", "rb"))
for row in reader:
print row
There are at least two bugs in your program:
curtime = time.strftime("%H")
...
for hour in range(int(s), int(f)):
nrt.append(hour)
# this is an inefficient synonym for
# nrt = range(int(s), int(f))
if curtime in nrt:
...
First, curtime is a string, whereas nrt is a list of integers. Python is strongly typed, so the two are not interchangeable, and won't compare equal:
'4' == 4 # False
'4' in [3, 4, 5] # False
This revised code addresses that issue, and is also more efficient than generating a list and searching for the current hour in it:
cur_hour = time.localtime().tm_hour
if int(s) <= cur_hour < int(f):
# You can "chain" comparison operators in Python
# so that a op1 b op2 c is equivalent to a op1 b and b op2c
...
A second issue that the above does not address is that your program will not behave properly if the hours wrap around midnight (e.g. s = 22 and f = 8).
Neither of these problems are necessarily related to "the script only ends up looping through one of the lines", but you haven't given us enough information to figure out why that might be. A more useful way to ask questions is to post a brief but complete code snippet that shows the behavior you are observing, along with sample input and the resulting error messages, if any (along with traceback).
Have you tried something more simple? Just to see how your file is actually read by Python:
db = open("db.csv")
for line in db:
print line
There can be problem with format of your csv-file. That happens, for instance, when you open Unix file in Windows environment. In that case the whole file looks like single string as Windows and Unix have different line separators. So, I don't know certain cause of your problem, but offer to think in that direction.
Update:
Your have multiple ways through the body of your loop:
when s is "no": "They always want alerts, sending email" will be printed.
when s is not "no" and curtime in nrt: "They don't want an alert during the current hour, not sending" will be printed.
when s is not "no" and curtime in nrt is false (the last else): nothing will be printed and no other action undertaken.
Shouldn't you place some print statement in the last else branch?
Also, what is exact output of your snippet? Is it "They always want alerts, sending email"?
I would check the logic in your conditionals. You looping construct should work.
You could go thro an existing well written IRC bot in Python Download
Be explicit with what's in a row. Using 0, 1, 2...n is actually your bug, and it makes code very hard to read in the future for yourself or others. So let's use the handy tuple to show what we're expecting from a row. This sort of works like code as documentation
db = open("db.csv")
for line in db.readlines():
recipient, start_hour, end_hour = line.split(",")
nrt = []
etc...
This shows the reader of your code what you're expecting a line to contain, and it would have shown your bug to you the first time you ran it :)