Flask jsonify: key starting with digit - python

Say i want to create the following JSON document in Flask:
{"1": {"name": "Tom"}}
I couldn't just call return jsonify(**kwargs), because Python forbids naming variables starting with a number, like 1.
Is it possible to create such a JSON document with Flask's jsonify? If not, what are my workarounds?
Clarification: I want to create a JSON document, which contains dicts indexed by ids, and ids have the form of 24 hexadecimal values (ObjectId from MongoDB). It means that most of the time ids will start with a digit.

Conveniently, you can use... **kwargs!
>>> def echo(**kwargs):
... print kwargs
...
>>> echo(**{"1":{"name": "Tom"}})
{'1': {'name': 'Tom'}}
Yes, you can't manually specify an individual keyword argument named 1... but you can pass a keyword argument named 1 via the ** keyword expansion operator.

Since flask.jsonify takes the same parameters as Python's dict, you can give it a dict as a parameter and let it sort out the rest:
#app.route('/')
def hello_world():
# note key is an int, not just a string with leading digits
# in your case this could be a mongodb object
return jsonify({1: {'name': 'bob'}})
Returns:
{
"1": {
"name": "bob"
}
}

Related

Implement hmset in python with dictionary of list and nested dictionary

I was trying to implement below redis code into python django application
hmset test_template:TEMPLATE_ID test_tags "[{\"key\":\"test_manual_entry_1\",\"value\":\"Some_value_1\"},{\"key\":\"test_manual_entry_2\",\"value\":\"Some_value_2\"}]"
I have tried hset and hmset functions but both are giving the error. Below is sample of my code looks like this
class RedisUtil:
def hset(self, key_name, data):
key_name = "test_template:TEMPLATE_ID"
list_data = [{"key": "test_manual_entry_1", "value": "Some_value1"}, {"key": "test_manual_entry_2", "value": "Some_value2"}]
data = {"test_tags": [json.dumps(d) for d in list_data]} # output list: ['{"key": "test_manual_entry_1", "value": "Some_value1"}', '{"key": "test_manual_entry_2", "value": "Some_value2"}']
I have tried below methods to save but all methods are giving me error
# Method 1
self.redis_client.hset(key_name, data) # Exception: redis.exceptions.DataError: Invalid input of type: 'dict'. Convert to a bytes, string, int or float first.
#Method 2
self.redis_client.hset(key_name, "test_tag", data["test_tags"]) # Exception: redis.exceptions.DataError: Invalid input of type: 'list'. Convert to a bytes, string, int or float first.
Also, I would like add there that there may be case where my list will be empty, this could be an edge case.
Thanks in advance for any help.
Here's Python Redis hset doc: https://redis.readthedocs.io/en/stable/commands.html?highlight=hset#redis.commands.core.CoreCommands.hset
The function signature is hset(name, key=None, value=None, mapping=None, items=None).
For method 1, You passed data as key. Besides, I presume data is a dict, which is differ from string.
For method 2, you use data["test_tags"] as value, But still, data["test_tags"] isn't a string but a list.
If you want to implement hmset, may you should use this one instead(but already deprecated, not recommended)?

Using a dict to call functions from a string

I would like the first two words of a user input string to be read as function arguments for where to save the string. I've settled on using a dict instead of many if statements, but I'm not sure how to structure the dict.
I believe this is a correct start:
input: "question physics What happens to atoms when they are hit by photons?"
result: program saves the input in location questions\physics
raw_entry = input("Enter text in the following format: type subtype text")
instructions = raw_entry.split()[:2]
The two words (each being a "get_id" in the example) will designate where to save the text. This example seems to be what I'm looking for, but I'm not sure how to change it for my case.
function_dict = {'get_id':
(
# function
requests.get,
# tuple of arguments
(url + "/users/" + user,),
# dict of keyword args
{'headers': self.headers}
)
}
Let me know if I'm going about this logically or if it doesn't make sense. Thanks!
You will need to define the functions separately from the dictionary
For example:
def get_id():
... the function's code ...
function_dict = { "get_id":get_id, ... }
you can then call the function with its keyword:
function_dict["get_id"]()
but you can also do this without a dictionary if the keyword is the same as the function name:
globals()["get_id"]()

Modifying a python dictionary from user inputted dot notation

I'm trying to provide an API like interface in my Django python application that allows someone to input an id and then also include key/values with the request as form data.
For example the following field name and values for ticket 111:
ticket.subject = Hello World
ticket.group_id = 12345678
ticket.collaborators = [123, 4567, 890]
ticket.custom_fields: [{id: 32656147,value: "something"}]
On the backend, I have a corresponding Dict that should match this structure (and i'd do validation). Something like this:
ticket: {
subject: "some subject I want to change",
group_id: 99999,
collaborator_ids: [ ],
custom_fields: [
{
id: 32656147,
value: null
}
]
}
1) I'm not sure exactly the best way to parse the dot notation there, and
2) Assuming I am able to parse it, how would I be able to change the values of the Dict to match what was passed in. I'd imagine maybe something like a class with these inputs?
class SetDictValueFromUserInput(userDotNotation, userNewValue, originalDict)
...
SetDictValueFromUserInput("ticket.subject", "hello world", myDict)
Fastest way is probably splitting the string and indexing based on seperation. For example:
obj = "ticket.subject".split(".")
actual_obj = eval(obj[0]) # this is risky, they is a way around this if you just use if statements and predifined variables.
actual_obj[obj[1]] = value
To have further indexing where an object like ticket.subject.name might work try using a for loop as so.
for key in obj[1:-2]: # basically for all the values in between the object name and the defining key
actual_obj = actual_obj[key] # make the new object based on the value in-between.
actual_obj[obj[-1]] = value

