{ "info": { "author": "Ivan Korobkov", "author_email": "ivan.korobkov@gmail.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 4 - Beta", "Intended Audience :: Developers", "License :: OSI Approved :: Apache Software License", "Operating System :: OS Independent", "Programming Language :: Python :: 2.7", "Topic :: Internet :: WWW/HTTP", "Topic :: Internet :: WWW/HTTP :: WSGI", "Topic :: Software Development :: Libraries" ], "description": "Pdef Python\n===========\nPython code generator for [Pdef compiler](https://github.com/pdef/pdef)\nand Python implementation of descriptors, JSON format and HTTP RPC.\n\nRequirements\n------------\nPython 2.6 or Python 3.3+.\n\n\nInstallation\n------------\n- Code generator:\n ```bash\n $ pip install pdef-python\n ```\n\n Or [download](https://github.com/pdef/pdef-python/releases) the release,\n unzip it and in the `generator` directory run:\n ```bash\n $ python setup.py install\n ```\n\n The python generator will appear in the installed generators:\n ```bash\n $ pdefc generate -h\n usage: pdefc generate [...]\n available generators:\n - python: Python code generator, supports module names, does not support prefixes.\n ```\n\n- Python package:\n ```bash\n $ pip install pdef\n ```\n\n Or add it as a requirement to your project in `setup.py` or in pip `requirements.txt`.\n See [releases](https://github.com/pdef/pdef-python/releases) for the latest version.\n\nCode generation\n---------------\nPass a pdef package path or a url to the compiler:\n```bash\n$ pdefc generate-python https://raw.github.com/pdef/pdef/1.1/example/world.yaml \\\n --out generated\n```\n\nThe generator uses absolute module names (`package.module`) + `protocol.py` as python module names.\nFor example, `world.continents` is converted into `world/continents/protocol.py`.\nUse `--module` to manually map pdef modules to python modules.\n```bash\n$ pdefc generate-python https://raw.github.com/pdef/pdef/1.1/example/world.yaml \\\n --module world.space:world_space\n --module world:world_api\n --out generated\n```\n\nMessages\n--------\nGenerated messages implement `__eq__`, `__copy__`, `__deepcopy__`, and `__str__` magic methods,\nand merging methods. The messages are not thread-safe. The examples are based\non the [pdef example package](https://github.com/pdef/pdef/tree/master/example).\n\n```python\nhuman = Human(id=1, name=\"John\")\nhuman.location = Location(lat=30, lng=40)\nhuman.birthday = datetime.datetime(1900, 1, 2)\n\nimport copy\nanother = copy.deepcopy(human)\n\nassert copy == human\n```\n\nMessages support merging which deep copies fields from a source message to a destination one.\n```python\nhuman = Human(id=1, name=\"John\")\n\nanother = Human()\nanother.merge(human)\n\nassert another == human\n```\n\nMessages try to be None-safe and return default values for empty fields.\nIf an empty field is a collection or a message then it is initialized to an empty\nobject on the first access.\n```python\n# All properties return default values when the fields are empty.\nhuman = Human()\nassert human.id == 0\nassert human.name == \"\"\n\n# Special properties allow to check if the field is present.\nassert not human.has_id\nassert not human.has_name\n\n# Absent collection and message fields are initialized to empty objects on first access.\ncontinent = Continent()\nassert not continent.has_humans\n\n# The collection is initialized to an empty one.\ncontinent.humans.append(human)\nassert continent.humans == [human]\n```\n\nJSON Format\n-----------\nPdef uses built-in json parser/serializer:\n```python\n# From a JSON-compatible dictionary.\nhuman = Human.from_dict({\n \"id\": 123\n \"name\": \"John})\n\n# From a JSON string.\ns = get_json_string()\nhuman = Human.from_json(s)\n\n# From a file-like object.\nwith open('human.json', 'rt') as f:\n human = Human.from_json_stream(f)\n```\n\nSerialization:\n```python\n# To a JSON-compatible dictionary.\nd = human.to_dict()\n\n# To a JSON string.\ns = human.to_json(ident=None)\n\n# To a file-like object.\nwith open('myfile.json', 'wt') as f:\n human.to_json_stream(f, indent=None)\n```\n\nUse `pdef.jsonformat` to read/write other pdef data types:\n```python\n# Write a list of ints to a JSON-string.\nlist0 = [1, 2, 3]\nlistd = pdef.descriptors.list0(pdef.descriptors.int32)\ns = pdef.jsonformat.write(list0, listd)\n\n# Read a list of ints from a JSON-string.\nlist1 = pdef.jsonformat.read(s, listd)\nassert list0 == list1\n```\n\n\nHTTP RPC Client\n---------------\nRPC clients are thread-safe.\n\nCreate a default HTTP RPC client based on [requests](http://www.python-requests.org/en/latest/).\n```python\nclient = pdef.rpc_client(World, url='http://example.com/world/')\nworld_client = client.proxy()\n\n# Execute a remote method.\nhumans = world.humans().all(limit=10, offset=0)\n\n# Execute a void remote method.\nworld.switchDayNight()\n```\n\nNone primitive results are converted into default values.\n```python\n# It's safe to write:\ncount = in world.humans().count()\ncount += 1 # Cannot be None\n```\n\nFull client example:\n```python\n# Create a requests session.\nsession = my_requests_session()\n\n# Create an rpc client.\nclient = pdef.rpc_client(World, url='http://example.com/world/', session=session)\n\n# Create an interface proxy with the client as an invocation handler.\nproxy = pdef.proxy(World, invocation_handler=client)\n\n# Execute a remote method.\nproxy.humans().all(limit=10)\n```\n\nHTTP RPC Server\n---------------\nRPC handlers are thread-safe.\n\nCreate an rpc handler and a WSGI application:\n```python\nworld = get_my_world()\nhandler = pdef.rpc_handler(World, world)\nwsgi_app = pdef.wsgi_app(handler)\n# Pass the app to a web server.\n```\n\nNone primitive arguments are converted into default values:\n```python\nclass MyHumans(Humans):\n def all(self, limit, offset):\n # None limit and offset are set to 0.\n pass\n```\n\nTo support other frameworks (such as Django, Flask, etc.) you need to convert custom requests\ninto `RpcRequests` and handle `RpcResults`.\n```python\n# In Django something like this will work.\n\n# urlpatterns\nurlpatterns = patterns('',\n url(r'^myapp/api/(?P\\.+)$', 'myapp.views.api'),\n)\n\n# views\ndef api(request, path):\n # Convert a django request into an rpc request.\n rpc_req = RpcRequest(method=request.method, path=path)\n rpc_req.query = request.GET\n rpc_req.post = request.POST\n\n # Handle the rpc request.\n handler = get_rpc_handler()\n success, rpc_result = handler(rpc_req)\n\n # Convert the rpc result into a django response.\n response = HttpResponse(rpc_result.to_json(), content_type=\"application/json;charset=utf-8\")\n if success:\n # It's a successful result.\n response.status_code = 200\n else:\n # It's an expected application exception.\n response.status_code = 422 # Unprocessable entity.\n\n # Send the response.\n return response\n```\n\nLicense and Copyright\n---------------------\nCopyright: 2013 Ivan Korobkov \n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at:\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.", "description_content_type": null, "docs_url": null, "download_url": "UNKNOWN", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "http://github.com/pdef/pdef-python", "keywords": null, "license": "Apache License 2.0", "maintainer": null, "maintainer_email": null, "name": "pdef", "package_url": "https://pypi.org/project/pdef/", "platform": "UNKNOWN", "project_url": "https://pypi.org/project/pdef/", "project_urls": { "Download": "UNKNOWN", "Homepage": "http://github.com/pdef/pdef-python" }, "release_url": "https://pypi.org/project/pdef/1.2.0/", "requires_dist": null, "requires_python": null, "summary": "Protocol definition language", "version": "1.2.0" }, "last_serial": 996967, "releases": { "1.0.0": [ { "comment_text": "", "digests": { "md5": "ab8c94180dd4720a2a0ef4703b3dc499", "sha256": "9c0547aad4be1a30881a2b0b2fa4d81fa0cd2e612dca74f505e0059a81ca39c9" }, "downloads": -1, "filename": "pdef-1.0.0.tar.gz", "has_sig": false, "md5_digest": "ab8c94180dd4720a2a0ef4703b3dc499", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 16506, "upload_time": "2013-12-04T07:49:40", "url": "https://files.pythonhosted.org/packages/a8/00/8a9ed27d4c15da95976a56b96f170b5f3a1d9049c2344922cc2da8b40361/pdef-1.0.0.tar.gz" } ], "1.0.1": [ { "comment_text": "", "digests": { "md5": "3a2b80611bde951121386aa77af33d17", "sha256": "0134a9b2b4abd718937206349b7455e34789d63f33c90ef31f8051a6251ffc09" }, "downloads": -1, "filename": "pdef-1.0.1.tar.gz", "has_sig": false, "md5_digest": "3a2b80611bde951121386aa77af33d17", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 16718, "upload_time": "2013-12-18T13:27:46", "url": "https://files.pythonhosted.org/packages/50/c2/07f7db90d0033d960fc73b96ae6c07a9c9e4869081db093abb20836f6fdd/pdef-1.0.1.tar.gz" } ], "1.0.2": [ { "comment_text": "", "digests": { "md5": "97fcb6d1681592c2fe49497760e41819", "sha256": "b598865bbb1489852dbeaa4ac92643c7c19008789efa4315cf7a8fc14368f0b1" }, "downloads": -1, "filename": "pdef-1.0.2.tar.gz", "has_sig": false, "md5_digest": "97fcb6d1681592c2fe49497760e41819", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 20784, "upload_time": "2013-12-18T14:40:08", "url": "https://files.pythonhosted.org/packages/d8/70/ee4ad930aa678b4243129b3180d0f48ab570d956168e12db84c329e2b986/pdef-1.0.2.tar.gz" } ], "1.1.0": [ { "comment_text": "", "digests": { "md5": "d5b5db319183ed6f6c2b88eed89f4657", "sha256": "6d8a00a7c642adaa0749a3b1655413ce144dd1831f375b6a0c3bae723700350f" }, "downloads": -1, "filename": "pdef-1.1.0.tar.gz", "has_sig": false, "md5_digest": "d5b5db319183ed6f6c2b88eed89f4657", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 20891, "upload_time": "2013-12-22T16:09:47", "url": "https://files.pythonhosted.org/packages/0e/f1/de35f6c27efcff562a8546fe45d2bfe40b942f691ab70bcdc24edc921ed9/pdef-1.1.0.tar.gz" } ], "1.1.1": [ { "comment_text": "", "digests": { "md5": "c425c29686675fac7b409449a374976a", "sha256": "9d73dfbfd0cbc5cb6db9e46c5216e6b6580c95639b9fc5e40a6d14d39d52fbb2" }, "downloads": -1, "filename": "pdef-1.1.1.tar.gz", "has_sig": false, "md5_digest": "c425c29686675fac7b409449a374976a", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 20915, "upload_time": "2014-01-14T11:35:33", "url": "https://files.pythonhosted.org/packages/ec/63/c238aea0482fd5e0b4b7ae6f0d0071190ef369de616f577e179d828c0977/pdef-1.1.1.tar.gz" } ], "1.2.0": [ { "comment_text": "", "digests": { "md5": "ee66f8a93da61df3469e6daf5a08ff70", "sha256": "0288597cd9ccccf6e8123250948c75614efc98315b1a94bf678063ca35ecbb6b" }, "downloads": -1, "filename": "pdef-1.2.0.tar.gz", "has_sig": false, "md5_digest": "ee66f8a93da61df3469e6daf5a08ff70", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 21006, "upload_time": "2014-02-11T10:26:50", "url": "https://files.pythonhosted.org/packages/46/99/0ca0d4bd24910e76d3805e1763bedef0db0aad05aee8ab4e7bb0b5dc22a0/pdef-1.2.0.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "ee66f8a93da61df3469e6daf5a08ff70", "sha256": "0288597cd9ccccf6e8123250948c75614efc98315b1a94bf678063ca35ecbb6b" }, "downloads": -1, "filename": "pdef-1.2.0.tar.gz", "has_sig": false, "md5_digest": "ee66f8a93da61df3469e6daf5a08ff70", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 21006, "upload_time": "2014-02-11T10:26:50", "url": "https://files.pythonhosted.org/packages/46/99/0ca0d4bd24910e76d3805e1763bedef0db0aad05aee8ab4e7bb0b5dc22a0/pdef-1.2.0.tar.gz" } ] }