Check if sub-methods exist in one line (python) - python

I'm developing telegram bot on python (3.7).
I'm getting POST updates/messages from users (class telegram.update.Update)
if request.method == "POST":
update = Update.de_json(request.get_json(force=True), bot)
Then I'm storing all the parameters of the incoming "message" in variables.
For example, if there is a user status update, I save it this way:
if update and update.my_chat_member and update.my_chat_member.new_chat_member \
and update.my_chat_member.new_chat_member.status:
new_status = update.my_chat_member.new_chat_member.status
else:
new_status = None
It's important to me to save 'None' if this parameter is not provided.
And I need to save about 20 parameters of this "message". Repeating this construction for 20 times for each parameter seems to be inefficient.
I tried to create a checking function to reuse it and to check if parameters exist in one line for each parameter:
def check(f_input):
try:
f_output = f_input
except: # i understand it's too broad exception but as I learned it's fine for such cases
f_output = None
return f_output
new_status = check(update.my_chat_member.new_chat_member.status)
but , if a certain Update doesn't have update.my_chat_member, the error pops up already on the stage of calling the 'check' function
new_status = check(update.my_chat_member.new_chat_member.status)
>>> 'NoneType' object has no attribute 'new_chat_member'
and not inside the check().
Could someone guide me pls, if there is an intelligent way to save these 20 parameters (or save None), when the set of these parameters changes from message to message?

You're trying to invoke methods on a NoneType object before passing it to your check function. The update.my_chat_member object itself is NoneType and has no new_chat_member method. A way to check that could look like this.
if not isinstance(update.my_chat_member, type(None)):
*do what you need to a valid response*
else:
*do what you need to a NoneType response*
Also as #2e0byo noted the check function doesn't really do much. You're checking to see if you can assign a variable to "f_output" which outside of a few cases will always pass without exception. So the except part will almost never run and certainly not as intended. You need to try something that can cause an expected error. This is an example using your code.
def check(f_input):
try:
f_output = f_input.new_chat_member.status()
except AttributeError:
f_output = None
return f_ouput
new_status = check(update.my_chat_member)

Related

How to use content of a string variable to refer to a "string defined" key in a dictionary?

I am currently trying to make a battle system where different types have weaknesses. These weaknesses are stored in a dictionary under their "master type" as a string value for the key. I'm trying to use another variable which has the exact same String Format (I.E i.e if the key I wanted was "Normal", then the other variable is also "Normal".
However, when I try to use the .get() method with this other variable inside it, it just returns a "NoneType" value and throws all my code off.
Below is the code that I am using to load the values into the dictionary.
def weakness_load():
pokeweakness.seek(0)
dump = pokeweakness.read().split("\n")
for i in dump:
print(i)
if i != "":
basetype,allbaseweaknesses = i.split(",")
print(basetype,allbaseweaknesses)
weakness_dict[basetype] = allbaseweaknesses
print(weakness_dict[basetype])
print("\n")
And Below is the code that I am using to see if the defender's type is weak to the attackers type.
def check_weakness(attack,defender,mover):
defweakness = weakness_dict.get(defender)
print(defweakness)
if attack in defweakness:
plattackcrit = False
aiattackcrit = False
if mover == 1:
plattackcrit = True
return(plattackcrit)
elif mover == 2:
aiattackcrit = True
return(aiattackcrit)
The above code fails when it gets to
if attack in defweakness:
Because of a "TypeError: argument of type: 'NoneType' is not iterable."
Sample data for dictionary:
Key: Rock || Data: Fighting;Steel;Ground;Water;Grass;
Any help would be greatly appreciated as I'm not quite sure how I can get around this and I'm struggling to find any content around this online too.
SOLVED
Like a complete idiot, I forgot to return weakness_dict so I never actually had the updated dictionary stored.
I made sure to update the "weakness_load()" function to return weakness_dict and also added weakness_dict = weakness_load() just before I call upon my main code so that it's all loaded before the code runs.

Flask NoneType error appears randomly even tho type is correct, and sometimes, it works randomly

