{ "info": { "author": "Lincoln de Sousa", "author_email": "lincoln@comum.org", "bugtrack_url": null, "classifiers": [], "description": "# Extensible serialization spec\n\nThere are countless scenarios that we need to exchange data between\ndifferent systems, implemented in different languages and technologies.\nEven in the same system, when implementing data exchange between the\nbackend and the frontend we face the need to convert the language data\ntypes to another format and then do the oposite when the data arrives in\nthe other side of the wire.\n\nA very simple and flexible format that seems to fit most of our needs is\nthe JavaScript Object Notation, or simple `json`. It is very hard to\nfind a programming language these days that does not support it, even\nthe low level ones, like C, C++, etc.\n\nJson is enough when we need to exchange data types like integers,\ndoubles, strings, lists and hash tables. The problem starts when we need\nto exchange a complex data type. And it's the exact aim of this\ndocument: providing an API to extend the `json` library to make it easy\nto register new serializers and new deserializers.\n\n## How to identify a data type\n\nBefore talking about how to serialize or deserialize a data type, it is\nimportant to know how we identify the type of a complex python\nobject. Let's start with the basic ones. The number `1` is just an\ninstance of the built-in class `int`. The literal `\"stuff\"` is\ntranslated to something like `str(\"stuff\")` and is an instance of the\n`str` class. Lists and dictionaries are the same:\n\n```python\nmylist = [1, 2, 3]\nisinstance(mylist, list) # Yeah, it's an instance of the list class\nmydict = {\"a\": 1, \"b\": 2}\nisinstance(mydict, dict) # Also, it's an instance of the dict class\n```\n\nBut what about a home made class? Like this this one:\n\n```python\nclass A(object):\n def __init__(self):\n self.myint = 42\n self.mystr = \"nothing special\"\n self.mylist = [self.myint, self.mystr]\n```\n\nAs we know, python classes are *also* python *types*. So, if you create\na new instance of `A()`, let's say, like this: `a = A()`. You can say\nthat the type of the `a` variable is `A`, just like the type of `1` is\n`int`. In other words, the built-in function `isinstance()` will tell\nyou if an instance type is equals to a given type/class.\n\n## What the json library knows about types\n\nSo, the `json` module knows how to deal with these built-in types, but\nit does not understand the complex types. Have you tried to dump a\n`datetime.datetime` instance with the `json` library? Here's what you\nget:\n\n```\nTraceback (most recent call last):\n File \"\", line 1, in \n (...)\n File \".../encoder.py\"\n raise TypeError(repr(o) + \" is not JSON serializable\")\nTypeError: datetime.datetime(2012, 8, 22, 12, 19, 12, 577078) is not JSON serializable\n```\n\nIt happens because the `json` library doesn't know how to deal with\nthese objects. A simple fix would be doing something like this:\n\n```python\n>>> import json\n>>> def converter(val):\n... if isinstance(val, datetime):\n... return val.isoformat()\n... raise TypeError\n...\n>>> date = datetime(2012, 8, 22, 12, 23)\n>>> json.dumps({'a': 'b', 'b': date}, default=converter)\n'{\"a\": \"b\", \"b\": \"2012-08-22T12:23:00\"}'\n```\n\n## How to extend the json library in an elegant way\n\nInstead of creating a module with all the types that you are willing to\nsupport in your system, this spec suggests the introduction of an API\nthat register types and their handlers.\n\nIt is a two step process. First, let's declare a complex type called\n`Person`. The second step consists in letting the `ejson` library know\nhow to serialize objects of that class. To do that, you need to\nregister a serializer. Take a look at the full example:\n\n```python\n>>> class Person(object):\n... def __init__(self, name, age, gender):\n... self.name = name\n... self.age = age\n... self.gender = gender\n...\n>>> import ejson\n>>> @ejson.register_serializer(Person)\n... def serialize_person(instance):\n... return {\n... 'name': instance.name,\n... 'age': instance.age,\n... 'gender': instance.gender,\n... }\n...\n>>> from ejson import dumps\n>>> dumps(Person('Lincoln', 25, 'male'))\n'{\"__class__\": \"steadymark.core.Person\", \"__value__\": {\"gender\": \"male\", \"age\": 25, \"name\": \"Lincoln\"}}'\n```\n\n### One more step serializing complex objects\n\nIn order to find the right deserializer for a given value, we also add\nthe dotted path that leads to the factory that built the instance to the\n`json` info returned by our custom `dumps()` function.\n\n## Deserializing objects is a little bit harder\n\nIn the last example, we've serialized an instance of the `Person` class\nwith the help of the registered serializer. But, what happens if we need\nto deserialize that object after receiving its json description from the\nwire?\n\nIt is not simple to guess that a dictionary with the \"name\", \"age\" and\n\"gender\" keys is a `Person` instance. To make it a bit easier to handle\nthis scenario, this spec suggests the introduction of a registry of\ndeserializers and an easy way to retrieve them. Thus, if you are writing\na component that needs to handle a field that you are sure that\nrepresents a `Person`, you can do something like this:\n\n```python\n>>> import ejson\n>>> import json\n>>>\n>>> class Person(object):\n... def __init__(self, name, age, gender):\n... self.name = name\n... self.age = age\n... self.gender = gender\n...\n>>> @ejson.register_deserializer(Person)\n... def deserialize_person(data):\n... return Person(data['name'], data['age'], data['gender'])\n...\n>>>\n>>> import ejson\n>>> content = '{\"gender\": \"male\", \"age\": 25, \"name\": \"Lincoln\"}'\n>>> obj = json.loads(content)\n>>> person = ejson.deserialize(Person, obj)\n>>> isinstance(person, Person)\nTrue\n```\n\n### Automating deserialization\n\nThe `json.loads` function is not aware of our special parameter\n`__class__`, so we also provide a wrapper for it, called `ejson.loads`.\nWriting code to deserialize objects that were serialized by the `ejson`\nlibrary should be as simple as this following example:\n\n```python\n# steadymark: ignore\n>>> import ejson\n>>> from yourapp.person import Person\n>>> person = ejson.loads(http_response.content)\n>>> isinstance(person, Person) == True\n```", "description_content_type": null, "docs_url": null, "download_url": "UNKNOWN", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/Yipit/ejson", "keywords": null, "license": "GPL", "maintainer": null, "maintainer_email": null, "name": "ejson", "package_url": "https://pypi.org/project/ejson/", "platform": "UNKNOWN", "project_url": "https://pypi.org/project/ejson/", "project_urls": { "Download": "UNKNOWN", "Homepage": "https://github.com/Yipit/ejson" }, "release_url": "https://pypi.org/project/ejson/0.1.6/", "requires_dist": null, "requires_python": null, "summary": "Extensible json serializer/deserializer library", "version": "0.1.6" }, "last_serial": 1097608, "releases": { "0.1.0": [ { "comment_text": "", "digests": { "md5": "9f657550bd5b445d8a383ee114399e44", "sha256": "6ca455aa42c2f1fe46ee3240f4a73f4fe946a019ca6b1b0dcf578aee6b174005" }, "downloads": -1, "filename": "ejson-0.1.0.tar.gz", "has_sig": false, "md5_digest": "9f657550bd5b445d8a383ee114399e44", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6121, "upload_time": "2013-03-30T23:01:17", "url": "https://files.pythonhosted.org/packages/85/23/b1663c7ae5af6e0f897e2a749273e995b24ea4d13c6c2d4015ef416ace05/ejson-0.1.0.tar.gz" } ], "0.1.1": [ { "comment_text": "", "digests": { "md5": "8f0f12a9120bf834df785eee88374f60", "sha256": "517faa43bb8a7bce3e7fc77e04d56111ab83476790de246a19df0acc2eccf945" }, "downloads": -1, "filename": "ejson-0.1.1.tar.gz", "has_sig": false, "md5_digest": "8f0f12a9120bf834df785eee88374f60", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6966, "upload_time": "2013-03-31T04:55:02", "url": "https://files.pythonhosted.org/packages/e3/69/0afe84b0871f07bb9ee5dd67900335d86b96fcbdc04f5a55eb4f50428372/ejson-0.1.1.tar.gz" } ], "0.1.2": [ { "comment_text": "", "digests": { "md5": "9c0c29d17d16834efcbf2b87ffd840a8", "sha256": "c327bf71846439d3c0791dfbd47faedf273944455e22a160176a8d31e5379d2c" }, "downloads": -1, "filename": "ejson-0.1.2.tar.gz", "has_sig": false, "md5_digest": "9c0c29d17d16834efcbf2b87ffd840a8", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 7445, "upload_time": "2013-04-01T15:03:46", "url": "https://files.pythonhosted.org/packages/3a/40/7b9c71195df65d7a981dba53fa93ea06665b6d3a336aaa78956707c282e0/ejson-0.1.2.tar.gz" } ], "0.1.3": [ { "comment_text": "", "digests": { "md5": "8fa366d6482083234e31ed4babb9bb48", "sha256": "0a352bf0465add0b2ab3a5f22035e4d49718976c43b783fd220b42d0bbe50c5d" }, "downloads": -1, "filename": "ejson-0.1.3.tar.gz", "has_sig": false, "md5_digest": "8fa366d6482083234e31ed4babb9bb48", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 9923, "upload_time": "2013-04-01T15:08:07", "url": "https://files.pythonhosted.org/packages/cf/cd/1cdbb7cdfed312a2ddace2da463deacc1b8cfbf4b9e515718609c9473992/ejson-0.1.3.tar.gz" } ], "0.1.4": [ { "comment_text": "", "digests": { "md5": "e4ec20e646691b6cc0f1c2eb191109f3", "sha256": "8d4f837d8e39dcf1a26523ca2bb86d97217cbebfd17aede8bf5a332a7cac800e" }, "downloads": -1, "filename": "ejson-0.1.4.tar.gz", "has_sig": false, "md5_digest": "e4ec20e646691b6cc0f1c2eb191109f3", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 9929, "upload_time": "2013-04-10T22:18:49", "url": "https://files.pythonhosted.org/packages/18/54/fd6ef88ecd00b2049c901d16e23c096aca141e906b5a0f53060fc5edc6b6/ejson-0.1.4.tar.gz" } ], "0.1.5": [ { "comment_text": "", "digests": { "md5": "02978c9c36cea652bd0242510c7f8875", "sha256": "7c64559bc87ee5d1925d0a73d654e2bb7d5f764e7cd55b8caacc26289549e985" }, "downloads": -1, "filename": "ejson-0.1.5.tar.gz", "has_sig": false, "md5_digest": "02978c9c36cea652bd0242510c7f8875", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 10252, "upload_time": "2013-04-29T18:43:21", "url": "https://files.pythonhosted.org/packages/b3/fd/c3ca33683c2d56c81384d681a6169ff272ab442b36e2572436f2c63a7717/ejson-0.1.5.tar.gz" } ], "0.1.6": [ { "comment_text": "", "digests": { "md5": "79341153094024cfcd2813bd81a8c82c", "sha256": "8ef4b2563fbe2e0fdf28efb52e8b06d1f8d9099aa7685c26ce51761d116da4ef" }, "downloads": -1, "filename": "ejson-0.1.6.tar.gz", "has_sig": false, "md5_digest": "79341153094024cfcd2813bd81a8c82c", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 10244, "upload_time": "2013-11-13T15:50:14", "url": "https://files.pythonhosted.org/packages/f4/f2/e4aaeab6afabe15fc527a92c9f89c58ec26d93129c85517b703e5f5b1807/ejson-0.1.6.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "79341153094024cfcd2813bd81a8c82c", "sha256": "8ef4b2563fbe2e0fdf28efb52e8b06d1f8d9099aa7685c26ce51761d116da4ef" }, "downloads": -1, "filename": "ejson-0.1.6.tar.gz", "has_sig": false, "md5_digest": "79341153094024cfcd2813bd81a8c82c", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 10244, "upload_time": "2013-11-13T15:50:14", "url": "https://files.pythonhosted.org/packages/f4/f2/e4aaeab6afabe15fc527a92c9f89c58ec26d93129c85517b703e5f5b1807/ejson-0.1.6.tar.gz" } ] }