So I'm currently trying to create a dynamic function, that will take 1 kwarg, and use that in it's filter_by.
This is what the function currently looks like:
def Get_from_var(session, **data):
for entry in data:
if bool(session.query(Tutor).filter_by(entry=data[entry]).first()):
return session.query(Tutor).filter_by(entry=data[entry]).first()
return "No tutor found"
I know that my function will only recieve 1 kwarg, so I'm not worried about some weird exceptions. But currently it seems that the 'entry' paramter in both of the filter_by functions, are interpreted literally, and not as variables? Because It tells me that "tutor has no property 'entry'"
This is how I'm currently calling it:
tutor = Tutor.Get_from_var(session, tutor_id=filters["id"])
You can use **data in filter_by directly to get the correct result.
session.query(Tutor).filter_by(**data).first()
** unpacks your data into key-value pairs and passes them to the filter_by function.
Also, you probably dont want to query twice just to check your if statement.
Related
I want to create a method, which can dynamically add keyword arguments to another function that I intend to call within this method, something like:
def func(query1: str, query2: str):
func2(query1, query2)
where, the query1, query2 in the func are strings of the type "a=3", "b=4", the func should essentially take these strings and then call them in a keyword argument way like:
func2(a=3, b=4)
The a, b here are not fixed, they may vary, I mean to say I want to be able to take the a and b from the LHS of the string "a=3"
So my function takes the string "a=3" and parses the "a" as the keyword for the other function and the 3 as the value and calls the other function like func2(a=3)
I want to know if this kind of implementation is even possible or if there are any workarounds for achieving the same goal.
The reason why I want this is because I have a django application in which I want to create a model where I can store some filter rules and apply them each time that view is called, so I want to allow the user to select a bunch of filters and then I want to store them in the database and call those rules to get a queryset specific to that user's preferences.
def some_view(request):
# Get the filter rule strings from the model
queryset = some_model.objects.filter(<Pass all the rules here from those strings>)
return Response
edit: Add more details on the use case
Not sure I really understand what you want. You could translate those query strings to a dict, then use that to call the other function with **kwargs:
def f(a, b):
print(a, b)
def g(*queries):
return f(**dict((q.split("=", 1) for q in queries)))
>>> g("a=4", "b='string with = in the middle'")
4 'string with = in the middle'
Note: just split("=") might fail if the parameter is a string containing =; thus you might want to use split("=", 1) instead.
However, this passes all the arguments as raw strings; you might want to eval, or rather ast.literal_eval to the values, but that may also pose some risks. Something like this:
import ast
def g(*queries):
return f(**{k: ast.literal_eval(v)
for k, v in (q.split("=", 1) for q in queries)})
I'm trying to use the ast module in Python to parse input code, but am struggling with a lot of the syntax of how to do so. For instance, I have the following code as a testing environment:
import ast
class NodeVisitor(ast.NodeVisitor):
def visit_Call(self, node):
for each in node.args:
print(ast.literal_eval(each))
self.generic_visit(node)
line = "circuit = QubitCircuit(3, True)"
tree = ast.parse(line)
print("VISITOR")
visitor = NodeVisitor()
visitor.visit(tree)
Output:
VISITOR
3
True
In this instance, and please correct me if I'm wrong, the visit_Call will be used if it's a function call? So I can get each argument, however there's no guarantee it will work like this as there are different arguments available to be provided. I understand that node.args is providing my arguments, but I'm not sure how to do things with them?
I guess what I'm asking is how do I check what the arguments are and do different things with them? I'd like to check, perhaps, that the first argument is an Int, and if so, run processInt(parameter) as an example.
The value each in your loop in the method will be assigned to the AST node for each of the arguments in each function call you visit. There are lots of different types of AST nodes, so by checking which kind you have, you may be able to learn things about the argument being passed in.
Note however that the AST is about syntax, not values. So if the function call was foo(bar), it's just going to tell you that the argument is a variable named bar, not what the value of that variable is (which it does not know). If the function call was foo(bar(baz)), it's going to show you that the argument is another function call. If you only need to handle calls with literals as their arguments, then you're probably going to be OK, you'll just look instances of AST.Num and similar.
If you want to check if the first argument is a number and process it if it is, you can do something like:
def visit_Call(self, node):
first_arg = node.args[0]
if isinstance(first_arg, ast.Num):
processInt(first_arg.n)
else:
pass # Do you want to do something on a bad argument? Raise an exception maybe?
I am a beginner Python user and I have come across an output to a function that I don't understand. I can't give all the code because some of it is IP at my company.
I am basically using a library written by one of our devs to pull a metric from out data warehouse. I want to then use this metric value in another application to when i get the value i will pass it to my own DB.
My issue is I dont understand the output of the function I am using to actually extrapolate the value I want.
If someone with more Python experience could tell me what the return of the function is doing as the best I can tell it is building a dict, but I don't fully understand how and where. I must add this is the function from inside the lib
def get(self, **kwargs):
if 'SchemaName' not in kwargs:
kwargs['SchemaName'] = self.find_schema_by_params(**kwargs)
if 'Stat' in kwargs and kwargs['Stat'] not in MWS.VALID_Stat:
raise MWSException("Incorrect Stat value: %s" % kwargs['Stat'])
if 'Period' in kwargs and kwargs['Period'] not in MWS.VALID_Period:
raise MWSException("Incorrect Period value: %s" % kwargs['Period'])
self._validate_schema(kwargs, MWS.DEFAULT_GET_PARAMETERS)
self._encode_start_time(kwargs)
if 'EndTime' not in kwargs:
if kwargs['StartTime'].startswith('-P'):
kwargs['EndTime'] = '-P00D'
else:
kwargs['EndTime'] = datetime.datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%S.000Z")
return self._mws_action('GetMetricData', **kwargs)['StatisticSeries']
Apparently, _mws_action() is a method that is passed a string, 'GetMetricData' and the same keyword arguments as your get method (with a few modifications). _mws_action() returns a dictionary, and you return the 'StatisticSeries' element of that dictionary.
**kwargs converts a dictionary to/from keyword arguments. So you can call get as
get(SchemaName='schema', Stat='somestat', EndTime="-P00D")
and kwargs will be:
{'SchemaName': 'schema', 'Stat':'somestat', 'EndTime':"-P00D"}
I have a function that returns the replaced values correctly, but for some reason, the run_instances function receives the entire string as a single object (instead of 4 separate values).
import boto
ec2_conn = boto.connect_ec2(aws_access_key_id='XXX', aws_secret_access_key='XXX')
ami='ami-XXX'
key_name='XXX15a.pem'
instance_type='t1.macro'
aid="image_id='%s', placement='us-east-1a', key_name='%s', instance_type='%s'" % (ami, key_name, instance_type)
When I try to execute the run_instances function...
ec2_conn.run_instances(aid)
<Message>Invalid id: "image_id='ami-XXX', placement='us-east-1a', key_name='XXX.pem', instance_type='t1.macro'" (expecting "ami-...")</Message>
Is there any way to pass the values to the function correctly?
Simplifying the problem statement to: how to pass multiple variables around so they can be passed into a function later on without passing all variables individually...:
params = dict(ami='ami-XXX', key_name='XXX15a.pem', instance_type='t1.macro', placement='us-east-1a')
ec2_conn.run_instances(**params)
Store them in a dict and expand them to keyword arguments with **.
Does python have the ability to create dynamic keywords?
For example:
qset.filter(min_price__usd__range=(min_price, max_price))
I want to be able to change the usd part based on a selected currency.
Yes, It does. Use **kwargs in a function definition.
Example:
def f(**kwargs):
print kwargs.keys()
f(a=2, b="b") # -> ['a', 'b']
f(**{'d'+'e': 1}) # -> ['de']
But why do you need that?
If I understand what you're asking correctly,
qset.filter(**{
'min_price_' + selected_currency + '_range' :
(min_price, max_price)})
does what you need.
You can easily do this by declaring your function like this:
def filter(**kwargs):
your function will now be passed a dictionary called kwargs that contains the keywords and values passed to your function. Note that, syntactically, the word kwargs is meaningless; the ** is what causes the dynamic keyword behavior.
You can also do the reverse. If you are calling a function, and you have a dictionary that corresponds to the arguments, you can do
someFunction(**theDictionary)
There is also the lesser used *foo variant, which causes you to receive an array of arguments. This is similar to normal C vararg arrays.
Yes, sort of.
In your filter method you can declare a wildcard variable that collects all the unknown keyword arguments. Your method might look like this:
def filter(self, **kwargs):
for key,value in kwargs:
if key.startswith('min_price__') and key.endswith('__range'):
currency = key.replace('min_price__', '').replace('__range','')
rate = self.current_conversion_rates[currency]
self.setCurrencyRange(value[0]*rate, value[1]*rate)