{ "info": { "author": "Stephen Moore", "author_email": "delfick755@gmail.com", "bugtrack_url": null, "classifiers": [], "description": "LIFX Photons Messages Generator\n===============================\n\nThis is the code that takes in the LIFX protocol definition and some adjustments\nand outputs the code for the ``photons_messages`` module.\n\nPhotons is a framework for interacting with LIFX products and can be found at\nhttps://github.com/delfick/photons-core\n\nChangelog\n---------\n\n0.6.1 - 21 September 2019\n * Formatted code with black and converted tests to pytest\n * Upgraded to `delfick_project `_\n\n0.6.0 - 21 September 2019\n * I changed the many option in photons, it is now \"multiple\" instead\n\n0.5.4 - 1 September 2019\n * Emit fmt: off and fmt: on stanzas so black doesn't destroy the code\n\n0.5.3 - 28 June 2019\n * Emit fields as lists instead of tuples to ensure it's a list when there's\n only one item in it.\n\n0.5.2 - 23 Jan 2019\n * Started using ruamel.yaml instead of PyYaml to load configuration\n\n0.5.1 - 12 Jan 2019\n * Make it possible to say an enum value allows unknown values\n\n0.5 - 3 Jan 2019\n Initial release\n\nTests\n-----\n\nCreate a virtualenv somewhere and run the following in that virtualenv from this\ndirectory::\n\n $ pip install -e .\n $ pip install -e \".[tests]\"\n $ ./test.sh\n\nGenerating messages\n-------------------\n\nOnce you have this installed in your virtualenv you can run the\n``generate_photons_messages`` script in your PATH.\n\nThis takes in the following options:\n\n--src or the SRC environment variable\n The path to the yaml file containing the definition of all the messages\n\n--adjustments or the ADJUSTMENTS environment variable\n The path to the adjustments.yml that contains all the customization\n\n--output-folder or the OUTPUT_FOLDER environment variable\n The directory that is the root of the output\n\nAuto customization\n------------------\n\nThe generator will make the following changes for you without you having to\nspecify them in the adjustments.yml\n\nPacket names\n Packet names in the source yaml are of the form .\n The code will strip the . So for example DeviceSetLabel is turned\n into SetLabel under the DeviceMessages class.\n\n If the name is ``Get`` then it's turned into ``Get``.\n Similar transformation is done for ``Set``. A ``State``\n message is kept as is.\n\nField names\n All field names are snake_case after transformation. For example if the field\n was called AmazingField, it would appear as amazing_field.\n\nAdjustments\n-----------\n\nThe main point of this code is that ``photons_messages`` has some high level\nconcepts and changes to the source definition. The adjustments.yml looks like\nthis:\n\n.. code-block:: yaml\n\n ---\n\n # If fields end up with these names then the generator complains\n invalid_field_names: [\"payload\", \"count\", \"index\", \"fields\", \"Meta\"]\n\n # Where to start counting reserved fields from\n # So because we say 5 here, the first reserved field will be called reserved6\n # the next will be reserved7, etc\n num_reserved_fields_in_frame: 5\n\n # The packets are split up by namespace, this list will say the order of the\n # namespaces in the list. All other namespaces not in the list will be added\n # at the end in whatever order they've been defined\n namespace_order: [\"core\", \"discovery\", \"device\", \"light\"]\n \n # We can use this to rename an entire namespace\n # So here we're saying the namespace `some_namespace` should actually be\n # called `other_namespace`. This new name is used in output options and the\n # namespace_order option above\n rename_namespaces:\n some_namespace: other_namespace\n \n # We can choose to ignore structs from being output\n # Here we're saying don't output either StructOne or StructTwo in fields.py\n # and replace StructOne with a `T.Bytes(size_bytes * 8)` where the size_bytes\n # comes from the field that is using this struct\n # And fields using StructTwo with the fields that are in StructTwo. Note that\n # StructOne doesn't need to actually be in the source yaml, but StructTwo does.\n ignore:\n StructOne: {}\n StructTwo:\n expanded: true\n \n # Output options define where we put our output\n # This is a list of options. You must specify printing enums, fields and all\n # the packets\n #\n # Each item in the list has the following options:\n #\n # create\n # either \"enums\", \"fields\" or \"packets\"\n #\n # dest\n # either a string that is the name of the file under output_directory\n # or a list of strings specifying the path. So saying ``[\"messages\", \"lan.py\"]``\n # would produce a file at ``/messages/lan.py``\n #\n # static\n # A string that is put at the top of that file\n #\n # options\n # If create is packet then this is a dictionary of ``include`` and ``exclude``\n # These are either a string or a list of strings of globs to be applied to\n # the namespaces. Include is applied first and then exclude is applied.\n # To include all namespaces, say ``include: \"*\"``\n output:\n - create: enums\n dest: \"enums.py\"\n static: |\n from enum import Enum\n \n - create: fields\n dest: \"fields.py\"\n static: |\n from photons_messages import enums\n \n from photons_protocol.packets import dictobj\n from photons_protocol.messages import T\n \n from lru import LRU\n \n - create: packets\n dest: \"messages.py\"\n options:\n include: \"*\"\n static: |\n from photons_messages import enums, fields\n from photons_messages.frame import msg\n \n from photons_protocol.messages import T, Messages, MultiOptions\n from photons_protocol.types import Optional\n \n def empty(pkt, attr):\n return pkt.actual(attr) in (Optional, sb.NotSpecified)\n \n # Types let's us specify special types that can then be used multiple times\n # by packets and structs. This let's us specify transformations in one place\n # rather than many.\n # They are of the form ``{: }`` and can be used by specifying\n # ``special_type: `` in the options for a field (see \"changes\" below)\n # Note that we specify the type here so that you can only override a field\n # with the same type as this special type\n # So here we're defining a type called duration_type, it will appear in\n # fields.py like this:\n # \n # duration_type = T.Uint32.default(0).transform(\n # lambda _, value: int(1000 * float(value))\n # , lambda value: float(value) / 1000\n # ).allow_float()\n #\n types:\n duration_type:\n type: uint32\n size_bytes: 4\n default: \"0\"\n extras:\n - |\n transform(\n lambda _, value: int(1000 * float(value))\n , lambda value: float(value) / 1000\n )\n - \"allow_float()\"\n \n # Clones let us create a clone of a struct that has different options for use\n # elsewhere. For example the clone here is the LightHsbk struct but where all\n # the fields are optional\n # The options for each field include ``more_extras`` and ``remove_default``\n # where more_extras adds more options to the type and remove_default makes it\n # so the type has no default even if one was set on the original struct.\n # Note that in this case LightHsbk has extras and defaults specified under\n # the \"changes\" section.\n clones:\n hsbk_with_optional:\n cloning: LightHsbk\n fields:\n Hue:\n more_extras: [\"optional()\"]\n Saturation:\n more_extras: [\"optional()\"]\n Brightness:\n more_extras: [\"optional()\"]\n Kelvin:\n remove_default: true\n more_extras: [\"optional()\"]\n\n scaled_hue:\n ...\n\n scaled_to_65535:\n ...\n \n # The changes section lets us specify renames, different types, field renames\n # , namespace changes, many_options and using helper\n # Note that all names here are the original names in the source yaml\n # We are guaranteed that enums/structs/packets are all unique names and so\n # you don't need to specify what name is what type.\n changes:\n # First we're renaming LightHsbk as hsbk\n # Then we're saying that if it's used like ``[8]`` then we will\n # use the classname of Color and give it a cache amount of 8000\n # We also give special types to some fields. This produces:\n #\n #\n # hsbk = (\n # (\"hue\", scaled_hue)\n # , (\"saturation\", scaled_to_65535)\n # , (\"brightness\", scaled_to_65535)\n # , (\"kelvin\", T.Uint16.default(3500))\n # )\n # \n # class Color(dictobj.PacketSpec):\n # fields = hsbk\n # Color.Meta.cache = LRU(8000)\n #\n # Then if anything uses many of these then they will say\n # ``T.Bytes(size_bytes * 8).many(lambda pkt: fields.Color)``\n #\n LightHsbk:\n rename: hsbk\n many_options:\n name: Color\n cache_amount: 8000\n fields:\n Hue:\n special_type: scaled_hue\n Saturation:\n special_type: scaled_to_65535\n Brightness:\n special_type: scaled_to_65535\n Kelvin:\n default: \"3500\"\n\n # Here we rename the enum DeviceService to Services\n DeviceService:\n rename: Services\n \n # Here we put the DeviceAcknowledgement packet in the \"core\" namespace\n DeviceAcknowledgement:\n namespace: core\n \n # Here we're saying the Label field on the DeviceSetLabel packet is a string\n # This only works for fields that are bytes and will output\n # ``T.String(size_bytes * 8)`` instead of ``T.Bytes(size_bytes * 8)``\n DeviceSetLabel:\n fields:\n Label:\n string_type: true\n \n # Here we're saying DeviceStateLabel has the same fields as DeviceSetLabel\n # And will output ``StateLabel = SetLabel.using(pkt_type)`` where\n # pkt_type is the pkt_type for DeviceStateLabel from the source yaml.\n # This will complain if the fields are infact not the same.\n DeviceStateLabel:\n using: DeviceSetLabel\n \n # Here we're saying that GetService is under the discovery namespace and\n # has a multi option of -1\n # So it will output:\n # \n # GetService = msg(2\n # , multi = -1\n # )\n #\n DeviceGetService:\n namespace: discovery\n multi: \"-1\"\n \n # Here we're renaming the Payload field on EchoRequest to be echoing\n # This is because payload is one of our fields we're not allowed to have.\n DeviceEchoRequest:\n fields:\n Payload:\n rename: echoing\n\n # Here we're giving the Version field a version_number() option\n # So it'll output\n #\n # StateHostFirmware = msg(15\n # , (\"build\", T.Uint64)\n # , (\"install\", T.Uint64)\n # , (\"version\", T.Uint32.version_number())\n # )\n #\n DeviceStateHostFirmware:\n fields:\n Version:\n extras: [\"version_number()\"]\n \n # Here we give Duration the special type of duration_type\n # So it produces\n #\n # SetColor = msg(102\n # , (\"reserved6\", T.Reserved(8))\n # , *fields.hsbk\n # , (\"duration\", fields.duration_type)\n # )\n #\n # Note that the *fields.hsbk means we are using the fields from hsbk here\n # inline.\n LightSetColor:\n rename: SetColor\n fields:\n Duration:\n special_type: duration_type\n \n # Here we use override_struct to use our hsbk_with_optional clone instead\n # of hsbk which is what would otherwise be used\n LightSetWaveformOptional:\n fields:\n Color:\n override_struct: hsbk_with_optional\n \n # Apply is an enum here (as defined in the source yaml) and so the code\n # will make sure the default we specify is a valid value from that enum.\n MultiZoneSetColorZones:\n fields:\n Apply:\n default: \"APPLY\"\n \n # We can split up a field into a value for each of the bits in that field\n # So let's say we have a packet called ExamplePacket with a field Flags\n # that is a uint8, then the following will produce:\n #\n # ExamplePacket = msg(9001\n # , (\"option_one\", T.Bool)\n # , (\"option_two\", T.Bool)\n # , (\"option_three\", T.Bool)\n # , (\"option_four\", T.Bool)\n # , (\"option_five\", T.Bool)\n # , (\"option_six\", T.Bool)\n # , (\"option_seven\", T.Bool)\n # , (\"option_eight\", T.Bool)\n # )\n #\n # Note that the number of options must match the number of bits for that\n # field.\n ExamplePacket:\n fields:\n Flags:\n bits:\n - OptionOne\n - OptionTwo\n - OptionThree\n - OptionFour\n - OptionFive\n - OptionSix\n - OptionSeven\n - OptionEight", "description_content_type": "", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "http://github.com/delfick/photons-messages-generator", "keywords": "lifx photons", "license": "MIT", "maintainer": "", "maintainer_email": "", "name": "lifx-photons-messages-generator", "package_url": "https://pypi.org/project/lifx-photons-messages-generator/", "platform": "", "project_url": "https://pypi.org/project/lifx-photons-messages-generator/", "project_urls": { "Homepage": "http://github.com/delfick/photons-messages-generator" }, "release_url": "https://pypi.org/project/lifx-photons-messages-generator/0.6.1/", "requires_dist": null, "requires_python": "", "summary": "Code for generating the photons_messages module", "version": "0.6.1" }, "last_serial": 5865218, "releases": { "0.5": [ { "comment_text": "", "digests": { "md5": "15461453b6bbf3c5f46a00357127dd6c", "sha256": "75dec7478d5295959c16a39aaf9151173a12869e5869444dc45dd1bc7c532865" }, "downloads": -1, "filename": "lifx-photons-messages-generator-0.5.tar.gz", "has_sig": false, "md5_digest": "15461453b6bbf3c5f46a00357127dd6c", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 21085, "upload_time": "2019-01-03T00:21:38", "url": "https://files.pythonhosted.org/packages/5a/8a/ce3fff7f87de8c5192852edfa37fc9e63c7f58b1a3e5c17860b387eb99c8/lifx-photons-messages-generator-0.5.tar.gz" } ], "0.5.1": [ { "comment_text": "", "digests": { "md5": "4f2c843feac9e9180cb10821b3a642ba", "sha256": "d382d0a388cf34dccb3015081dae29b769d5c639c54546fc9b02c5d6a8a74c8c" }, "downloads": -1, "filename": "lifx-photons-messages-generator-0.5.1.tar.gz", "has_sig": false, "md5_digest": "4f2c843feac9e9180cb10821b3a642ba", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 17528, "upload_time": "2019-01-12T01:34:16", "url": "https://files.pythonhosted.org/packages/a9/a9/0fa5466c0aa21590c53381461e2b156131cca6a5398cccb1364cabe335cf/lifx-photons-messages-generator-0.5.1.tar.gz" } ], "0.5.2": [ { "comment_text": "", "digests": { "md5": "617c3a7e095cf1072c1e9fdc5b2f50ab", "sha256": "bf0139c5244c80c425fbf58a1ff610352ccc1e5b3860aab019793ecc1b453be1" }, "downloads": -1, "filename": "lifx-photons-messages-generator-0.5.2.tar.gz", "has_sig": false, "md5_digest": "617c3a7e095cf1072c1e9fdc5b2f50ab", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 17635, "upload_time": "2019-01-23T11:11:03", "url": "https://files.pythonhosted.org/packages/b0/10/4eff69d7c601cac1c35087878e194e22e28bbcf3f161af4630ffceef8cbe/lifx-photons-messages-generator-0.5.2.tar.gz" } ], "0.5.3": [ { "comment_text": "", "digests": { "md5": "ef644b6b60af2cee99810bcf0fea824a", "sha256": "e274cdf88186e2d4e51b0ffa22ee44b5620a1b0d9b2b070d2988b344d669e2a7" }, "downloads": -1, "filename": "lifx-photons-messages-generator-0.5.3.tar.gz", "has_sig": false, "md5_digest": "ef644b6b60af2cee99810bcf0fea824a", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 17729, "upload_time": "2019-06-28T01:54:07", "url": "https://files.pythonhosted.org/packages/19/36/c72d9c1167cb35692e72ac0d47382acee4cf1e32da4739ac2745f98b897c/lifx-photons-messages-generator-0.5.3.tar.gz" } ], "0.5.4": [ { "comment_text": "", "digests": { "md5": "e31930211856ec1ca02119ac1cc5742d", "sha256": "8f080a46e9d6baaea5945ef7787e38bef92c0785ec090e5ee3cca8bb7c10c769" }, "downloads": -1, "filename": "lifx-photons-messages-generator-0.5.4.tar.gz", "has_sig": false, "md5_digest": "e31930211856ec1ca02119ac1cc5742d", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 17869, "upload_time": "2019-09-01T01:32:19", "url": "https://files.pythonhosted.org/packages/2b/29/3dbcf54a1f7a06b85e552a03b1d2fa5741c19224bb6aa21caa349997cb4e/lifx-photons-messages-generator-0.5.4.tar.gz" } ], "0.6.0": [ { "comment_text": "", "digests": { "md5": "03f66856de7de50f40c6d80e6a86d2ad", "sha256": "ed927552ece620f39dc3f1745091bb4ad947e217043c842a4977bdee0bc3ea99" }, "downloads": -1, "filename": "lifx-photons-messages-generator-0.6.0.tar.gz", "has_sig": false, "md5_digest": "03f66856de7de50f40c6d80e6a86d2ad", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 18126, "upload_time": "2019-09-21T04:51:47", "url": "https://files.pythonhosted.org/packages/6f/62/4c0a75f2eee76b265057656da7a3ab77ec5d4a5e7b09edf2bbf5195658ed/lifx-photons-messages-generator-0.6.0.tar.gz" } ], "0.6.1": [ { "comment_text": "", "digests": { "md5": "1da3888cf9f52fbc3fffc3772338c86f", "sha256": "8ef661b0af1a089b89119eb36a9e2e32cc283bc04059527071d6a8f2ab9050c7" }, "downloads": -1, "filename": "lifx-photons-messages-generator-0.6.1.tar.gz", "has_sig": false, "md5_digest": "1da3888cf9f52fbc3fffc3772338c86f", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 22255, "upload_time": "2019-09-21T05:26:11", "url": "https://files.pythonhosted.org/packages/7a/2c/690c22e7089fdc27ab04bee6df7617f5e9686c587bde2e0130e79d90b82c/lifx-photons-messages-generator-0.6.1.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "1da3888cf9f52fbc3fffc3772338c86f", "sha256": "8ef661b0af1a089b89119eb36a9e2e32cc283bc04059527071d6a8f2ab9050c7" }, "downloads": -1, "filename": "lifx-photons-messages-generator-0.6.1.tar.gz", "has_sig": false, "md5_digest": "1da3888cf9f52fbc3fffc3772338c86f", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 22255, "upload_time": "2019-09-21T05:26:11", "url": "https://files.pythonhosted.org/packages/7a/2c/690c22e7089fdc27ab04bee6df7617f5e9686c587bde2e0130e79d90b82c/lifx-photons-messages-generator-0.6.1.tar.gz" } ] }