{ "info": { "author": "Jazeps Basko", "author_email": "jazeps.basko@gmail.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 4 - Beta", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7" ], "description": "###########\nwr-profiles\n###########\n\nIntroduction\n============\n\n**wr-profiles** allows declaring a profile -- a collection of key-value pairs -- backed by environment variables\nand accessing the profile contents through dot notation with auto-complete working in your IDE.\nYou can also have multiple separate environments declared and switch between profiles by changing just one environment\nvariable (just like you normally do when working with multiple AWS accounts if you have that background).\nwr-profiles are designed with testability in mind.\n\n *wr-* in the package name stands for *Wheel Reinvented*. Just like all other packages whose name starts with\n *wr-*, the meaning of this library (as in *meaning of life*) lies in its existence and evolution\n and not in any external application of it.\n\nSupported Python Versions\n-------------------------\n\n* Python 3.6\n* Python 3.7\n\nExample\n=======\n\nDeclare the profile:\n\n.. code-block:: python\n\n from wr_profiles import envvar_profile_cls\n\n @envvar_profile_cls\n class WarehouseProfile:\n host: str = \"localhost\"\n username: str\n password: str\n\n warehouse_profile = WarehouseProfile()\n\n\nSet up the environments:\n\n.. code-block:: bash\n\n export WAREHOUSE_STAGING_PARENT_PROFILE=\"production\"\n export WAREHOUSE_STAGING_PASSWORD=\"staging-password\"\n export WAREHOUSE_PRODUCTION_USERNAME=\"production-username\"\n export WAREHOUSE_PRODUCTION_PASSWORD=\"production-password\"\n\nSelect the active environment:\n\n.. code-block:: shell\n\n export WAREHOUSE_PROFILE=staging\n\n\nUse the profile:\n\n.. code-block:: python\n\n from profiles import warehouse_profile\n\n assert warehouse_profile.host == \"localhost\"\n assert warehouse_profile.username == \"production-username\"\n assert warehouse_profile.password == \"staging-password\"\n\n\nInstallation\n============\n\n.. code-block:: bash\n\n pip install wr-profiles\n\nIf you decide to use this library, make sure you pin the version number in your requirements file.\n\nWe are following interpretation of the semantic versioning schema. Example:\n\n* ``v2.x.a -> v2.x.b`` - bugfix or non-breaking change, safe to upgrade.\n* ``v2.x.* -> v3.y.*`` - potentially breaking changes, feature added, minimal changes to user code may be required\n* ``v2.* -> v3.*`` - complete changeover\n\n\nChangelog\n=========\n\nv4.2.0\n------\n\n* Added ``profile_delegate`` feature.\n\nv4.1.0\n------\n\n* Added ``EnvvarProfile.create_env`` which creates an ``Environment`` which can be applied\n as a context manager.\n\n\nUser Guide\n==========\n\nConcepts\n--------\n\nProfile\n^^^^^^^\n\nA **profile** represents a set of configurable **properties** of a single service\nbacked by environment variables.\n\nIn your application, there can be multiple unrelated profiles each providing interface\nto properties of a different service.\n\nInstances of profiles associated with the same service share the same base class and are identified by\n``profile_root`` specified in that base class. Is is the root from which all relevant\nenvironment variable names are formed.\n\nProfiles of unrelated services do not share any information.\nIn the discussion below, different instances or kinds of profiles all relate to the same service,\ne.g. same ``profile_root``.\n\nWarehouse Profile (Example)\n\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\n\nIn the discussion below, we will use a profile for a data warehouse access as an example.\nClass ``WarehouseProfile`` declares the profile and the properties it provides.\nObject ``warehouse_profile`` is the single instance through which user must look up service's\nactive configuration.\n\n.. code-block:: python\n\n from wr_profiles import envvar_profile_cls\n\n @envvar_profile_cls\n class WarehouseProfile:\n host: str = \"localhost\"\n username: str\n password: str\n\n warehouse_profile = WarehouseProfile()\n\n\nProfile Name\n^^^^^^^^^^^^\n\nIndividual instances of profiles are identified by their name (``profile_name`` property).\n\n\nActive Profile\n^^^^^^^^^^^^^^\n\nThe **active profile** is the profile of a service that should be used \naccording to the environment variables.\n\nBy default, the active profile can be switched by setting a special environment variable\n``_PROFILE``. For ``WarehouseProfile`` that would be ``WAREHOUSE_PROFILE``.\n\nThe name of this variable can be customised by setting your class's ``profile_activating_envvar``.\n\nIf this variable is not set, the active profile is *an empty string*, and the environment variables\nconsulted are in the form:\n\n.. code-block:: bash\n\n _\n\nFor example, ``WAREHOUSE_HOST``.\n\nIf ``_PROFILE`` is set then the active profile consults environment variables in the form:\n\n.. code-block::\n\n __\n\nFor example, if ``WAREHOUSE_PROFILE`` is set to ``staging`` then ``host`` property will be looked up\nunder ``WAREHOUSE_STAGING_HOST``.\n\n\nParent Profile\n^^^^^^^^^^^^^^\n\nAny particular profile (for example, ``staging`` profile of ``WarehouseProfile``) can be instructed\nto inherit its property values from a **parent profile** by setting:\n\n.. code-block:: bash\n\n __PARENT_PROFILE\n\nFor example, ``WAREHOUSE_STAGING_PARENT_PROFILE``, if set to ``production``, would mean that\nif environment variable ``WAREHOUSE_STAGING_HOST`` was not set, property value loader would\nconsult ``WAREHOUSE_PRODUCTION_HOST`` instead. And only if that variable was not present,\nthe default value of the property would be used.\n\n*Limitation*: The default profile (``profile_name=\"\"``) cannot be used as a parent profile.\nIf you specify empty string as ``__PARENT_PROFILE`` then this\nprofile won\"t have any parent profile. It is the same as having no value set. \n\n\nLive Profile vs Frozen Profile\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nA **live** profile always consults environment variables (``os.environ``) whereas\na **frozen** profile does so only during instantiation and when explicitly loaded\nwith ``load()`` method.\n\nCommon Scenarios\n----------------\n\n\nGet Current Active Profile\n^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nCurrent active profile is always available through the instance of your profile class which is\ninstantiated with no arguments:\n\n.. code-block:: python\n\n warehouse_profile = WarehouseProfile()\n\nNormally you'd only need a single instance of your profile class pointing to the active profile.\n\n\nGet Concrete Profile\n^^^^^^^^^^^^^^^^^^^^\n\nTo work with a concrete profile which may not necessarily be activated, use ``load``\nfactory method:\n\n.. code-block:: python\n\n staging = WarehouseProfile.load(\"staging\")\n\nBy default, this profile will be frozen which means it will be loaded only once during instantiation.\nIf you want it to always consult environment variables, pass ``profile_is_live=True``:\n\n.. code-block:: python\n\n staging = WarehouseProfile.load(\"staging\", profile_is_live=True)\n\n\nCustomise Profile-Activating Environment Variable\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nImagine you have your ``WarehouseProfile`` and you want to use it in tests. In tests it should have different defaults.\n\n.. code-block:: python\n\n @envvar_profile_cls\n class WarehouseTestProfile(WarehouseProfile):\n\n # If you don't set this, it would be \"WAREHOUSE_PROFILE\" which would conflict\n # with your non-test profile.\n profile_activating_envvar = \"WAREHOUSE_TEST_PROFILE\"\n\n host: str = \"test-host\"\n username: str = \"test-user\"\n\n\nIn your application you would then have two instances:\n\n.. code-block:: python\n\n profile = WarehouseProfile()\n test_profile = WarehouseTestProfile()\n\nNow you can reuse your non-test profiles in tests when it makes sense. For example, if you have set up environment\nvariables in the form ``WAREHOUSE_SANDBOX_*`` then this \"sandbox\" profile can be used in tests by just setting\n``WAREHOUSE_TEST_PROFILE`` to ``sandbox``.\n\nNote that ``profile_root`` for both profiles is the same.\n\nActivate Profile\n^^^^^^^^^^^^^^^^\n\nTo activate a profile, call ``activate`` method on a frozen instance of the profile without any arguments,\nor, ``activate(profile_name)`` on the live current profile instance:\n\n.. code-block:: python\n\n staging.activate()\n # or:\n warehouse_profile.activate(\"staging\")\n\n\nGet All Values\n^^^^^^^^^^^^^^\n\n.. code-block:: python\n\n warehouse_profile.to_dict()\n\n\nSet Environment Variables\n^^^^^^^^^^^^^^^^^^^^^^^^^\n\nNote that the environment variables you set normally apply only to the current process and its sub-processes\nso this will have limited use -- it will only make sense when you are launching sub-processes or you do this\nsomewhere early in the code before environment variables are loaded by other parts of your code.\n\n.. code-block:: python\n\n os.environ.update(warehouse_profile.to_envvars())\n\n\nCheck If Property Has Non-Default Value\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n.. code-block:: python\n\n warehouse_profile.has_prop_value(\"username\")\n # or\n warehouse_profile.has_prop_value(WarehouseProfile.username)\n\n\nInspect Property\n^^^^^^^^^^^^^^^^\n\n.. code-block:: python\n\n from wr_profiles import EnvvarProfileProperty\n\n assert isinstance(WarehouseProfile.username, EnvvarProfileProperty)\n assert WarehouseProfile.username.name == \"username\"\n assert WarehouseProfile.username.default == \"default-username\"\n\n\nEnvironment Objects\n^^^^^^^^^^^^^^^^^^^\n\nStarting from version 4.1 you can create an instance of ``Environment`` which can then be applied on ``os.environ``\nor pytest's ``monkeypatch`` fixture. ``Environment`` is a dictionary of environment variables that neet to\nbe set or unset in order to apply the specified environment. The values are determined at environment\ncreation time.\n\n.. code-block:: python\n\n test_env = warehouse_profile.create_env(username='test', password=None)\n with test_env.applied():\n assert warehouse_profile.username == 'test'\n assert os.environ['WAREHOUSE_USERNAME'] == 'test'\n\n assert warehouse_profile.password is None\n assert 'WAREHOUSE_PASSWORD' not in os.environ\n\n\nConfig Object that Delegates to Profile\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nEnvironment variables are not necessarily the only source of configuration.\nIn a non-trivial application you probably won't be consulting the profile object from your application code\ndirectly. Instead, you'll have a config object which will consult different sources including the\nenvironment variable profile.\nIt is very likely that the properties defined in your profile class will\nbe a subset of those exposed by the config object. If you don't want to repeat yourself, you can have your\nconfig class extend the profile class and have the config class delegate all the attributes to the profile\nclass except for those implemented in the config class.\n\n.. code-block:: python\n\n profile = WarehouseProfile()\n\n class WarehouseConfig(WarehouseProfile):\n @property\n def profile_delegate(self):\n return profile\n\n @property\n def username(self):\n return profile.username or \"anonymous\"\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/jbasko/wr-profiles", "keywords": "", "license": "MIT", "maintainer": "Jazeps Basko", "maintainer_email": "jazeps.basko@gmail.com", "name": "wr-profiles", "package_url": "https://pypi.org/project/wr-profiles/", "platform": "", "project_url": "https://pypi.org/project/wr-profiles/", "project_urls": { "Homepage": "https://github.com/jbasko/wr-profiles" }, "release_url": "https://pypi.org/project/wr-profiles/4.2.1/", "requires_dist": null, "requires_python": "", "summary": "Load environment variable based profiles in Python 3.6+ with ease", "version": "4.2.1" }, "last_serial": 4452638, "releases": { "1.0.1": [ { "comment_text": "", "digests": { "md5": "d8bbdde4980d6acb7b9db70d15177d1e", "sha256": "d5f8f11724c09103c5f9c5e5dd5c4fe2f5612eecd9901349bf6e33c585ad9062" }, "downloads": -1, "filename": "wr-profiles-1.0.1.tar.gz", "has_sig": false, "md5_digest": "d8bbdde4980d6acb7b9db70d15177d1e", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 8550, "upload_time": "2018-07-14T16:22:56", "url": "https://files.pythonhosted.org/packages/e1/89/35af250f57a07277f1a32319e408b028410a0615b8670422dc503d9b8803/wr-profiles-1.0.1.tar.gz" } ], "2.0.0": [ { "comment_text": "", "digests": { "md5": "6dbc80bd25519d41534687140e7e0ccc", "sha256": "6c7d3823cdfd689882ebf728ef51cc195f94cba8bde897e550ab7b5fb000defa" }, "downloads": -1, "filename": "wr-profiles-2.0.0.tar.gz", "has_sig": false, "md5_digest": "6dbc80bd25519d41534687140e7e0ccc", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 9830, "upload_time": "2018-07-27T09:31:29", "url": "https://files.pythonhosted.org/packages/3d/23/d696f16e52e644ec92df08995afd9afec20a92b27dc04bc8c4870755b2cc/wr-profiles-2.0.0.tar.gz" } ], "2.1.0": [ { "comment_text": "", "digests": { "md5": "f8f2d11c12997cebe1422bd4e56aee38", "sha256": "770ebe2796e612f7cbd487f96fe6a0f0c1c912f45290e6dbaf136417e83b6aab" }, "downloads": -1, "filename": "wr-profiles-2.1.0.tar.gz", "has_sig": false, "md5_digest": "f8f2d11c12997cebe1422bd4e56aee38", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 11248, "upload_time": "2018-07-29T16:45:36", "url": "https://files.pythonhosted.org/packages/31/e8/9c84baf43d7a17cd04759c4698e05894c02c5e0f9fd623bf68773abfc134/wr-profiles-2.1.0.tar.gz" } ], "2.2.4": [ { "comment_text": "", "digests": { "md5": "27425238f97a5a29ac24591d82f520bc", "sha256": "be02b4e49cf3d07026541974e69e9891c1474f6f6aa583455e5e9565320762e6" }, "downloads": -1, "filename": "wr-profiles-2.2.4.tar.gz", "has_sig": false, "md5_digest": "27425238f97a5a29ac24591d82f520bc", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 12210, "upload_time": "2018-08-04T11:13:57", "url": "https://files.pythonhosted.org/packages/73/0c/cd46d3391720623681c26b3da072cbcac2219e2388f9f474414e49ca64c5/wr-profiles-2.2.4.tar.gz" } ], "3.0.0": [ { "comment_text": "", "digests": { "md5": "eb75c971d905ef101eea56862d638cf2", "sha256": "877c1c7d91c00e4268c362cb1c36270de5feb4a17163359aa9ff3ba274639faa" }, "downloads": -1, "filename": "wr-profiles-3.0.0.tar.gz", "has_sig": false, "md5_digest": "eb75c971d905ef101eea56862d638cf2", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 14056, "upload_time": "2018-09-05T08:24:50", "url": "https://files.pythonhosted.org/packages/ef/f2/5a7930ad9cafd4887882984530bc57866e40aaf1ab029ab2d74becad0c27/wr-profiles-3.0.0.tar.gz" } ], "4.0.0": [ { "comment_text": "", "digests": { "md5": "1242e1234f11e868757c789bc1a9edb4", "sha256": "f1eedd2113e311ce1649b1e97642ec7bd782ed2330389ea35fd0bbd997613039" }, "downloads": -1, "filename": "wr-profiles-4.0.0.tar.gz", "has_sig": false, "md5_digest": "1242e1234f11e868757c789bc1a9edb4", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 14225, "upload_time": "2018-09-08T13:21:30", "url": "https://files.pythonhosted.org/packages/67/21/57821dbc2087010b6172ae5ea2d0b4d4f6167fc19da2a17e96decf4097d2/wr-profiles-4.0.0.tar.gz" } ], "4.1.0": [ { "comment_text": "", "digests": { "md5": "d551295ce788cca61c6f86f7b3adebef", "sha256": "15e38bb9f77305f604f5334a306d8e708a315950e3b043c49ceb39678bc30c1a" }, "downloads": -1, "filename": "wr-profiles-4.1.0.tar.gz", "has_sig": false, "md5_digest": "d551295ce788cca61c6f86f7b3adebef", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 16265, "upload_time": "2018-09-29T14:35:51", "url": "https://files.pythonhosted.org/packages/c4/55/f70cf5847f993abfa1df55e0dc4a0e6993935b21280a388c96dea5e4d300/wr-profiles-4.1.0.tar.gz" } ], "4.1.1": [ { "comment_text": "", "digests": { "md5": "2235d96bc110f28286f1787d34039c0d", "sha256": "7372b995b1684952025f6ca15f68a4925c83bbc7de67267bca23f8aaa2642f1b" }, "downloads": -1, "filename": "wr-profiles-4.1.1.tar.gz", "has_sig": false, "md5_digest": "2235d96bc110f28286f1787d34039c0d", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 16271, "upload_time": "2018-09-29T14:56:20", "url": "https://files.pythonhosted.org/packages/b4/8b/ab38ab17a49ee9e1a96022196c676c07d29705c6e11c74c180232e56fd97/wr-profiles-4.1.1.tar.gz" } ], "4.2.0": [ { "comment_text": "", "digests": { "md5": "2809011d1bfd3822a128d6b19bb36549", "sha256": "2b315cbd79dcad5383d1337e8334db682278cedc5d7acb6e9006cd2c92acac29" }, "downloads": -1, "filename": "wr-profiles-4.2.0.tar.gz", "has_sig": false, "md5_digest": "2809011d1bfd3822a128d6b19bb36549", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 17281, "upload_time": "2018-11-04T10:19:11", "url": "https://files.pythonhosted.org/packages/ca/eb/8fe4ef683c1ca10a531786e8ea5783a32f5d4ad80c95db7d4f83a0c98096/wr-profiles-4.2.0.tar.gz" } ], "4.2.1": [ { "comment_text": "", "digests": { "md5": "e8c8af76e183d6d94fe19335f53e2728", "sha256": "18be7ec6ac7aece69e65a98b429dc93406fe99b8fbcae19197c3afbc48257140" }, "downloads": -1, "filename": "wr-profiles-4.2.1.macosx-10.13-x86_64.tar.gz", "has_sig": false, "md5_digest": "e8c8af76e183d6d94fe19335f53e2728", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 15522, "upload_time": "2018-11-05T11:55:20", "url": "https://files.pythonhosted.org/packages/07/81/90b6d64aab0279d528bd4688a77131f38b8a76692174a4bd211c455dcb89/wr-profiles-4.2.1.macosx-10.13-x86_64.tar.gz" }, { "comment_text": "", "digests": { "md5": "1612076bc14e08627296c6f96cd55609", "sha256": "40167b05c757042e7693a647aa7de12dfe01715916961634c351c1a38f5a9074" }, "downloads": -1, "filename": "wr_profiles-4.2.1-py3-none-any.whl", "has_sig": false, "md5_digest": "1612076bc14e08627296c6f96cd55609", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 9734, "upload_time": "2018-11-05T11:55:19", "url": "https://files.pythonhosted.org/packages/db/97/044a5e3ee3f49266b9768f26c34a8d951f30b5553b5a28e0b03e6af9c1f8/wr_profiles-4.2.1-py3-none-any.whl" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "e8c8af76e183d6d94fe19335f53e2728", "sha256": "18be7ec6ac7aece69e65a98b429dc93406fe99b8fbcae19197c3afbc48257140" }, "downloads": -1, "filename": "wr-profiles-4.2.1.macosx-10.13-x86_64.tar.gz", "has_sig": false, "md5_digest": "e8c8af76e183d6d94fe19335f53e2728", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 15522, "upload_time": "2018-11-05T11:55:20", "url": "https://files.pythonhosted.org/packages/07/81/90b6d64aab0279d528bd4688a77131f38b8a76692174a4bd211c455dcb89/wr-profiles-4.2.1.macosx-10.13-x86_64.tar.gz" }, { "comment_text": "", "digests": { "md5": "1612076bc14e08627296c6f96cd55609", "sha256": "40167b05c757042e7693a647aa7de12dfe01715916961634c351c1a38f5a9074" }, "downloads": -1, "filename": "wr_profiles-4.2.1-py3-none-any.whl", "has_sig": false, "md5_digest": "1612076bc14e08627296c6f96cd55609", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 9734, "upload_time": "2018-11-05T11:55:19", "url": "https://files.pythonhosted.org/packages/db/97/044a5e3ee3f49266b9768f26c34a8d951f30b5553b5a28e0b03e6af9c1f8/wr_profiles-4.2.1-py3-none-any.whl" } ] }