How to parse python b' before dict - python

How to access id or nickname value with python3:
response._content = b'{"id":44564,"nickname":'Demo'}

It looks like you're trying to read in a Json string and convert it to a dict, e.g.:
import json
# response._content = b'{"id":44564,"nickname":"Demo"}'
data = json.loads(response._content.decode('utf-8'))
# data = {'id': 44564, 'nickname': 'Demo'}

This is a byte string that includes JSON as stated above. Another way to look at it is that is a dict definition (i.e python code). You can use eval for that:
foo = eval( b'{"id":44564,"nickname":"Demo"}')
foo['nickname']
Probably this is not the preferred or secure way to do it because eval is considered dangerous
https://nedbatchelder.com/blog/201206/eval_really_is_dangerous.html

Related

Using custom field names for json encoding in python

I have a python script that should generate a json file in a specific structure.
So to achieve that, my plan was to create my entity data classes that represents the structure of this json file, construct them, do all the magic needed for generation, and dump my object into a json file with json.dumps(my_object).
Now my problem is that this json structure have fields like weird-field:. since I can't use the "dash" symbol in my dataclass because of python syntax, I can't create my entity class that represents my json structure. (This json file will be used by another system, so I have no way to change the structure.)
Right now I worked around it by using wrong field names like weird_field that are accepted by python, then after encoding them to json I manually replaced those wrong field names in the json string.
I wonder if there is a better way to do it. In java you can just use a special annotation on those fields in your class to say "Hey Jackson, use this string for encoding instead of the name of the class' field". What's the python way to do the same?
In code what I'd like to do is:
#dataclass
class MyClass:
weird-field: int = 0 # syntax error here
json_obj = MyClass()
json_obj.weird-field = 621
print(json.dumps(json_obj))
I'd like to get
{
weird-field: 621
}
But it crashes since '-' can't be used for field name in python.
Use dictionaries.
json_obj = dict()
json_obj['weird-field'] = 621
my_weird_value = json_obj['weird-field'] # returns 621
print(json.dumps(json_obj))

convert string representation of a dict inside json dict value to dict

