{ "info": { "author": "Johan Stokking", "author_email": "johan@thethingsnetwork.org", "bugtrack_url": null, "classifiers": [], "description": "Table of Contents\n=================\n\n- `Description <#description>`__\n- `MQTTClient <#mqttclient>`__\n\n - `connect <#connect>`__\n - `close <#close>`__\n - `set_uplink_callback <#set_uplink_callback>`__\n\n - `uplink_callback <#uplink_callback>`__\n\n - `set_connect_callback <#set_connect_callback>`__\n\n - `connect_callback <#connect_callback>`__\n\n - `set_downlink_callback <#set_downlink_callback>`__\n\n - `downlink_callback <#downlink_callback>`__\n\n - `set_close_callback <#set_close_callback>`__\n\n - `close_callback <#close_callback>`__\n\n - `send <#send>`__\n - `UplinkMessage <#uplinkmessage>`__\n\n- `ApplicationClient <#applicationclient>`__\n\n - `get <#get>`__\n - `set_payload_format <#set_payload_format>`__\n - `set_custom_payload_functions <#set_custom_payload_functions>`__\n - `unregister <#unregister>`__\n - `device <#device>`__\n - `devices <#devices>`__\n - `update_device <#update_device>`__\n - `delete_device <#delete_device>`__\n - `Device <#deviceobject>`__\n - `Application <#application>`__\n\n- `HandlerClient <#handlerclient>`__\n\n - `data <#data>`__\n - `application <#application>`__\n\n- `Troubleshooting <#troubleshooting>`__\n\nDescription\n-----------\n\nThis package provides you an easy way to exchange traffic with The\nThings Network via MQTT and manage your applications.\n\nMQTTClient\n----------\n\nThe class constructor can be called following this scheme:\n\n.. code:: python\n\n MQTTClient(app_id, access_key, mqtt_address=\"\", discovery_address=\"discovery.thethings.network:1900\", reconnect=True)\n\n- ``app_id``: **string** this the name given to the application when it\n was created. |Screenshot of the console with app section|\n- ``access_key``: **string** this can be found at the bottom of the\n application page under **ACCESS KEYS**. |Screenshot of the console\n with accesskey section|\n- ``mqtt_address``: **string** this is the address of the handler to\n which the application was registered, in the ``{hostname}:{port}``\n format.\n- ``discovery_address``: **string** this is the address of the\n discovery server to use in order to find back the address of the MQTT\n handler, in the ``{hostname}:{port}`` format.\n- ``reconnect``: **boolean** whether to automatically reconnect to\n the MQTT server on unexpected disconnect (useful if you'd like to\n keep the connection alive for several hours)\n\n If the ``mqtt_address`` is set, the ``discovery_address`` doesn\u2019t\n need to be set as it is only used to retrieve the ``mqtt_address``\n from the discovery server. The constructor returns an **MQTTClient\n object** set up with the application informations, ready to be\n connected to The Things Network.\n\nconnect\n~~~~~~~\n\nConnects and starts the client in the background. This function also\nre-establishes the client\u2019s connection in case it was closed.\n\n.. code:: python\n\n client.connect()\n\nclose\n~~~~~\n\nDisconnects and stops the client from which the method is called.\n\n.. code:: python\n\n client.close()\n\nUsing Callbacks\n~~~~~~~~~~~~~~~\n\nThe callback functions are functions which are executed when a trigger\nevent happens.\n\nset_uplink_callback\n^^^^^^^^^^^^^^^^^^^\n\nAdd a callback function, to be called when an uplink message is\nreceived.\n\n.. code:: python\n\n client.set_uplink_callback(uplink_callback)\n\nuplink_callback\n'''''''''''''''\n\nThe callback function must be declared in the script following this\nstructure:\n\n- ``uplink_callback(msg, client)``\n\n - ``msg``: **UplinkMessage object** the message received by the\n client.\n - ``client``: **MQTTClient object** the client from which the\n callback is executed.\n\nset_uplink_callback_raw\n^^^^^^^^^^^^^^^^^^^^^^^\n\nAdd a callback function, to be called when an uplink message is\nreceived. This function provides compatibility with existing\npaho.mqtt.client implementations.\n\n.. code:: python\n\n client.set_uplink_callback_raw(uplink_callback_raw)\n\nuplink_callback_raw\n'''''''''''''''''''\n\nThe callback function must be declared in the script following this\nstructure:\n\n- ``uplink_callback_raw(msg, client)``\n\n - ``msg``: **paho.mqtt.client.MQTTMessage object** the message\n received by the client.\n - ``client``: **MQTTClient object** the client from which the\n callback is executed.\n\nset_connect_callback\n^^^^^^^^^^^^^^^^^^^^\n\nAdd a connection callback function to be executed when the client\nconnects to the broker.\n\n.. code:: python\n\n client.set_connect_callback(connect_callback)\n\nconnect_callback\n''''''''''''''''\n\n- ``connect_callback(res, client)``: the function which will be\n executed on connection to the broker.\n\n - ``res``: **boolean** the result of the connection. If it\u2019s true,\n the connection succeeded. If not, it means the connection failed.\n - ``client``: **MQTTClient object** the TTN client from which the\n callback is called.\n\nset_downlink_callback\n^^^^^^^^^^^^^^^^^^^^^\n\nAdd a downlink callback function, with actions to execute when a\ndownlink message is sent.\n\n.. code:: python\n\n client.set_downlink_callback(downlinkCallback)\n\ndownlink_callback\n'''''''''''''''''\n\n- ``downlink_callback(mid, client)``: the function which will be a new\n publish behavior for our MQTT client.\n\n - ``mid``: **int** this is the message ID for the downlink request.\n It can be used to track the request.\n - ``client``: **MQTTClient object** the TTN client from which the\n callback is called.\n\nset_close_callback\n^^^^^^^^^^^^^^^^^^\n\nAdd a callback to be executed when the connection to the TTN broker is\nclosed.\n\n.. code:: python\n\n client.set_close_callback(close_callback)\n\nclose_callback\n''''''''''''''\n\n- ``close_callback(res, client)``: the function which will be executed\n when the connection is closed.\n\n - ``res``: **boolean** the result of the disconnection. If it\u2019s\n true, it went all as expected. If not, it means the disconnection\n was unexpected.\n - ``client``: **MQTTClient object** the TTN client from which we\n call the callback.\n\nsend\n~~~~\n\nSends a downlink to the device.\n\n.. code:: python\n\n client.send(dev_id, payload, port=1, confirmation=False, schedule=\"replace\")\n\n- ``dev_id``: **string** the ID of the device which will receive the\n message.\n- ``payload``: the payload of the message to be published to the\n broker. It can be an hexadecimal **string**, a base64 **string** like\n ``AQ==`` (this will send the raw payload ``01`` to your device) or a\n **dictionary** of JSON nature. Here is an example of a **dictionary**\n argument that could be passed to the method:\n\n.. code:: json\n\n { \"led_state\": \"on\", \"counter\": 1 }\n\nIn case it\u2019s a **dictionary** with fields, please make sure the\n**encoder** function (Payload Formats section) of the application is set\nto make sense of the informations transmitted in each field. |Screenshot\nof an encoder function in the console|\n\n- ``port``: **int** the port of the device to which the message will be\n sent.\n- ``confirmation``: **boolean** this boolean indicates if you wish to\n receive a confirmation after sending the downlink message.\n- ``schedule``: **string** this string provides the type of schedule on\n which the message should be sent. It can take the following values:\n ``first``, ``last``, ``replace``.\n\nUplinkMessage\n~~~~~~~~~~~~~\n\nThis type of object is constructed dynamically from the message received\nby the client, so this means some attributes can change from one message\nto another. Here are some constant attributes usually found in\nUplinkMessage objects:\n\n- ``app_id``: the application ID to which the device is registered\n- ``dev_id``: the ID of the device\n- ``port``: the port number on which the message was sent\n- ``payload_raw``: a buffer which contains the payload in hexadecimal\n- ``metadata``: this field is another object which contains all the\n metadata of the message. Such as: the date, the frequency, the data\n rate and the list of gateways.\n\nApplicationClient\n-----------------\n\nThe class constructor can be called following this scheme:\n\n.. code:: python\n\n ApplicationClient(app_id, access_key, handler_address=\"\", cert_content=\"\", discovery_address=\"discovery.thethings.network:1900\")\n\n- ``app_id``: **string** this the name given to the application when it\n was created. |Screenshot of the console with app section|\n- ``access_key``: **string** this can be found at the bottom of the\n application page under **ACCESS KEYS**. You will need a key allowing\n you to change the settings if you wish to update your application.\n- ``handler_address``: **string** this is the address of the handler to\n which the application was registered, in the ``{hostname}:{port}``\n format. Example: ``handler.eu.thethings.network:1904``.\n- ``cert_content``: **string** this is the content of the certificate\n used to connect in a secure way to the handler. Here is a certificate\n example:\n\n::\n\n -----BEGIN CERTIFICATE-----\n MIIBmjCCAUCgAwIBAgIRANKKhUVFRXhyx0gCX2h7EFwwCgYIKoZIzj0EAwIwHTEb\n MBkGA1UEChMSVGhlIFRoaW5ncyBOZXR3b3JrMB4XDTE3MDgwMTA4MzQxMloXDTE4\n MDgwMTA4MzQxMlowHTEbMBkGA1UEChMSVGhlIFRoaW5ncyBOZXR3b3JrMFkwEwYH\n KoZIzj0CAQYIKoZIzj0DAQcDQgAEiXbWvyYjOMP4ebTYtVvdIsBwS+U3laWltR7V\n ox4+kQWcGLLEg+suI9SRZyKK+frhw9JPKbVNIgEv/S50YKfMEaNhMF8wDgYDVR0P\n AQH/BAQDAgKkMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAPBgNVHRMB\n Af8EBTADAQH/MB0GA1UdEQQWMBSCB2hhbmRsZXKCCWxvY2FsaG9zdDAKBggqhkjO\n PQQDAgNIADBFAiEA+vajlz7HDZ7x6KKi/uMlrwCePEcchZRYJPc/6kPyYogCIFSy\n etQ54MyIOWtwYlxG+blnxT4PWCgas5rPiaK6VP/Z\n -----END CERTIFICATE-----\n\n- ``discovery_address``: **string** this is the address of the\n discovery server to use in order to find back the address of the\n handler to which the application in registered, in the\n ``{hostname}:{port}`` format. Example:\n ``discovery.thethings.network:1900``.\n\n The constructor returns an **ApplicationClient** object set up with\n the application informations, ready to get the application registered\n on The Things Network.\n\nget\n~~~\n\nGives back the `**Application** <#application>`__.\n\n.. code:: python\n\n client.get()\n\nset_payload_format\n~~~~~~~~~~~~~~~~~~\n\nSets the payload format of the application.\n\n.. code:: python\n\n client.set_payload_format(payload_format)\n\n- payload_format: **string** the new payload format. Example:\n ``custom``\n\nset_custom_payload_functions\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nSets the payload functions of the application.\n\n.. code:: python\n\n client.set_custom_payload_functions(encoder=\"\", decoder=\"\", validator=\"\", converter=\"\")\n\n- ``decoder``: **string** Javascript decoder function.\n- ``encoder``: **string** Javascript encoder function.\n- ``validator``: **string** Javascript validator function.\n- ``converter``: **string** Javascript converter function.\n\n Arguments left empty are ignored and won\u2019t be updated. Example:\n\n.. code:: python\n\n decoder_fn = \"\"\"function Decoder(payload) {\n return { led: 1 };\n }\"\"\"\n client.set_custom_payload_functions(decoder=decoder_fn)\n\nunregister\n~~~~~~~~~~\n\nUnregisters the application.\n\n.. code:: python\n\n client.unregister()\n\nregister_device\n~~~~~~~~~~~~~~~\n\nRegisters a new device to the application.\n\n.. code:: python\n\n client.register_device(dev_id, device)\n\n- ``dev_id``: **string** the id of the device to be registered.\n- ``device``: **dictionary** the dictionary with fields to be set as a\n new device of the application. See the `Device <#deviceobject>`__\n section to know the structure of the dictionary that should be passed\n and the name of the fields.\n\ndevice\n~~~~~~\n\nGives back the `**Device** <#deviceobject>`__ object of the given id.\n\n.. code:: python\n\n client.device(dev_id)\n\n- ``dev_id``: **string** the id of the device.\n\ndevices\n~~~~~~~\n\nGives back the list of all the devices registered to the application.\n\n.. code:: python\n\n client.devices()\n\nupdate_device\n~~~~~~~~~~~~~\n\nUpdates an already existing device of the application.\n\n.. code:: python\n\n client.update_device(dev_id, updates)\n\n- ``dev_id``: **string** the id of the device to be updated.\n- ``updates``: **dictionary** a dictionary with the fields to be\n updated in the device.\n\ndelete_device\n~~~~~~~~~~~~~\n\nDeletes the device with the given id.\n\n.. code:: python\n\n client.delete_device(dev_id)\n\n- ``dev_id``: **string** the id of the device to be deleted.\n\n.. device-1:\n\nDevice\n~~~~~~\n\nThis objet is returned by the method ``device()`` of the\nApplicationClient class. Here are its attributes:\n\n- ``app_id``: **string**\n- ``dev_id``: **string**\n- ``latitude``: **float**\n- ``longitude``: **float**\n- ``altitude``: **float**\n- ``description``: **string**\n- ``attributes``: **dictionary**\n- ``lorawan_device``: **dictionary**\n\n - ``app_eui``: **string** 8 bytes in hexadecimal\n - ``dev_eui``: **string** 8 bytes in hexadecimal\n - ``dev_addr``: **string** 4 bytes in hexadecimal\n - ``nwk_s_key``: **string** 16 bytes in hexadecimal\n - ``app_s_key``: **string** 16 bytes in hexadecimal\n - ``app_key``: **string** 16 bytes in hexadecimal\n - ``f_cnt_up``: **int**\n - ``f_cnt_down``: **int**\n - ``disable_f_cnt_check``: **boolean**\n - ``uses32_bit_f_cnt``: **boolean**\n\nApplication\n~~~~~~~~~~~\n\nThis object is returned by the method ``get()`` of the ApplicationClient\nclass. Here are its attributes:\n\n- ``app_id``: **string**\n- ``payload_format``: **string**\n- ``decoder``: **string**\n- ``encoder``: **string**\n- ``converter``: **string**\n- ``validator``: **string**\n- ``register_on_join_access_key``: **string**\n\nHandlerClient\n-------------\n\nThe class constructor can be called following this scheme:\n\n.. code:: python\n\n HandlerClient(app_id, access_key, discovery_address=\"discovery.thethings.network:1900\", cert_path=\"\")\n\n- ``app_id``: **string** this the name given to the application when it\n was created. |Screenshot of the console with app section|\n- ``access_key``: **string** this can be found at the bottom of the\n application page under **ACCESS KEYS**. The key needs the\n ``settings`` authorization.\n- ``discovery_address``: **string** this is the address of the\n discovery server to use in order to find back the address of the\n handler to which the application in registered, in the\n ``{hostname}:{port}`` format.\n- ``cert_path``: **string** this is the path to the certificate used to\n connect in a secure way to the discovery server.\n\ndata\n~~~~\n\nCreates an `**MQTTClient** <#mqttclient>`__ object.\n\n.. code:: python\n\n handler.data(reconnect=True)\n\n- ``reconnect``: **boolean** whether to automatically reconnect to\n the MQTT server on unexpected disconnect (useful if you'd like to\n keep the connection alive for several hours)\n\nReturns an `**MQTTClient** <#mqttclient>`__ object.\n\n.. application-1:\n\napplication\n~~~~~~~~~~~\n\nCreates an `**ApplicationClient** <#applicationclient>`__ object\n\n.. code:: python\n\n handler.application()\n\nReturns an `**ApplicationClient** <#applicationclient>`__ object.\n\nTroubleshooting\n---------------\n\nErrors can happen on connection or on some ApplicationClient\u2019s methods\ncall, for different reasons:\n\n- Wrong ``app_id``, ``access_key`` or ``mqtt_address`` were provided to\n the constructor.\n- The machine may not have access to the network/The MQTT server could\n be down/Firewall restrictions could prevent connection.\n- The client process doesn\u2019t have system capabilities to open a socket\n- The MQTT server uses MQTTS, but the client won\u2019t accept the TLS\n certificate.\n- The Application client is not able to get the application or a\n device. Errors could also happen when closing connection, in case the\n disconnection is unexpected. This errors are the most common ones,\n there are also edges cases not mentioned in this section.\n\n.. |Screenshot of the console with app section| image:: ./images/app-console.png?raw=true\n.. |Screenshot of the console with accesskey section| image:: ./images/accesskey-console.png?raw=true\n.. |Screenshot of an encoder function in the console| image:: ./images/encoder-function.png?raw=true", "description_content_type": "", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/TheThingsNetwork/python-app-sdk", "keywords": "", "license": "MIT", "maintainer": "", "maintainer_email": "", "name": "ttn", "package_url": "https://pypi.org/project/ttn/", "platform": "", "project_url": "https://pypi.org/project/ttn/", "project_urls": { "Homepage": "https://github.com/TheThingsNetwork/python-app-sdk" }, "release_url": "https://pypi.org/project/ttn/2.1.5/", "requires_dist": null, "requires_python": "", "summary": "The Things Network Client", "version": "2.1.5" }, "last_serial": 4696219, "releases": { "2.0.0": [ { "comment_text": "", "digests": { "md5": "769eb93c72ea0b33e2d5a536b0b4ce19", "sha256": "1e57b9b83dd4c5b3a2134a66832dece575056bc65b772b0d60d93f6a34cb6e94" }, "downloads": -1, "filename": "ttn-2.0.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "769eb93c72ea0b33e2d5a536b0b4ce19", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 11039, "upload_time": "2017-11-29T13:16:40", "url": "https://files.pythonhosted.org/packages/ad/63/8aaad50bd787d48bb73cf01b45e82fa1cfd13411184eb13f96162b97cf41/ttn-2.0.0-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "d619ed73fe50ad49f14d7fc80bea9360", "sha256": "ee25d270e8e271ee20f6d3fdafb98279ac47c6a5e412d2e61d70aaef2490f357" }, "downloads": -1, "filename": "ttn-2.0.0.tar.gz", "has_sig": false, "md5_digest": "d619ed73fe50ad49f14d7fc80bea9360", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6049, "upload_time": "2017-11-29T13:16:41", "url": "https://files.pythonhosted.org/packages/42/06/0d2ada70191830252d00802f71de39c6e136d6fb9d2d3becd005d40a6717/ttn-2.0.0.tar.gz" } ], "2.0.1": [ { "comment_text": "", "digests": { "md5": "ebf758b453f8891e29819bb237d0bd17", "sha256": "d78ac198ec28dc0a8163990f4959c343d9577161e6594b2d89bac8b39a37732d" }, "downloads": -1, "filename": "ttn-2.0.1.tar.gz", "has_sig": false, "md5_digest": "ebf758b453f8891e29819bb237d0bd17", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 19387, "upload_time": "2018-01-04T09:48:26", "url": "https://files.pythonhosted.org/packages/fa/4f/0a215a236bf9f07dd181e13ca89dfc4fc14eac73be82631b11b0d7c716c9/ttn-2.0.1.tar.gz" } ], "2.0.2": [ { "comment_text": "", "digests": { "md5": "5dbd7af24c9e7dcd422d00742c0ceb60", "sha256": "12c13ad08ed40b09ce29d526869990c49412e0278c29e5712bd577b619a936e1" }, "downloads": -1, "filename": "ttn-2.0.2.tar.gz", "has_sig": false, "md5_digest": "5dbd7af24c9e7dcd422d00742c0ceb60", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 19394, "upload_time": "2018-01-04T09:51:51", "url": "https://files.pythonhosted.org/packages/74/be/017cf1a38c04424d33466d897bd01d60866dd9b3155d2c0cb7020550179e/ttn-2.0.2.tar.gz" } ], "2.1.0": [ { "comment_text": "", "digests": { "md5": "add6e96af9dafb3d20b5d1141182fc6b", "sha256": "760352a9995f33e80975a1f25bb412c0c888c1a2e7e5aa1548e423e4ed0fe5c7" }, "downloads": -1, "filename": "ttn-2.1.0.tar.gz", "has_sig": false, "md5_digest": "add6e96af9dafb3d20b5d1141182fc6b", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 13948, "upload_time": "2018-02-07T08:58:28", "url": "https://files.pythonhosted.org/packages/61/53/2579759644de3a8d558d82c996e9161c02dd812fec19fb0a89e6051af5ad/ttn-2.1.0.tar.gz" } ], "2.1.1": [ { "comment_text": "", "digests": { "md5": "792153dbaab89ba4d42a5260251ff5db", "sha256": "0bf28580755f62b91dc471ede074b6748753d5bbcff35648550066178af54289" }, "downloads": -1, "filename": "ttn-2.1.1.tar.gz", "has_sig": false, "md5_digest": "792153dbaab89ba4d42a5260251ff5db", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 90125, "upload_time": "2018-03-06T14:22:02", "url": "https://files.pythonhosted.org/packages/90/d6/ab1d21e746e8094a5576fdfda0461319681f0c270e367b9f32d9c9ee5962/ttn-2.1.1.tar.gz" } ], "2.1.2": [ { "comment_text": "", "digests": { "md5": "a1dd7475d1071b65b2444ef450b4eff9", "sha256": "c278401847c07011d6e3caaf9cd98fab1078a1cd7f82a3481e64f1ec26baddb0" }, "downloads": -1, "filename": "ttn-2.1.2.tar.gz", "has_sig": false, "md5_digest": "a1dd7475d1071b65b2444ef450b4eff9", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 90116, "upload_time": "2018-07-09T09:27:47", "url": "https://files.pythonhosted.org/packages/cb/cf/f0f4d6a1755ad7fa1b16bdf219ee8972817bdbc8e225178c0fad44233235/ttn-2.1.2.tar.gz" } ], "2.1.3": [ { "comment_text": "", "digests": { "md5": "f6190db8fa881657e908d02f0556895d", "sha256": "fd922a47767804430561cd150cf08b62c876e658f00cb734fce3c2c2086db812" }, "downloads": -1, "filename": "ttn-2.1.3.tar.gz", "has_sig": false, "md5_digest": "f6190db8fa881657e908d02f0556895d", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 90034, "upload_time": "2018-08-30T08:16:23", "url": "https://files.pythonhosted.org/packages/11/d4/0f6ec2bb5f4776ab4791f9d9513c1c65707ed238fa2273b2f662c70aba24/ttn-2.1.3.tar.gz" } ], "2.1.4": [ { "comment_text": "", "digests": { "md5": "395d2aa0952bc808e564545a44ede25a", "sha256": "b27218e50778771549ec700add6a8a1f6da95cccd18ddfb11e17bb88e7f7cc5c" }, "downloads": -1, "filename": "ttn-2.1.4.tar.gz", "has_sig": false, "md5_digest": "395d2aa0952bc808e564545a44ede25a", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 90319, "upload_time": "2018-09-19T14:46:46", "url": "https://files.pythonhosted.org/packages/a9/ca/73a804fad0b922f7eb50cd535af8796b7e8c6aa779700f1c5b8746eb18c3/ttn-2.1.4.tar.gz" } ], "2.1.5": [ { "comment_text": "", "digests": { "md5": "63833642eb6f73bfe04a56a1d3861d34", "sha256": "f4be5e4fc396a2ac169034a5f5c14063b459c17857f016fe2254946c8480c196" }, "downloads": -1, "filename": "ttn-2.1.5.tar.gz", "has_sig": false, "md5_digest": "63833642eb6f73bfe04a56a1d3861d34", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 90578, "upload_time": "2019-01-14T21:44:15", "url": "https://files.pythonhosted.org/packages/9d/67/e126d29d95c091484da7463deffa4c0283dc3665da6000f87c7204cf3503/ttn-2.1.5.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "63833642eb6f73bfe04a56a1d3861d34", "sha256": "f4be5e4fc396a2ac169034a5f5c14063b459c17857f016fe2254946c8480c196" }, "downloads": -1, "filename": "ttn-2.1.5.tar.gz", "has_sig": false, "md5_digest": "63833642eb6f73bfe04a56a1d3861d34", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 90578, "upload_time": "2019-01-14T21:44:15", "url": "https://files.pythonhosted.org/packages/9d/67/e126d29d95c091484da7463deffa4c0283dc3665da6000f87c7204cf3503/ttn-2.1.5.tar.gz" } ] }