{ "info": { "author": "", "author_email": "", "bugtrack_url": null, "classifiers": [], "description": "# Command Handler\n[![PyPI version](https://badge.fury.io/py/command-handler.svg)](https://badge.fury.io/py/command-handler)\n[![Build Status](https://travis-ci.com/sacoding/commandHandler.py.svg?branch=master)](https://travis-ci.com/sacoding/commandHandler.py)\n\nCommand Handler is a library for [Flask framework](https://github.com/pallets/flask)\nwhich provides:\n- API method for posting new commands,\n- tools for easy command handlers management.\n\n## Installation\n\n```sh\npip install command_handler\n```\n\n## Usage\n\nTo use `command_handler` import `CommandHandler` object and call it with your `flask` application passed.\n\n```py\nfrom command_handler import CommandHandler\nfrom flask import Flask\n\napp = Flask(__name__)\nch = CommandHandler(app)\n```\n\nThis will add a new endpoint to your API: `/command` which is specified in [_Command input_ section](#command-input).\n\nHandlers can be added by `addHandler` method of the returned object as described in [_Defining handlers_ section](#defining-handlers).\n\n### Configuration\n\nThe way `CommandHandler` is designed allows to pass config parameters to the initializer.\n\n#### Command input endpoint URL\n\nIt is possible to prefix default `/command` route with any string accepted by Flask's routing\nby defining `rulePrefix` parameter.\n\nFollowing code sets URL to `/foo/bar/command`:\n\n```py\nch = CommandHandler(app, rulePrefix=\"/foo/bar\")\n```\n\nIt is also possible to change default `/command` route suffix by defining `ruleSuffix`.\n\nFollowing code sets URL to `/baz`:\n\n```py\nch = CommandHandler(app, ruleSuffix=\"baz\")\n```\n\n#### Request validators\n\nIt is possible to define command request validators.\n`CommandHandler` by default sets `command` and `json` validators and it is not possible to remove them.\n\nValidators can be defined by setting `validators` parameter which accepts list of strings.\n\n```py\nch = CommandHandler(app, validators=[\"command\", \"json\"])\n```\n\nList of possible validators can be found in [_Validators_ section](#validators)\n\n##### Custom validators\n\nTo register custom validator pass it to the `command_handler.request.validator.ValidatorFactory.addAssert` method.\nIt has to accept one positional parameter which contains request passed to the view defined by `CommandHandler`.\n\nIf request is invalid it is needed to raise `command_handler.request.validator.exceptions.AssertionFailedException`.\nFirst parameter of its constructor will be send to the response's body and second will be send as response code.\n\n```py\nfrom command_handler.request.validator.ValidatorFactory\nfrom command_handler.request.validator.exceptions import AssertionFailedException\n\n\ndef fooValidator(request):\n raise AssertionFailedException(\"Something went wrong\", 418)\n\n\nValidatorFactory.addAssert(\"foo\", fooValidator)\n```\n\n### Command input\n\nBy default route to the command input endpoint is `/command`.\nIt can be configured as described in [_Configuration_ section](#command-input-endpoint-url).\n\nCommand input endpoint accepts only `POST` requests\nwith the content matching following [JSON schema](http://json-schema.org):\n\n```json\n{\n \"type\": \"object\",\n \"properties\": {\n \"command\": {\n \"type\": \"string\",\n \"description\": \"Name of the sent command\",\n \"examples\": [\n \"foo\",\n \"foo.bar\",\n \"foo.bar.baz\"\n ]\n },\n \"payload\": {\n \"type\": \"object\",\n \"description\": \"Payload of the sent command\",\n }\n },\n \"required\": [\n \"command\",\n \"payload\"\n ]\n}\n```\n\nIt is also required to send `Content-Type` header which value matches `^application/.*json$` regular expression.\n\nAdditional validators can be defined as specified in [_Validators_ section](#validators).\n\n### Defining handlers\n\nCommand handlers can be defined by calling `addHandler` method of `CommandHandler` instance.\n\n```py\nch = CommandHandler(app)\n\nch.addHandler(lambda payload, command: None, \"foo.*\", {})\n```\n\nThe following parameters are accepted by `addHandler` method:\n\n##### `handler`\n\nInvokable object which is called when matching command has been posted.\n\n`handler` function has to accept two parameters:\n1. command's payload,\n2. command's name.\n\n##### `command`\n\nString which command's name is matched against.\n\nCommand matching is described in [_Command matching_ section](#command-matching).\n\n##### `schema`\n\n[JSON schema](http://json-schema.org) object used to validate command's payload.\n\n##### `transformer = None`\n\n`transformer` parameter can be used to transform command's payload before passing it to the handler.\n\nIt gets command's payload as only parameter and returns object passed to the handler as payload.\n\n##### `postProcessor = None`\n\nInvokable object which is called when handler processing is done.\n\nIt has to accept same parameters as [handler](#handler).\nIf `transformer` was passed to the `addHandler` call it has additional named parameter `origPayload`\nwhich contains original payload passed to the invoker.\n\nIf inner handler returns any value, it is passed as `innerResult` named parameter.\n\n#### Raising exceptions\n\nThere is no possibility of changing response of a [command input endpoint](#command-input)\nexcept raising an exception.\n\nWhen `command_handler.request.exceptions.InvalidRequestException` is raised\n[command input endpoint](#command-input) returns response with HTTP code\nspecified during `InvalidRequestEndpoint` creation (by default it is `400: Bad Request`)\nand message which matches following [JSON schema](http://json-schema.org):\n\n```json\n{\n \"type\": \"object\",\n \"properties\": {\n \"type\": \"string\",\n \"description\": \"Message passed to the `InvalidRequestException` during creation\",\n \"default\": \"\"\n },\n \"required\": [\n \"error\"\n ]\n}\n```\n\nIt is preferred to use `4xx` codes with `InvalidRequestException`.\n\nFollowing snippet will respond with `418: I'm a teapot` HTTP code and\n`{\"error\": \"I'm a teapot handler\"}` when `foo.bar` command is sent:\n\n```py\ndef fooHandler(payload, command):\n raise InvalidRequestException(\"I'm a teapot handler\", code=418)\n\nch = CommandHandler(app)\nch.addHandler(fooHandler, \"foo.bar\", {})\n```\n\nWhen any other exception is raised [command input endpoint](#command-input)\nreturns response with HTTP code `500: Internal server error`.\n\n### Command matching\n\nEach command name sent to [command input endpoint](#command-input)\nhas to be a list of words delimited by dots.\n\nCommand name passed to [`addHandler`](#defining-handlers) method must also be\nin the same form. There are two special words for command name assigned to the handler:\n- `*` can substitute exactly one word,\n- `#` can substitute zero or more words.\n\nCommand handler invoker will call handler which matches command name of handler\npassed to [`addHandler`](#defining-handlers) method. If there is no matching\nhandler [command input endpoint](#command-input) will respond with `500: Internal server error`.\n\nIf there is more than one match the handler which was added first will be called.\nHowever handler's registry is not allowing to add handler which is assigned to the already covered name.\nIt means that order of adding handler matters.\n\nFor example following snippet will work properly but adding those handlers in reverse order will cause\nin raising an exception.\n\n```py\nch.addHandler(lambda payload, command: None, \"foo.bar\", {})\nch.addHandler(lambda payload, command: None, \"foo.#\", {})\n```\n\n### Validators\n\nCommand Handler contains following predefined request validators:\n\n##### `command`\n\nValidator which verifies if:\n- request contains `payload` and `command` fields,\n- `command` field value is a string,\n- `payload` field value is a dictionary,\n- value of `command` field is matchable to defined handlers,\n- value of `payload` field matches schema which had been assigned to the handler,\n\n##### `json`\n\nValidator which verifies if:\n- request contains `Content-Type` header with value matching to `^application/.*json$` regex,\n- request content is json-parseable.\n\n##### `privateIp`\n\nValidator which verifies if remote IP address of the request\nis [private](https://tools.ietf.org/html/rfc1918).\n\n\n", "description_content_type": "text/markdown", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/sacoding/commandHandler.py/", "keywords": "", "license": "", "maintainer": "", "maintainer_email": "", "name": "command-handler", "package_url": "https://pypi.org/project/command-handler/", "platform": "", "project_url": "https://pypi.org/project/command-handler/", "project_urls": { "Homepage": "https://github.com/sacoding/commandHandler.py/" }, "release_url": "https://pypi.org/project/command-handler/1.2.1/", "requires_dist": [ "Flask (<2,>=1.0)", "jsonschema (<3,>=2.4)" ], "requires_python": ">=3.6", "summary": "Library for handling POST commands for Flask framework", "version": "1.2.1" }, "last_serial": 4873678, "releases": { "1.0.0": [ { "comment_text": "", "digests": { "md5": "eae791118d060c17a0851e2e076821f9", "sha256": "23a77deb3270fdebaba4100b6ada7abbf787c41def95855c3126f198433837f7" }, "downloads": -1, "filename": "command_handler-1.0.0-py3-none-any.whl", "has_sig": false, "md5_digest": "eae791118d060c17a0851e2e076821f9", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6", "size": 19220, "upload_time": "2018-07-13T07:19:59", "url": "https://files.pythonhosted.org/packages/fc/b4/f2d27bfd4c78afd02c36dcbb1ff82d97b1860a0e72fd9271c881b1ffdcf8/command_handler-1.0.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "9ad331be2edbd1eb54f87910013a456f", "sha256": "abe6fb90c0bf98b56c75ddcc630426602cf7eaa640a10643696995a506b67e9a" }, "downloads": -1, "filename": "command_handler-1.0.0.tar.gz", "has_sig": false, "md5_digest": "9ad331be2edbd1eb54f87910013a456f", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 10324, "upload_time": "2018-07-13T07:20:00", "url": "https://files.pythonhosted.org/packages/8e/92/1e297924f9d8662aa0a2a093b783d4f45cd5cbe88a5333ff32ebdcccf786/command_handler-1.0.0.tar.gz" } ], "1.0.1": [ { "comment_text": "", "digests": { "md5": "d20333c67bb234c6bf7903792a1936e6", "sha256": "07a9e6ec324730c1a8a8aea816a5644c9e743b15b7353f6fa62bc962b56d7976" }, "downloads": -1, "filename": "command_handler-1.0.1-py3-none-any.whl", "has_sig": false, "md5_digest": "d20333c67bb234c6bf7903792a1936e6", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6", "size": 19334, "upload_time": "2018-07-17T05:20:39", "url": "https://files.pythonhosted.org/packages/1a/45/b463ac226a866cba5e72a3468eeec4477645fea742f8ed3601b42a2f32c0/command_handler-1.0.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "f1a8a059b5127665901ca21778e38587", "sha256": "52644fbc5f2bed011b56ff0170efbf3b765b2a3a74c214ed97b01022353240b5" }, "downloads": -1, "filename": "command_handler-1.0.1.tar.gz", "has_sig": false, "md5_digest": "f1a8a059b5127665901ca21778e38587", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 10465, "upload_time": "2018-07-17T05:20:40", "url": "https://files.pythonhosted.org/packages/12/9a/33a98b1b23c0b75620e45d7b430c6f620e9b6cd34c6dae36cdc3b16b4f25/command_handler-1.0.1.tar.gz" } ], "1.0.2": [ { "comment_text": "", "digests": { "md5": "7412913f146601ab7ea6842123a5f7e2", "sha256": "81ee79c6b5f918cd16df9767cfa350c1ddc01a82fe324c2973778c835a656db7" }, "downloads": -1, "filename": "command_handler-1.0.2-py3-none-any.whl", "has_sig": false, "md5_digest": "7412913f146601ab7ea6842123a5f7e2", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6", "size": 19526, "upload_time": "2018-07-19T08:15:18", "url": "https://files.pythonhosted.org/packages/ba/2c/518ddedbeaed57b78231242d22d89a242118ecb5140b9f6f8420b49d724a/command_handler-1.0.2-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "82377f8d7d40f0662b60f0ee5e3ef892", "sha256": "528e69096110ded2b2edf6aaf78f62cd2f39bf31e692a5342f884d2a18194b17" }, "downloads": -1, "filename": "command_handler-1.0.2.tar.gz", "has_sig": false, "md5_digest": "82377f8d7d40f0662b60f0ee5e3ef892", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 10782, "upload_time": "2018-07-19T08:15:19", "url": "https://files.pythonhosted.org/packages/d3/0e/1e61ac362f8c6358671ed377a286171f1f8a103768009db82fec0b06a3b3/command_handler-1.0.2.tar.gz" } ], "1.0.3": [ { "comment_text": "", "digests": { "md5": "694b52f462c973678d0eacc20f384632", "sha256": "d81cefcd4f6fd25a822112f95950fd0bf066c4dbaab0d8affdd3511a4f57acbf" }, "downloads": -1, "filename": "command_handler-1.0.3-py3-none-any.whl", "has_sig": false, "md5_digest": "694b52f462c973678d0eacc20f384632", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6", "size": 19683, "upload_time": "2018-08-16T07:23:24", "url": "https://files.pythonhosted.org/packages/c5/0f/1184e5e49b36cc98714586b97fc179463ca775499bad4a149011940785b9/command_handler-1.0.3-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "8261e951a2b9b1bd82024f75c8d247ef", "sha256": "7a5806314c5a99c1b1301d9130b6d1e509991df4697c73ca9d85236d233ff82d" }, "downloads": -1, "filename": "command_handler-1.0.3.tar.gz", "has_sig": false, "md5_digest": "8261e951a2b9b1bd82024f75c8d247ef", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 12384, "upload_time": "2018-08-16T07:23:25", "url": "https://files.pythonhosted.org/packages/1f/34/d0e80cc6eab907980fa5ff03eb81a334ca2c42e1818f53fa140dfa113183/command_handler-1.0.3.tar.gz" } ], "1.0.4": [ { "comment_text": "", "digests": { "md5": "75d473f98eda99d4a9d49f77ec6e4d22", "sha256": "882958c5686a0128de030c7128ce30427e88758fcb3b13d93184a577418022cc" }, "downloads": -1, "filename": "command_handler-1.0.4-py3-none-any.whl", "has_sig": false, "md5_digest": "75d473f98eda99d4a9d49f77ec6e4d22", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6", "size": 19805, "upload_time": "2018-10-04T11:02:17", "url": "https://files.pythonhosted.org/packages/13/ac/42dfecb4c6bb3bf29c9cf675764dd55db88f16b752f4c1fd87305e633653/command_handler-1.0.4-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "866b2bcda63d9ceb29e508abd79cb206", "sha256": "8b69032a948e06fccda1c7ea6898a25d7f2fdf6d1663f3c7729d8122986b2b6b" }, "downloads": -1, "filename": "command_handler-1.0.4.tar.gz", "has_sig": false, "md5_digest": "866b2bcda63d9ceb29e508abd79cb206", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 12453, "upload_time": "2018-10-04T11:02:19", "url": "https://files.pythonhosted.org/packages/af/a6/c13a4c63e7fe67ad4e35dbd4ac3296bd8e2824d2d2ae2ba310f859506f4b/command_handler-1.0.4.tar.gz" } ], "1.1.0": [ { "comment_text": "", "digests": { "md5": "c3ac0b1abb81277defe62ef2ff9583a2", "sha256": "a40b8e4e43090c71ea3c413e6d8d0102b3089ce19a6b9748a2732afd32d40ca0" }, "downloads": -1, "filename": "command_handler-1.1.0-py3-none-any.whl", "has_sig": false, "md5_digest": "c3ac0b1abb81277defe62ef2ff9583a2", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6", "size": 20168, "upload_time": "2018-10-12T13:14:51", "url": "https://files.pythonhosted.org/packages/cc/99/27f4e9c9bb0d0d023bc65c3100357f7f5340223b72d4bc2f35e0dfa858de/command_handler-1.1.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "15f84eea33621a7316ba4b9354ba3378", "sha256": "e45f5bab191240d28a49933cf774e90ba64b26632f4a33c26a1442a84562db42" }, "downloads": -1, "filename": "command_handler-1.1.0.tar.gz", "has_sig": false, "md5_digest": "15f84eea33621a7316ba4b9354ba3378", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 13045, "upload_time": "2018-10-12T13:14:53", "url": "https://files.pythonhosted.org/packages/7a/4a/c09a93aab1aa5e413b6bec7e96134bba0de61c805c2aec228197318dfd62/command_handler-1.1.0.tar.gz" } ], "1.1.1": [ { "comment_text": "", "digests": { "md5": "63ad5a3b66e5cf0bcba7ce5e42f794f1", "sha256": "f6c0f80e8818b325633f2c246e78d05838675762af3a261fa20c92031e973271" }, "downloads": -1, "filename": "command_handler-1.1.1-py3-none-any.whl", "has_sig": false, "md5_digest": "63ad5a3b66e5cf0bcba7ce5e42f794f1", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6", "size": 20260, "upload_time": "2018-11-06T10:44:10", "url": "https://files.pythonhosted.org/packages/93/19/518bdd12684c3aca6fa19a4ce96de894049076fb06477acb95f2d68837de/command_handler-1.1.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "c493506c31afcb924415c71eeef2b2f2", "sha256": "740dbea441c3a71a50c9073beee86c0639cf1b96d51f5b34c02161ed993d6748" }, "downloads": -1, "filename": "command_handler-1.1.1.tar.gz", "has_sig": false, "md5_digest": "c493506c31afcb924415c71eeef2b2f2", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 13145, "upload_time": "2018-11-06T10:44:12", "url": "https://files.pythonhosted.org/packages/60/74/027f2c197f016c89edbfb233cafeef4519824318404f078705c57919dcc8/command_handler-1.1.1.tar.gz" } ], "1.1.2": [ { "comment_text": "", "digests": { "md5": "dfae97cba97a05ca417f11a4cde01894", "sha256": "a4b4f0c5056186767225c78733e31ac9da40f63adcd5dbd8274758383ea007cd" }, "downloads": -1, "filename": "command_handler-1.1.2-py3-none-any.whl", "has_sig": false, "md5_digest": "dfae97cba97a05ca417f11a4cde01894", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6", "size": 20454, "upload_time": "2018-11-26T12:08:52", "url": "https://files.pythonhosted.org/packages/17/58/52f079a1ef2ba8f55d28f540c2d8ca7b1533de03daefda606bb9be8ff968/command_handler-1.1.2-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "1405106cd8f801e9b7b0ba4329fce57e", "sha256": "aaeb567d5844b8811e6a51b32bc00e6d68f3a5f5d66805931c4f0555728712cc" }, "downloads": -1, "filename": "command_handler-1.1.2.tar.gz", "has_sig": false, "md5_digest": "1405106cd8f801e9b7b0ba4329fce57e", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 13292, "upload_time": "2018-11-26T12:08:55", "url": "https://files.pythonhosted.org/packages/b1/f5/1f084a61fa999835e39ce02a6de338bb1b8f9f263766c5fec5489bdda57b/command_handler-1.1.2.tar.gz" } ], "1.2.0": [ { "comment_text": "", "digests": { "md5": "4478818c85881b6a9016511651d27eaf", "sha256": "d9663c39ab79f4f330dc2658e2fd0877a695f8f5759ad6db77e7f715385840d5" }, "downloads": -1, "filename": "command_handler-1.2.0-py3-none-any.whl", "has_sig": false, "md5_digest": "4478818c85881b6a9016511651d27eaf", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6", "size": 20600, "upload_time": "2019-02-18T11:17:21", "url": "https://files.pythonhosted.org/packages/22/5d/1bedf3ac3c90f8773470b50abf24b3370ecd6fa4f2a4fe6e776fc520a45d/command_handler-1.2.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "8fa3c494d764af72defd97487d3084dd", "sha256": "57e97d3509420dc088fa81c382bd2c942b5d92644c526e666d5258b3e08d9167" }, "downloads": -1, "filename": "command_handler-1.2.0.tar.gz", "has_sig": false, "md5_digest": "8fa3c494d764af72defd97487d3084dd", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 16283, "upload_time": "2019-02-18T11:17:22", "url": "https://files.pythonhosted.org/packages/bc/ca/bdee4ad6de87eac81245f9820671937ee530171860bb65ce659a7cb99718/command_handler-1.2.0.tar.gz" } ], "1.2.1": [ { "comment_text": "", "digests": { "md5": "4c64c826572709eba467e56c82a37c3c", "sha256": "fa40126ee14bbd210e3fdc48f8bb37a81c06c62f28d71725a8ae5d996f8dcfec" }, "downloads": -1, "filename": "command_handler-1.2.1-py3-none-any.whl", "has_sig": false, "md5_digest": "4c64c826572709eba467e56c82a37c3c", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6", "size": 20588, "upload_time": "2019-02-22T08:58:25", "url": "https://files.pythonhosted.org/packages/1b/07/5f6500045f9ce587a7aee39ed5fa496a0daafc7c4f6912cbcc1b28ddb160/command_handler-1.2.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "20101f60290f85cf97d195264f6f1c6d", "sha256": "bfdd77830b45e09546e6efb404d6a433d4dc7f462fd70fe957e90d8e2a857e3d" }, "downloads": -1, "filename": "command_handler-1.2.1.tar.gz", "has_sig": false, "md5_digest": "20101f60290f85cf97d195264f6f1c6d", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 16350, "upload_time": "2019-02-22T08:58:27", "url": "https://files.pythonhosted.org/packages/7c/78/6605e7ce9c4993ae88143bd638654a930250137e4a3c6ff7bb6ffac1fab9/command_handler-1.2.1.tar.gz" } ], "1.2.3rc2": [ { "comment_text": "", "digests": { "md5": "4c361a290fca882e784ceca334678187", "sha256": "f444c380cc8ab85b9b6802bfed433a8df4763b39bcbe669ac06d991ba161b52a" }, "downloads": -1, "filename": "command_handler-1.2.3rc2-py3-none-any.whl", "has_sig": false, "md5_digest": "4c361a290fca882e784ceca334678187", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6", "size": 20613, "upload_time": "2019-02-25T10:11:41", "url": "https://files.pythonhosted.org/packages/50/e6/341d19de0fece26569f13a2886d5a4f870caf16fcfb6e40e00cbb8daf576/command_handler-1.2.3rc2-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "8afbcde167df71611579c0d4a12172d3", "sha256": "3474c36aa1de317240e53922196544f75b74237a637b46aee4f2a841bb6279b9" }, "downloads": -1, "filename": "command_handler-1.2.3rc2.tar.gz", "has_sig": false, "md5_digest": "8afbcde167df71611579c0d4a12172d3", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 16397, "upload_time": "2019-02-25T10:11:43", "url": "https://files.pythonhosted.org/packages/7b/10/933e308a9488b46250d2fad98ba5f009bb5ed7a11cfed771f90c0d6037a4/command_handler-1.2.3rc2.tar.gz" } ], "1.2.3rc3": [ { "comment_text": "", "digests": { "md5": "51cda66e1a42982189f125359da5562e", "sha256": "62847cb58485e912c685f5b2c14d915ac860142f96edcd23f9027d474d072619" }, "downloads": -1, "filename": "command_handler-1.2.3rc3-py3-none-any.whl", "has_sig": false, "md5_digest": "51cda66e1a42982189f125359da5562e", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6", "size": 21514, "upload_time": "2019-02-27T11:03:03", "url": "https://files.pythonhosted.org/packages/64/74/22c520174be1f56c8df87977213c627f16b9f2d654507ef0bcd244301dd8/command_handler-1.2.3rc3-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "302895f8a653952cdecea2388eb5e7cb", "sha256": "8f559620fb5e77d6376330384e9ff8d2582221d2d00dc8d5db967c3a6c5c2d10" }, "downloads": -1, "filename": "command_handler-1.2.3rc3.tar.gz", "has_sig": false, "md5_digest": "302895f8a653952cdecea2388eb5e7cb", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 16772, "upload_time": "2019-02-27T11:03:05", "url": "https://files.pythonhosted.org/packages/7f/53/fa4af8ff8d8a27062a46276202ef4404dd5727c3c86ca9ad19335aa02710/command_handler-1.2.3rc3.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "4c64c826572709eba467e56c82a37c3c", "sha256": "fa40126ee14bbd210e3fdc48f8bb37a81c06c62f28d71725a8ae5d996f8dcfec" }, "downloads": -1, "filename": "command_handler-1.2.1-py3-none-any.whl", "has_sig": false, "md5_digest": "4c64c826572709eba467e56c82a37c3c", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6", "size": 20588, "upload_time": "2019-02-22T08:58:25", "url": "https://files.pythonhosted.org/packages/1b/07/5f6500045f9ce587a7aee39ed5fa496a0daafc7c4f6912cbcc1b28ddb160/command_handler-1.2.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "20101f60290f85cf97d195264f6f1c6d", "sha256": "bfdd77830b45e09546e6efb404d6a433d4dc7f462fd70fe957e90d8e2a857e3d" }, "downloads": -1, "filename": "command_handler-1.2.1.tar.gz", "has_sig": false, "md5_digest": "20101f60290f85cf97d195264f6f1c6d", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 16350, "upload_time": "2019-02-22T08:58:27", "url": "https://files.pythonhosted.org/packages/7c/78/6605e7ce9c4993ae88143bd638654a930250137e4a3c6ff7bb6ffac1fab9/command_handler-1.2.1.tar.gz" } ] }