{ "info": { "author": "Henrique Bastos", "author_email": "henrique@bastos.net", "bugtrack_url": null, "classifiers": [ "Development Status :: 5 - Production/Stable", "Framework :: Django", "Framework :: Flask", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Natural Language :: English", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", "Topic :: Software Development :: Libraries" ], "description": "Python Decouple: Strict separation of settings from code\n========================================================\n\n*Decouple* helps you to organize your settings so that you can\nchange parameters without having to redeploy your app.\n\nIt also makes easy for you to:\n\n#. store parameters on *ini* or *.env* files;\n#. define comprehensive default values;\n#. properly convert values to the correct data type;\n#. have **only one** configuration module to rule all your instances.\n\nIt was originally designed for Django, but became an independent generic tool\nfor separating settings from code.\n\n.. image:: https://img.shields.io/travis/henriquebastos/python-decouple.svg\n :target: https://travis-ci.org/henriquebastos/python-decouple\n :alt: Build Status\n\n.. image:: https://landscape.io/github/henriquebastos/python-decouple/master/landscape.png\n :target: https://landscape.io/github/henriquebastos/python-decouple/master\n :alt: Code Health\n\n.. image:: https://img.shields.io/pypi/v/python-decouple.svg\n :target: https://pypi.python.org/pypi/python-decouple/\n :alt: Latest PyPI version\n\n\n\n.. contents:: Summary\n\n\nWhy?\n====\n\nWeb framework's settings stores many different kinds of parameters:\n\n* Locale and i18n;\n* Middlewares and Installed Apps;\n* Resource handles to the database, Memcached, and other backing services;\n* Credentials to external services such as Amazon S3 or Twitter;\n* Per-deploy values such as the canonical hostname for the instance.\n\nThe first 2 are *project settings* the last 3 are *instance settings*.\n\nYou should be able to change *instance settings* without redeploying your app.\n\nWhy not just use environment variables?\n---------------------------------------\n\n*Envvars* works, but since ``os.environ`` only returns strings, it's tricky.\n\nLet's say you have an *envvar* ``DEBUG=False``. If you run:\n\n.. code-block:: python\n\n if os.environ['DEBUG']:\n print True\n else:\n print False\n\nIt will print **True**, because ``os.environ['DEBUG']`` returns the **string** ``\"False\"``.\nSince it's a non-empty string, it will be evaluated as True.\n\n*Decouple* provides a solution that doesn't look like a workaround: ``config('DEBUG', cast=bool)``.\n\nUsage\n=====\n\nInstall:\n\n.. code-block:: console\n\n pip install python-decouple\n\n\nThen use it on your ``settings.py``.\n\n#. Import the ``config`` object:\n\n .. code-block:: python\n\n from decouple import config\n\n#. Retrieve the configuration parameters:\n\n .. code-block:: python\n\n SECRET_KEY = config('SECRET_KEY')\n DEBUG = config('DEBUG', default=False, cast=bool)\n EMAIL_HOST = config('EMAIL_HOST', default='localhost')\n EMAIL_PORT = config('EMAIL_PORT', default=25, cast=int)\n\nWhere the settings data are stored?\n-----------------------------------\n\n*Decouple* supports both *.ini* and *.env* files.\n\nIni file\n~~~~~~~~\n\nSimply create a ``settings.ini`` next to your configuration module in the form:\n\n.. code-block:: ini\n\n [settings]\n DEBUG=True\n TEMPLATE_DEBUG=%(DEBUG)s\n SECRET_KEY=ARANDOMSECRETKEY\n DATABASE_URL=mysql://myuser:mypassword@myhost/mydatabase\n PERCENTILE=90%%\n #COMMENTED=42\n\n*Note*: Since ``ConfigParser`` supports *string interpolation*, to represent the character ``%`` you need to escape it as ``%%``.\n\nEnv file\n~~~~~~~~\n\nSimply create a ``.env`` text file on your repository's root directory in the form:\n\n.. code-block:: console\n\n DEBUG=True\n TEMPLATE_DEBUG=True\n SECRET_KEY=ARANDOMSECRETKEY\n DATABASE_URL=mysql://myuser:mypassword@myhost/mydatabase\n PERCENTILE=90%\n #COMMENTED=42\n\nExample: How do I use it with Django?\n-------------------------------------\n\nGiven that I have a ``.env`` file at my repository root directory, here is a snippet of my ``settings.py``.\n\nI also recommend using `pathlib `_\nand `dj-database-url `_.\n\n.. code-block:: python\n\n # coding: utf-8\n from decouple import config\n from unipath import Path\n from dj_database_url import parse as db_url\n\n\n BASE_DIR = Path(__file__).parent\n\n DEBUG = config('DEBUG', default=False, cast=bool)\n TEMPLATE_DEBUG = DEBUG\n\n DATABASES = {\n 'default': config(\n 'DATABASE_URL',\n default='sqlite:///' + BASE_DIR.child('db.sqlite3'),\n cast=db_url\n )\n }\n\n TIME_ZONE = 'America/Sao_Paulo'\n USE_L10N = True\n USE_TZ = True\n\n SECRET_KEY = config('SECRET_KEY')\n\n EMAIL_HOST = config('EMAIL_HOST', default='localhost')\n EMAIL_PORT = config('EMAIL_PORT', default=25, cast=int)\n EMAIL_HOST_PASSWORD = config('EMAIL_HOST_PASSWORD', default='')\n EMAIL_HOST_USER = config('EMAIL_HOST_USER', default='')\n EMAIL_USE_TLS = config('EMAIL_USE_TLS', default=False, cast=bool)\n\n # ...\n\nAttention with *undefined* parameters\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nOn the above example, all configuration parameters except ``SECRET_KEY = config('SECRET_KEY')``\nhave a default value to fallback if it does not exist on the ``.env`` file.\n\nIf ``SECRET_KEY`` is not present on the ``.env``, *decouple* will raise an ``UndefinedValueError``.\n\nThis *fail fast* policy helps you avoid chasing misbehaviors when you eventually forget a parameter.\n\nOverriding config files with environment variables\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nSome times you may want to change a parameter value without having to edit the ``.ini`` or ``.env`` files.\n\nSince version 3.0, *decouple* respect the *unix way*.\nTherefore environment variables have precedence over config files.\n\nTo override a config parameter you can simply do:\n\n.. code-block:: console\n\n DEBUG=True python manage.py\n\n\nHow it works?\n=============\n\n*Decouple* always searches for *Options* in this order:\n\n#. Environment variables;\n#. Repository: ini or .env file;\n#. default argument passed to config.\n\nThere are 4 classes doing the magic:\n\n\n- ``Config``\n\n Coordinates all the configuration retrieval.\n\n- ``RepositoryIni``\n\n Can read values from ``os.environ`` and ini files, in that order.\n\n **Note:** Since version 3.0 *decouple* respects unix precedence of environment variables *over* config files.\n\n- ``RepositoryEnv``\n\n Can read values from ``os.environ`` and ``.env`` files.\n\n **Note:** Since version 3.0 *decouple* respects unix precedence of environment variables *over* config files.\n\n- ``AutoConfig``\n\n This is a *lazy* ``Config`` factory that detects which configuration repository you're using.\n\n It recursively searches up your configuration module path looking for a\n ``settings.ini`` or a ``.env`` file.\n\n Optionally, it accepts ``search_path`` argument to explicitly define\n where the search starts.\n\nThe **config** object is an instance of ``AutoConfig`` that instantiates a ``Config`` with the proper ``Repository``\non the first time it is used.\n\n\nUnderstanding the CAST argument\n-------------------------------\n\nBy default, all values returned by `decouple` are `strings`, after all they are\nread from `text files` or the `envvars`.\n\nHowever, your Python code may expect some other value type, for example:\n\n* Django's DEBUG expects a boolean True or False.\n* Django's EMAIL_PORT expects an integer.\n* Django's ALLOWED_HOSTS expects a list of hostnames.\n* Django's SECURE_PROXY_SSL_HEADER expects a `tuple` with two elements, the name of the header to look for and the required value.\n\nTo meet this need, the `config` function accepts a `cast` argument which\nreceives any *callable*, that will be used to *transform* the string value\ninto something else.\n\nLet's see some examples for the above mentioned cases:\n\n.. code-block:: pycon\n\n >>> os.environ['DEBUG'] = 'False'\n >>> config('DEBUG', cast=bool)\n False\n\n >>> os.environ['EMAIL_PORT'] = '42'\n >>> config('EMAIL_PORT', cast=int)\n 42\n\n >>> os.environ['ALLOWED_HOSTS'] = '.localhost, .herokuapp.com'\n >>> config('ALLOWED_HOSTS', cast=lambda v: [s.strip() for s in v.split(',')])\n ['.localhost', '.herokuapp.com']\n\n >>> os.environ['SECURE_PROXY_SSL_HEADER'] = 'HTTP_X_FORWARDED_PROTO, https'\n >>> config('SECURE_PROXY_SSL_HEADER', cast=Csv(tuple_=True))\n ('HTTP_X_FORWARDED_PROTO', 'https')\n\nAs you can see, `cast` is very flexible. But the last example got a bit complex.\n\nBuilt in Csv Helper\n~~~~~~~~~~~~~~~~~~~\n\nTo address the complexity of the last example, *Decouple* comes with an extensible *Csv helper*.\n\nLet's improve the last example:\n\n.. code-block:: pycon\n\n >>> from decouple import Csv\n >>> os.environ['ALLOWED_HOSTS'] = '.localhost, .herokuapp.com'\n >>> config('ALLOWED_HOSTS', cast=Csv())\n ['.localhost', '.herokuapp.com']\n\nYou can also parametrize the *Csv Helper* to return other types of data.\n\n.. code-block:: pycon\n\n >>> os.environ['LIST_OF_INTEGERS'] = '1,2,3,4,5'\n >>> config('LIST_OF_INTEGERS', cast=Csv(int))\n [1, 2, 3, 4, 5]\n\n >>> os.environ['COMPLEX_STRING'] = '%virtual_env%\\t *important stuff*\\t trailing spaces '\n >>> csv = Csv(cast=lambda s: s.upper(), delimiter='\\t', strip=' %*')\n >>> csv(os.environ['COMPLEX_STRING'])\n ['VIRTUAL_ENV', 'IMPORTANT STUFF', 'TRAILING SPACES']\n\nBy default *Csv* returns a `list`, but you can get a `tuple` or whatever you want using the `post_process` argument:\n\n.. code-block:: pycon\n\n >>> os.environ['SECURE_PROXY_SSL_HEADER'] = 'HTTP_X_FORWARDED_PROTO, https'\n >>> config('SECURE_PROXY_SSL_HEADER', cast=Csv(post_process=tuple))\n ('HTTP_X_FORWARDED_PROTO', 'https')\n\n\nContribute\n==========\n\nYour contribution is welcome.\n\nSetup you development environment:\n\n.. code-block:: console\n\n git clone git@github.com:henriquebastos/python-decouple.git\n cd python-decouple\n python -m venv .venv\n source .venv/bin/activate\n pip install -r requirements.txt\n tox\n\n*Decouple* supports both Python 2.7 and 3.6. Make sure you have both installed.\n\nI use `pyenv `_ to\nmanage multiple Python versions and I described my workspace setup on this article:\n`The definitive guide to setup my Python workspace\n`_\n\nYou can submit pull requests and issues for discussion. However I only\nconsider merge tested code.\n\n\nLicense\n=======\n\nThe MIT License (MIT)\n\nCopyright (c) 2017 Henrique Bastos \n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.", "description_content_type": null, "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "http://github.com/henriquebastos/python-decouple/", "keywords": "", "license": "MIT", "maintainer": "", "maintainer_email": "", "name": "python-decouple", "package_url": "https://pypi.org/project/python-decouple/", "platform": "any", "project_url": "https://pypi.org/project/python-decouple/", "project_urls": { "Homepage": "http://github.com/henriquebastos/python-decouple/" }, "release_url": "https://pypi.org/project/python-decouple/3.1/", "requires_dist": null, "requires_python": "", "summary": "Strict separation of settings from code.", "version": "3.1" }, "last_serial": 3079719, "releases": { "2.2": [ { "comment_text": "", "digests": { "md5": "dbdbb492f07b94e6e9d0612e70f414e1", "sha256": "2ae86e2b24ba1b70a8a43e2e6d5e9b4b7e0d85883a5f58586ccc0f0f5f25f150" }, "downloads": -1, "filename": "python-decouple-2.2.tar.gz", "has_sig": false, "md5_digest": "dbdbb492f07b94e6e9d0612e70f414e1", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6285, "upload_time": "2014-02-25T05:47:41", "url": "https://files.pythonhosted.org/packages/12/36/558852d9c166fd22094aa65c0dce0907d9d5248157e834f87f620922cc48/python-decouple-2.2.tar.gz" } ], "2.3": [ { "comment_text": "", "digests": { "md5": "14adac89598dd2655fd870e1e74948b3", "sha256": "b9fbf747fa8e711d330f2f436b9b2ecf5eed9eb67a637ca81abcd11c2abedec8" }, "downloads": -1, "filename": "python-decouple-2.3.tar.gz", "has_sig": false, "md5_digest": "14adac89598dd2655fd870e1e74948b3", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 7514, "upload_time": "2014-08-19T18:40:20", "url": "https://files.pythonhosted.org/packages/09/13/d1b082e53660595d249db8760e66f07d0beb39410e1e324bab985d7c2efc/python-decouple-2.3.tar.gz" } ], "2.4": [ { "comment_text": "", "digests": { "md5": "e33885dadd2bd2592dda9e66558f3eb0", "sha256": "c589884fa8abd0e67c8307e91b6d07a666472c4c5ca5f245fd2efdb73b2dcbf9" }, "downloads": -1, "filename": "python-decouple-2.4.tar.gz", "has_sig": false, "md5_digest": "e33885dadd2bd2592dda9e66558f3eb0", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 7534, "upload_time": "2015-09-15T02:56:15", "url": "https://files.pythonhosted.org/packages/81/e0/5d2677b20407f4ff797f0e579500c92348fe2a7899dd5fa82b711282d6b0/python-decouple-2.4.tar.gz" } ], "3.0": [ { "comment_text": "", "digests": { "md5": "3b6ac3907f9075d030657a607713ef90", "sha256": "99834c9ff7ce5c5b2f4a18bc0880753e54ea3aaabc3cfb16961a92d5046665df" }, "downloads": -1, "filename": "python-decouple-3.0.tar.gz", "has_sig": false, "md5_digest": "3b6ac3907f9075d030657a607713ef90", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 7528, "upload_time": "2015-09-15T03:09:18", "url": "https://files.pythonhosted.org/packages/5f/fc/9f3ec3f7844f9045406562512dbb599e9576e0c2ce3192a5e4d459f66e99/python-decouple-3.0.tar.gz" } ], "3.1": [ { "comment_text": "", "digests": { "md5": "8f09b183b1c677793acdfd598bab94b7", "sha256": "1317df14b43efee4337a4aa02914bf004f010cd56d6c4bd894e6474ec8c4fe2d" }, "downloads": -1, "filename": "python-decouple-3.1.tar.gz", "has_sig": false, "md5_digest": "8f09b183b1c677793acdfd598bab94b7", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 8653, "upload_time": "2017-08-07T23:12:49", "url": "https://files.pythonhosted.org/packages/9b/99/ddfbb6362af4ee239a012716b1371aa6d316ff1b9db705bfb182fbc4780f/python-decouple-3.1.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "8f09b183b1c677793acdfd598bab94b7", "sha256": "1317df14b43efee4337a4aa02914bf004f010cd56d6c4bd894e6474ec8c4fe2d" }, "downloads": -1, "filename": "python-decouple-3.1.tar.gz", "has_sig": false, "md5_digest": "8f09b183b1c677793acdfd598bab94b7", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 8653, "upload_time": "2017-08-07T23:12:49", "url": "https://files.pythonhosted.org/packages/9b/99/ddfbb6362af4ee239a012716b1371aa6d316ff1b9db705bfb182fbc4780f/python-decouple-3.1.tar.gz" } ] }