#Here is my class:
class CryptoClass:
def __init__(self, cfrom, cto):
self.cfrom = cfrom
self.cto = cto
def priceConverter(self):
dic = cryptocompare.get_price([self.cfrom],[self.cto])
return [self.cfrom,self.cto,dic[self.cfrom][self.cto]]
#Here is the function:
def converter():
A = str(request.form.get("FROM"))
B = str(request.form.get("TO"))
if A!="" and B!="":
price1 = CryptoClass(A,B)
a = price1.priceConverter()
return render_template("converter.html", fromResult = a[0],toResult = a[2],toResultName = a[1])
#Finally, here is the Error I'm getting:
return [self.cfrom,self.cto,dic[self.cfrom][self.cto]]
TypeError: 'NoneType' object is not subscriptable
What I find weird with my problem is the fact that sometimes, it works, and sometimes it doesn't, but I can't find the logic behind it, any help would be appreciated :)
P.S: If I replace A and B by A = "BTC" and B = "ETH", it works like a charm, I made sure the request is actually working and tried printing A and B using values from the form, but when I put all the code together, I can't even access the form page since I'd have this error popping.
Probably your issue is caused by two things:
Invalid values (FROM and TO);
The cryptocompare.get_price response.
Let's start with 1. You have three possible scenarios in your request handling, both values were provided and are valid cryptocurency (let say FROM=ETH and TO=BTC), only one value was provided (FROM=ETH or TO=BTC) and when some of the values provided (or both) is not a valid cryptocurrency(FROM=XYZ and TO=AAAAAAAA).
Let's deal with the last two, since the first one is already covered in your source code.
Values not provided: be sure to suggest a default value when calling request.form.get() or be aware that, in case the requested value does not exist, this function will return None (not an empty string). Also, It would be good to improve your code like this:
A = request.form.get("FROM", "")
B = request.form.get("TO", "")
Invalid Cryptocurrencies: On this point I'm making some assumptions (based on Web API calls to min-api.cryptocompare.com and the source code. When you call cryptocompare.get_price with invalid arguments, let's say cryptocompare.get_price(['BTC'], ['AAAAAAAAA']), it return a None object.
Having that in mind, the value of dic will be None, and when you try to run this dic[self.cfrom][self.cto] you will be trying to subscript a None object. Hence, the error: TypeError: 'NoneType' object is not subscriptable.
It's recommended to check the dic object before the return statement:
dic = cryptocompare.get_price([self.cfrom],[self.cto])
if dic:
return [self.cfrom,self.cto,dic[self.cfrom][self.cto]]
return [self.cfrom,self.cto,None]
Note that if the dic is None the last part of the list in the return statement is None too, and need to be treated accordingly in the portion of your code that receive this response.
Good luck!

unbound method delete() must be called with Subscription instance as first argument (Stripe API)

I'm working with Stripe API to cancel a subscription using the subscription ID. In all the tests, the stripe.Subscription.delete works fine but in some (very few) cases, it just gives this error unbound method delete() must be called with Subscription instance as the first argument.
First I thought that the Stripe object wasn't defined correctly but in the same function, I'm making another Stripe API call to get the subscription list (stripe.Subscription.list). This works every time.
This is a bit confusing scenario so any help would be great.
try:
sub_id = <sub_id from the API call>
logging.info('sub_id = %s', sub_id)
logging.info('isinstance(sub_id, unicode) = %s', isinstance(sub_id, unicode))
if isinstance(sub_id, unicode):
sub_id = sub_id.encode('ascii', 'ignore')
logging.info('sub_id is unicode. Converting to ascii = %s', sub_id)
else:
logging.info('sub_id is _not_ a unicode string')
except Exception as e:
subject_str = 'hit exception when canceling subcription in stripe. Error = %s'%e
logging.error(subject_str)
stripe.Subscription.delete(sub_id)
return True
Added try-except just to make sure I'm always passing string argument.
Thank you!
If I had to guess, it's happening because the Subscription ID is for a sub that doesn't exist. You might want to file this as an issue in Github - along with details of the version you're using - as there may be something odd going on under the hood. https://github.com/stripe/stripe-python/

Why is the same object throwing a "NoneType" object Attribute error in one instance and not others?

I am using django to set up the cart functionality on my ecommerce site. All items are entered as cart_items in a MySQL table.
Before the question, the relevant code:
charm = False
if postdata.get('charm_sku'):
charm_sku = postdata.get('charm_sku','')
ch = get_object_or_404(Charm, sku=charm_sku)
#get products in cart
cart_products = get_cart_items(request)
product_in_cart = False
# check to see if item is already in cart
for cart_item in cart_products:
if cart_item.product.id == p.id:
if charm == True:
if cart_item.charm.id == ch.id:
# update the quantity if found
cart_item.augment_quantity(quantity)
product_in_cart = True
else:
if cart_item.charm.id == "":
# update the quantity if found
cart_item.augment_quantity(quantity)
product_in_cart = True
Edit:
I reworked the code as shown above, causing BOTH if cart_item.charm.id's to throw the attirbuteerror: 'NoneType' object has no attribute 'id'. In a way, I think this has improved the situation, since I suspect the first one seeming to "succeed" was in fact the first if charm == True failing, thus never testing the first if cart_item.charm.id == ch.id. The question remains: why is this trowing the AttributeError, when the For loop is clearly declaring the cart_item, and cart_items clearly have both a charm column and id's assigned to said columns?
Edit 2:
Can I not reference cart_item from the nested if's? That is the only thing I can think, but at the same time I feel like I should be able to, so maybe that is wrong?
NoneType means that instead of an instance of a class, you've actually got None. That probably means that an assignment failed or or function call returned an unexpected result. Your assignment to cart_item is probably failing in the case where charm == False. Check whatever code (assignment or function call) that's setting those two variables.
Somehow your charm == False condition also implies that cart_item.charm is None. Since you don't check for None before you access the id attribute, an exception is thrown.
I don't know enough about these variables and object types to understand why but it's that if conditional that's masking away your problem.

