Library for converting between python objects and JSON data structures - python

I need to work in an environment where the server has data objects cached in memory, and some or all of them needs to be sent over a websocket to a client. The conversion between the objects and the data structures is very straingforward. For example, here is a TypeScript definition of a data transfer object:
export interface IFieldStruct {
field_name: string;
type: string;
displaylabel: string;
notnull: boolean;
}
The corresponding Python objects looks like this:
class FieldStuct:
def __init__(field_name: str, type: str, displaylabel: str, notnull: bool):
self.field_name = field_name
self.field_name = field_name
self.displaylabel = displaylabel
self.notnull = notnull
Actually, the Python objects on the server side are smarter than that. They also have methods, and they also have some attributes that need not to be exported to JSON. Some of their attributes can be lists and dictionaries containing other smart objects.
Here is the problem. I would like to take advantage of code completion and code inspection in my Python IDE (pycharm). So I don't want to store this data as a data structure in Python. But I also want to be able to convert and send these objects easily.
I know that I could write my own serializer/deserializer for this. But there will be hundreds of data object classes, and I do not want to write a serializer manually. I wonder if there is good a library that already does this for me with object introspection? I do not want to reinvent the wheel. There are too many libs on PyPi, and I'm not able to find the right one. I'm not asking for opinions, I'm just asking for a list of the most popular libs that can help me in the conversion.

Pickle is one of the most popular (de)serializations libs out there, if not the most popular.
https://docs.python.org/3/library/pickle.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))

Converting a String to Type Object - Python

I have created a DataStore, and the type of fields in the data store has been saved in json format.
Something like
{"SchemaName": "Caztor", "FieldType": {"cain": "<type 'float'>"}}
Now when i load the json using json.load , the type of the field cain is being loaded as Unicode. Is there any pre defined methods available in python which can be used to typecast this String to Type object. Ofcourse I can make a function that would handle and solve the problem. But if there is already a solution to this in the python library then it would save a bit of overhead and might be more efficient in handling the problem than I might do.
You can use the module pickle to solve the typecast. this module can serialize the instances into a string
The Documentation is present on https://docs.python.org/2/library/pickle.html
Example
import pickle
schema = {"SchemaName": "Caztor", "FieldType": {"cain": float}}
result = pickle.dumps(schema) # Will result a string
To deserialize use:
result2 = pickle.loads(result) # Will result a dictionary with typecast
There is no solution. JSON is a universal format across all languages and it doesn't make sense for it to be able to store Python classes. You need to define a fixed way to go back and forth between strings and types, which includes determining which types are acceptable. Here's an example:
class Example(object):
pass
json_types = [int, float, str, Example]
string_to_type_dict = {t.__name__: t for t in json_types}
assert len(string_to_type_dict) == len(json_types)
def string_to_type(s):
return string_to_type_dict[s]
def type_to_string(t):
return t.__name__

Layer between data extraction and storage

