How to test for the existence of multiple keys in python? - python

I'm receiving a JSON response from my server where several of the keys may or may not exist. I've mostly been using a bunch of ternary operators to test each key before passing them into a Django object.create method. Here's something along the lines of what I'm dealing with
incoming = {"name":"hackNightly", "age":25, "field":"web development"}
# here's where it gets nasty
name = incoming["name"] if "name" in incoming else None
age = incoming["age"] if "age" in incoming else None
user = User.objects.create(
name = name,
age = age
)
etc. Of course, this works fine, it just feels like I'm doing something wrong. Is there a more pythonistic way to accomplish this? Thank you.

name = incoming.get('name')
age = incoming.get('age')
Dictionaries have a .get() method which can be called with 1 argument (what you're looking up), or 2 arguments (what you're looking up, and a default value if not found). By default, using 1 argument, get will just return None if nothing is found, so you can leave it as is.

Related

Is there a better way to ask if an argument exists AND does it match what I expect?

I'm new to python and I am sure there's a better way to do this. For my specific issue I have stored an API key. I've given the user means to send an argument with a new API key if needed. Otherwise the argument is set as False. So if the user sends an API key, I first want to find out if it's different from the one I already have. And if it is different I then want to update it in my secret manager.
There's one addtl layer of possible complication. It's a header in a webhook.
So I'm writing an if function but it feels very inelegant. This is what I currently have written. I'm also using Flask, hence request.
This is my code:
if request.headers['x-api-key'] and request.headers['x-api-key'] not in stored_api_key:
# do something
Would love to know how I should be writing this. Thank you.
Flask's request.headers acts like a dictionary, and so if you do
request.headers['x-api-key']
And the key x-api-key does not exist in the user's request, this will throw an error. Similar to dict, you can use the .get() method to default to a value in the case it does not exist. In this case, your code would look like so:
api_key = request.headers.get('x-api-key')
if api_key and api_key not in stored_api_key:
# do something
Otherwise, you must do the following:
if 'x-api-key' in request.headers and request.headers['x-api-key'] not in stored_api_key:
I wouldn't try to jam this into a single if statement. You have two checks where one check can use the output of the last. IMO it reads much more clearly to me to have two if statements. You could use an assignment expression to help simplify your logic:
if api_key := request.headers.get('x-api-key'):
if api_key not in stored_api_key:
...
The first if assigns api_key and checks for truthiness. get is used to avoid KeyErrors. The second if uses the value from above where we know api_key is not None.
You could also one liner this if you really want to, but is definitely less readable:
if (key := request.headers.get('x-api-key')) and key not in stored_api_key:
...

Maapping template default to None if no input from user

I have one API GET method integrated with lambda, in lambda integration mapping template.
mapping template:
{
"name" : "$input.params('name')",
"std_out" : "$input.params('std_out')"
}
condition is to set std_out default value to none but if user sends something in std_out then users values will be assign to it.
I'm not getting how to make std_out default to none but still accepts input if user pass any.
Things that I tried:
One way I think is instead of using GET, I will use POST method and will not use any mapping template. but this is not standard way.
I can ask User to send None if not passing any values, but still exploring if I can do something on my level to reduce the overhead from user.
So Is there any solution using GET method.
Although VTL variables seem to allow for an alternate value when empty, apparently API Gateway does not support that and fails to transform request.
The next best option is to use an inline if/else condition to perform the same:
## setting to a variable for readability, but not strictly necessary
#set( $std_out = $input.params('std_out') )
{
"name" : "$input.params('name')",
"std_out": #if( $std_out != '' )"$std_out"#{else}"None"#end
}
In case you want to skip passing the field if the user did not pass it, wrap the whole field inside the if/else:
{
## putting before 'name' so we don't have to deal with the comma there
#if( $input.params('std_out') != '' )
"std_out": "$input.params('std_out')",
#end
"name" : "$input.params('name')"
}

python active directory module pyad max returned group members

How can I return all group members if it is over 1500, I'm using below code
Using execute_query member attribute in the group is empty
import pyad.adquery
q = pyad.adquery.ADQuery()
q.execute_query(
attributes = ["CN", "sAMAccountName", "sAMAccountType", "name", "title", "distinguishedName", "mail", "managedBy", "member", "memberOf"][::-1],
where_clause = "{0} = '{1}'".format(query_attribute,query_value),
base_dn = "DC=domain,DC=company,DC=net",
) --> Using execute_query member attribute is empty
result = list(q.get_results())[0]['member'] --> result is None
using pyad.from_cn only first 1500 users returned
f = pyad.pyad.from_cn('Group Name')
f.get_attribute('member') or f.get_members() --> both return only 1500 Users
This limit doesn't come from pyad, but AD itself. Active Directory will only give you 1500 rows from a multi-value attribute. To get the rest, you have to specifically ask for more.
I haven't tried this in Python, but to ask for the next 1500, you should be able to do something like this:
f.get_attribute('member;range=1500-*')
Try that and see if it works.
Looking at the Pyad source code, that might not actually work (because of the hasattr check, which might not remove the "range" part when checking if the attribute is valid). There is also an issue logged for this, which hasn't been replied to. And since the project is no longer maintained, it's unlikely to get fixed unless you fork it and fix it yourself (it should be as easy as removing that hasattr check).
But if that does happen to work, you will have to put that into a loop and keep going until you get an error, which means there are no more results. I have an example in C# here. You can translate the logic in the loop to Python.

