{ "info": { "author": "UNKNOWN", "author_email": "UNKNOWN", "bugtrack_url": null, "classifiers": [], "description": "\n.. image:: https://api.travis-ci.org/derrley/yamlicious.png\n :target: https://travis-ci.org/derrley/yamlicious\n\nYamlicious is a (work-in-progress) lightweight configuration library built on\ntop of YAML. It's for folks who love to write their configuration files in\nYAML, but who find themselves writing additional boilerplate each time they\nwant to use YAML to encode a configuration file.\n\nIn addition to a parser, yamlicious provides code that:\n\n- Validates the correctness of a file and prints an understandable failure\n message when the file doesn't quite match\n\n- Understands your environemnt, and allows you to configure different properties\n for different environment dimensions without unnecessary DRY-violation\n\n- Reads configuration from multiple files\n\n- Provides a cascading set of configuration sources, including environment\n variables\n\n- Lazily loads certain parts of a large configuration. (read: when your\n \"configuration\" really starts to feel more like \"data.\")\n\n- Is generically extensible to new behavior, just in case you need to add\n something we haven't thought of\n\nYamlicious does all this by being like any other YAML parser, but by treating a\nhandful of specific keys in a special way. It can be configured to recognize\nand evaluate any subset of these *feature keys*, allowing a developer to bake\nin as much (or as little!) of the crazy capabilities as seems reasonable for\nthe situation. (The craziest stuff is turned off by default.)\n\nSkip to `Feature Key Definitions`_ if you want the formality without the\nEnglish verbiage.\n\n.. contents::\n\n\nThe Yamlicious File\n====================\n\nA configuration file specified in Yamlicious *is just YAML*. In fact, nothing stops\nyou from parsing a Yamlicious file with any YAML library. This can be useful for\nsearching, cleaning, or editing (with syntax highlighting) the file.\n\nEnvironment Variable Subtitution\n---------------------------------\n\nYamlicious gives your configuration file automatic access to the environment. \n\n.. code-block:: yaml\n\n some:\n key:\n user_$(USER): not cool\n user_kyle: cool\n\nDon't worry. The Yamlicious API gives you (the developer) the ability to both\nlimit the environment variables your configuration file is allowed to access\nand provide overriding values for anything in the environment. You're neither\nforced to use environment variables nor doomed to a free for all.\n\nYamlicious supports list values in the environment, and splits environment variables\non the comma character. If a Yamlicious file substitutes a list variable into a\nstring, that string renders into multiple strings (one for each value in the\nlist variable).\n\nIf a string references a variable that's not in the environment, yamlicious\ndoes not modify the string. It will leave the variable reference alone, ``$()``\ncharacters included. This makes string substitution have a neat property -- it\ncan be applied to the same document iteratively as the environment grows.\n\nList substitution behavior varies subtly by situation.\n\n\nWhen substituting into a single value string\n````````````````````````````````````````````\n\n.. code-block:: yaml\n\n some_list: $(MY_LIST)\n\nrenders to the following, if ``MY_LIST=one,two,three`` is in the environment.\n\n.. code-block:: yaml\n\n some_list:\n - one\n - two\n - three\n\n\nWhen substituting into a value list\n```````````````````````````````````\n\n.. code-block:: yaml\n\n some_list:\n - first\n - $(LIST)\n\nbecomes\n\n.. code-block:: yaml\n\n some_list:\n - first\n - one\n - two\n - three\n\n\nWhen substituting into a key string\n```````````````````````````````````\n\nKey strings are special, because you almost certainly don't intend to make a\nlist into the key of a dictionary. Instead, you likely mean to define a key in\nthe dictionary for each item in the list. Yamlicious provides a special\nvariable in the environment, ``_KEY``, to help you out in this situation.\n\n.. code-block:: yaml\n\n $(LIST): $(_KEY) is in the list!\n\nbecomes\n\n.. code-block:: yaml\n\n one: one is in the list\n two: two is in the list\n three: three is in the list\n\n``_KEY`` is set to the first-level key in the document, regardless of whether\nthe key was derived from string substitution. To get the second-level key, use\n``__KEY``, and so forth:\n\n.. code-block:: yaml\n\n $(LIST):\n second_level_key: $(_KEY) on top and $(__KEY) on bottom\n\nbecomes\n\n.. code-block:: yaml\n\n one:\n second_level_key: one on top and second_level_key on bottom\n two:\n second_level_key: two on top and second_level_key on bottom\n three:\n second_level_key: three on top and second_level_key on bottom\n\n\nWhen substituting multiple list values into the same string\n````````````````````````````````````````````````````````````\n\nThis is interpreted as a dot product. Yamlicious will substitute every\ncombination of variables between the two lists.\n\nIf ``BOYS=joey,johnny,bobby`` and ``GIRLS=sally,mary`` then:\n\n.. code-block:: yaml\n\n \"$(BOYS) likes $(GIRLS)\"\n\nbecomes:\n\n.. code-block:: yaml\n\n - joey likes sally\n - joey likes mary\n - johnny likes sally\n - johnny likes mary\n - bobby likes sally\n - bobby likes mary\n\nNote -- the rest of the \"positional\" list substitution rules (defined in the\nimmediately previous sections) apply to dot product substitutions.\n\n\nLoad Another File\n----------------------\n\nSometimes, it makes sense to define sub-configuration somewhere outside the\nmain configuration file. (e.g., secrets go somewhere special.) Yamlicious gives\nyou the `insert`_ key to accomplish this.\n\nNote: `insert_` is a *functional feature key*. (Defined more in the `Functional\nFeature Keys`_ section.) These are keys that participate in something like a\nfunction call -- the entire map that contains a functional key evaluates to\nfunctional behavior applied to the key's value. (No project is complete without\na smidge of functional programming.) You can only use one of these keys in a\nmap at a time because yamlicious replaces the key-containing map with a\ndocument -- the result of the function applied to the key's value. Multiple\nkeys is an abiguous definition.\n\n.. code-block:: yaml\n\n some_place:\n placed_here:\n _insert: other/file.yaml\n\nIn this case, the rendered YAML output of ``other/file.yaml`` is placed under\nthe ``placed_here`` key.\n\n.. code-block:: yaml\n\n some_place:\n placed_here:\n contents of:\n - that other file\n - which can be arbitrary YAML\n\nYou can use variable substitution with the `insert`_ feature to get conditional\nconfiguration.\n\n.. code-block:: yaml\n\n user_settings:\n _insert: $(USER)/conf.yaml\n\n\nMerge\n---------------\n\nYamlicious allows you to *merge* an external file into a bit of config.\n\n.. code-block:: yaml\n\n merged_settings:\n _merge:\n - some_list: ['thing']\n some_thing: 'thing'\n\n - _insert: some_other_place.yaml\n\nWhen you ask Yamlicious to do this, it will use a strategy I call *safe deep merge\nwith list append*. Yamlicious merges dictionaries recursively by combining their\nkey-value pairs. It merges lists by list addition. It refuses, however, to\nmerge anything else. (Anything else would be shoot-self-in-foot territory, and\nI'd rather not encourage it.)\n\nif ``some_other_place.yaml`` looked like this:\n\n.. code-block:: yaml\n\n some_list: ['second_thing']\n some_other_thing: 'thing'\n\n\nThe above configuration would render as follows:\n\n.. code-block:: yaml\n\n merged_settings:\n some_list: ['thing', 'second_thing']\n some_thing: 'thing'\n some_other_thing: 'thing'\n\nIf you're looking to implement the common *default override* pattern, specify\n`The Default Document`_ as part of the Yamlicious API. That feature is specifically\nbuilt to help you not have to allow arbitrary overrides when including files.\nIf you absolutely must allow overrides, use the `merge_override`_ keyword,\nbut note that it is turned off by default.\n\nInsert and Merge\n------------------\n\nLoading several files and merging them is a common pattern, and it would be\nnice if folks didn't have to be verbose if that's the behavior they're looking\nfor. This is what the `insert_merge`_ key is for.\n\n.. code-block:: yaml\n\n merged_stuff:\n _insert_merge:\n - first/place.yaml\n - second/place.yaml\n - third/place.yaml\n\nThis key will load each file in order and merge that file into the previous\nfile.\n\n\n\nMerging Entire Documents\n-------------------------\n\nIf you'd like to merge an entire document with your own, use the `include`_\nfeature key.\n\nNote: `include`_ is a *document feature key*. (Defined more in the `Document\nFeature Keys`_ section.) Unlike functional feature keys, which apply behavior\nto any map embedded anywhere in the document hierarchy, document feature keys\napply behavior to the entire document, and therefore must exist at the top of\nthe YAML document.\n\n\nChanging the Environment\n-------------------------\n\nYou can also use the `env`_ document key to place new variables into the\nenvironment.\n\n.. code-block:: yaml\n\n _env:\n COOLEST_PERSON: kyle\n\nThese variables can be used either in *the same document* (although the utility\nof that is not immediately obvious, other than for mitigating DRY violation)\nor, more importantly, *in documents that include it*. Yamlicious supports this\nby taking special care to re-run string substitution each time it changes a\ndocument's environment. (Remember, string substitution is idempotent.)\n\nThis behavior is somewhat dangerous if the included document defines a variable\nthat's already defined in the including document. If the including document\nuses string subtitution to define included document paths, those substitutions\ncan happen using only the *initial* version of the environment (before it is\nmutated by the act of inclusion). If the included document then changes any key\nthat's used in the process of inclusion, things get hard to reason about.\n\nRather than allow such craziness, Yamlicious bans it. That is, it does not\nallow multiple documents included in the same parent document to define\ndiffering versions of the same environment variable. It does allow actual\nenvironment variables to coexist with (and override) those defined in `env`_.\nNot allowing this would be brittle and would remove a very common use case,\nwhere setting an environment variable changes some sort of important behavior.\n\n\nThe Default Document\n---------------------\n\nYamlicious merge-overrides the configuration document it renders with a\n*default document* that it is configured to use.\n\nThis is the only place that, by default, uses the merge-override (rather than\nsafe merge) behavior. For that reason, it's best to use the default document\nfeature to specify override behavior. If you're wanting override behavior that\ncan't be done by using the default document, chances are you're doing something\nthat's either too complex or wrong. If you insist, there's always\n`merge_override`_.\n\n\nFunctional Conditional Keys\n---------------------------------\n\nTo specify a condition in-line, you can use the *functional conditional*\nfeature keys (`case`_ and `cond`_), each inspired by Lisp. This adds a bit too\nmuch Turing completeness to the project for the taste of most, so these are\ndisabled by default.\n\n.. code-block:: yaml\n\n case_configuration:\n '_case':\n - '$(USER)'\n - {'kyle': 'is awesome'}\n - {'_otherwise': 'is not awesome'}\n cond_configuration:\n '_cond':\n - {\"$(ENV) in ['test', 'prod']\": 'go!'}\n - {true: 'undefined'}\n\nNote the use of the python expression. This is mostly for convenience and\nterseness. Nobody wants to write a boolean expression in YAML, and I don't\nparticularly want to implement it, either, so Yamlicious ``eval()`` s every single\nstring that it finds below either functional conditional key.\n\n\nList substitution works in both kinds of functional conditional. For example,\nif ``GOOD_USERS=kyle,anthony``, then the following expression\n\n.. code-block:: yaml\n\n access_configuration:\n '_case':\n - {'$(GOOD_USERS)': 'go!'}\n - {'_otherwise': 'stay. :('}\n\nevaluates to\n\n.. code-block:: yaml\n\n access_configuration:\n '_case':\n - {'kyle': 'go!',\n 'anthony': 'go!'}\n - ['_otherwise', 'stay. :(']\n\nYamlicious is careful to \"do the right thing\" here. While there is no defined\norder in how it matches either the key ``'anthony'`` or ``'kyle'``, it will try\nto match both before falling back to the `otherwise`_ key.\n\nBe careful to not do something like this unless you really mean it:\n\n.. code-block:: yaml\n\n access_configuration:\n '_case':\n - {'$(GOOD_USERS)': '$(_KEY)'}\n - {'_otherwise': 'stay. :('}\n\nWhile it will technically work, Yamlicious offers no definition for what the\nabove expression evaluates to -- the order of iteration for a map/dictionary is\nan implementation detail.\n\n\nLazy Loading\n--------------\n\nIf you notice an explosion in the number of Yamlicious files that your program\nincludes, and you also notice that only a few of them ever get used, you'll\nlikely want to conditionally load said files only when they're needed. Yamlicious\nprovides two lazy loading keys to help you with this.\n\nThe `lazy`_ key changes nothing about the semantic meaning of the document it\npoints to. It does change the time when functional key evaluation happens.\nYamlicious evaluates embedded functional keys at *lookup time*, rather than\nduring the depth-first functional key evaluation of the entire document.\n\nIn this example\n\n.. code-block:: yaml\n\n _lazy:\n one:\n _insert: some/other/file.yaml\n\nThe `insert`_ evaluation happens only when someone tries to look at the\n``one`` key.\n\nThe `lazy_lookup`_ key delays functional key evaluation just like `lazy`_, and\nit also allows you to use string substitution of the special variable\n``$(_KEY)`` to define how every key in the document is looked up. Rather than\ndefining a document for *every key* in the map, you define *one expression*\nthat, after string subtitution, can evaluate to *any key*.\n\nTo get the most power, pair lazy lookup with file inclusion. Here's an example\ninspired by YAML configuration of SQL tables.\n\n.. code-block:: yaml\n\n tables:\n _lazy_lookup:\n _insert_merge:\n - generic/schema/$(_KEY).table.yaml\n - $(SYSTEM)/schema/$(_KEY).table.yaml\n - $(INSTITUTION)/schema/$(_KEY).table.yaml\n\nNote that there's nothing that prevents lazy-loaded documents from merging with\none another. If you're feeling particularly masochistic, you can define this\nconfusing yet equivalent thing.\n\n.. code-block:: yaml\n\n tables:\n _merge:\n - _lazy_lookup:\n _insert_merge:\n - generic/schema/$(_KEY).table.yaml\n - $(SYSTEM)/schema/$(_KEY).table.yaml\n - _lazy_lookup:\n _insert_merge:\n - $(INSTITUTION)/schema/$(_KEY).table.yaml\n\nOrder Of Operations\n====================\n\nYamlicious goes through the following phases when processing a document:\n\n1. String substitution.\n2. Document key evaluation.\n3. String substitution.\n4. Functional key evaluation (depth-first).\n\n\nFeature Key Definitions\n========================\n\nEnough with your words. Let's define this stuff explicitly.\n\nDocument Feature Keys\n------------------------\n\nThese keys must be placed at the *top* level of a document, and affect the\nentire document that they're placed inside. They disappear when rendered.\n\n\nenv \n````````````````````````````````\n\n.. code-block:: yaml\n\n _env:\n : \n ...\n\nSets document environment variables to given values.\n\ninclude\n`````````````````\n\n.. code-block:: yaml\n\n _include:\n - \n - \n - ...\n\nLoads and safe-merges several files into the document.\n\n\nFunctional Feature Keys\n------------------------\n\nThe key must exist by itself in its containing dictionary. The feature key,\nitself, describes a transformation operation on the given document. \n\n.. code-block:: yaml\n\n _: \n\n\n\ninsert\n````````````````````````````````\n\n.. code-block:: yaml\n\n _insert \n\nEvaluates to the loaded and processed configuration document found at\n``file_path``.\n\n\nmerge\n````````````````````````````````\n\n.. code-block:: yaml\n\n _merge: [ , , ... ]\n\nUses safe-merge-with-list-append to merge given documents together. Can safely\nmerge dictionaries and lists, but nothing else.\n\n\nmerge_override\n````````````````````````````````\n\n.. code-block:: yaml\n\n _merge_override: [ , , ... ]\n\nUses deep-merge to merge given documents together. Can safely merge anything.\nFor scalar values, documents further down the list override documents earlier\nin the list.\n\n\ninsert_merge\n````````````````````````````````\n\n.. code-block:: yaml\n\n _insert_merge [ , , ... ]\n\nLoads files and then merges them with safe-merge-with-list-append.\n\n\ncase\n````````````````````````````````\n(NOT IMPLEMENTED)\n\n.. code-block:: yaml\n\n '_case':\n - \n - {, }\n ...\n\nFunctional case. Evaluates to the first outcome expression whose match\nexpression is python-equal to the key expression.\n\n\notherwise\n````````````````````````````````\n(NOT IMPLEMENTED)\n\n.. code-block:: yaml\n\n '_otherwise': \n\nEvaluates to a case condition that always matches.\n\n\ncond\n````````````````````````````````\n(NOT IMPLEMENTED)\n\n.. code-block:: yaml\n\n '_cond':\n - {, }\n ...\n\nFunctional cond. Evaluates to the first outcome expression whose boolean\nexpression is true.\n\n\nlazy\n````````````````````````````````\n(NOT IMPLEMENTED)\n\n.. code-block:: yaml\n\n '_lazy': \n\nEvaluates to document, but where each of the keys in document is lazy-loaded.\n\n\nlazy_lookup\n````````````````````````````````\n(NOT IMPLEMENTED)\n\n.. code-block:: yaml\n\n '_lazy_lookup': \n\nEvaluates to a lazy-loaded dictionary, where every key is evaluated at lookup\ntime by evaluating the value-expression, which is allowed to use the ``_KEY``\nenvironment variable\n\n\nThe Validator\n==============\n\nTBD\n\nThe Command\n====================\n\nYamlicious comes with a convenient command, ``yamlicious``, that reads input\nfrom stdin and writes to stdout. It uses a default configuration, along with\nall environment variables, in order to process the yaml document fed to it on\nstandard in::\n\n [10:49:46][kderr@Kyles-MacBook-Pro][~/Repositories/derrley/yamlicious]\n $ cat /tmp/test\n Hello: \"$(PWD) is the current wd\"\n\n\n [10:49:52][kderr@Kyles-MacBook-Pro][~/Repositories/derrley/yamlicious]\n $ cat /tmp/test | yamlicious\n {Hello: /Users/kderr/Repositories/derrley/yamlicious is the current wd}\n\n\nThe API\n=================\n\nTBD\n\nCustom Feature Keys\n====================\n\nTBD\n", "description_content_type": null, "docs_url": null, "download_url": "UNKNOWN", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "UNKNOWN", "keywords": null, "license": "UNKNOWN", "maintainer": null, "maintainer_email": null, "name": "yamlicious", "package_url": "https://pypi.org/project/yamlicious/", "platform": "UNKNOWN", "project_url": "https://pypi.org/project/yamlicious/", "project_urls": { "Download": "UNKNOWN", "Homepage": "UNKNOWN" }, "release_url": "https://pypi.org/project/yamlicious/0.0.0/", "requires_dist": null, "requires_python": null, "summary": "UNKNOWN", "version": "0.0.0" }, "last_serial": 1356422, "releases": { "0.0.0": [ { "comment_text": "", "digests": { "md5": "3fca28c084c7ec03f521a1dd573506db", "sha256": "ec27e3f9f51d1de6bf22f2effa808838840ca0af68a20b2d62945ba2190cf588" }, "downloads": -1, "filename": "yamlicious-0.0.0.tar.gz", "has_sig": false, "md5_digest": "3fca28c084c7ec03f521a1dd573506db", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 14818, "upload_time": "2014-12-21T17:47:08", "url": "https://files.pythonhosted.org/packages/ea/20/06c01344462d823e9a46d8d0953a331d928f1481db19d6680c9a45c64356/yamlicious-0.0.0.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "3fca28c084c7ec03f521a1dd573506db", "sha256": "ec27e3f9f51d1de6bf22f2effa808838840ca0af68a20b2d62945ba2190cf588" }, "downloads": -1, "filename": "yamlicious-0.0.0.tar.gz", "has_sig": false, "md5_digest": "3fca28c084c7ec03f521a1dd573506db", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 14818, "upload_time": "2014-12-21T17:47:08", "url": "https://files.pythonhosted.org/packages/ea/20/06c01344462d823e9a46d8d0953a331d928f1481db19d6680c9a45c64356/yamlicious-0.0.0.tar.gz" } ] }