{ "info": { "author": "DramaFever", "author_email": "admin@dramafever.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 1 - Planning", "Intended Audience :: Developers", "License :: Other/Proprietary License", "Natural Language :: English", "Operating System :: OS Independent", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.4" ], "description": "Calcifer\n========\n\n|Docs| |Version| |Status| |License|\n\n**Calcifer** is designed to provide interfaces for describing the evaluation\nand processing of nested higher-order data structures by nested definitions of\npolicy rules.\n\nPolicies may be used to evaluate some source object both for validation, and to\ngenerate template descriptions of a \"complete\" version of that object. This\nevaluation is done at runtime and can hook into arbitrary functions, e.g.\nfor choosing policies based on some current system state. (Hypermedia style)\n\nPolicies may be defined with implicit non-determinism, allowing the\nspecification of multiple policy choices with minimal boilerplate for handling\nthe aggregation of results. (Prolog style)\n\nCalcifer also provides a system by which application-layer code can annotate\nspecific policy rules, making the point-in-time context of a policy computation\ninto a first-class value. This allows for rich error handling, by being aware\nof specific points of policy failure and allowing annotated policy rules\nto control the formatting of their own errors.\n\nThis library was written to facilitate the development of a hypermedia\nsubscription management API. This library's design is informed by that API's\ngoals of business logic cohesion and adaptability to changing policy rules.\nA major goal for that project has been to alleviate client integrations of\ntheir need to perform any policy determination locally; Calcifer has stemmed\nlargely from this effort.\n\n\nInstallation\n------------\n\n::\n\n pip install calcifer\n\n\nDevelopment\n-----------\n\n1. Create a new virtual environment\n2. Install development requirements from *dev-requirements.txt*\n3. Run tests ``nosetests``\n4. `detox`_ is installed and will run the test suite across all supported python platforms\n5. `python setup.py build_sphinx` will generate documentation into *build/sphinx/html*\n\n\nTL;DR\n+++++\n\n::\n\n $ virtualenv env\n $ ./env/bin/pip install -qr dev-requirements.txt\n $ source env/bin/activate\n (env) $ nosetests\n (env) $ python setup.py build_sphinx\n (env) $ detox\n\n\n.. include:: ../HISTORY.rst\n\n\nTest-case Usage Examples\n------------------------\n\n.. code-block:: python\n\n # from tests/test_contexts.py\n\n def test_apply_alchemy(self):\n # for our test today, we will be doing some basic alchemy\n inventory = [\n \"aqua fortis\",\n \"glauber's salt\",\n \"lunar caustic\",\n \"mosaic gold\",\n \"plumbago\",\n \"salt\",\n \"tin salt\",\n \"butter of tin\",\n \"stibnite\",\n \"naples yellow\",\n ]\n\n # backstory:\n # ~~~~~~~~~~\n #\n # falling asleep last night, you finally figured out how to complete\n # your life's work: discovering the elusive *elixir of life*!\n #\n # and it's only two ingredients! and you have them on hand!\n #\n # ...\n #\n # unfortunately this morning you can't remember which two\n # ingredients it was.\n #\n # you'll know it once you've gotten it, just have to try out\n # all possible mixtures. (should be safe enough, right?)\n\n forgotten_elixir_of_life = set(random.sample(inventory, 2))\n\n discoveries_today = set([\"frantic worry\", \"breakfast\"])\n\n # ok time to go do some arbitrary alchemy!\n #\n # game plan:\n alchemy_ctx = Context()\n\n # you'll grab one ingredient,\n selected_first_ctx = alchemy_ctx.select(\"/inventory\").each()\n first_substance = selected_first_ctx.value\n\n # and another,\n selected_second_ctx = selected_first_ctx.select(\"/inventory\").each()\n second_substance = selected_second_ctx.value\n\n # take them to your advanced scientific mixing equipment,\n workstation_ctx = selected_second_ctx.select(\"/workstation\")\n\n # (btw this is your advanced scientific procedure that you are\n # 100% certain will tell you what some mixture is)\n def mix(first, second):\n \"\"\"takes two ingredients and returns the resulting substance\"\"\"\n if set([first, second]) == forgotten_elixir_of_life:\n return \"elixir of life\"\n return \"some kind of brown goo\"\n\n # then you'll mix your ingredients...\n mixed_ctx = workstation_ctx.apply(\n mix,\n first_substance, second_substance\n )\n resulting_mixture = mixed_ctx.value\n\n # ... and! in today's modern age, scientists now know to record their\n # results!\n mixed_ctx.select(\"/discoveries\").append_value(resulting_mixture)\n\n # got it? good!\n result = run_policy(\n alchemy_ctx.finalize(),\n {\"inventory\": inventory, \"discoveries\": discoveries_today}\n )\n\n # in a flurry of excitement, i bet you didn't even stop to\n # look at your discoveries as you made them!\n #\n # well, let's see...\n\n self.assertIn(\"elixir of life\", result[\"discoveries\"])\n\n def test_apply_dangerous_alchemy(self):\n # nice job! and you even finished in time to go foraging for\n # more ingredients!\n inventory = [\n \"aqua fortis\",\n \"glauber's salt\",\n \"lunar caustic\",\n \"mosaic gold\",\n \"plumbago\",\n \"salt\",\n \"tin salt\",\n \"butter of tin\",\n \"stibnite\",\n \"naples yellow\",\n\n # nice find\n \"anti-plumbago\"\n ]\n\n # but unfortunately, it's the next day, and the same thing\n # has happened to you! except this time it was for your\n # other life's goal: discover the ~elixir of discord~!\n #\n # well, since it was so easy...\n\n whatever_concoction = set(['some ingredients'])\n\n discoveries_today = set([])\n should_be_fine = 'overconfidence' not in discoveries_today\n assert should_be_fine\n\n # doing alchemy la la la\n alchemy_ctx = Context()\n\n # grabbin' things off shelves\n selected_first_ctx = alchemy_ctx.select(\"/inventory\").each()\n first_substance = selected_first_ctx.value\n\n selected_second_ctx = selected_first_ctx.select(\"/inventory\").each()\n second_substance = selected_second_ctx.value\n\n # got our ingredients\n got_ingredients_ctx = selected_second_ctx\n\n workstation_ctx = got_ingredients_ctx.select(\"/workstation\")\n\n # mixin' - don't stop to think\n def mix(first, second):\n mixture = set([first, second])\n if mixture == whatever_concoction:\n return 'missing elixir'\n if mixture == set(['plumbago', 'anti-plumbago']):\n return 'concentrated danger'\n return 'more brown goo'\n\n mixed_ctx = workstation_ctx.apply(\n mix,\n first_substance, second_substance\n )\n resulting_mixture = mixed_ctx.value\n\n mixed_ctx.select(\"/discoveries\").append_value(resulting_mixture)\n\n # wait wait wait!!\n def danger(mixture):\n if mixture == 'concentrated danger':\n return True\n return False\n\n # we can't have that.\n danger_ctx = mixed_ctx.check(\n danger,\n resulting_mixture\n )\n danger_ctx.forbid()\n\n # moral:\n #\n # a strong understanding of policies and processes facilitates a\n # hazard-free lab environment.\n result = run_policy(\n alchemy_ctx.finalize(),\n {\"inventory\": inventory, \"discoveries\": discoveries_today}\n )\n\n self.assertIn(\"errors\", result)\n self.assertTrue(len(result['errors']))\n\n\n\nLicense\n-------\n\n`The Calcifer library is distributed under the MIT License `_\n\n\n.. _detox: https://testrun.org/tox/\n\n.. |Docs| image:: https://readthedocs.org/projects/calcifer/badge/?version=latest\n :alt: Documentation Status\n :scale: 100%\n :target: https://calcifer.readthedocs.io/en/latest/?badge=latest\n\n.. |Version| image:: https://img.shields.io/pypi/v/calcifer.svg?maxAge=86400\n :target: https://pypi.python.org/pypi/calcifer\n\n.. |Status| image:: https://travis-ci.org/DramaFever/calcifer.svg?branch=master\n :target: https://travis-ci.org/DramaFever/calcifer\n\n.. |License| image:: https://img.shields.io/badge/license-MIT-blue.svg\n :target: https://raw.githubusercontent.com/DramaFever/calcifer/master/LICENSE", "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/DramaFever/calcifer", "keywords": null, "license": "UNKNOWN", "maintainer": null, "maintainer_email": null, "name": "calcifer", "package_url": "https://pypi.org/project/calcifer/", "platform": "UNKNOWN", "project_url": "https://pypi.org/project/calcifer/", "project_urls": { "Download": "UNKNOWN", "Homepage": "https://github.com/DramaFever/calcifer" }, "release_url": "https://pypi.org/project/calcifer/0.3.0/", "requires_dist": null, "requires_python": null, "summary": "A Python based policy framework.", "version": "0.3.0" }, "last_serial": 2843386, "releases": { "0.0.0": [ { "comment_text": "", "digests": { "md5": "42e37b44b47defed66edcded07bf719b", "sha256": "4e441e5c0391c82c39118881aa7894b8f9f623592546dcec125c9e27ef446e90" }, "downloads": -1, "filename": "calcifer-0.0.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "42e37b44b47defed66edcded07bf719b", "packagetype": "bdist_wheel", "python_version": "2.7", "requires_python": null, "size": 24553, "upload_time": "2016-06-21T17:24:29", "url": "https://files.pythonhosted.org/packages/b7/f0/f47b138ab0ffd07bb8319e3d6227b7f441c72fbf6758d891dee724644854/calcifer-0.0.0-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "cd47b53e156b30cb16c2e71c1cf619e0", "sha256": "532a7280d6959a4f4eb9ed5849c810285bce7a60b5f9f5e547ebe726de93b425" }, "downloads": -1, "filename": "calcifer-0.0.0.tar.gz", "has_sig": false, "md5_digest": "cd47b53e156b30cb16c2e71c1cf619e0", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 26838, "upload_time": "2016-06-21T17:25:00", "url": "https://files.pythonhosted.org/packages/5a/5d/9317b7a699a2589ad8bb456efb9ef6ffecc0109d685cb90f03ccb3b8daca/calcifer-0.0.0.tar.gz" } ], "0.1.0": [ { "comment_text": "", "digests": { "md5": "9c077b5d4c31f3bbecf13f8976b973d1", "sha256": "e3c6b1c6614c2926df5f44e21330e73ef8afbf167637c230947ec7e9f77617ed" }, "downloads": -1, "filename": "calcifer-0.1.0.tar.gz", "has_sig": false, "md5_digest": "9c077b5d4c31f3bbecf13f8976b973d1", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 35550, "upload_time": "2016-08-21T21:58:33", "url": "https://files.pythonhosted.org/packages/99/c3/843f752dc534c73ee868887a5c18193488cdaa214b5dd614d44d7b040250/calcifer-0.1.0.tar.gz" } ], "0.2.0": [ { "comment_text": "", "digests": { "md5": "951940806a98c2b795ea3c2d3abdcff3", "sha256": "b9f47d55ddf45815d03ba8489f2e75ead724970bd86395199a084ff6c09fb2a4" }, "downloads": -1, "filename": "calcifer-0.2.0.tar.gz", "has_sig": false, "md5_digest": "951940806a98c2b795ea3c2d3abdcff3", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 35467, "upload_time": "2016-11-07T18:51:42", "url": "https://files.pythonhosted.org/packages/3e/44/a75e33f1ca9a16c568b7a98dcb81aff195a1f6ebb59c3e819d1384688ea4/calcifer-0.2.0.tar.gz" } ], "0.2.1": [ { "comment_text": "", "digests": { "md5": "3ef05b1bfa5a1163ecb15d1782140ecb", "sha256": "5a6cf76357727f5537df1844fd6f16b8cf21457961d5fe92387b545fe27a2deb" }, "downloads": -1, "filename": "calcifer-0.2.1.tar.gz", "has_sig": false, "md5_digest": "3ef05b1bfa5a1163ecb15d1782140ecb", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 35772, "upload_time": "2016-11-10T16:50:51", "url": "https://files.pythonhosted.org/packages/6f/3f/9cd39123e7409e4e16aabdcfae0dc0de4c8a1e718a114c45c337492632e2/calcifer-0.2.1.tar.gz" } ], "0.3.0": [ { "comment_text": "", "digests": { "md5": "968c200cb9e657d93c0811aea658e91a", "sha256": "48c2eae22ef08e8b983a878c3382068172ed0561da75c6c55909c40fe30d7fda" }, "downloads": -1, "filename": "calcifer-0.3.0.tar.gz", "has_sig": false, "md5_digest": "968c200cb9e657d93c0811aea658e91a", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 36947, "upload_time": "2017-05-01T21:40:01", "url": "https://files.pythonhosted.org/packages/1e/d9/ca2161959b3faae60150257938a9b0b32e089ff5862f0213921ad3f0fa2a/calcifer-0.3.0.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "968c200cb9e657d93c0811aea658e91a", "sha256": "48c2eae22ef08e8b983a878c3382068172ed0561da75c6c55909c40fe30d7fda" }, "downloads": -1, "filename": "calcifer-0.3.0.tar.gz", "has_sig": false, "md5_digest": "968c200cb9e657d93c0811aea658e91a", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 36947, "upload_time": "2017-05-01T21:40:01", "url": "https://files.pythonhosted.org/packages/1e/d9/ca2161959b3faae60150257938a9b0b32e089ff5862f0213921ad3f0fa2a/calcifer-0.3.0.tar.gz" } ] }