Hello all and sorry if the title was worded poorly. I'm having a bit of trouble wrapping my head around how to solve this issue I have encountered. I would have liked to simply pass a dict as the value for this key in my json obj but sadly I have to pass it as a string. So, I have a json dict object that looks like this
data = {"test": "Fuzz", "options": "'{'size':'Regular','connection':'unconnected'}'"}. Obviously, I would prefer that the second dict value weren't a string representation of a dictionary but rather a dictionary. Is the best route here to just strip the second and second to last single quotes for the data[options] or is there a better alternative?
Sorry for any confusion. This is how the json object looks after I perform
json.dump(data, <filename>)
The value for options can be thought of as another variable say x and it's equivalent to '{'size':'Regular','connection':'unconnected'}'
I could do x[1:-1] but I'm not sure if that is the most pythonic way to do things here.
import ast
bad_string_dict = "'{'size':'Regular','connection':'unconnected'}'"
good_string_dict = bad_string_dict.strip("'")
good_dict = ast.literal_eval(good_string_dict)
print(good_dict)
You will have to strip quotation mark, no other way around
Given OP's comments I suggest the following:
Set the environment variable to a known data format (example: json/yaml/...), not a specific language (python)
Use the json module (or the format you've chosen) to load the data
The data should look like this:
raw_data = {"test": "Fuzz", "options": "{\"size\": \"Regular\", \"connection\": \"unconnected\"}"}
And the code should look like this:
raw_options = raw_data['options']
options = json.loads(raw_options)
data = {**raw_data, 'options': options}

Avoid double encoding json

I'm trying to wrap a pandas dataframe in another json response. You can see below that I use to_json() to create job.result. But when I wrap it with other json items it either does not serialize because it is a dict, or encodes the pandas object twice. How can I wrap the pandas item with other json items without double encoding? I considered using to_dict() instead of to_json(), but then I run into date format issues.
job.result = result.to_json(date_format='iso')
data = {
'status': job.get_status(),
'result': job.result,
}
response = make_response(data)
response.mimetype = 'application/json'
return response
Doing some quick research on pandas to_json, that function returns a string representation of your json object, not the actual json object.
If your intent is to send it as part of the actual object instead of just a string, I would parse it before sending it, aka, the equivalent of: job.result = JSON.parse(result.to_json(date_format='iso')).
Edit: because I kind of answered in the context of javascript instead of python, json.loads(result.to_json(date_format='iso')) is the Python solution the OP ended up using.

How can I log a dictionary into a log file?

I have a dictionary:
d = {name : "John", age: 10}.
And a log file setup as:
logging.basicConfig(level = logging.DEBUG, filename = "sample.log")
Is it possible to log this dictionary into the "sample.log" file? If yes, how can I do it?
Simple solution that works
The logging functions will convert the '%s' to string representation (and if the object happens to be a container, then repr() will be used for the contained objects)
import logging
logging.basicConfig(level=logging.DEBUG, filename='sample.log')
logging.debug('Sample dict log: %s', {'name' : "John", 'age': 10})
How it shows in the log file:
DEBUG:root:Sample dict log: {'age': 10, 'name': 'John'}
If you have custom objects (e.g. instances of your own classes), you should implement a sensible __str__ and/or __repr__ for it, and the above will work without any hacks.
More on this here What is the difference between __str__ and __repr__?
A Note on performance
Notice that
logging.debug('%s', some_dict) is not same as
logging.debug('{0}'.format(some_dict))
In the first one, the function is passed 2 arguments '%s' and the original some_dict.
In the second one, the function is passed one argument which is the already-converted some_dict to a string.
Because a function needs the arguments evaluated, the second example will always do the conversion, even if logging configs have turned off the logging of debug messages.
That's an unnecessary performance penalty.
In the the first example, the logging.debug function can decide to do the conversion, or not.
JSON is not very good for this
For objects that aren't JSON-like (object instances, datetime, etc), json.dumps() would require a custom serializer e.g. with datetime objects you get:
TypeError: datetime.datetime(...) is not JSON serializable
This goes for any type that isn't supported by json.dumps()
Whereas the logging module would figure out a good representation for the object
Simple you can use
dict_data = {"test":"data"}
logger.info("Loging dict ---> {0}".format(dict_data))
you can convert it to string:
string_dictionary = str(d)
and then log the string dictionary variable to the file
using JSON
import json
d = {"name":"John","age":10}
json_string = json.dumps(d)
and if you want to convert the string back:
d = json.loads(json_string)
The problem with str(dictionary) and json.dumps(dictionary) is that the output can human unfriendly, especially if the dictionary is big and has nested structures.
If that's the case, you can Python's built-in pprint to pretty format the dictionary before logging:
import pprint
my_complex_dict = pprint.pformat(my_complex_dict)
logger.info(f"My complex dict:\n{my_complex_dict}")
I came to this question when I wanted to log JSON lines for Cloudwatch.
I ended up using python-json-logger.
Install it: pip install python-json-logger
Use pythonjsonlogger.jsonlogger.JsonFormatter as the formatter class.

How to retrieve GET vars in python bottle app

I'm trying to make a simple REST api using the Python bottle app.
I'm facing a problem in retrieving the GET variables from the request global object.
Any suggestions how to retrieve this from the GET request?
They are stored in the request.query object.
http://bottlepy.org/docs/dev/tutorial.html#query-variables
It looks like you can also access them by treating the request.query attribute like a dictionary:
request.query['city']
So dict(request.query) would create a dictionary of all the query parameters.
As #mklauber notes, this will not work for multi-byte characters. It looks like the best method is:
my_dict = request.query.decode()
or:
dict(request.query.decode())
to have a dict instead of a <bottle.FormsDict object at 0x000000000391B...> object.
If you want them all:
from urllib.parse import parse_qs
dict = parse_qs(request.query_string)
If you want one:
one = request.GET.get('one', '').strip()
Can you try this please:
For this example : http://localhost:8080/command?param_name=param_value
In your code:
param_value = request.query.param_name
from the docs
name = request.cookies.name
# is a shortcut for:
name = request.cookies.getunicode('name') # encoding='utf-8' (default)
# which basically does this:
try:
name = request.cookies.get('name', '').decode('utf-8')
except UnicodeError:
name = u''
So you might prefer using attribute accessor (request.query.variable_name) than request.query.get('variable_name')
Another point is you can use request.params.variable_name which works both for GET and POST methods, than having to swich request.query.variable_name or request.forms.variable_name depending GET/POST.

Categories