{ "info": { "author": "Emmanuel Bretelle", "author_email": "chantra@fb.com", "bugtrack_url": null, "classifiers": [ "Programming Language :: Python" ], "description": "# ATC Api\n\nATC API is a Django app that allow to bridge a REST API to ATCD's thrift API.\n\n# Setup\n\n## Requirements\n\n* [Django 1.10](https://github.com/django/django)\n* [Django REST framework 3.X](https://github.com/tomchristie/django-rest-framework)\n* [atc_thrift](../atc_thrift)\n\n## Installation\n\nThe easiest way to install `django-atc-api` is to install it directly from [pip](https://pypi.python.org/pypi).\n\n### From pip\n```bash\npip install django-atc-api\n```\n### From source\n\n```bash\n$ cd path/to/django-atc-api\npip install .\n```\n\n## Configuration\n\n1. Edit your Django project's `settings.py` and add `atc_api` and `rest_framework` to your `INSTALLED_APPS`:\n\n```python\n INSTALLED_APPS = (\n ...\n 'atc_api',\n 'rest_framework',\n )\n```\n\n2. Include the `atc_api` URLconf in your Django project urls.py like this:\n\n```python\n url(r'^api/v1/', include('atc_api.urls')),\n```\n\n3. Start the development server\n\n```bash\npython manage.py runserver 0.0.0.0:8000\n```\n\n4. Visit http://127.0.0.1:8000/api/v1/shape/ to set/unset shaping.\n\n\nSome settings like the `ATCD_HOST` and `ATCD_PORT` can be changes in your Django project'settings.py:\n\n```python\nATC_API = {\n 'ATCD_HOST': 'localhost',\n 'ATCD_PORT': 9090,\n}\n```\n\nsee [ATC api settings](atc_api/settings.py) for more details.\n\n\n# API usage\n\nLet's suppose the api is available under `/api/v1`. The core API is limited and allow to:\n\n* Getting the shaping staus of an device by GETing `/api/v1/shape/`\n* Shape a device by POSTing to `/api/v1/shape/`\n* Unshape a device by sending a DELETE request to `/api/v1/shape/`\n\n## Shaping Status\n\nTo find out if a device is shaped, you can GET `/api/v1/shape/[ip/]`\n\nIf the device is being shaped, HTTP will return 200 and the current shaping of the device.\n\nIf the device is not being shaped, HTTP will return code 404.\n\nExamples:\n\n* Check if I am being shaped (device not being shaped, HTTP code 404):\n\n```sh\n$ curl -H 'Accept: application/json; indent=2' http://127.0.0.1:8080/api/v1/shape/\n{\n \"detail\": \"This IP (10.0.2.2) is not being shaped\"\n}\n```\n\n* Check if I am being shaped (device being shaped, HTTP code 200):\n\n```sh\n$ curl -H 'Accept: application/json; indent=2' http://127.0.0.1:8080/api/v1/shape/\n{\n \"down\": {\n \"rate\": 400,\n \"loss\": {\n \"percentage\": 5.0,\n \"correlation\": 0.0\n },\n \"delay\": {\n \"delay\": 15,\n \"jitter\": 0,\n \"correlation\": 0.0\n },\n \"corruption\": {\n \"percentage\": 0.0,\n \"correlation\": 0.0\n },\n \"reorder\": {\n \"percentage\": 0.0,\n \"correlation\": 0.0,\n \"gap\": 0\n }\n },\n \"up\": {\n \"rate\": 200,\n \"loss\": {\n \"percentage\": 1.0,\n \"correlation\": 0.0\n },\n \"delay\": {\n \"delay\": 10,\n \"jitter\": 0,\n \"correlation\": 0.0\n },\n \"corruption\": {\n \"percentage\": 0.0,\n \"correlation\": 0.0\n },\n \"reorder\": {\n \"percentage\": 0.0,\n \"correlation\": 0.0,\n \"gap\": 0\n }\n }\n}\n```\n\n* Check if 1.1.1.1 is being shaped (device not being shaped, HTTP code 404):\n\n```sh\n$ curl -H 'Accept: application/json; indent=2' http://127.0.0.1:8080/api/v1/shape/1.1.1.1/\n{\n \"detail\": \"This IP (1.1.1.1) is not being shaped\"\n}\n```\n\n## Shaping a device\n\nShaping a device is done by posting the shaping setting payload to `/api/v1/shape/[ip/]`\n\n\nExamples:\n\n* Shape my own device, 200kb up, added latency of 10ms with 1% packet loss and 400kb down with added latency of 15ms and 5% packet loss\nThis will always retun HTTP code 201 on success. If the device was already being shaped, the new setting is going to be applied and the onld one deleted.\n\nMind the (Ctrl-D)\n\n```sh\n$ curl -X POST -d '@-' -i -H 'Content-Type: application/json' -H 'Accept: application/json; indent=2' http://127.0.0.1:8080/api/v1/shape/\n{\n \"down\": {\n \"rate\": 400,\n \"loss\": {\n \"percentage\": 5.0,\n \"correlation\": 0.0\n },\n \"delay\": {\n \"delay\": 15,\n \"jitter\": 0,\n \"correlation\": 0.0\n },\n \"corruption\": {\n \"percentage\": 0.0,\n \"correlation\": 0.0\n },\n \"reorder\": {\n \"percentage\": 0.0,\n \"correlation\": 0.0,\n \"gap\": 0\n }\n },\n \"up\": {\n \"rate\": 200,\n \"loss\": {\n \"percentage\": 1.0,\n \"correlation\": 0.0\n },\n \"delay\": {\n \"delay\": 10,\n \"jitter\": 0,\n \"correlation\": 0.0\n },\n \"corruption\": {\n \"percentage\": 0.0,\n \"correlation\": 0.0\n },\n \"reorder\": {\n \"percentage\": 0.0,\n \"correlation\": 0.0,\n \"gap\": 0\n }\n }\n}\nCtrl-D\nHTTP/1.1 201 CREATED\nServer: gunicorn/19.2.1\nDate: Fri, 27 Feb 2015 20:02:05 GMT\nConnection: close\nTransfer-Encoding: chunked\nVary: Accept, Cookie\nContent-Type: application/json; indent=2\nAllow: GET, POST, DELETE, HEAD, OPTIONS\n\n{\n \"down\": {\n \"rate\": 400,\n \"loss\": {\n \"percentage\": 5.0,\n \"correlation\": 0.0\n },\n \"delay\": {\n \"delay\": 15,\n \"jitter\": 0,\n \"correlation\": 0.0\n },\n \"corruption\": {\n \"percentage\": 0.0,\n \"correlation\": 0.0\n },\n \"reorder\": {\n \"percentage\": 0.0,\n \"correlation\": 0.0,\n \"gap\": 0\n }\n },\n \"up\": {\n \"rate\": 200,\n \"loss\": {\n \"percentage\": 1.0,\n \"correlation\": 0.0\n },\n \"delay\": {\n \"delay\": 10,\n \"jitter\": 0,\n \"correlation\": 0.0\n },\n \"corruption\": {\n \"percentage\": 0.0,\n \"correlation\": 0.0\n },\n \"reorder\": {\n \"percentage\": 0.0,\n \"correlation\": 0.0,\n \"gap\": 0\n }\n }\n}\n```\n\nor... more simply:\n\n```sh\n$ curl -H 'Accept: application/json; indent=2' http://127.0.0.1:8080/api/v1/shape/\n{\n \"down\": {\n \"rate\": 400, \n \"loss\": {\n \"percentage\": 5.0\n }, \n \"delay\": {\n \"delay\": 15\n }, \n \"corruption\": {}, \n \"reorder\": {}\n }, \n \"up\": {\n \"rate\": 200, \n \"loss\": {\n \"percentage\": 1.0\n }, \n \"delay\": {\n \"delay\": 10\n }, \n \"corruption\": {}, \n \"reorder\": {}\n }\n}\nCTRL-D\n... same response...\n```\n\nLikely, device 1.1.1.1 could be shaped by using URL http://127.0.0.1:8080/api/v1/shape/1.1.1.1/ instead.\n\n## Unshaping a device\n\nUnshaping a device is done by sending a DELETE request to `/api/v1/shape/[ip]/`\n\nExamples:\n\n* Unshape myself (device being shaped, HTTP code 204)\n\n```sh\n$ curl -X DELETE -i -H 'Accept: application/json; indent=2' http://127.0.0.1:8080/api/v1/shape/\nHTTP/1.1 204 NO CONTENT\nServer: gunicorn/19.2.1\nDate: Fri, 27 Feb 2015 19:46:58 GMT\nConnection: close\nVary: Accept, Cookie\nContent-Length: 0\nAllow: GET, POST, DELETE, HEAD, OPTIONS\n\n```\n\n* Unshape myself (device not being shaped, HTTP code 400):\n\n```sh\n$ curl -X DELETE -i -H 'Accept: application/json; indent=2' http://127.0.0.1:8080/api/v1/shape/\nHTTP/1.1 400 BAD REQUEST\nServer: gunicorn/19.2.1\nDate: Fri, 27 Feb 2015 19:43:36 GMT\nConnection: close\nTransfer-Encoding: chunked\nVary: Accept, Cookie\nContent-Type: application/json; indent=2\nAllow: GET, POST, DELETE, HEAD, OPTIONS\n\n{\n \"detail\": \"{'message': 'No session for IP 10.0.2.2 found', 'result': 12}\"\n}\n```\n\n* Unshape 1.1.1.1 (device not being shaped, HTTP code 400):\n\n```sh\n$ curl -X DELETE -i -H 'Accept: application/json; indent=2' http://127.0.0.1:8080/api/v1/shape/1.1.1.1/\nHTTP/1.1 400 BAD REQUEST\nServer: gunicorn/19.2.1\nDate: Fri, 27 Feb 2015 19:47:57 GMT\nConnection: close\nTransfer-Encoding: chunked\nVary: Accept, Cookie\nContent-Type: application/json; indent=2\nAllow: GET, POST, DELETE, HEAD, OPTIONS\n\n{\n \"detail\": \"{'message': 'No session for IP 1.1.1.1 found', 'result': 12}\"\n}\n```\n\n## Authentication and Authorization\n\nATC employs a token-based authentication system to allow devices to securely shape others.\n\nTo use this system, the controlled device must ask for a token from ATC. Once a token is obtained,\n\nthe controlling device can post this token to ATC to authorize itself to shape the device.\n\n### Retrieving a Token\n\nUse the `/api/v1/token/` endpoint to retrieve a token.\n\nThis endpoint will use the HTTP Header `HTTP_X_REAL_IP` to generate the token.\n\nFor security reasons this is the only way to set the client IP. See [Proxy Setup](#proxy-security) below.\n\n```sh\n$ curl -i -H 'Accept: application/json; indent=2' http://127.0.0.1:8080/api/v1/token/\nHTTP/1.1 200 OK\nServer: gunicorn/19.3.0\nDate: Mon, 16 Mar 2015 19:16:42 GMT\nConnection: close\nTransfer-Encoding: chunked\nVary: Accept, Cookie\nContent-Type: application/json; indent=2\nAllow: GET, HEAD, OPTIONS\n\n{\n \"valid_until\": 1426533420,\n \"token\": 186032,\n \"interval\": 60,\n \"address\": \"10.0.2.2\"\n}\n```\n\n### \n\nOnce you have the token, authorize the controlling device using the `/api/v1/auth/ADDR` endpoint:\n\nNote the `Ctrl-D`\n\n```sh\n$ curl -i -XPOST -d '@-' -H 'Content-Type: application/json; indent=2' http://127.0.0.1:8080/api/v1/auth/10.0.2.2/\n{\n \"token\": 186032\n}\nCtrl-D\nHTTP 200 OK\nContent-Type: application/json\nVary: Accept\nAllow: GET, POST, HEAD, OPTIONS\n\n{\n \"controlling_ip\": \"127.0.0.1\",\n \"controlled_ip\": \"10.0.2.2\"\n}\n```\n\n\n### Proxy Security\n\nIf you are using an HTTP proxy such as [nginx](http://nginx.org/), make sure it is configured to set the\n`HTTP_X_REAL_IP` header, or token generation will not work.\n\nOne security implication of using the `HTTP_X_REAL_IP` field to determine the client address is that the client can\nmanipulate this field to obtain a token for an arbitrary address. For example, `curl -H 'X_REAL_IP: 1.2.3.4'`.\n\nTo prevent this, ATC restricts which clients are allowed to set the `HTTP_X_REAL_IP` request header.\nThis is done by use of the `PROXY_IPS` field of the `ATC_API` dict in the django settings file:\n\n ATC_API = {\n 'PROXY_IPS': ['1.2.3.4', '2.3.4.5'],\n }", "description_content_type": null, "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/facebook/augmented-traffic-control", "keywords": "", "license": "", "maintainer": "", "maintainer_email": "", "name": "django-atc-api", "package_url": "https://pypi.org/project/django-atc-api/", "platform": "UNKNOWN", "project_url": "https://pypi.org/project/django-atc-api/", "project_urls": { "Homepage": "https://github.com/facebook/augmented-traffic-control" }, "release_url": "https://pypi.org/project/django-atc-api/0.1.6/", "requires_dist": [ "atc-thrift", "djangorestframework" ], "requires_python": "", "summary": "REST API for ATC", "version": "0.1.6" }, "last_serial": 2366854, "releases": { "0.1.0": [ { "comment_text": "", "digests": { "md5": "566d1da184f01d79d43dd52575ee32b2", "sha256": "6ff899d50717abdb79588968f553fe88b47545bdad75cad6bca502883764ed0e" }, "downloads": -1, "filename": "django_atc_api-0.1.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "566d1da184f01d79d43dd52575ee32b2", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 14672, "upload_time": "2015-03-23T08:52:53", "url": "https://files.pythonhosted.org/packages/95/cc/50c15dea6d6650f760765fcac7302c009c7a607cf9542526bc206c86964a/django_atc_api-0.1.0-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "7f9c6cbaeacec24bfb3cb5ef5ea9a796", "sha256": "0096577ca9eb8d031e5aa85a1f41b573414fd7600fb2bcc52d5401c3f68c2f9a" }, "downloads": -1, "filename": "django-atc-api-0.1.0.tar.gz", "has_sig": false, "md5_digest": "7f9c6cbaeacec24bfb3cb5ef5ea9a796", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 9419, "upload_time": "2015-03-23T08:52:50", "url": "https://files.pythonhosted.org/packages/b6/ac/ac85a7e85248b768e092ca59e33f4b78d7f9570794c9e3bc94569d5f677d/django-atc-api-0.1.0.tar.gz" } ], "0.1.1": [ { "comment_text": "", "digests": { "md5": "4de3e011989b825f53a8ad20491d6594", "sha256": "c2a4480641c185185b5959bab593eb2ca0e8bf36da08c8f17f48c9ffebd20c85" }, "downloads": -1, "filename": "django_atc_api-0.1.1-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "4de3e011989b825f53a8ad20491d6594", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 14674, "upload_time": "2015-03-30T21:10:44", "url": "https://files.pythonhosted.org/packages/50/6a/ceb89659a0fe09b5ed674b4d6de6e463056302d164ffceaada4744f52b95/django_atc_api-0.1.1-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "b3be7bcd09c227d3c9123ffd606ce41f", "sha256": "061c015caeb298c948c106f320d032edd77d811e4c4ac4c975873800012ca9e6" }, "downloads": -1, "filename": "django-atc-api-0.1.1.tar.gz", "has_sig": false, "md5_digest": "b3be7bcd09c227d3c9123ffd606ce41f", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 10112, "upload_time": "2015-03-30T21:10:47", "url": "https://files.pythonhosted.org/packages/9d/13/ce63e85b8f599e8aeded45858da9533eefe5baaae725ccfe740b395bdf40/django-atc-api-0.1.1.tar.gz" } ], "0.1.2": [ { "comment_text": "", "digests": { "md5": "e6b753e0d8287bac69697e3d1b60ecfc", "sha256": "4776e5af53c070456f72fcfd6b7856b2953fd0c4ce0b2c8d1767eb6592384b16" }, "downloads": -1, "filename": "django_atc_api-0.1.2-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "e6b753e0d8287bac69697e3d1b60ecfc", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 15023, "upload_time": "2015-07-16T22:56:45", "url": "https://files.pythonhosted.org/packages/bf/08/717e22962b153189bf6c04abd54ef5013ca260dd515e9f4b5b4c970340df/django_atc_api-0.1.2-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "793aa2d24ba06bada2328e70a8d1b843", "sha256": "e45f86f629fd0673db5f2f10cad11898a1f0f76b52b4552005d3fb105fdeaebb" }, "downloads": -1, "filename": "django-atc-api-0.1.2.tar.gz", "has_sig": false, "md5_digest": "793aa2d24ba06bada2328e70a8d1b843", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 10331, "upload_time": "2015-07-16T22:56:41", "url": "https://files.pythonhosted.org/packages/a6/51/b8f94bedcbf5a276e9a7bd15fe6c0c2d4f351be8825aeefa6b81aac5584f/django-atc-api-0.1.2.tar.gz" } ], "0.1.3": [ { "comment_text": "", "digests": { "md5": "9248c4cd8e4c3fcfb7073130fc8f0f3d", "sha256": "b6b71414ce6f436fe81c4cff608e4a2d7b83e321d842f86db1727928ea276af2" }, "downloads": -1, "filename": "django_atc_api-0.1.3-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "9248c4cd8e4c3fcfb7073130fc8f0f3d", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 15019, "upload_time": "2015-10-15T19:33:56", "url": "https://files.pythonhosted.org/packages/fb/d0/12d87cf325cbced4ccd6b175798ffae77d374ed290bfb662c4e87a6f807f/django_atc_api-0.1.3-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "a5bcc032a73764541cf643c381a7d250", "sha256": "3a970730e1375b603bf258775e5a8f444066ad20719eefe2bb6e84186bd6d68e" }, "downloads": -1, "filename": "django-atc-api-0.1.3.tar.gz", "has_sig": false, "md5_digest": "a5bcc032a73764541cf643c381a7d250", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 10316, "upload_time": "2015-10-15T19:33:52", "url": "https://files.pythonhosted.org/packages/6e/ba/5495b43f0a870bb172768e3b80d97a811cc591fae3d8bd84cd2eb4f4d6ed/django-atc-api-0.1.3.tar.gz" } ], "0.1.4": [ { "comment_text": "", "digests": { "md5": "80e7bbf6f8bba815b504116ae6aaa85c", "sha256": "80f1adeaa14a0a1416cec14867d038098b5cf0cb51ac739e2ebb6156ec919ebf" }, "downloads": -1, "filename": "django_atc_api-0.1.4-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "80e7bbf6f8bba815b504116ae6aaa85c", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 15016, "upload_time": "2016-08-10T19:02:22", "url": "https://files.pythonhosted.org/packages/73/10/2eb78a93ec015aceb4c63232c2f4120e2b8a87bad34a2e7854c2e3826a49/django_atc_api-0.1.4-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "73266eb4b65808b6a1313a5b85650ee7", "sha256": "cb91a10ab16bdc9051dd38faa33ed8b64ffba9a048b05a7f602fd5e282d53f77" }, "downloads": -1, "filename": "django-atc-api-0.1.4.tar.gz", "has_sig": false, "md5_digest": "73266eb4b65808b6a1313a5b85650ee7", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 10322, "upload_time": "2016-08-10T19:02:24", "url": "https://files.pythonhosted.org/packages/11/57/d8e72ae12091e27453bb10f43036d1cc4387c815a4a96e178f05026a939d/django-atc-api-0.1.4.tar.gz" } ], "0.1.5": [ { "comment_text": "", "digests": { "md5": "1358d1c27880253edc0eed3532c15628", "sha256": "af51eb6055f103fa1926760b27328adae73bd3b4a74362711c36eba74e04f27a" }, "downloads": -1, "filename": "django_atc_api-0.1.5-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "1358d1c27880253edc0eed3532c15628", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 15019, "upload_time": "2016-08-18T15:46:55", "url": "https://files.pythonhosted.org/packages/be/90/5286602a25f8cb12b01cb62fac2829a0fe601fc6adbd987e9e9c2ac1a473/django_atc_api-0.1.5-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "7b95c072fa187c400edac7423e169570", "sha256": "9258fadf4071d730b182afaa519dc934c88af3d38dcff9867c0745e2cd0547a4" }, "downloads": -1, "filename": "django-atc-api-0.1.5.tar.gz", "has_sig": false, "md5_digest": "7b95c072fa187c400edac7423e169570", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 10316, "upload_time": "2016-08-18T15:46:57", "url": "https://files.pythonhosted.org/packages/e0/3e/ef29e52d90864009ff3cb1ae15bf1ae4248bcd1c407239e72060159e3b94/django-atc-api-0.1.5.tar.gz" } ], "0.1.6": [ { "comment_text": "", "digests": { "md5": "fa196fc9af2311d47dbbfdaa83a28632", "sha256": "a9a17a982c3e3e616bf7d76710b18207057e3ce5737fbbd9b9563c6586edd4d4" }, "downloads": -1, "filename": "django_atc_api-0.1.6-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "fa196fc9af2311d47dbbfdaa83a28632", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 15012, "upload_time": "2016-09-27T17:38:57", "url": "https://files.pythonhosted.org/packages/fd/6f/831b9bcbd32936b0d6f81ceee8eb15fa86321798897543e7ab135489faf3/django_atc_api-0.1.6-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "98bdfe87d3d794bfc2fea6ced8d141fa", "sha256": "6ba2392f84e61fdde6fd84e11de8309f1bba78398dc5b627f017cff32603e1fa" }, "downloads": -1, "filename": "django-atc-api-0.1.6.tar.gz", "has_sig": false, "md5_digest": "98bdfe87d3d794bfc2fea6ced8d141fa", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 10309, "upload_time": "2016-09-27T17:39:00", "url": "https://files.pythonhosted.org/packages/0c/b1/c622ec881734fd651fdcf3f34aecf9cbb1fcff4b9ef7c12b9a3714cca869/django-atc-api-0.1.6.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "fa196fc9af2311d47dbbfdaa83a28632", "sha256": "a9a17a982c3e3e616bf7d76710b18207057e3ce5737fbbd9b9563c6586edd4d4" }, "downloads": -1, "filename": "django_atc_api-0.1.6-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "fa196fc9af2311d47dbbfdaa83a28632", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 15012, "upload_time": "2016-09-27T17:38:57", "url": "https://files.pythonhosted.org/packages/fd/6f/831b9bcbd32936b0d6f81ceee8eb15fa86321798897543e7ab135489faf3/django_atc_api-0.1.6-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "98bdfe87d3d794bfc2fea6ced8d141fa", "sha256": "6ba2392f84e61fdde6fd84e11de8309f1bba78398dc5b627f017cff32603e1fa" }, "downloads": -1, "filename": "django-atc-api-0.1.6.tar.gz", "has_sig": false, "md5_digest": "98bdfe87d3d794bfc2fea6ced8d141fa", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 10309, "upload_time": "2016-09-27T17:39:00", "url": "https://files.pythonhosted.org/packages/0c/b1/c622ec881734fd651fdcf3f34aecf9cbb1fcff4b9ef7c12b9a3714cca869/django-atc-api-0.1.6.tar.gz" } ] }