What I am doing:
Get data from data source (could be from API or scraping) in form of a dictionary
Clean/manipulate some of the fields
Combine fields from data source dictionary into new dictionaries that represent objects
Save the created dictionaries into database
Is there a pythonic way to do this? I am wondering about the whole process but I'll give some guiding questions:
What classes should I have?
What methods/classes should the cleaning of fields from the data source to objects be in?
What methods/classes should the combining/mapping of fields from the data source to objects be in?
If the method is different in scraping vs. api, please explain how and why
Here is an example:
API returns:
{data: {
name: "<b>asd</b>",
story: "tame",
story2: "adjet"
}
}
What you want to do:
Clean name
Create a name_story object
Set name_story.name = dict['data']['name']
Set name_story.story = dict['data']['story'] + dict['data']['story2']
Save name_story to database
(and consider that there could be multiple objects to create and multiple incoming data sources)
How would you structure this process? An interface of all classes/methods would be enough for me without any explanation.
What classes should I have?
In Python, there is no strong need to use classes. Classes are the way to manage complexity. If your solution is not complex, use functions (or, maybe, module-level code, if it is one-time solution)
If the method is different in scraping vs. api, please explain how and why
I prefer to organize my code in respect with modularity and principle of least knowledge and define clear interfaces between parts of modules system.
Example of modular solution
You can have module (either function or class) for fetching information, and it should return dictionary with specified fields, no matter what exactly it does.
Another module should process dictionary and return dictionary too (for example).
Third module can save information from that dictionary to database.
There is great possibility, that this plan far from what you need or want and you should develop your modules system yourself.
And some words about your wants:
Clean name
Consider this stackoverflow answer
Create a name_story object
Set name_story.name = dict['data']['name']
Set name_story.story = dict['data']['story'] + dict['data']['story2']
If you want to have access to attributes of object through dot (as you specified in 3 and 4 items, you could use either python namedtuple or plain python class. If indexed access is OK for you, use python dictionary.
In case of namedtuple, it will be:
from collections import namedtuple
NameStory = namedtuple('NameStory', ['name', 'story'])
name_story1 = NameStory(name=dict['data']['name'], story=dict['data']['story'] + dict['data']['story2'])
name_story2 = NameStory(name=dict2['data']['name'], story=dict2['data']['name'])
If your choice if dictionary, it's easier:
name_story = {
'name': dict['data']['name'],
'story': dict['data']['story'] + dict['data']['story2'],
}
Save name_story to database
This is much more complex question.
You can use raw SQL. Specific instructions depends on your database. Google for 'python sqlite' or 'python postgresql' or what you want, there are plenty of good tutorials.
Or you can utilize one of python ORMs:
peewee
SQLAlchemy
google for more options
By the way
It's strongly recommended to not override python built-in types (list, dict, str etc), as you did in this line:
name_story.name = dict['data']['name']

Get a list of inbuild types

Is it possible to get a list of inbuilt types in Python including types included in imported modules? So the code would return something like [int, list, dict str, etc..etc]
The reason for doing this is as follows. I am an enthusiastic new user of Python. To help me ramp up I decided to commit to memory inbuilt methods. To do this I used the Anki flash card program on Ubuntu. With this tool you can import a csv like file with questions and answers on each line separated by a delimiter.
Firstly I began with the build in methods. I found a suitable html table here and I wrote a script using BeautifulSoup4 to locate and convert this data to a csv format I could import into Anki. This worked great and I committed them all to memory. Then I realized that if I wanted to do the same with other data types I would need to find similar extensive lists which are not available on the site I used to start with.
I am considering taking each data type, running a dir on it to get all the methods that can act on it and then to call help() on each public method, for example help(str.beginswith). I would then do some parsing to separate the method name from the description and write this to file in a csv format. Please don’t someone write this for me only pointers/hints please.
You can use types module:
>>> import types
>>> [t for t in vars(types).values() if isinstance(t, type)]
[<type 'int'>, <type 'type'>, <type 'code'>, ..., <type 'NoneType'>]
But, this is not complete as the documentation says:
This module defines names for some object types that are used by the
standard Python interpreter, but not for the types defined by various
extension modules. Also, it does not include some of the types that
arise during processing such as the listiterator type. ...

How to inspect mystery deserialized object in Python

I'm trying to load JSON back into an object. The "loads" method seems to work without error, but the object doesn't seem to have the properties I expect.
How can I go about examining/inspecting the object that I have (this is web-based code).
results = {"Subscriber": {"firstname": "Neal", "lastname": "Walters"}}
subscriber = json.loads(results)
for item in inspect.getmembers(subscriber):
self.response.out.write("<BR>Item")
for subitem in item:
self.response.out.write("<BR> SubItem=" + subitem)
The attempt above returned this:
Item
SubItem=__class__
I don't think it matters, but for context:
The JSON is actually coming from a urlfetch in Google App Engine to
a rest web service created using this utility:
http://code.google.com/p/appengine-rest-server.
The data is being retrieved from a datastore with this definition:
class Subscriber(db.Model):
firstname = db.StringProperty()
lastname = db.StringProperty()
Thanks,
Neal
Update #1: Basically I'm trying to deserialize JSON back into an object.
In theory it was serialized from an object, and I want to now get it back into an object.
Maybe the better question is how to do that?
Update #2: I was trying to abstract a complex program down to a few lines of code, so I made a few mistakes in "pseudo-coding" it for purposes of posting here.
Here's a better code sample, now take out of website where I can run on PC.
results = '{"Subscriber": {"firstname": "Neal", "lastname": "Walters"}}'
subscriber = json.loads(results)
for key, value in subscriber.items():
print " %s: %s" %(key, value)
The above runs, what it displays doesn't look any more structured than the JSON string itself. It displays this:
Subscriber: {u'lastname': u'Walters', u'firstname': u'Neal'}
I have more of a Microsoft background, so when I hear serialize/deserialize, I think going from an object to a string, and from a string back to an object. So if I serialize to JSON, and then deserialize, what do I get, a dictionary, a list, or an object? Actually, I'm getting the JSON from a REST webmethod, that is on my behalf serializing my object for me.
Ideally I want a subscriber object that matches my Subscriber class above, and ideally, I don't want to write one-off custom code (i.e. code that would be specific to "Subscriber"), because I would like to do the same thing with dozens of other classes. If I have to write some custom code, I will need to do it generically so it will work with any class.
Update #3: This is to explain more of why I think this is a needed tool. I'm writing a huge app, probably on Google App Engine (GAE). We are leaning toward a REST architecture for several reasons, but one is that our web GUI should access the data store via a REST web layer. (I'm a lot more used to SOAP, so switching to REST is a small challenge in itself). So one of the classic ways of getting and update data is through a business or data tier. By using the REST utility mention above, I have the choice of XML or JSON. I'm hoping to do a small working prototype of both before we develop the huge app). Then, suppose we have a successful app, and GAE doubles it prices. Then we can rewrite just the data tier, and take our Python/Django user tier (web code), and run it on Amazon or somewhere else.
If I'm going to do all that, why would I want everything to be dictionary objects. Wouldn't I want the power of full-blown class structure? One of the next tricks is sort of an object relational mapping (ORM) so that we don't necessarily expose our exact data tables, but more of a logical layer.
We also want to expose a RESTful API to paying users, who might be using any language. For them, they can use XML or JSON, and they wouldn't use the serialize routine discussed here.
json only encodes strings, floats, integers, javascript objects (python dicts) and lists.
You have to create a function to turn the returned dictionary into a class and then pass it to a json.loads using the object_hook keyword argument along with the json string. Heres some code that fleshes it out:
import json
class Subscriber(object):
firstname = None
lastname = None
class Post(object):
author = None
title = None
def decode_from_dict(cls,vals):
obj = cls()
for key, val in vals.items():
setattr(obj, key, val)
return obj
SERIALIZABLE_CLASSES = {'Subscriber': Subscriber,
'Post': Post}
def decode_object(d):
for field in d:
if field in SERIALIZABLE_CLASSES:
cls = SERIALIZABLE_CLASSES[field]
return decode_from_dict(cls, d[field])
return d
results = '''[{"Subscriber": {"firstname": "Neal", "lastname": "Walters"}},
{"Post": {"author": {"Subscriber": {"firstname": "Neal",
"lastname": "Walters"}}},
"title": "Decoding JSON Objects"}]'''
result = json.loads(results, object_hook=decode_object)
print result
print result[1].author
This will handle any class that can be instantiated without arguments to the constructor and for which setattr will work.
Also, this uses json. I have no experience with simplejson so YMMV but I hear that they are identical.
Note that although the values for the two subscriber objects are identical, the resulting objects are not. This could be fixed by memoizing the decode_from_dict class.
results in your snippet is a dict, not a string, so the json.loads would raise an exception. If that is fixed, each subitem in the inner loop is then a tuple, so trying to add it to a string as you are doing would raise another exception. I guess you've simplified your code, but the two type errors should already show that you simplified it too much (and incorrectly). Why not use an (equally simplified) working snippet, and the actual string you want to json.loads instead of one that can't possibly reproduce your problem? That course of action would make it much easier to help you.
Beyyond peering at the actual string, and showing some obvious information such as type(subscriber), it's hard to offer much more help based on that clearly-broken code and such insufficient information:-(.
Edit: in "update2", the OP says
It displays this: Subscriber: {u'lastname': u'Walters', u'firstname': u'Neal'}
...and what else could it possibly display, pray?! You're printing the key as string, then the value as string -- the key is a string, and the value is another dict, so of course it's "stringified" (and all strings in JSON are Unicode -- just like in C# or Java, and you say you come from a MSFT background, so why does this surprise you at all?!). str(somedict), identically to repr(somedict), shows the repr of keys and values (with braces around it all and colons and commas as appropriate separators).
JSON, a completely language-independent serialization format though originally centered on Javascript, has absolutely no idea of what classes (if any) you expect to see instances of (of course it doesn't, and it's just absurd to think it possibly could: how could it possibly be language-independent if it hard-coded the very concept of "class", a concept which so many languages, including Javascript, don't even have?!) -- so it uses (in Python terms) strings, numbers, lists, and dicts (four very basic data types that any semi-decent modern language can be expected to have, at least in some library if not embedded in the language proper!). When you json.loads a string, you'll always get some nested combination of the four datatypes above (all strings will be unicode and all numbers will be floats, BTW;-).
If you have no idea (and don't want to encode by some arbitrary convention or other) what class's instances are being serialized, but absolutely must have class instances back (not just dicts etc) when you deserialize, JSON per se can't help you -- that metainformation cannot possibly be present in the JSON-serialized string itself.
If you're OK with the four fundamental types, and just want to see some printed results that you consider "prettier" than the default Python string printing of the fundamental types in question, you'll have to code your own recursive pretty-printing function depending on your subjective definition of "pretty" (I doubt you'd like Python's own pprint standard library module any more than you like your current results;-).
My guess is that loads is returning a dictionary. To iterate over its content, use something like:
for key, value in subscriber.items():
self.response.out.write("%s: %s" %(key, value))

Categories