Querying DB for users when not all given parameters are filled

Sorry about the title being confusing it was hard to figure out how to word the question.
Currently I have a sqllite db with some users in it they have a first name, last name, dob, high school, and high school class. The db is connected to flask using sqlalchemy. What I'm wondering is for my search function I have 4 inputs and I want to have it so if an input isn't used then it won't be used in the search query. Say the person searches for the last name and high school I want it to search just using those parameters. I've tried doing this using a bunch of if statements but it seems messy there must be a better way. Below is the query that I use but it only works if all 4 are filled. Is there a better way than a bunch of if statements with different queries? I've looked around and haven't found anything.
userq=User.query.filter_by(first_name=fname_strip,last_name=lname_strip,hs_class=hs_class_strip).all()
You can try if/else statements like the following:
q = User.query.filter_by(first_name=first_name)
if lname_strip:
q = q.filter_by(last_name=lname_strip)
if hs_class_strip:
q= q.filter_by(hs_class=hs_class_strip)
# Execute the query
q.all()
Updated needs the q to be an assignment.
Okay so what I did was go through and make an if statement like you said but made them into different vars. Then check to see if they where none or not correct and if they were good then they queryied correctly if not then the queried for everything not null. Then changed them to be a set then did set intersection to see what was the same through all of them. Thank you for ionheart for helping me through this and providing the information this is the complete answer using his partial solution.
userf=set()
userl=set()
userc=set()
userh=set()
if fname_strip!='':
userf = User.query.filter_by(first_name=fname_strip).all()
print(userf)
else:
userf = User.query.filter(User.first_name.isnot(None))
if lname_strip!='':
userl = User.query.filter_by(last_name=lname_strip).all()
print(userl)
else:
userl = User.query.filter(User.last_name.isnot(None))
try:
int(hs_class_strip)
userc = User.query.filter_by(hs_class=hs_class_strip).all()
print(userc)
except:
userc = User.query.filter(User.hs_class.isnot(None))
if hs_strip!='':
userh = User.query.filter_by(hs=hs_strip).all()
print(userh)
else:
userh = User.query.filter(User.hs.isnot(None))
userq=[]
common=set(userf) & set(userl) & set(userc) & set(userh)
print(common)
If you pass the arguments to your search function as keyword arguments you can change the signature to accept kwargs and pass those on to the filter query
def search(**kwargs):
userq = User.query.filter_by(**kwargs).all()
This way any arguments you don't specify when calling search will not be passed onto the query, for example calling search(first_name='bob', last_name='fossil') will only add first name and surname arguments to the query

How to check the existance of single Entity? Google App Engine, Python

Sorry for noobster question again.
But I'm trying to do some very easy stuff here, and I don't know how. Documentation gives me hints which do not work, or apply.
I recieve a POST request and grab a variable out of it. It says "name".
I have to search all over my entities Object (for example) and find out if there's one that has the same name. Is there's none, I must create a new Entity with this name. Easy it may look, but I keep Failing.
Would really appreciate any help.
My code currently is this one:
objects_qry = Object.query(Object.name == data["name"])
if (not objects_qry ):
obj = Object()
obj .name = data["name"]
obj .put()
class Object(ndb.Model):
name = ndb.StringProperty()
Using a query to perform this operation is really inefficient.
In addition your code is possibly unreliable, if name doesn't exist and you have two requests at the same time for name you could end up with two records. And you can't tell because your query only returns the first entity with the name property equal to some value.
Because you expect only one entity for name a query is expensive and inefficient.
So you have two choices you can use get_or_insert or just do a get, and if you have now value create a new entity.
Any way here is a couple of code samples using the name as part of the key.
name = data['name']
entity = Object.get_or_insert(name)
or
entity = Object.get_by_id(name)
if not entity:
entity = Object(id=name)
entity.put()
Calling .query just creates a query object, it doesn't execute it, so trying to evaluate is as a boolean is wrong. Query object have methods, fetch and get that, respectively, return a list of matching entities, or just one entity.
So your code could be re-written:
objects_qry = Object.query(Object.name == data["name"])
existing_object = objects_qry.get()
if not existing_object:
obj = Object()
obj.name = data["name"]
obj.put()
That said, Tim's point in the comments about using the ID instead of a property makes sense if you really care about names being unique - the code above wouldn't stop two simultaneous requests from creating entities with the same name.

Categories