How to create URL Parameters from a list

I have a form with multiple select field. It is working through GET method.
An example of request parameters generated by the form:
action=not-strummed&action=not-rewarded&keywords=test&page=2
Note that there is two "action" parameters. This is happening because of the multiple select.
What I want to do is:
Make a dict from parameters
Remove "page" key from the dict
Transform-back the dict into the parameter string
The urllib.urlencode() isn't smart enough to generate url parameters from the list.
For example:
{
"action": [u"not-strummed", u"not-rewarded"]
}
urllib.urlencode() transforms this dict as:
action=%5Bu%27not-strummed%27%2C+u%27not-rewarded%27%5D
This is completely wrong and useless.
That's why i wrote this iteration code to re-generate url parameters.
parameters_dict = dict(self.request.GET.iterlists())
parameters_dict.pop("page", None)
pagination_parameters = ""
for key, value_list in parameters_dict.iteritems():
for value in value_list:
pagination_item = "&%(key)s=%(value)s" % ({
"key": key,
"value": value,
})
pagination_parameters += pagination_item
It is working well. But it doesn't cover all possibilities and it is definitely not very pythonic.
Do you have a better (more pythonic) idea for creating url parameters from a list?
Thank you
You should be able to use the second doseq parameter urlencode offers:
http://docs.python.org/2/library/urllib.html
So basically, you can pass a dictionary of lists to urlencode like so:
urllib.urlencode(params, True)
And it will do the right thing.

protoRPC: returning dict

How does one return a dict like object through protoRPC ?
I tried using the FieldList to no avail. I only see the following field definitions:
'IntegerField',
'FloatField',
'BooleanField',
'BytesField',
'StringField',
'MessageField',
'EnumField',
There are two scenarios:
1) Your dict has a well-defined schema: This is the best use case for ProtoRPC and if possible you should try to fit it into a schema. In this case, you would use a MessageField with some Message class that matches the schema in your dictionary.
For example, instead of
{'amount': 31, 'type': 'fish', mine: False}
you could define
from protorpc import messages
class MyCatch(messages.Message):
amount = messages.IntegerField(1)
type = messages.StringField(2)
mine = messages.BooleanField(3)
and then use this message definition in a field via
messages.MessageField(MyCatch, index, ...)
2) Your dict does not have a well-defined schema: In this case you can use json to dump your dictionary to a string and request ensure_ascii=True to make sure the return type is a bytes (str) object. Then you can just use a BytesField.
For example:
import json
class MyMessage(messages.Message):
some_dict = messages.BytesField(1)
my_dict = {'amount': 31, 'type': 'fish', mine: False}
message = MyMessage(some_dict=json.dumps(my_dict, ensure_ascii=True))
The use of ensure_ascii is optional as True is the default, but this may change depending on your environment.
Instead you could use pickle to serialize your dictionary. The method pickle.dumps always outputs ASCII/binary, so by swapping out json.dumps for pickle.dumps and dropping the ensure_ascii=True, you'd have the same outcome.
It's possible to create a custom JsonField like this :
In [1]: class JsonField(messages.StringField):
type = dict
You can then use it as any other field :
In [2]: class MyMessage(messages.Message):
data = JsonField(1)
In [3]: m = MyMessage(data={"foo": "bar"})
In [4]: m.data
Out [4]: {'foo': 'bar'}
For the first option in the approved answer, we can add a parameter repeated=True, so we'll have a list of json as the answer. I checked about it at https://developers.google.com/appengine/docs/python/tools/protorpc/overview?hl=en#Defining_the_Response_Message
A bit involved, but I have a recipe for something quite close to a dict implementation for protorpc: https://gist.github.com/linuxluser/32d4a9c36ca0b8715ad4
It is restricted to using string-only keys and simple (not nested) values. But if your data fits in that category, this solution should work well.
The idea has 2 parts:
Create a new field type MultiField that can hold an arbitrary value type.
Create a dict-like type MapField that stores key-value pairs in a list of MultiField types.
You use it like so:
import messages
import mapfield
class MyMessage(messages.Message):
some_dict = mapfield.MapField(1)
my_message = MyMessage(some_dict={"foo": 7, "bar": False, "baz": 9.2, "qux": "nog"})
It's only a start. Probably could be better. Improvements are welcomed. :)

Categories