Python OO: how to stop procedure flow in an entire class with `return` statement?

When I run this code:
from nltk import NaiveBayesClassifier,classify
import USSSALoader
import random
class genderPredictor():
def getFeatures(self):
if self._loadNames() != None:
maleNames,femaleNames=self._loadNames()
else:
print "There is no training file."
return
featureset = list()
for nameTuple in maleNames:
features = self._nameFeatures(nameTuple[0])
featureset.append((features,'M'))
for nameTuple in femaleNames:
features = self._nameFeatures(nameTuple[0])
featureset.append((features,'F'))
return featureset
def trainAndTest(self,trainingPercent=0.80):
featureset = self.getFeatures()
random.shuffle(featureset)
name_count = len(featureset)
cut_point=int(name_count*trainingPercent)
train_set = featureset[:cut_point]
test_set = featureset[cut_point:]
self.train(train_set)
return self.test(test_set)
def classify(self,name):
feats=self._nameFeatures(name)
return self.classifier.classify(feats)
def train(self,train_set):
self.classifier = NaiveBayesClassifier.train(train_set)
return self.classifier
def test(self,test_set):
return classify.accuracy(self.classifier,test_set)
def getMostInformativeFeatures(self,n=5):
return self.classifier.most_informative_features(n)
def _loadNames(self):
return USSSALoader.getNameList()
def _nameFeatures(self,name):
name=name.upper()
return {
'last_letter': name[-1],
'last_two' : name[-2:],
'last_is_vowel' : (name[-1] in 'AEIOUY')
}
if __name__ == "__main__":
gp = genderPredictor()
accuracy=gp.trainAndTest()
And self._loadNames() returns None, I got this error (from random imported module):
shuffle C:\Python27\lib\random.py 285
TypeError: object of type 'NoneType' has no len()
This happend because despite I put a return statment in getFeatures(self), the flow jumps into the next class method (which is trainAndTest(self,trainingPercent=0.80)) which calls the random module (random.shuffle(featureset)).
So, I'd like to know: how to stop the procedure flow not only in the getFeatures(self) method, but in the entire class that contains it?
By the way, thanks Stephen Holiday for sharing the code.
This happend because despite I put a return statment in
getFeatures(self), the flow jumps into the next class method (which is
trainAndTest(self,trainingPercent=0.80)) which calls the random module
(random.shuffle(featureset)).
An important thing to remember is that None is a perfectly valid value. The return statement in your getFeatures() is doing exactly what it is told and returning the valid value. Only an exceptional situation, or you explicitly, will stop that flow.
Instead of asking how you can "return from the class", what you might want to look into is checking the return values of functions you call and making sure its what you expect before you proceed. There are two places you could do this:
def trainAndTest(self,trainingPercent=0.80):
featureset = self.getFeatures()
...
def _loadNames(self):
return USSSALoader.getNameList()
In the first spot, you could check if featureset is None, and react if it is None.
In the second spot, instead of blindly returning, you could check it first and react there.
Secondly. you have the option of raising exceptions. Exceptions are a situation where the code has encountered an error and can't continue. It is then the responsibility of the calling function to either handle it or let it ride up the chain. If nothing handles the exception, your application will crash. As you can see, you are getting an exception being raised from the random class because you are allowing a None to make its way into the shuffle call.
names = USSSALoader.getNameList()
if names is None:
# raise an exception?
# do something else?
# ask the user to do something?
The question at that point is, what do you want your program to do at that moment when it happens to get a None instead of a valid list? Do you want an exception similar to the one being raised by random, but more helpful and specific to your application? Or maybe you just want to call some other method that gets a default list. Is not having the names list even a situation where your application do anything other than exit? That would be an unrecoverable situation.
names = USSSALoader.getNameList()
if names is None:
raise ValueError("USSSALoader didn't return any "
"valid names! Can't continue!")
Update
From your comment, I wanted to add the specific handling you wanted. Python has a handful of built in exception types to represent various circumstances. The one you would most likely want to raise is an IOError, indicating that the file could not be found. I assume "file" means whatever file USSSALoader.getNameList() needs to use and can't find.
names = USSSALoader.getNameList()
if names is None:
raise IOError("No USSSALoader file found")
At this point, unless some function higher up the calling chain handles it, your program will terminate with a traceback error.
There is nothing like "return from the entire class". You need to organize your code so that return values are valid in the functions that get them. Those functions can test the value to determine what to do next. The class boundaries have no effect on program flow, just the namespacing of methods.
Generally what you would do here is check for validity after you call the function, e.g.:
featureset = self.getFeatures()
if not featureset:
# You could log an error message if you expected to get something, etc.
return

Categories

Resources