{ "info": { "author": "Florimond Husquinet", "author_email": "florimond@emitter.io", "bugtrack_url": null, "classifiers": [ "Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "License :: OSI Approved :: Eclipse Public License 1.0 (EPL-1.0)", "Programming Language :: Python :: 2", "Programming Language :: Python :: 3", "Topic :: Communications", "Topic :: Internet :: WWW/HTTP" ], "description": "# Emitter Python SDK\n\n[![PyPI - Emitter version](https://img.shields.io/pypi/v/emitter-io.svg)](https://pypi.org/project/emitter-io) [![PyPI - Python versions](https://img.shields.io/pypi/pyversions/emitter-io.svg?logo=python)](https://github.com/emitter-io/python) [![GitHub - License](https://img.shields.io/github/license/emitter-io/python.svg)](https://github.com/emitter-io/python/blob/master/LICENSE)\n\nThis repository contains a Python client for [Emitter](https://emitter.io) (see also [Emitter GitHub](https://github.com/emitter-io/emitter)). Emitter is an **open-source** real-time communication service for connecting online devices. At its core, emitter.io is a distributed, scalable and fault-tolerant publish-subscribe messaging platform based on MQTT protocol and featuring message storage.\n\nThis library provides a nicer high-level MQTT interface fine-tuned and extended with specific features provided by [Emitter](https://emitter.io). The code uses the [Eclipse Paho MQTT Python Client](https://github.com/eclipse/paho.mqtt.python) for handling all the network communication and MQTT protocol.\n\n\n* [Installation](#install)\n* [Examples](#examples)\n* [API reference](#api)\n* [ToDo](#todo)\n* [License](#license)\n\n\n\n## Installation\n\nThis SDK is available as a pip package. Install with: \n```\npip install emitter-io\n```\n\n\n\n## Examples\n\nThese examples show you the whole communication process.\n* Python 2: [*sample-python2.py*](emitter/sample-python2.py)\n* Python 3: [*sample-python3.py*](emitter/sample-python3.py)\n\n\n\n## API reference\n\n* [`Client()`](#client)\n * [`.connect()`](#connect)\n * [`.disconnect()`](#disconnect)\n * [`.keygen()`](#keygen)\n * [`.link()`](#link)\n * [`.me()`](#me)\n * [`.on_connect`](#on_connect)\n * [`.on_disconnect`](#on_disconnect)\n * [`.on_error`](#on_error)\n * [`.on_keygen`](#on_keygen)\n * [`.on_me`](#on_me)\n * [`.on_message`](#on_message)\n * [`.on_presence`](#on_presence)\n * [`.presence()`](#presence)\n * [`.publish()`](#publish)\n * [`.publish_with_link()`](#publish_with_link)\n * [`.subscribe()`](#subscribe)\n * [`.subscribe_with_group()`](#subscribe_with_group)\n * [`.unsubscribe()`](#unsubscribe)\n* [`EmitterMessage()`](#message)\n * [`.as_string()`](#as_string)\n * [`.as_object()`](#as_object)\n * [`.as_binary()`](#as_binary)\n\n-------------------------------------------------------\n\n### Client()\n\nThe `Client` class represents the client connection to an Emitter server.\n\n-------------------------------------------------------\n\n### Emitter#connect(host=\"api.emitter.io\", port=443, secure=True, keepalive=30)\n\n```\nemitter = Client()\n\nemitter.connect()\n```\nConnects to an Emitter server.\n* `host` is the address of the Emitter broker. (Optional | `Str` | Default: `\"api.emitter.io\"`)\n* `port` is the port of the emitter broker. (Optional | `Int` | Default: `443`)\n* `secure` whether the connection should be secure. (Optional | `Bool` | Default: `True`)\n* `keepalive` is the time the connection is kept alive (Optional | `Int` | Default: `30`)\n\nIf you don't want a secure connection, set the port to 8080, unless your broker is configured differently.\n\nTo handle connection events, see the [`.on_connect`](#on_connect) property.\n\n-------------------------------------------------------\n\n### Emitter#disconnect()\n\n```\nemitter.disconnect()\n```\nDisconnects from the connected Emitter server.\n\nTo handle disconnection events, see the [`.on_disconnect`](#on_disconnect) property.\n\n-------------------------------------------------------\n\n### Emitter#keygen(key, channel, permissions, ttl=0)\n\n```\ninstance.keygen(\"Z5auMQhNr0eVnGBAgWThXus1dgtSsvuQ\", \"channel/\", \"rwslpex\")\n```\nSends a key generation request to the server. See also [`Emitter`](#client-keygen) for a description of the event and [`Emitter#on()`](#on) for the possibilities of event handling.\n* `key` is your *master key* to use for the operation. (Required | `Str`)\n* `channel` is the channel name to generate a key for. (Required | `Str`)\n* `permissions` are the permissions associated to the key. (Required | `Str`)\n - `r` for read\n - `w` for write\n - `s` for store\n - `l` for load\n - `p` for presence\n - `e` for extend\n - `x` for execute\n* `ttl` is the time to live of the key. `0` means it never expires (Optional | `Int` | Default: `0`)\n\nTo handle keygen responses, see the [`.on_keygen`](#on_keygen) property.\n\n-------------------------------------------------------\n\n### Emitter#link(key, channel, name, private, subscribe, options={})\n\n```\ninstance.link(\"5xZjIQp6GA9fpxso1Kslqnv8d4XVWChb\",\n \"channel\",\n \"a0\",\n False,\n True,\n {Client.with_ttl(604800), Client.without_echo()}) // one week\n```\nSends a link creation request to the server. This allows for the creation of a link between a short 2-character name and an actual channel. This function also allows the creation of a private channel. For more information, see \n[Emitter: Simplify Client/Server and IoT Apps with Links and Private Links (on YouTube)](https://youtu.be/_FgKiUlEb_s) and the [Emitter Pull Request (on GitHub)](https://github.com/emitter-io/emitter/pull/183).\n* `key` is the key to the channel. (Required | `Str`)\n* `channel` is the channel name. (Required | `Str`)\n* `name` is the short name for the channel. (Required | `Str`)\n* `private` whether the request is for a private channel. (Required | `Bool`)\n* `subscribe` whether or not to subscribe to the channel. (Required | `Bool`)\n* `options` a set of options. Currently available options are:\n - `with_at_most_once()` to send with QoS0.\n - `with_at_least_once()` to send with QoS1.\n - `with_retain()` to retain this message.\n - `with_ttl(ttl)` to set a time to live for the message.\n - `without_echo()` to tell the broker not to send the message back to this client.\n\n-------------------------------------------------------\n\n### Emitter#me()\n\n```\ninstance.me()\n```\nRequests information about the connection. Information provided in the response contains the id of the connection, as well as the links that were established with [`.link()`](#link) requests.\n\nTo handle the responses, see the [`.on_me`](#on_me) property.\n\n-------------------------------------------------------\n\n### Emitter#on_connect\n\nProperty used to get or set the connection handler, that handle events emitted upon successful (re)connection. No arguments provided.\n\n-------------------------------------------------------\n\n### Emitter#on_disconnect\n\nProperty used to get or set the disconnection handler, that handle events emitted after a disconnection. No arguments provided.\n\n-------------------------------------------------------\n\n### Emitter#on_error\n\nProperty used to get or set the error handler, that handle events emitted when an error occurs following any request. The event comes with a status code and a text message describing the error.\n\n```\n{\"status\": 400,\n \"message\": \"the request was invalid or cannot be otherwise served\"}\n```\n\n-------------------------------------------------------\n\n### Emitter#on_keygen\n\n**ToDo: Description!**\n-------------------------------------------------------\n\n### Emitter#on_me\n\nProperty used to get or set the handler that handle responses to [`.me()`](#me) requests. Information provided in the response contains the id of the connection, as well as the links that were established with [`.link()`](#link) requests.\n\n```\n{\"id\": \"74W77OC5OXDBQRUUMSHROHRQPE\",\n \"links\": {\"a0\": \"test/\",\n \"a1\": \"test/\"}}\n```\n\n-------------------------------------------------------\n\n### Emitter#on_message\n\nEmitted when the client receives a message packet. The message object will be of [EmitterMessage](#message) class, encapsulating the channel and the payload.\n\n-------------------------------------------------------\n\n### Emitter#on_presence\n\nEmitted either when a presence call was made requesting a status, using the [`Emitter#presence()`](#presence) function, or when a user subscribed/unsubscribed to the channel and updates were previously requested using again a call to the [`Emitter#presence()`](#presence) function. Example arguments below.\n\n```\n{\"time\": 1577833210,\n \"event\": \"status\",\n \"channel\": \"\",\n \"who\": [{\"id\": \"ABCDE12345FGHIJ678910KLMNO\", \"username\": \"User1\"},\n {\"id\": \"PQRST12345UVWXY678910ZABCD\"}]}\n{\"time\": 1577833220,\n \"event\": \"subscribe\",\n \"channel\": \"\",\n \"who\": {\"id\": \"ABCDE12345FGHIJ678910KLMNO\", \"username\": \"User1\"}}\n{\"time\": 1577833230,\n \"event\": \"unsubscribe\",\n \"channel\": \"\",\n \"who\": {\"id\": \"ABCDE12345FGHIJ678910KLMNO\"}}\n````\n* `time` is the time of the event as *Unix time*.\n* `event` is the event type: `subscribe` when an remote instance subscribed to the channel, `unsubscribe` when an remote instance unsubscribed from the channel and `status` when [`Emitter#presence()`](#presence) is called the first time.\n* `channel` is the channel name.\n* `who` in case of the `event` is `(un)subscribe` one dict with the user id, when the `event` is `status`, it is a list with the users. When more than 1000 users at the moment subscribed to the channel, 1000 randomly selected are displayed.\n * `id` is an internal generated id of the remote instance.\n * `username` is a custom chosen name by the remote instance. Please note that it is **optional** and check always if this parameter exists. \n\n-------------------------------------------------------\n\n### Emitter#presence(key, channel, status=False, changes=False, optional_handler=None)\n\n```\ninstance.presence(\"\"5xZjIQp6GA9fpxso1Kslqnv8d4XVWChb\"\",\n \"channel\",\n True,\n True)\n```\nSends a presence request to the server.\n* `key` is the channel key to use for the operation. (Required | `Str`)\n* `channel` is the channel name of which you want to call the presence. (Required | `Str`)\n* `status` is whether the broker should send a full status of the channel. (Optional | `Bool` | Default: `False`)\n* `changes` is whether to subscribe to presence changes on the channel. (Optional | `Bool` | Default: `False`)\n* `optional_handler` is the handler to insert in the handler trie. (Optional | `callable` | Default: `None`)\n\nNote: if you do not provide a handler here, make sure you did set the default handler for all presence messages using the [`.on_presence`](#on_presence) property.\n\n-------------------------------------------------------\n\n### Emitter#publish(key, channel, message, options={})\n\n```\nemitter.publish(\"5xZjIQp6GA9fpxso1Kslqnv8d4XVWChb\",\n \"channel\",\n \"Hello Emitter!\",\n {Client.with_ttl(604800), Client.without_echo()}) // one week\n```\nPublishes a message to a particual channel.\n* `key` is the channel key to use for the operation. (Required | `Str`)\n* `channel` is the channel name to publish to. (Required | `Str`)\n* `message` is the message to publish (Required | `String`)\n* `options` a set of options. Currently available options are:\n - `with_at_most_once()` to send with QoS0.\n - `with_at_least_once()` to send with QoS1.\n - `with_retain()` to retain this message.\n - `with_ttl(ttl)` to set a time to live for the message.\n - `without_echo()` to tell the broker not to send the message back to this client.\n\n-------------------------------------------------------\n\n### Emitter#publish_with_link(link, message)\n\n```\ninstance.publishWithLink(\"a0\",\n \"Hello Emitter!\")\n```\nSends a message through the link.\n* `link` is the 2-character name of the link. (Required | `Str`)\n* `message` is the message to send through the link. (Required | `Str`)\n\n-------------------------------------------------------\n\n\n### Emitter#subscribe(key, channel, optional_handler=None, options={})\n\n```\ninstance.subscribe(\"5xZjIQp6GA9fpxso1Kslqnv8d4XVWChb\",\n \"channel\",\n options={Client.with_last(5)})\n```\nSubscribes to a particular channel.\n* `key` is the channel key to use for the operation. (Required | `Str`)\n* `channel` is the channel name to subscribe to. (Required | `Str`)\n* `optional_handler` is the handler to insert in the handler trie. (Optional | `callable` | Default: `None`)\n* `options` a set of options. Currently available options are:\n - `with_last(x)` to receive the last `x` messages stored on the channel.\n\nTODO\n - `with_from`\n - `with_until`\n\nNote: if you do not provide a handler here, make sure you did set the default handler for all messages using the [`.on_message`](#on_message) property.\n\n-------------------------------------------------------\n\n\n### Emitter#subscribe_with_group(key, channel, share_group, optional_handler=None, options={})\n\n```\ninstance.subscribe(\"5xZjIQp6GA9fpxso1Kslqnv8d4XVWChb\",\n \"channel\",\n \"sg\")\n```\nSubscribes to a particular share group for a channel. A message sent to that channel will be forwarded to only one member of the share group, chosen randomly. For more information about share groups, see \n[Emitter: Load-balance Messages using Subscriber Groups (on YouTube)](https://youtu.be/Vl7iGKEQrTg).\n\n* `key` is the channel key to use for the operation. (Required | `Str`)\n* `channel` is the channel name to subscribe to. (Required | `Str`)\n* `share_group` is the name of the group to join. (Required | `Str`)\n* `optional_handler` is the handler to insert in the handler trie. (Optional | `callable` | Default: `None`)\n* `options` a set of options.\n\n\nNote: if you do not provide a handler here, make sure you did set the default handler for all messages using the [`.on_message`](#on_message) property.\n\n-------------------------------------------------------\n\n### Emitter#unsubscribe(key, channel)\n\n```\ninstance.unsubscribe(\"5xZjIQp6GA9fpxso1Kslqnv8d4XVWChb\",\n \"channel\")\n```\nUnsubscribes from a particual channel.\n* `key` is the channel key to use for the operation. (Required | `Str`)\n* `channel` is the channel name to unsubscribe from. (Required | `Str`)\n\nThis deletes handlers for that channel from the trie.\n\n-------------------------------------------------------\n\n### EmitterMessage()\n\nThe `EmitterMessage` class represents a message received from the Emitter server. It contains two properties:\n* `channel` is the channel name the message was published to. (`Str`)\n* `binary` is the buffer associated with the payload. (Binary `Str`)\n\n-------------------------------------------------------\n\n### EmitterMessage#asString()\n\n```\nmessage.asString()\n```\nReturns the payload as a utf-8 `String`.\n\n-------------------------------------------------------\n\n### EmitterMessage#asObject()\n\n```\nmessage.asObject()\n```\nReturns the payload as a JSON-deserialized dictionary.\n\n-------------------------------------------------------\n\n### EmitterMessage#asBinary()\n\n```\nmessage.asBinary()\n```\nReturns the payload as a raw binary buffer.\n\n\n\n## ToDo\n\nThere are some points where the Python libary can be improved:\n- Complete the [keygen](#client-keygen) entry in the README (see the **ToDo** markings)\n- Describe how to use the trie of handlers for regular messages and presence.\n- Add `with_from` and `with_until`.\n- asObject should return an actual object instead of a dictionary.\n\n\n## License\n\nEclipse Public License 1.0 (EPL-1.0)\n\nCopyright (c) 2016-2019 [Misakai Ltd.](http://misakai.com)", "description_content_type": "text/markdown", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://emitter.io", "keywords": "emitter mqtt realtime cloud service", "license": "", "maintainer": "", "maintainer_email": "", "name": "emitter-io", "package_url": "https://pypi.org/project/emitter-io/", "platform": "", "project_url": "https://pypi.org/project/emitter-io/", "project_urls": { "Homepage": "https://emitter.io" }, "release_url": "https://pypi.org/project/emitter-io/2.0.3/", "requires_dist": null, "requires_python": "", "summary": "A Python library to interact with the Emitter API.", "version": "2.0.3" }, "last_serial": 5572362, "releases": { "1.0.0": [ { "comment_text": "", "digests": { "md5": "a7123054486a9160fcd9b6dab204d171", "sha256": "cca2c8f085acbeb38ed07b386734cac26298a647d93d00aa60c6a62c087f80b1" }, "downloads": -1, "filename": "emitter-io-1.0.0.tar.gz", "has_sig": false, "md5_digest": "a7123054486a9160fcd9b6dab204d171", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 28993, "upload_time": "2016-12-28T23:15:41", "url": "https://files.pythonhosted.org/packages/84/b5/1daedb76637886c227fa3e91871a381306916a819523a3fcb20759a1e59b/emitter-io-1.0.0.tar.gz" } ], "1.0.1": [ { "comment_text": "", "digests": { "md5": "549b800bded93805d5243402b93df290", "sha256": "bb09e1cad0bb4479f7d2f063781b6b6e46060252efa281d7d7f980339e18fd78" }, "downloads": -1, "filename": "emitter-io-1.0.1.tar.gz", "has_sig": false, "md5_digest": "549b800bded93805d5243402b93df290", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 29023, "upload_time": "2017-01-07T23:17:00", "url": "https://files.pythonhosted.org/packages/b5/3c/eccbb0b1dd4431b562e484612b7c57e48f881243cebc63a7aae300dc3d6e/emitter-io-1.0.1.tar.gz" } ], "1.0.2": [ { "comment_text": "", "digests": { "md5": "c1bce59897b50e7720fc231b346360ec", "sha256": "0b0c184312c4eb2aaa15b77cb2bc5c2046a1e6aec5cd0fde966c8b8c6553bc54" }, "downloads": -1, "filename": "emitter-io-1.0.2.tar.gz", "has_sig": false, "md5_digest": "c1bce59897b50e7720fc231b346360ec", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6001, "upload_time": "2018-02-04T16:41:53", "url": "https://files.pythonhosted.org/packages/76/67/2e4cf85e1cde10d48ab4783bf4fc148a7dd1703949bcad8b2de08ce56312/emitter-io-1.0.2.tar.gz" } ], "1.0.3": [ { "comment_text": "", "digests": { "md5": "e518ffdddf36af3e304db256be5334d6", "sha256": "5d0f85e38630ebb4323e8beea5af68239c065062eec6f9af993da3e70ed56597" }, "downloads": -1, "filename": "emitter-io-1.0.3.tar.gz", "has_sig": false, "md5_digest": "e518ffdddf36af3e304db256be5334d6", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6014, "upload_time": "2018-04-01T15:40:56", "url": "https://files.pythonhosted.org/packages/1f/bc/f03a02e6a110064a4649054a337f3e3d305a53615dd8c01b8f06b732a6b6/emitter-io-1.0.3.tar.gz" } ], "1.1.0": [ { "comment_text": "", "digests": { "md5": "7fb8c3cc8371501ab18a766444e6a2a7", "sha256": "70c04801db289c1edb193e08565768bcf3d8274d715d96a9aa61f6bcb711ad41" }, "downloads": -1, "filename": "emitter-io-1.1.0.tar.gz", "has_sig": false, "md5_digest": "7fb8c3cc8371501ab18a766444e6a2a7", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5843, "upload_time": "2018-11-02T11:43:29", "url": "https://files.pythonhosted.org/packages/8d/7c/1e7abb25c2a8d35aef19a8052c588aa0fa807fc5dbb76b023511e18a9d4a/emitter-io-1.1.0.tar.gz" } ], "1.1.1": [ { "comment_text": "", "digests": { "md5": "d88b700e56fbe9ab86fde5ca8fc7ee4c", "sha256": "880c52f3303e6f2612987044f0c1ee7cdb707bd84aba7b3c7c22cb7042692722" }, "downloads": -1, "filename": "emitter-io-1.1.1.tar.gz", "has_sig": false, "md5_digest": "d88b700e56fbe9ab86fde5ca8fc7ee4c", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 7561, "upload_time": "2018-11-11T09:11:38", "url": "https://files.pythonhosted.org/packages/81/99/becbcad4364e04938fcfad217aac013e0ba5f3448cf2354b96489210caa3/emitter-io-1.1.1.tar.gz" } ], "1.2.0": [ { "comment_text": "", "digests": { "md5": "83c3289bd8bac52513f31d9cbb86fe66", "sha256": "1a3d448e69f87297258f994d8b65af926fec3dcf45cf4ae6c85f9ca72c1995e5" }, "downloads": -1, "filename": "emitter-io-1.2.0.tar.gz", "has_sig": false, "md5_digest": "83c3289bd8bac52513f31d9cbb86fe66", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 7984, "upload_time": "2019-01-19T17:43:37", "url": "https://files.pythonhosted.org/packages/bc/fa/7302c433f21b81323c91e5f3abfdd12b7572af1a1d41bc808e09b5711aff/emitter-io-1.2.0.tar.gz" } ], "1.3.0": [ { "comment_text": "", "digests": { "md5": "5ee52ad1bb6abec0f467293841cd5c1e", "sha256": "5bdc6e91f78ef7145035578aadddd168d16ffda9bb075bb445013f71a51000b8" }, "downloads": -1, "filename": "emitter-io-1.3.0.tar.gz", "has_sig": false, "md5_digest": "5ee52ad1bb6abec0f467293841cd5c1e", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 10055, "upload_time": "2019-02-16T16:27:05", "url": "https://files.pythonhosted.org/packages/32/ca/9f5bb89570098c116b9d080998925a70d5198e0bdb9f55f69b35bf5bb36a/emitter-io-1.3.0.tar.gz" } ], "2.0.0": [ { "comment_text": "", "digests": { "md5": "708a91083cb3fe88c33585da6e2e924c", "sha256": "f15f9f9ae457343e15707040ff6ff7bd2a978297d3839caffb7df982308c6e7e" }, "downloads": -1, "filename": "emitter-io-2.0.0.tar.gz", "has_sig": false, "md5_digest": "708a91083cb3fe88c33585da6e2e924c", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 11880, "upload_time": "2019-05-19T08:52:15", "url": "https://files.pythonhosted.org/packages/9e/e7/88a39292bd74f6bb1b03244e7102dccbc885886529702f684db5ec1ad377/emitter-io-2.0.0.tar.gz" } ], "2.0.1": [ { "comment_text": "", "digests": { "md5": "f596b9b602cb03045ae04836e389a8dc", "sha256": "2a6d8c6fe2149fcd33f0645e59d507fcc418fa47f37a3597f0b18f72c7f6647f" }, "downloads": -1, "filename": "emitter-io-2.0.1.tar.gz", "has_sig": false, "md5_digest": "f596b9b602cb03045ae04836e389a8dc", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 11902, "upload_time": "2019-06-08T07:22:49", "url": "https://files.pythonhosted.org/packages/18/b1/69e1c49e1a616a9f4c72384699e63e3cb08432f1bdd0bee9fe9c7c49f218/emitter-io-2.0.1.tar.gz" } ], "2.0.2": [ { "comment_text": "", "digests": { "md5": "f0c2d108017161ce4a974ab51408c9d3", "sha256": "4a6435a1c0806e28bfae9fcebc69188c02262ff924294f8070b8906f2cce840f" }, "downloads": -1, "filename": "emitter-io-2.0.2.tar.gz", "has_sig": false, "md5_digest": "f0c2d108017161ce4a974ab51408c9d3", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 11939, "upload_time": "2019-06-08T12:54:26", "url": "https://files.pythonhosted.org/packages/36/90/ed66e9c9b521b5825168d883285a608e0573853d0568cd38891bec5f67b4/emitter-io-2.0.2.tar.gz" } ], "2.0.3": [ { "comment_text": "", "digests": { "md5": "de8087eacbe1356e8e1b3b7646830b37", "sha256": "ad18ea27e461976236b0c30845f2a06143a691316490b8c59ff048792c3d18ae" }, "downloads": -1, "filename": "emitter-io-2.0.3.tar.gz", "has_sig": false, "md5_digest": "de8087eacbe1356e8e1b3b7646830b37", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 12095, "upload_time": "2019-07-23T13:12:56", "url": "https://files.pythonhosted.org/packages/2f/9c/417ea0eeeed81a65e68b03be4afedc2ea07bc34dd5a5997ab573b24ee913/emitter-io-2.0.3.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "de8087eacbe1356e8e1b3b7646830b37", "sha256": "ad18ea27e461976236b0c30845f2a06143a691316490b8c59ff048792c3d18ae" }, "downloads": -1, "filename": "emitter-io-2.0.3.tar.gz", "has_sig": false, "md5_digest": "de8087eacbe1356e8e1b3b7646830b37", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 12095, "upload_time": "2019-07-23T13:12:56", "url": "https://files.pythonhosted.org/packages/2f/9c/417ea0eeeed81a65e68b03be4afedc2ea07bc34dd5a5997ab573b24ee913/emitter-io-2.0.3.tar.gz" } ] }