{"action":"created","comment":{"url":"https://api.github.com/repos/sampsyo/confit/pulls/comments/28209060","id":28209060,"diff_hunk":"@@ -1,260 +1,427 @@\n Confit: Painless Configuration\n ==============================\n \n-`Confit`_ (*con-FEE*) is a straightforward, full-featured configuration system\n-for Python.\n+`Confit`_ (*con-FEE*) is a straightforward, full-featured configuration\n+library written in Python.\n \n .. _Confit: https://github.com/sampsyo/confit\n \n+When to Use Confit\n+------------------\n \n-Using Confit\n-------------\n+Confit abstracts the process of compiling a runtime configuration. In this\n+context, a configuration holds values that would otherwise be hard coded\n+into your application or library. Common examples include:\n \n-Set up your Configuration object, which provides unified access to\n-all of your application’s config settings::\n+- A host and port for a remote service.\n+- A username and password for a remote service.\n+- A port number to bind.\n+- A timeout in milliseconds.\n+- A path to a temporary directory.\n+- A log level.\n \n-    config = confit.Configuration('MyGreatApp', __name__)\n+Configurations are distinct from data, although the line is hard to define.\n+In our approximation, an application can run without data, but it cannot run\n+without a configuration. A configuration can be packaged and imported, but\n+data cannot.\n \n-The first parameter is required; it’s the name of your application that\n-will be used to search the system for config files. The second parameter\n-is optional: it’s the name of a module that will guide the search for a\n-*defaults* file. Use this if you want to include a\n-``config_default.yaml`` file inside your package. (The included\n-``example`` package does exactly this.)\n \n-Now, you can access your configuration data as if it were a simple\n-structure consisting of nested dicts and lists—except that you need to\n-call the method ``.get()`` on the leaf of this tree to get the result as\n-a value::\n+Features\n+--------\n \n-    value = config['foo'][2]['bar'].get()\n \n-Under the hood, accessing items in your configuration tree builds up a\n-*view* into your app’s configuration. Then, ``get()`` flattens this view\n-into a file, performing a search through each configuration data source\n-to find an answer. More on view later.\n+- Put your **default configuration in code** so that your application or\n+  library will run out of the box.\n+- Easily let your users **override the configuration** with **command-line\n+  arguments, environment variables, and configuration files in multiple\n+  formats**.\n+- Define your own **custom sources**, e.g., for reading configuration from a\n+  database.\n+- Choose a precedence order for **any number or combination of sources** that\n+  make sense for you.\n+- Easily **type check and validate** configuration overrides and emit **human\n+  readable errors** that point users to the offending overrides.\n+- Look for configuration files in **platform-specific paths** like\n+  ``$XDG_CONFIG_HOME`` or ``~/.config`` on Unix; ``Application Support`` on\n+  Mac OS X; and ``%APPDATA%`` on Windows.\n \n-If you know that a configuration value should have a specific type, just\n-pass that type to ``get()``::\n \n-    int_value = config['number_of_goats'].get(int)\n+Examples\n+--------\n \n-This way, Confit will either give you an integer or raise a\n-``ConfigTypeError`` if the user has messed up the configuration. You’re\n-safe to assume after this call that ``int_value`` has the right type. If\n-the key doesn’t exist in any configuration file, Confit will raise a\n-``NotFoundError``. Together, catching these exceptions (both subclasses\n-of ``confit.ConfigError``) lets you painlessly validate the user’s\n-configuration as you go.\n+Hello World\n+^^^^^^^^^^^\n \n+::\n \n-View Theory\n+  1| import confit\n+  2| default_config = confit.from_mapping({'greeting': 'Hello, world!'})\n+  3| sys_config = confit.from_yaml('/etc/example.yml')\n+  4| config = default_config + sys_config\n+  5| config['greeting'].get(str)\n+\n+Let's step through each line in this example:\n+\n+1. Import Confit.\n+2. Create a configuration from code---that is, from a mapping literal. It\n+   will serve as our default.\n+3. Read a configuration from a `YAML`_ file in the system configuration\n+   directory.\n+4. Compose the two configurations by laying the system configuration over the\n+   default configuration. Every variable in the system configuration will\n+   override the ones in the default.\n+5. Read a string variable from the configuration.\n+\n+.. _YAML: http://yaml.org/\n+\n+This example is just enough to get a taste for Confit. Details are explained\n+in later sections.\n+\n+\n+Git\n+^^^\n+\n+To demonstrate the full power of Confit, consider the `configuration model\n+for Git <http://git-scm.com/docs/git-config#FILES>`_.\n+\n+::\n+\n+  from_git_ini = lambda path: confit.from_ini(path, sep=\".\")\n+  sys_config = from_git_ini(confit.sys_config_path(\"git\", \"config\"))\n+  second_user_config = sum(map(from_git_ini, confit.user_config_paths(\"git\", \"config\")))\n+  first_user_config = from_git_ini(os.expanduser(\"~/.gitconfig\"))\n+  repo_config = from_git_ini(os.path.join(git_dir(), \"config\"))\n+  # Git takes configuration from environment variables with names different\n+  # from the configuration variables they map to. That requires some custom\n+  # (but simple) logic not built in to Confit. It is left as an exercise for\n+  # the reader.\n+  env_config = ...\n+  config = sum((defaults, sys_config, second_user_config, first_user_config, repo_config, env_config))\n+\n+\n+curl\n+^^^^\n+\n+Confit is useful for libraries in addition to applications. Consider libcurl,\n+which loads configuration from `~/.curlrc` and special environment variables\n+(`http_proxy`, `https_proxy`, `no_proxy`, etc). Libraries can use all the\n+facilities of Confit (with the exception of ``from_args``) to ease handling\n+of their configuration.\n+\n+\n+Configuration\n+-------------\n+\n+A configuration consists of variable bindings. In each new project, a\n+configuration is born when some variable holds an arbitrary value, e.g.  a\n+path to a temporary directory. The value is moved to the configuration as a\n+default, and the variable's value is loaded from the configuration.\n+\n+Variables\n+^^^^^^^^^\n+\n+In Confit, a configuration is an immutable mapping from string names to\n+*variables*. Variables have two methods, ``get`` and ``origin``.\n+\n+::\n+\n+  get(cast=lambda x: x)\n+\n+Call *cast* with the variable's value and return the result. *cast* is useful\n+for casting the value to a different type (i.e., \"get the value as a ___\").\n+*cast* may also check the value against some validity criteria, e.g. whether\n+a string can be parsed, or whether an integer fits within a range. If *cast*\n+raises an exception, then it will be wrapped in a ``ConfitCastError``, that,\n+if uncaught, will be pretty-printed to the console (using ``sys.excepthook``)\n+indicating both the failing call to ``get`` and the origin of the faulty\n+value::\n+\n+  /usr/bin/script:123:\n+      port = config['port'].get(is_not_privileged)\n+  failed on the override at /home/user/.example.yml:8:\n+  port: 80","path":"docs/index.rst","position":175,"original_position":175,"commit_id":"01be95dc47a204041183d48f68ab73eb042c8d58","original_commit_id":"6126b99a53e5a1ae4dc6e3a649ea0cb787715958","user":{"login":"thejohnfreeman","id":1133852,"avatar_url":"https://avatars.githubusercontent.com/u/1133852?v=3","gravatar_id":"","url":"https://api.github.com/users/thejohnfreeman","html_url":"https://github.com/thejohnfreeman","followers_url":"https://api.github.com/users/thejohnfreeman/followers","following_url":"https://api.github.com/users/thejohnfreeman/following{/other_user}","gists_url":"https://api.github.com/users/thejohnfreeman/gists{/gist_id}","starred_url":"https://api.github.com/users/thejohnfreeman/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/thejohnfreeman/subscriptions","organizations_url":"https://api.github.com/users/thejohnfreeman/orgs","repos_url":"https://api.github.com/users/thejohnfreeman/repos","events_url":"https://api.github.com/users/thejohnfreeman/events{/privacy}","received_events_url":"https://api.github.com/users/thejohnfreeman/received_events","type":"User","site_admin":false},"body":"I'm cool with that. Maybe we can include a function to register a standard pretty printing exception hook for the convenience of users who want it?","created_at":"2015-04-12T23:57:34Z","updated_at":"2015-04-12T23:57:34Z","html_url":"https://github.com/sampsyo/confit/pull/16#discussion_r28209060","pull_request_url":"https://api.github.com/repos/sampsyo/confit/pulls/16","_links":{"self":{"href":"https://api.github.com/repos/sampsyo/confit/pulls/comments/28209060"},"html":{"href":"https://github.com/sampsyo/confit/pull/16#discussion_r28209060"},"pull_request":{"href":"https://api.github.com/repos/sampsyo/confit/pulls/16"}}},"pull_request":{"url":"https://api.github.com/repos/sampsyo/confit/pulls/16","id":33009018,"html_url":"https://github.com/sampsyo/confit/pull/16","diff_url":"https://github.com/sampsyo/confit/pull/16.diff","patch_url":"https://github.com/sampsyo/confit/pull/16.patch","issue_url":"https://api.github.com/repos/sampsyo/confit/issues/16","number":16,"state":"open","locked":false,"title":"doc: proposed design","user":{"login":"thejohnfreeman","id":1133852,"avatar_url":"https://avatars.githubusercontent.com/u/1133852?v=3","gravatar_id":"","url":"https://api.github.com/users/thejohnfreeman","html_url":"https://github.com/thejohnfreeman","followers_url":"https://api.github.com/users/thejohnfreeman/followers","following_url":"https://api.github.com/users/thejohnfreeman/following{/other_user}","gists_url":"https://api.github.com/users/thejohnfreeman/gists{/gist_id}","starred_url":"https://api.github.com/users/thejohnfreeman/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/thejohnfreeman/subscriptions","organizations_url":"https://api.github.com/users/thejohnfreeman/orgs","repos_url":"https://api.github.com/users/thejohnfreeman/repos","events_url":"https://api.github.com/users/thejohnfreeman/events{/privacy}","received_events_url":"https://api.github.com/users/thejohnfreeman/received_events","type":"User","site_admin":false},"body":"I moved the changes to a branch, killing the old pull request. This way you can rebase onto master for a clean log if you want.","created_at":"2015-04-10T00:25:15Z","updated_at":"2015-04-12T23:57:34Z","closed_at":null,"merged_at":null,"merge_commit_sha":"47cf235d1ecc21713bb86c1f8d3a54cc9fc02aa9","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/sampsyo/confit/pulls/16/commits","review_comments_url":"https://api.github.com/repos/sampsyo/confit/pulls/16/comments","review_comment_url":"https://api.github.com/repos/sampsyo/confit/pulls/comments{/number}","comments_url":"https://api.github.com/repos/sampsyo/confit/issues/16/comments","statuses_url":"https://api.github.com/repos/sampsyo/confit/statuses/01be95dc47a204041183d48f68ab73eb042c8d58","head":{"label":"thejohnfreeman:v2","ref":"v2","sha":"01be95dc47a204041183d48f68ab73eb042c8d58","user":{"login":"thejohnfreeman","id":1133852,"avatar_url":"https://avatars.githubusercontent.com/u/1133852?v=3","gravatar_id":"","url":"https://api.github.com/users/thejohnfreeman","html_url":"https://github.com/thejohnfreeman","followers_url":"https://api.github.com/users/thejohnfreeman/followers","following_url":"https://api.github.com/users/thejohnfreeman/following{/other_user}","gists_url":"https://api.github.com/users/thejohnfreeman/gists{/gist_id}","starred_url":"https://api.github.com/users/thejohnfreeman/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/thejohnfreeman/subscriptions","organizations_url":"https://api.github.com/users/thejohnfreeman/orgs","repos_url":"https://api.github.com/users/thejohnfreeman/repos","events_url":"https://api.github.com/users/thejohnfreeman/events{/privacy}","received_events_url":"https://api.github.com/users/thejohnfreeman/received_events","type":"User","site_admin":false},"repo":{"id":33448005,"name":"confit","full_name":"thejohnfreeman/confit","owner":{"login":"thejohnfreeman","id":1133852,"avatar_url":"https://avatars.githubusercontent.com/u/1133852?v=3","gravatar_id":"","url":"https://api.github.com/users/thejohnfreeman","html_url":"https://github.com/thejohnfreeman","followers_url":"https://api.github.com/users/thejohnfreeman/followers","following_url":"https://api.github.com/users/thejohnfreeman/following{/other_user}","gists_url":"https://api.github.com/users/thejohnfreeman/gists{/gist_id}","starred_url":"https://api.github.com/users/thejohnfreeman/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/thejohnfreeman/subscriptions","organizations_url":"https://api.github.com/users/thejohnfreeman/orgs","repos_url":"https://api.github.com/users/thejohnfreeman/repos","events_url":"https://api.github.com/users/thejohnfreeman/events{/privacy}","received_events_url":"https://api.github.com/users/thejohnfreeman/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/thejohnfreeman/confit","description":"painless YAML config files that Just Work (for Python)","fork":true,"url":"https://api.github.com/repos/thejohnfreeman/confit","forks_url":"https://api.github.com/repos/thejohnfreeman/confit/forks","keys_url":"https://api.github.com/repos/thejohnfreeman/confit/keys{/key_id}","collaborators_url":"https://api.github.com/repos/thejohnfreeman/confit/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/thejohnfreeman/confit/teams","hooks_url":"https://api.github.com/repos/thejohnfreeman/confit/hooks","issue_events_url":"https://api.github.com/repos/thejohnfreeman/confit/issues/events{/number}","events_url":"https://api.github.com/repos/thejohnfreeman/confit/events","assignees_url":"https://api.github.com/repos/thejohnfreeman/confit/assignees{/user}","branches_url":"https://api.github.com/repos/thejohnfreeman/confit/branches{/branch}","tags_url":"https://api.github.com/repos/thejohnfreeman/confit/tags","blobs_url":"https://api.github.com/repos/thejohnfreeman/confit/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/thejohnfreeman/confit/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/thejohnfreeman/confit/git/refs{/sha}","trees_url":"https://api.github.com/repos/thejohnfreeman/confit/git/trees{/sha}","statuses_url":"https://api.github.com/repos/thejohnfreeman/confit/statuses/{sha}","languages_url":"https://api.github.com/repos/thejohnfreeman/confit/languages","stargazers_url":"https://api.github.com/repos/thejohnfreeman/confit/stargazers","contributors_url":"https://api.github.com/repos/thejohnfreeman/confit/contributors","subscribers_url":"https://api.github.com/repos/thejohnfreeman/confit/subscribers","subscription_url":"https://api.github.com/repos/thejohnfreeman/confit/subscription","commits_url":"https://api.github.com/repos/thejohnfreeman/confit/commits{/sha}","git_commits_url":"https://api.github.com/repos/thejohnfreeman/confit/git/commits{/sha}","comments_url":"https://api.github.com/repos/thejohnfreeman/confit/comments{/number}","issue_comment_url":"https://api.github.com/repos/thejohnfreeman/confit/issues/comments{/number}","contents_url":"https://api.github.com/repos/thejohnfreeman/confit/contents/{+path}","compare_url":"https://api.github.com/repos/thejohnfreeman/confit/compare/{base}...{head}","merges_url":"https://api.github.com/repos/thejohnfreeman/confit/merges","archive_url":"https://api.github.com/repos/thejohnfreeman/confit/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/thejohnfreeman/confit/downloads","issues_url":"https://api.github.com/repos/thejohnfreeman/confit/issues{/number}","pulls_url":"https://api.github.com/repos/thejohnfreeman/confit/pulls{/number}","milestones_url":"https://api.github.com/repos/thejohnfreeman/confit/milestones{/number}","notifications_url":"https://api.github.com/repos/thejohnfreeman/confit/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/thejohnfreeman/confit/labels{/name}","releases_url":"https://api.github.com/repos/thejohnfreeman/confit/releases{/id}","created_at":"2015-04-05T16:56:36Z","updated_at":"2015-04-10T00:14:45Z","pushed_at":"2015-04-12T16:49:53Z","git_url":"git://github.com/thejohnfreeman/confit.git","ssh_url":"git@github.com:thejohnfreeman/confit.git","clone_url":"https://github.com/thejohnfreeman/confit.git","svn_url":"https://github.com/thejohnfreeman/confit","homepage":"","size":268,"stargazers_count":0,"watchers_count":0,"language":"Python","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"sampsyo:master","ref":"master","sha":"1cf047abdd61ec0112230e1fcf0bbb72afa374ff","user":{"login":"sampsyo","id":188033,"avatar_url":"https://avatars.githubusercontent.com/u/188033?v=3","gravatar_id":"","url":"https://api.github.com/users/sampsyo","html_url":"https://github.com/sampsyo","followers_url":"https://api.github.com/users/sampsyo/followers","following_url":"https://api.github.com/users/sampsyo/following{/other_user}","gists_url":"https://api.github.com/users/sampsyo/gists{/gist_id}","starred_url":"https://api.github.com/users/sampsyo/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sampsyo/subscriptions","organizations_url":"https://api.github.com/users/sampsyo/orgs","repos_url":"https://api.github.com/users/sampsyo/repos","events_url":"https://api.github.com/users/sampsyo/events{/privacy}","received_events_url":"https://api.github.com/users/sampsyo/received_events","type":"User","site_admin":false},"repo":{"id":3331516,"name":"confit","full_name":"sampsyo/confit","owner":{"login":"sampsyo","id":188033,"avatar_url":"https://avatars.githubusercontent.com/u/188033?v=3","gravatar_id":"","url":"https://api.github.com/users/sampsyo","html_url":"https://github.com/sampsyo","followers_url":"https://api.github.com/users/sampsyo/followers","following_url":"https://api.github.com/users/sampsyo/following{/other_user}","gists_url":"https://api.github.com/users/sampsyo/gists{/gist_id}","starred_url":"https://api.github.com/users/sampsyo/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sampsyo/subscriptions","organizations_url":"https://api.github.com/users/sampsyo/orgs","repos_url":"https://api.github.com/users/sampsyo/repos","events_url":"https://api.github.com/users/sampsyo/events{/privacy}","received_events_url":"https://api.github.com/users/sampsyo/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/sampsyo/confit","description":"painless YAML config files that Just Work (for Python)","fork":false,"url":"https://api.github.com/repos/sampsyo/confit","forks_url":"https://api.github.com/repos/sampsyo/confit/forks","keys_url":"https://api.github.com/repos/sampsyo/confit/keys{/key_id}","collaborators_url":"https://api.github.com/repos/sampsyo/confit/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/sampsyo/confit/teams","hooks_url":"https://api.github.com/repos/sampsyo/confit/hooks","issue_events_url":"https://api.github.com/repos/sampsyo/confit/issues/events{/number}","events_url":"https://api.github.com/repos/sampsyo/confit/events","assignees_url":"https://api.github.com/repos/sampsyo/confit/assignees{/user}","branches_url":"https://api.github.com/repos/sampsyo/confit/branches{/branch}","tags_url":"https://api.github.com/repos/sampsyo/confit/tags","blobs_url":"https://api.github.com/repos/sampsyo/confit/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/sampsyo/confit/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/sampsyo/confit/git/refs{/sha}","trees_url":"https://api.github.com/repos/sampsyo/confit/git/trees{/sha}","statuses_url":"https://api.github.com/repos/sampsyo/confit/statuses/{sha}","languages_url":"https://api.github.com/repos/sampsyo/confit/languages","stargazers_url":"https://api.github.com/repos/sampsyo/confit/stargazers","contributors_url":"https://api.github.com/repos/sampsyo/confit/contributors","subscribers_url":"https://api.github.com/repos/sampsyo/confit/subscribers","subscription_url":"https://api.github.com/repos/sampsyo/confit/subscription","commits_url":"https://api.github.com/repos/sampsyo/confit/commits{/sha}","git_commits_url":"https://api.github.com/repos/sampsyo/confit/git/commits{/sha}","comments_url":"https://api.github.com/repos/sampsyo/confit/comments{/number}","issue_comment_url":"https://api.github.com/repos/sampsyo/confit/issues/comments{/number}","contents_url":"https://api.github.com/repos/sampsyo/confit/contents/{+path}","compare_url":"https://api.github.com/repos/sampsyo/confit/compare/{base}...{head}","merges_url":"https://api.github.com/repos/sampsyo/confit/merges","archive_url":"https://api.github.com/repos/sampsyo/confit/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/sampsyo/confit/downloads","issues_url":"https://api.github.com/repos/sampsyo/confit/issues{/number}","pulls_url":"https://api.github.com/repos/sampsyo/confit/pulls{/number}","milestones_url":"https://api.github.com/repos/sampsyo/confit/milestones{/number}","notifications_url":"https://api.github.com/repos/sampsyo/confit/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/sampsyo/confit/labels{/name}","releases_url":"https://api.github.com/repos/sampsyo/confit/releases{/id}","created_at":"2012-02-02T03:16:05Z","updated_at":"2015-03-29T21:29:43Z","pushed_at":"2015-04-12T16:49:54Z","git_url":"git://github.com/sampsyo/confit.git","ssh_url":"git@github.com:sampsyo/confit.git","clone_url":"https://github.com/sampsyo/confit.git","svn_url":"https://github.com/sampsyo/confit","homepage":"","size":553,"stargazers_count":13,"watchers_count":13,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":6,"mirror_url":null,"open_issues_count":10,"forks":6,"open_issues":10,"watchers":13,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/sampsyo/confit/pulls/16"},"html":{"href":"https://github.com/sampsyo/confit/pull/16"},"issue":{"href":"https://api.github.com/repos/sampsyo/confit/issues/16"},"comments":{"href":"https://api.github.com/repos/sampsyo/confit/issues/16/comments"},"review_comments":{"href":"https://api.github.com/repos/sampsyo/confit/pulls/16/comments"},"review_comment":{"href":"https://api.github.com/repos/sampsyo/confit/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/sampsyo/confit/pulls/16/commits"},"statuses":{"href":"https://api.github.com/repos/sampsyo/confit/statuses/01be95dc47a204041183d48f68ab73eb042c8d58"}}}}