{ "info": { "author": "flashashen", "author_email": "flashashen@gmail.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 3 - Alpha", "Environment :: Console", "License :: OSI Approved :: MIT License", "Operating System :: MacOS", "Operating System :: POSIX :: Linux", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3.6", "Topic :: Software Development" ], "description": "# Flange \n\n![CircleCI](https://circleci.com/gh/flashashen/flange.svg?style=svg)\n[![PyPI version](https://badge.fury.io/py/flange.svg)](https://badge.fury.io/py/flange)\n![Python versions](https://img.shields.io/pypi/pyversions/flange.svg)\n![MIT License](https://img.shields.io/github/license/flashashen/flange.svg)\n\n\n---------------------------------------------------------\n\nConvenient configuration search and load with a model based object registry. \n\n*With bits of config you may already have lying around..*\n``` yaml\n\n # somewhere in a config file ..\n my_logger:\n name: myapp\n level: DEBUG\n format: \"%(asctime)s:%(levelname)s:%(name)s %(message)s\"\n\n\n # somewhere in a different config file ..\n my_mssql_db:\n driver: mssql+pymssql\n name: dbname\n user: devuser\n pass: devpass\n host: dbhost.dev.corp\n port: '1111'\n desc: dev db\n args: {'login_timeout':6}\n\n\n # from env vars\n export my_mssql_db__pass=devpass\n```\n\n*you can do this..*\n\n```\nsh> python -c \"from flange import cfg, dbengine; result = cfg.mget('my_mssql_db').execute('USE master SELECT @@version').first()[0]; cfg.mget('my_logger').debug(result)\"\n2018-03-09 15:49:55,726:DEBUG:myapp Microsoft SQL Server 2008 (SP4) - 10.0.6000.29 (X64) \n\tSep 3 2014 04:11:34 \n\tCopyright (c) 1988-2008 Microsoft Corporation\n\tEnterprise Edition (64-bit) on Windows NT 6.1 (Build 7601: Service Pack 1) (VM)\n```\n\n**You want this if**:\n\n- You're tired of boilerplate configuration code in your python projects\n- You're tired of boilerplate logger setup in your python projects\n- You're tired of boilerplate data access setup in your python projects\n- You're tired of boilerplate *{{fill in the blank}}* setup in your python projects\n- you want to hack in the python console and don't remember where you put all your bits \nof config and credentials\n- You want to keep passwords separate from main config\n\n\n## What it does\n\n- Automatically searches for and loads (configuration) data in various formats using Anyconfig\n- Merges configuration from various sources using Anyconfig\n- Pluggable, automatic object detection/creation from config data\n- Object registry with lazy init and cache\n- Convenient object access\n- Uses [dpath](https://github.com/akesterson/dpath-python) for matching keys in the config/data \n\nThis is partially inspired by the Spring framework. On init, the main configuration object \nwill search for a given set of file pattern at a given directory to a given depth for config \ndata and will merge this data into a single configuration object.\n\nAdditionally, an object registry is provided that can recognize patterns in the config data\nand return cached instances on demand of any type of object. Object initialization is automatic and lazy.\nRecognition of instances currently employs json schema \nto identify patterns and a python function is provided that serves as the factory function. \nThe factory method can be given explicity in python or specified as url that resolves to a \npython function. The combination of a schema and a factory function along with a name are \ncalled a 'model'. \n\n\n## Usage\n\n##### Model - Logger\n\nThis shows access to a logger object which is a built-in model of flange. The built-in logger json-schema looks like this:\n\n```\n{\n \"type\" : \"object\",\n \"properties\" : {\n 'name':{'type':'string'},\n 'level': { \"enum\": ['CRITICAL', 'ERROR', 'WARNING', 'INFO', 'DEBUG']},\n 'format':{'type':'string'},\n },\n \"required\": [\"name\", \"level\"]\n}\n```\n\nthe config looks like this (can appear anywhere in your config files):\n\n```\n{\n..\n my_logger:\n name: myapp\n level: DEBUG\n format: \"%(asctime)s:%(levelname)s %(message)s\"\n}\n```\n\nthe object is accessed with the obj(..) method given a [dpath](https://github.com/akesterson/dpath-python) expression like this:\n\n```\nIn [1]: from flange import cfg\n\nIn [2]: log = cfg.obj('**/my_logger')\n\nIn [3]: log.debug('hello')\n2018-03-09 14:08:17,261:DEBUG:myapp hello\n```\n\nif the key in the configuration is not known, then the instance can be fetched\nwith just the model name *(provided there is only one instance)*:\n\n```\nIn [4]: cfg.obj(model='logger').debug('hello')\n2018-03-09 14:43:07,514:DEBUG:myapp hello\n``` \n\n.. or just by specifying a value in the instance config with 'values' parameter:\n\n```\nIn [5]: cfg.obj(values='myapp').debug('hello')\n2018-03-09 14:42:50,785:DEBUG:myapp hello\n```\n\n.. or by specifying multiple values in the instance config with 'values' parameter:\n\n```\nIn [6]: cfg.obj(values=['myapp','DEBUG']).debug('hello')\n2018-03-09 14:51:36,742:DEBUG:myapp hello\n```\n\nAny combination of key, model, and values terms can be given to select a \nunique instance with the mget(..) method.\n\n\nthe raw config can also be accessed with the value(..) method:\n\n```\nIn [7]: cfg.value('**/my_logger')\nOut[7]: \n{'name', 'dshlog',\n 'level', 'DEBUG'),\n 'format', '%(asctime)s:%(levelname)s %(message)s'}\n```\n\nthe file that contained the config can be found with the src(..) or uri(...) methods. \nThe first returns a source that contains the contents, uri, and other information. \nThe latter simple returns the uri of the config/data resource'\n```\nIn [8]: cfg.src('**/my_logger')\nOut[8]: \n\nIn [9]: cfg.uri('**/my_logger')\nOut[9]: '/Users/panelson/.cmd.yml'\n\n```\n\n*Note: All of the access methods have versions with the same parameters that return multiple values.*\n- obj, objs\n- value, values\n- src, srcs\n- uri, uris\n\nThere is also a search*(...) method that is similar to the values(...) method \nexcept that search(...) returns key,value pairs.\n```\nIn [10]: cfg.search('**/my_logger')\nOut[10]: \n[(('vars', 'my_logger'),\n OrderedDict([('name', 'myapp'),\n ('level', 'DEBUG'),\n ('format',\n '%(asctime)s:%(levelname)s:%(name)s %(message)s')]))]```\n\n\n##### Model - dbengine / sqlalchemy \n\nThis is another example with the default settings. The loaded data is described\nwith the info() method. The the dbengine module is imported which automatically registers \nan sqlalchemy based model and searches for any configuration that is a valid/sufficient for a \nsqlalchemy engine. Note: sqlalchemy is an example built-in model. Any sort of model can be \nregistered. **Note that after the import of dbengine module, the 'dbengine' model and it's instances\nappear in the output.**\n\n```\nIn [2]: from flange import cfg\n\nIn [3]: cfg.info()\n\nmodels:\nlogger instances: logger\n\nbase dir: \t.\nsearch depth: \t1\nfile include patterns: \t['*.yml', '*cfg', '*settings', '*config', '*properties', '*props']\nfile exclude patterns: \t['*.tar', '*.jar', '*.zip', '*.gz', '*.swp', 'node_modules', 'target', '.idea', '*.hide', '*save']\n\nsources:\nNone os_env\nshellvars /Users/myuser/.gitconfig\nyml /Users/myuser/config_example.yml\nyml /Users/myuser/.cmd.yml\nshellvars /Users/myuser/.ansible.cfg\nyml /Users/myuser/.flangetest.yml\nshellvars /Users/myuser/.bundle/config\nshellvars /Users/myuser/.git/config\nyml /Users/myuser/.nyttth/config.yml\nshellvars /Users/myuser/.plotly/.config\nshellvars /Users/myuser/.ScreamingFrogSEOSpider/spider.config\nshellvars /Users/myuser/.ssh/config\nshellvars /Users/myuser/.subversion/config\nshellvars /Users/myuser/airflow/airflow.cfg\nshellvars /Users/myuser/airflow/unittests.cfg\nyml /Users/myuser/Downloads/config_example.yml\nyml /Users/myuser/workspace/docker-compose-swarm.yml\n\nIn [4]: from flange import dbengine\n\nIn [5]: cfg.info()\n\nmodels:\ndbengine instances: testdb,db1\nlogger instances: logger\n\nbase dir: \t.\nsearch depth: \t1\nfile include patterns: \t['*.yml', '*cfg', '*settings', '*config', '*properties', '*props']\nfile exclude patterns: \t['*.tar', '*.jar', '*.zip', '*.gz', '*.swp', 'node_modules', 'target', '.idea', '*.hide', '*save']\n\nsources:\nNone os_env\nyml /Users/myuser/config_example.yml\nyml /Users/myuser/.cmd.yml\nshellvars /Users/myuser/.ansible.cfg\nyml /Users/myuser/.flangetest.yml\nshellvars /Users/myuser/.bundle/config\nyml /Users/myuser/.nyttth/config.yml\nshellvars /Users/myuser/.plotly/.config\nshellvars /Users/myuser/.ScreamingFrogSEOSpider/spider.config\nshellvars /Users/myuser/.ssh/config\nshellvars /Users/myuser/.subversion/config\nshellvars /Users/myuser/airflow/airflow.cfg\nshellvars /Users/myuser/airflow/unittests.cfg\nyml /Users/myuser/Downloads/config_example.yml\nyml /Users/myuser/workspace/docker-compose-swarm.yml\n\n\nIn [6]: cfg.obj('db1')\nOut[6]: Engine(mssql+pymssql://corpdomain\\corpuser:***@dbhost:1111/dbname?charset=utf8)\n```\n\n## Plugins\n\nHere is how the dbengine (sqlalchemy) model is defined:\n\n``` Python\nfrom . import cfg\nfrom sqlalchemy import create_engine\n\ndbengine_schema = {\n \"type\" : \"object\",\n \"properties\" : {\n 'driver':{'type':'string'},\n 'name':{'type':'string'},\n 'user':{'type':'string'},\n 'pass':{'type':'string'},\n 'port':{'type':'string'},\n },\n \"required\": [\"driver\", \"name\", \"user\", \"pass\"]\n}\n\ndef dbengine_create_func(config):\n url_format_string = \"{:s}://{:s}:{:s}@{:s}:{:s}/{:s}?charset=utf8\"\n engine = create_engine(url_format_string.format(\n config['driver'],\n config['user'],\n config['pass'],\n config['host'],\n config['port'],\n config['name']), convert_unicode=True)\n\n return engine\n\n\ncfg.register_default_model(\n 'dbengine',\n model.Model('dbengine',\n model.Model.get_schema_validator(dbengine_schema),\n dbengine_create_func))\n\n```\n\nThe example above showed explicit registration from python. Plugin registration can also be accomplished \nwith just configuration. Here is an example from the \ntests in this project. For this to work, a python factory function must exist in the python \npath, resolved via a local url *(see example for url format)*. This config must also appear somewhere in the loaded\nconfig data loaded by flange. With those caveats, The following is all \nthat is required to register a custom model and start accessing instances: \n\n```\nconfig_with_plugin = {\n\n 'test_instance_key': {\n 'only_TestPlugin_would_match_this': 'some value'\n },\n\n 'test_plugin_config_key': {\n 'type': 'FLANGE.TYPE.PLUGIN',\n 'schema': {\n 'type': 'object',\n 'properties':{\n 'only_TestPlugin_would_match_this': {'type': 'string'}\n },\n 'required': ['only_TestPlugin_would_match_this']\n },\n 'factory': 'python://flange.test.TestPlugin().get_instance'\n }\n}\n```\n\n\n## Installation\n\n```\npip install flange\n```\n\n\n\n", "description_content_type": "", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/flashashen/flange", "keywords": "configuration yaml object registry spring", "license": "MIT", "maintainer": "", "maintainer_email": "", "name": "flange", "package_url": "https://pypi.org/project/flange/", "platform": "osx", "project_url": "https://pypi.org/project/flange/", "project_urls": { "Homepage": "https://github.com/flashashen/flange" }, "release_url": "https://pypi.org/project/flange/0.0.8/", "requires_dist": [ "anyconfig", "PyYAML", "six", "jsonschema", "dpath" ], "requires_python": "", "summary": "Autoload configuration from multiple sources, object registry, dpath access.", "version": "0.0.8" }, "last_serial": 4002325, "releases": { "0.0.2": [ { "comment_text": "", "digests": { "md5": "a478aa2f8e25d956ed1d744ee20c1ad0", "sha256": "b9193b39bf85773fbb5f959e8bc790ff7dde8be908c5d72368012362c623565c" }, "downloads": -1, "filename": "flange-0.0.2-py2-none-any.whl", "has_sig": false, "md5_digest": "a478aa2f8e25d956ed1d744ee20c1ad0", "packagetype": "bdist_wheel", "python_version": "py2", "requires_python": null, "size": 24745, "upload_time": "2017-11-10T22:05:04", "url": "https://files.pythonhosted.org/packages/da/3a/044a4429a847b9107f0274bc66f65a906a8045246708bf26774da053ab38/flange-0.0.2-py2-none-any.whl" }, { "comment_text": "", "digests": { "md5": "53c064c6647dbc7098da654f2393a119", "sha256": "df967a94da4fbae07a913ceff1ad6a4b794c298c222e52a481e9c7a65557197d" }, "downloads": -1, "filename": "flange-0.0.2.tar.gz", "has_sig": false, "md5_digest": "53c064c6647dbc7098da654f2393a119", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 24195, "upload_time": "2017-11-10T22:05:06", "url": "https://files.pythonhosted.org/packages/ab/63/58a4add1aee9119f9cf77bdc196e759030fffc7ba2dce7d52bd793fe0cca/flange-0.0.2.tar.gz" } ], "0.0.3": [ { "comment_text": "", "digests": { "md5": "c7519a0ce18679eb0103276779ebe975", "sha256": "acced229f1dc47d29cf9f0fb934eacf2f5c60e3b846e531d0c7b5e2431309c11" }, "downloads": -1, "filename": "flange-0.0.3-py2-none-any.whl", "has_sig": false, "md5_digest": "c7519a0ce18679eb0103276779ebe975", "packagetype": "bdist_wheel", "python_version": "py2", "requires_python": null, "size": 25096, "upload_time": "2017-11-13T04:01:18", "url": "https://files.pythonhosted.org/packages/d8/c5/40afee89e0c5997ff537afedb1aeed3ec3a35aac28f4ecec43b5a7739aff/flange-0.0.3-py2-none-any.whl" }, { "comment_text": "", "digests": { "md5": "05cbe06ea90e6181775dd13780c90e83", "sha256": "44b6993dc8cc1d548b4d39f55825a55915855487de637c5bf59df02c2e8f2628" }, "downloads": -1, "filename": "flange-0.0.3.tar.gz", "has_sig": false, "md5_digest": "05cbe06ea90e6181775dd13780c90e83", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 24531, "upload_time": "2017-11-13T04:01:19", "url": "https://files.pythonhosted.org/packages/7d/d6/11f870dd2f5dc0fff07127e9ad716fb81f564273ecbb345333fb8a42509e/flange-0.0.3.tar.gz" } ], "0.0.4": [ { "comment_text": "", "digests": { "md5": "65f64e9b94e3fd69c2d189919cb636e1", "sha256": "41a7fca20fdf70e0055f0d1aacba7fa6e6bd645ccd1f2b0ba7bd137032cb617c" }, "downloads": -1, "filename": "flange-0.0.4-py2-none-any.whl", "has_sig": false, "md5_digest": "65f64e9b94e3fd69c2d189919cb636e1", "packagetype": "bdist_wheel", "python_version": "py2", "requires_python": null, "size": 32633, "upload_time": "2018-03-10T14:24:10", "url": "https://files.pythonhosted.org/packages/d7/d4/a6b4b97ebb33b08a27ff9cdeac8698c544bd94ae1d760d1e8175d35b2dea/flange-0.0.4-py2-none-any.whl" }, { "comment_text": "", "digests": { "md5": "d824d524142bf5ec4be2ae758022fe25", "sha256": "2fdb05f7dcca522faa75d82c1f60bd5e8426e29207cab66d783e49228a81fa99" }, "downloads": -1, "filename": "flange-0.0.4.tar.gz", "has_sig": false, "md5_digest": "d824d524142bf5ec4be2ae758022fe25", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 28661, "upload_time": "2018-03-10T14:24:13", "url": "https://files.pythonhosted.org/packages/30/e2/ad1da0475b4fb33a906cceb19444148829b3069ed8266c174f5f0bbb9d39/flange-0.0.4.tar.gz" } ], "0.0.7": [ { "comment_text": "", "digests": { "md5": "bdfd8336dec92eea4f16a5a36dc34843", "sha256": "36fc2b1a0528838f673e5f061f9072db89b1360982b384039efbdd566efc219e" }, "downloads": -1, "filename": "flange-0.0.7-py2-none-any.whl", "has_sig": false, "md5_digest": "bdfd8336dec92eea4f16a5a36dc34843", "packagetype": "bdist_wheel", "python_version": "py2", "requires_python": null, "size": 37030, "upload_time": "2018-04-01T23:17:03", "url": "https://files.pythonhosted.org/packages/43/cd/7bc35e57f310fcbfcb5c77bd7e8313b43a59e46388205e14919eb6e0ad3b/flange-0.0.7-py2-none-any.whl" }, { "comment_text": "", "digests": { "md5": "89a3bedb3fed1c0120f790b6ea60554e", "sha256": "aa21762ff20d7c569c8c53625146a44d9d4114fde0aec6f2f6733a3a8411bf15" }, "downloads": -1, "filename": "flange-0.0.7.tar.gz", "has_sig": false, "md5_digest": "89a3bedb3fed1c0120f790b6ea60554e", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 31901, "upload_time": "2018-04-01T23:17:05", "url": "https://files.pythonhosted.org/packages/10/75/75386c037841186f2045593d26db3ffc812fb76384f6d7510f220197213e/flange-0.0.7.tar.gz" } ], "0.0.8": [ { "comment_text": "", "digests": { "md5": "8fc2cbf5fc1a421ed7029d1f3e2c214e", "sha256": "322bfb4381c64ce058274790a5cadd99f3e71a0daff018ecaf10ebb16fc1df06" }, "downloads": -1, "filename": "flange-0.0.8-py2-none-any.whl", "has_sig": false, "md5_digest": "8fc2cbf5fc1a421ed7029d1f3e2c214e", "packagetype": "bdist_wheel", "python_version": "py2", "requires_python": null, "size": 32563, "upload_time": "2018-06-26T02:28:55", "url": "https://files.pythonhosted.org/packages/9e/4c/18656acbc577c6ffd021b0ffc6eff4f32e3368e619e418396095d90bcd43/flange-0.0.8-py2-none-any.whl" }, { "comment_text": "", "digests": { "md5": "4bc6273506f800c313c099c2059269af", "sha256": "4bb3ca8acfbf4e5f992c11d7873faa1b38ceb8769bbc379b6dfe611ffcf72595" }, "downloads": -1, "filename": "flange-0.0.8.tar.gz", "has_sig": false, "md5_digest": "4bc6273506f800c313c099c2059269af", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 32317, "upload_time": "2018-06-26T02:28:56", "url": "https://files.pythonhosted.org/packages/c7/5c/fa44ed5b863afe3c1ff6d22b143e5b8d4b49c96f365eb01146e8929a508b/flange-0.0.8.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "8fc2cbf5fc1a421ed7029d1f3e2c214e", "sha256": "322bfb4381c64ce058274790a5cadd99f3e71a0daff018ecaf10ebb16fc1df06" }, "downloads": -1, "filename": "flange-0.0.8-py2-none-any.whl", "has_sig": false, "md5_digest": "8fc2cbf5fc1a421ed7029d1f3e2c214e", "packagetype": "bdist_wheel", "python_version": "py2", "requires_python": null, "size": 32563, "upload_time": "2018-06-26T02:28:55", "url": "https://files.pythonhosted.org/packages/9e/4c/18656acbc577c6ffd021b0ffc6eff4f32e3368e619e418396095d90bcd43/flange-0.0.8-py2-none-any.whl" }, { "comment_text": "", "digests": { "md5": "4bc6273506f800c313c099c2059269af", "sha256": "4bb3ca8acfbf4e5f992c11d7873faa1b38ceb8769bbc379b6dfe611ffcf72595" }, "downloads": -1, "filename": "flange-0.0.8.tar.gz", "has_sig": false, "md5_digest": "4bc6273506f800c313c099c2059269af", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 32317, "upload_time": "2018-06-26T02:28:56", "url": "https://files.pythonhosted.org/packages/c7/5c/fa44ed5b863afe3c1ff6d22b143e5b8d4b49c96f365eb01146e8929a508b/flange-0.0.8.tar.gz" } ] }