{ "info": { "author": "Joe Cross", "author_email": "joe.mcross@gmail.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 2 - Pre-Alpha", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.5", "Topic :: Software Development :: Libraries" ], "description": ".. image:: https://img.shields.io/travis/numberoverzero/texas/master.svg?style=flat-square\n :target: https://travis-ci.org/numberoverzero/texas\n.. image:: https://img.shields.io/coveralls/numberoverzero/texas/master.svg?style=flat-square\n :target: https://coveralls.io/github/numberoverzero/texas\n.. image:: https://img.shields.io/pypi/v/texas.svg?style=flat-square\n :target: https://pypi.python.org/pypi/texas\n.. image:: https://img.shields.io/github/issues-raw/numberoverzero/texas.svg?style=flat-square\n :target: https://github.com/numberoverzero/texas/issues\n.. image:: https://img.shields.io/pypi/l/texas.svg?style=flat-square\n :target: https://github.com/numberoverzero/texas/blob/master/LICENSE\n\nPure python. Path keys. ChainedMap on steroids.\n\nInstallation\n============\n\n::\n\n pip install texas\n\nQuick Start\n===========\n\n::\n\n import texas\n\n context = texas.Context()\n\n environment = context.include(\"environment\")\n cli = context.include(\"cli\")\n\n config = context.include(\"environment\", \"cli\")\n\n environment[\"src.root\"] = \"~/pics\"\n cli[\"src.type\"] = \"jpg\"\n\n config[\"src.root\"] # ~/pics\n config[\"src.type\"] # jpg\n\n # Change cli's root\n cli[\"src.root\"] = \"~/other\"\n\n # Doesn't change the underlying environment root\n environment[\"src.root\"] # ~/pics\n\n # Modifies cli, which is the top context in config\n del config[\"src.root\"]\n config[\"src.root\"] # ~/pics\n\n # Snapshot the contexts into a single dict for use in modules that\n # typecheck against dict (instead of collections.abc.Mapping)\n import pprint\n pprint.pprint(config.snapshot)\n # {\n # \"src\": {\n # \"root\": \"~/pics\",\n # \"type\": \"jpg\"\n # }\n # }\n\nUsage\n=====\n\nContexts are namespaced python dictionaries with (configurable) path lookups::\n\n import texas\n\n context = texas.Context()\n # Single context\n root = context.include(\"root\")\n\n # normal dictionary operations\n root[\"foo\"] = \"bar\"\n assert \"bar\" == root[\"foo\"]\n del root[\"foo\"]\n\n # paths\n root[\"foo.bar\"] = \"baz\"\n assert \"baz\" == root[\"foo.bar\"]\n del root[\"foo.bar\"]\n\nInclude\n-------\n\nInclude takes a variable number of context names to load into a view::\n\n bottom = context.include(\"bottom\")\n top = context.include(\"top\")\n\n both = context.include(\"bottom\", \"top\")\n\nThis can be used to create a priority when looking up values. The top of the\ncontext stack will be checked for a key first, then the next, until a context\nwith the given key is found::\n\n bottom[\"key\"] = \"bottom\"\n assert both[\"key\"] == \"bottom\"\n\n top[\"key\"] = \"top\"\n assert both[\"key\"] == \"top\"\n\nCombined with paths, this can be very powerful for configuration management::\n\n context = texas.Context()\n env = context.include(\"env\")\n cli = context.include(\"cli\")\n config = context.include(\"env\", \"cli\")\n\n env[\"src.root\"] = \"~/pics\"\n cli[\"src.type\"] = \"jpg\"\n\n assert config[\"src.root\"] == \"~/pics\"\n assert config[\"src.type\"] == \"jpg\"\n\nThis even works with individual path segments, since ContextView returns\nproxies against the underlying mapping objects::\n\n config[\"src\"] # \n config[\"src\"][\"type\"] # \"jpg\"\n\nSetting values only applies to the top context in the view, so the value in\nbottom is still the same::\n\n assert bottom[\"key\"] == \"bottom\"\n\nThis breaks down with mutable values - for instance, this will modify the list\nin the bottom context:\n\n context = texas.Context()\n bottom = context.include(\"bottom\")\n top = context.include(\"top\")\n both = context.include(\"bottom\", \"top\")\n\n bottom[\"list\"] = []\n top[\"list\"].append(\"modified!\")\n\n assert bottom[\"list\"] == [\"modified!\"]\n\nSnapshot\n--------\n\nContext does some heavy lifting to make paths and multiple dicts work together\ncomfortably. Unfortunately, some libraries make ``isinstance`` checks against\n``dict``, and not ``collections.abc.Mapping``.\n\nThis is also useful when passing a ContextView to code that will perform many\nlookups in a tight loop. Because an intermediate lookup on a deeply nested\nset of dicts creates one proxy per level (ie.\n``something[\"foo\"][\"bar\"][\"baz\"]`` creates two proxies for the value\n``something[\"foo.bar.baz\"] = \"blah\"``) it can be a significant speedup to\n\"snapshot\" or bake the ContextView for much faster reading.\n\nMerging dicts in general is a complex problem at best, with many ambiguities.\nTo simplify things, the following rules are used::\n\n (1) For every key in each context, the top-most[0] context that contains\n that key will determine if the value will be used directly, or merged\n with other contexts.\n (2) If that value is a collections.abc.Mapping, the value of that key in\n each context that contains that key will be merged.\n (A) If there is a context with that key whose value is NOT a mapping,\n its value will be ignored.\n (B) If that value is NOT a collections.abc.Mapping, the value will be\n used directly and no merging occurs[1].\n 3) These rules are applied recursively[2] for any nested mappings.\n\nThe \"top-most context that contains that key\" is not always the top context.\nIn the following, the bottom context is the only one that contains the key\n\"bottom\"::\n\n {\n \"bottom\": \"bottom-value\"\n },\n {\n \"top\": \"top-value\"\n }\n\n Snapshot:\n\n {\n \"bottom\": \"bottom-value\",\n \"top\": \"top-value\"\n }\n\nWhen there is a conflict in type (mapping, non-mapping) the top-most context\ndetermines the type. For example, this will take the mapping values from\nbottom and top, but not middle (whose value is not a mapping)::\n\n {\n \"key\": {\n \"bottom\": \"bottom-value\"\n }\n },\n {\n \"key\": [\"middle\", \"non\", \"mapping\"]\n },\n {\n \"key\": {\n \"top\": \"top-value\"\n }\n }\n\n Snapshot:\n\n {\n \"key\": {\n \"bottom\": \"bottom-value\",\n \"top\": \"top-value\"\n }\n }\n\nWhile snapshot applies its rules recursively to mappings, the implementation is\nnot recursive. A sample file that merges arbitrary iterables of mappings using\nthe same rules as texas is available\n`here `_.\n\nContext Factory\n---------------\n\nBy default, texas uses simple ``dict``s for storage. However, this can be\ncustomized with the ``context_factory`` function, such as using a\n``collections.OrderedDict`` or pre-loading values into the node.\n\nThis function is used when creating snapshots, the context root, new contexts,\nand intermediate segments when setting values by paths.\n\n::\n\n created = 0\n\n def factory():\n global created\n created += 1\n return dict()\n\n # Root context container\n context = texas.Context(context_factory=factory)\n assert created == 1\n\n # Including contexts\n ctx = context.include(\"some-context\")\n assert created == 2\n\n # Segments along a path when setting values\n ctx[\"foo.bar\"] = \"value\"\n assert created == 3\n\nInternals\n---------\n\nInternally, all data is stored in python dicts. You can inspect the global\nstate of a context through its ``contexts`` attribute::\n\n import texas\n context = texas.Context()\n\n context.include(\"root.something.or.foo\")\n context.include(\"bar\", \"and.yet.another.foo\", \"finally\")\n\n print(context._contexts)\n\nPath traversal is performed by the ``traverse`` function, which only handles\ntraversal of ``collestions.abc.Mapping``. Therefore, when a non-mapping value\nis expected at the end of a path, the path should be split like so::\n\n full_path = \"foo.bar.baz\"\n path, last = full_path.rsplit(\".\", 1)\n\n assert path == \"foo.bar\"\n assert last = \"baz\"\n\nThis allows us to travers a root and create the intermediate ``foo`` and\n``bar`` dicts without modifying or inspecting ``baz``::\n\n from texas.traversal import traverse, create_on_missing\n\n root = dict()\n full_path = \"foo.bar.baz\"\n path, key = full_path.rsplit(\".\", 1)\n\n node = traverse(root, path, \".\", create_on_missing(dict))\n node[key] = \"value\"\n\n assert root[\"foo\"][\"bar\"][\"baz\"] == \"value\"", "description_content_type": null, "docs_url": null, "download_url": "UNKNOWN", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/numberoverzero/texas", "keywords": "dict nested context", "license": "MIT", "maintainer": null, "maintainer_email": null, "name": "texas", "package_url": "https://pypi.org/project/texas/", "platform": "any", "project_url": "https://pypi.org/project/texas/", "project_urls": { "Download": "UNKNOWN", "Homepage": "https://github.com/numberoverzero/texas" }, "release_url": "https://pypi.org/project/texas/0.5.2/", "requires_dist": null, "requires_python": null, "summary": "nested dictionaries with paths", "version": "0.5.2" }, "last_serial": 1973420, "releases": { "0.1": [ { "comment_text": "", "digests": { "md5": "da7281c5a5aa5b2383bafd965eba3bf1", "sha256": "dcfd7562124616bcf5e51fbb08b62c06252a084042d105eee10b079cbfa3e61c" }, "downloads": -1, "filename": "texas-0.1.tar.gz", "has_sig": false, "md5_digest": "da7281c5a5aa5b2383bafd965eba3bf1", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 4004, "upload_time": "2016-02-18T10:58:36", "url": "https://files.pythonhosted.org/packages/3c/f2/ff91616cd0d1a7323f1cac80082f99ba4a6ccff867e95892141c83308355/texas-0.1.tar.gz" } ], "0.1.2": [ { "comment_text": "", "digests": { "md5": "05d7aaacc3566d7347c93e361084e86e", "sha256": "0f430254d923c14dd25f5e5b8e3d0ed1677ceb12a382d84b2cf599400d4783d3" }, "downloads": -1, "filename": "texas-0.1.2.tar.gz", "has_sig": false, "md5_digest": "05d7aaacc3566d7347c93e361084e86e", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 4082, "upload_time": "2016-02-18T11:05:57", "url": "https://files.pythonhosted.org/packages/a7/9c/f7e1e592ed780f41ac5d3d228856cfcb3c8b25ae57a74506473e1c3c4005/texas-0.1.2.tar.gz" } ], "0.2": [ { "comment_text": "", "digests": { "md5": "b4d7c72b2374bf4f077f1b94dc7e74e4", "sha256": "d6f83c48f4776819d1dc8e15af76ffa7a26771c2a89d1575a8ba5262ab054b86" }, "downloads": -1, "filename": "texas-0.2.tar.gz", "has_sig": false, "md5_digest": "b4d7c72b2374bf4f077f1b94dc7e74e4", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5597, "upload_time": "2016-02-21T06:45:00", "url": "https://files.pythonhosted.org/packages/38/ef/53e1ef9055c344cbb97c4be66c91b82047d4a4430d434dbcb1b41e3d203f/texas-0.2.tar.gz" } ], "0.2.1": [ { "comment_text": "", "digests": { "md5": "e22a1a6b0efc0f1206c075f7809f4ae3", "sha256": "b311f989dbc2b9acbaf2ba6a5c704d957a689632119bc9f61ee21d95299cf83e" }, "downloads": -1, "filename": "texas-0.2.1.tar.gz", "has_sig": false, "md5_digest": "e22a1a6b0efc0f1206c075f7809f4ae3", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5626, "upload_time": "2016-02-21T07:23:55", "url": "https://files.pythonhosted.org/packages/f4/b4/2f75c1b04154bdb5c55eada5c045c47a47e5f51e841ef0fa54e775ebbbd7/texas-0.2.1.tar.gz" } ], "0.3.0": [ { "comment_text": "", "digests": { "md5": "749f9c4c6ff949f1b1636733be78578c", "sha256": "f99df0e49d04c2ef2dc8d2fd2e4bd5bf713d73f4f58c6d37bdd41af672d4d2b6" }, "downloads": -1, "filename": "texas-0.3.0.tar.gz", "has_sig": false, "md5_digest": "749f9c4c6ff949f1b1636733be78578c", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 8408, "upload_time": "2016-02-21T12:55:43", "url": "https://files.pythonhosted.org/packages/4b/c3/9ab9108780f4386de2abf20737ba9b62cd0772bfc99a18a7b8518835f70b/texas-0.3.0.tar.gz" } ], "0.4.0": [ { "comment_text": "", "digests": { "md5": "478e0b52e8f499fe4eb552ef65017c22", "sha256": "af95fda23c61a602c13ca08c6b3bf59d39c70945b0b2bb4adcfe62d33e522e07" }, "downloads": -1, "filename": "texas-0.4.0.tar.gz", "has_sig": false, "md5_digest": "478e0b52e8f499fe4eb552ef65017c22", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 7679, "upload_time": "2016-02-22T04:20:41", "url": "https://files.pythonhosted.org/packages/80/18/95b1eb2b0fd6ca3518d77079dbcf358041551ba900d9893151baf32cb3c5/texas-0.4.0.tar.gz" } ], "0.5.0": [ { "comment_text": "", "digests": { "md5": "082c4ba00027ffdc8dd5526eba76915f", "sha256": "0252ea0141261554750aaf9cb07cfe22e71492a3d1ea44c5b3dbe5bdc1bd416f" }, "downloads": -1, "filename": "texas-0.5.0.tar.gz", "has_sig": false, "md5_digest": "082c4ba00027ffdc8dd5526eba76915f", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6952, "upload_time": "2016-02-22T09:49:16", "url": "https://files.pythonhosted.org/packages/4a/25/68dad24b668860e64ee7763fbc012002d332d6be754254fe2057ae119440/texas-0.5.0.tar.gz" } ], "0.5.1": [ { "comment_text": "", "digests": { "md5": "34470a80ad9c3f74bace508fc6fda8e1", "sha256": "9a844d9a99007b800a237b8759777b3c69a0a290b71be50e39b891d0944929fc" }, "downloads": -1, "filename": "texas-0.5.1.tar.gz", "has_sig": false, "md5_digest": "34470a80ad9c3f74bace508fc6fda8e1", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6960, "upload_time": "2016-02-22T11:00:55", "url": "https://files.pythonhosted.org/packages/85/4e/2bcbe1d79fd62a9768fd7f0f3bebf67de613965dfae4903b85a91902d68b/texas-0.5.1.tar.gz" } ], "0.5.2": [ { "comment_text": "", "digests": { "md5": "4c69556406cc3f98f375a7134695c1e4", "sha256": "7de9bc99972e57896ea40e755f6a0bb847bcf6e427dfb16582757d18ccd28adc" }, "downloads": -1, "filename": "texas-0.5.2.tar.gz", "has_sig": false, "md5_digest": "4c69556406cc3f98f375a7134695c1e4", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 7348, "upload_time": "2016-02-24T07:08:33", "url": "https://files.pythonhosted.org/packages/2a/b3/85c1a57990b1b46e47456dcb48026d0df14c1736901eac43570eec5249fd/texas-0.5.2.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "4c69556406cc3f98f375a7134695c1e4", "sha256": "7de9bc99972e57896ea40e755f6a0bb847bcf6e427dfb16582757d18ccd28adc" }, "downloads": -1, "filename": "texas-0.5.2.tar.gz", "has_sig": false, "md5_digest": "4c69556406cc3f98f375a7134695c1e4", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 7348, "upload_time": "2016-02-24T07:08:33", "url": "https://files.pythonhosted.org/packages/2a/b3/85c1a57990b1b46e47456dcb48026d0df14c1736901eac43570eec5249fd/texas-0.5.2.tar.gz" } ] }