{"action":"created","comment":{"url":"https://api.github.com/repos/pypa/interoperability-peps/pulls/comments/45142288","id":45142288,"diff_hunk":"@@ -0,0 +1,543 @@\n+:PEP: XX\n+:Title: Dependency specification for Python Software Packages\n+:Version: $Revision$\n+:Last-Modified: $Date$\n+:Author: Robert Collins <rbtcollins@hp.com>\n+:BDFL-Delegate: Donald Stufft <donald@stufft.io>\n+:Discussions-To: distutils-sig <distutils-sig@python.org>\n+:Status: Draft\n+:Type: Standards Track\n+:Content-Type: text/x-rst\n+:Created: 11-Nov-2015\n+:Post-History: XX\n+\n+\n+Abstract\n+========\n+\n+This PEP specifies the language used to describe dependencies for packages.\n+It draws a border at the edge of describing a single dependency - the\n+different sorts of dependencies and when they should be installed is a higher\n+level problem. The intent is provide a building block for higher layer\n+specifications.\n+\n+The job of a dependency is to enable tools like pip [#pip]_ to find the right\n+package to install. Sometimes this is very loose - just specifying a name, and\n+sometimes very specific - referring to a specific file to install. Sometimes\n+dependencies are only relevant in one platform, or only some versions are\n+acceptable, so the language permits describing all these cases.\n+\n+The language defined is a compact line based format which is already in\n+widespread use in pip requirements files, though we do not specify the command\n+line option handling that those files permit. There is one caveat - the\n+URL reference form, specified in PEP-440 [#pep440]_ is not actually\n+implemented in pip, but since PEP-440 is accepted, we use that format rather\n+than pip's current native format.\n+\n+Motivation\n+==========\n+\n+Any specification in the Python packaging ecosystem that needs to consume\n+lists of dependencies needs to build on an approved PEP for such, but\n+PEP-426 [#pep426]_ is mostly aspirational - and there are already existing\n+implementations of the dependency specification which we can instead adopt.\n+The existing implementations are battle proven and user friendly, so adopting\n+them is arguably much better than approving an aspirational, unconsumed, format.\n+\n+Specification\n+=============\n+\n+Examples\n+--------\n+\n+All features of the language shown with a name based lookup::\n+\n+    requests [security,tests] >= 2.8.1, == 2.8.* ; python_version < \"2.7.10\"\n+\n+A minimal URL based lookup::\n+\n+    pip @ https://github.com/pypa/pip/archive/1.3.1.zip#sha1=da9234ee9982d4bbb3c72346a6de940a148ea686\n+\n+Concepts\n+--------\n+\n+A dependency specification always specifies a distribution name. It may\n+include extras, which expand the dependencies of the named distribution to\n+enable optional features. The version installed can be controlled using\n+version limits, or giving the URL to a specific artifact to install. Finally\n+the dependency can be made conditional using environment markers.\n+\n+Grammar\n+-------\n+\n+We first cover the grammar briefly and then drill into the semantics of each\n+section later.\n+\n+A distribution specification is written in ASCII text. We use a parsley\n+[#parsley]_ grammar to provide a precise grammar. It is expected that the\n+specification will be embedded into a larger system which offers framing such\n+as comments, multiple line support via continuations, or other such features.\n+\n+The full grammar including annotations to build a useful parse tree is\n+included at the end of the PEP.\n+\n+Versions may be specified according to the PEP-440 [#pep440]_ rules. (Note:\n+URI is defined in std-66 [#std66]_::\n+\n+    version_cmp   = wsp* '<' | '<=' | '!=' | '==' | '>=' | '>' | '~=' | '==='\n+    version       = wsp* ( letterOrDigit | '-' | '_' | '.' | '*' )+\n+    version_one   = version_cmp version wsp*\n+    version_many  = version_one (wsp* ',' version_one)*\n+    versionspec   = ( '(' version_many ')' ) | version_many\n+    urlspec       = '@' wsp* <URI_reference>\n+\n+Environment markers allow making a specification only take effect in some\n+environments::\n+\n+    marker_op     = version_cmp | 'in' | 'not' wsp+ 'in'\n+    python_str_c  = (wsp | letter | digit | '(' | ')' | '.' | '{' | '}' |\n+                     '-' | '_' | '*')\n+    dquote        = '\"'\n+    squote        = '\\\\''\n+    python_str    = (squote (python_str_c | dquote)* squote |\n+                     dquote (python_str_c | squote)* dquote)\n+    env_var       = ('python_version' | 'python_full_version' |\n+                     'os_name' | 'sys_platform' | 'platform_release' |\n+                     'platform_system' | 'platform_version' |\n+                     'platform_machine' | 'python_implementation' |\n+                     'implementation_name' | 'implementation_version' |\n+                     'extra' # ONLY when defined by a containing layer\n+                     )\n+    marker_var    = env_var | python_str\n+    marker_expr   = ('(' wsp* marker wsp* ')'\n+                     | (marker_var wsp* marker_op wsp* marker_var))\n+    marker        = wsp* marker_expr ( wsp* ('and' | 'or') wsp* marker_expr)*\n+    quoted_marker = ';' wsp* marker\n+\n+Optional components of a distribution may be specified using the extras\n+field::\n+\n+    identifier    = letterOrDigit (\n+                    letterOrDigit |\n+                    (( letterOrDigit | '-' | '_' | '.')* letterOrDigit ) )*\n+    name          = identifier\n+    extras_list   = identifier (wsp* ',' wsp* identifier)*\n+    extras        = '[' wsp* extras_list? wsp* ']'\n+\n+Giving us a rule for name based requirements::\n+\n+    name_req      = name wsp* extras? wsp* versionspec? wsp* quoted_marker?\n+\n+And a rule for direct reference specifications::\n+\n+    url_req       = name wsp* extras? wsp* urlspec wsp+ quoted_marker?\n+\n+Leading to the unified rule that can specify a dependency.::\n+\n+    specification = wsp* ( url_req | name_req ) wsp*\n+\n+Whitespace\n+----------\n+\n+Non line-breaking whitespace is mostly optional with no semantic meaning. The\n+sole exception is detecting the end of a URL requirement.\n+\n+Names\n+-----\n+\n+Python distribution names are currently defined in PEP-345 [#pep345]_. Names\n+act as the primary identifier for distributions. They are present in all\n+dependency specifications, and are sufficient to be a specification on their\n+own. However, PyPI places strict restrictions on names - they must match a\n+case insensitive regex or they won't be accepted. Accordingly in this PEP we\n+limit the acceptable values for identifiers to that regex. A full redefinition\n+of name may take place in a future metadata PEP::\n+\n+    ^([A-Z0-9]|[A-Z0-9][A-Z0-9._-]*[A-Z0-9])$","path":"dependency-specification.rst","position":162,"original_position":156,"commit_id":"9beb2930707bf95433ef6f32c0e80e891fc10c5c","original_commit_id":"9812e3e7fb759f09b1020f4adaa529cf4c16a378","user":{"login":"ncoghlan","id":1026649,"avatar_url":"https://avatars.githubusercontent.com/u/1026649?v=3","gravatar_id":"","url":"https://api.github.com/users/ncoghlan","html_url":"https://github.com/ncoghlan","followers_url":"https://api.github.com/users/ncoghlan/followers","following_url":"https://api.github.com/users/ncoghlan/following{/other_user}","gists_url":"https://api.github.com/users/ncoghlan/gists{/gist_id}","starred_url":"https://api.github.com/users/ncoghlan/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ncoghlan/subscriptions","organizations_url":"https://api.github.com/users/ncoghlan/orgs","repos_url":"https://api.github.com/users/ncoghlan/repos","events_url":"https://api.github.com/users/ncoghlan/events{/privacy}","received_events_url":"https://api.github.com/users/ncoghlan/received_events","type":"User","site_admin":false},"body":"It's easy to miss the pipe operator in the middle there. The LHS is special casing single alphanumeric character distribution names (which are weird, but technically permitted), the RHS is the more typical case of \"2+ characters, must start and end with an alphanumeric character, may contain periods, hyphens and underscores\".","created_at":"2015-11-18T00:10:01Z","updated_at":"2015-11-18T00:10:01Z","html_url":"https://github.com/pypa/interoperability-peps/pull/56#discussion_r45142288","pull_request_url":"https://api.github.com/repos/pypa/interoperability-peps/pulls/56","_links":{"self":{"href":"https://api.github.com/repos/pypa/interoperability-peps/pulls/comments/45142288"},"html":{"href":"https://github.com/pypa/interoperability-peps/pull/56#discussion_r45142288"},"pull_request":{"href":"https://api.github.com/repos/pypa/interoperability-peps/pulls/56"}}},"pull_request":{"url":"https://api.github.com/repos/pypa/interoperability-peps/pulls/56","id":49912435,"html_url":"https://github.com/pypa/interoperability-peps/pull/56","diff_url":"https://github.com/pypa/interoperability-peps/pull/56.diff","patch_url":"https://github.com/pypa/interoperability-peps/pull/56.patch","issue_url":"https://api.github.com/repos/pypa/interoperability-peps/issues/56","number":56,"state":"open","locked":false,"title":"Define dependency specifications formally.","user":{"login":"rbtcollins","id":499678,"avatar_url":"https://avatars.githubusercontent.com/u/499678?v=3","gravatar_id":"","url":"https://api.github.com/users/rbtcollins","html_url":"https://github.com/rbtcollins","followers_url":"https://api.github.com/users/rbtcollins/followers","following_url":"https://api.github.com/users/rbtcollins/following{/other_user}","gists_url":"https://api.github.com/users/rbtcollins/gists{/gist_id}","starred_url":"https://api.github.com/users/rbtcollins/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rbtcollins/subscriptions","organizations_url":"https://api.github.com/users/rbtcollins/orgs","repos_url":"https://api.github.com/users/rbtcollins/repos","events_url":"https://api.github.com/users/rbtcollins/events{/privacy}","received_events_url":"https://api.github.com/users/rbtcollins/received_events","type":"User","site_admin":false},"body":"\n\n<!-- Reviewable:start -->\n[<img src=\"https://reviewable.io/review_button.png\" height=40 alt=\"Review on Reviewable\"/>](https://reviewable.io/reviews/pypa/interoperability-peps/56)\n<!-- Reviewable:end -->\n","created_at":"2015-11-06T03:28:26Z","updated_at":"2015-11-18T00:10:01Z","closed_at":null,"merged_at":null,"merge_commit_sha":"199aea8ccf841de494dcf222941611614854a48a","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/pypa/interoperability-peps/pulls/56/commits","review_comments_url":"https://api.github.com/repos/pypa/interoperability-peps/pulls/56/comments","review_comment_url":"https://api.github.com/repos/pypa/interoperability-peps/pulls/comments{/number}","comments_url":"https://api.github.com/repos/pypa/interoperability-peps/issues/56/comments","statuses_url":"https://api.github.com/repos/pypa/interoperability-peps/statuses/9beb2930707bf95433ef6f32c0e80e891fc10c5c","head":{"label":"rbtcollins:dependency","ref":"dependency","sha":"9beb2930707bf95433ef6f32c0e80e891fc10c5c","user":{"login":"rbtcollins","id":499678,"avatar_url":"https://avatars.githubusercontent.com/u/499678?v=3","gravatar_id":"","url":"https://api.github.com/users/rbtcollins","html_url":"https://github.com/rbtcollins","followers_url":"https://api.github.com/users/rbtcollins/followers","following_url":"https://api.github.com/users/rbtcollins/following{/other_user}","gists_url":"https://api.github.com/users/rbtcollins/gists{/gist_id}","starred_url":"https://api.github.com/users/rbtcollins/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rbtcollins/subscriptions","organizations_url":"https://api.github.com/users/rbtcollins/orgs","repos_url":"https://api.github.com/users/rbtcollins/repos","events_url":"https://api.github.com/users/rbtcollins/events{/privacy}","received_events_url":"https://api.github.com/users/rbtcollins/received_events","type":"User","site_admin":false},"repo":{"id":40106828,"name":"interoperability-peps","full_name":"rbtcollins/interoperability-peps","owner":{"login":"rbtcollins","id":499678,"avatar_url":"https://avatars.githubusercontent.com/u/499678?v=3","gravatar_id":"","url":"https://api.github.com/users/rbtcollins","html_url":"https://github.com/rbtcollins","followers_url":"https://api.github.com/users/rbtcollins/followers","following_url":"https://api.github.com/users/rbtcollins/following{/other_user}","gists_url":"https://api.github.com/users/rbtcollins/gists{/gist_id}","starred_url":"https://api.github.com/users/rbtcollins/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rbtcollins/subscriptions","organizations_url":"https://api.github.com/users/rbtcollins/orgs","repos_url":"https://api.github.com/users/rbtcollins/repos","events_url":"https://api.github.com/users/rbtcollins/events{/privacy}","received_events_url":"https://api.github.com/users/rbtcollins/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/rbtcollins/interoperability-peps","description":"Development repo for evolution of PyPA interoperability standards (released versions are published as PEPs on python.org)","fork":true,"url":"https://api.github.com/repos/rbtcollins/interoperability-peps","forks_url":"https://api.github.com/repos/rbtcollins/interoperability-peps/forks","keys_url":"https://api.github.com/repos/rbtcollins/interoperability-peps/keys{/key_id}","collaborators_url":"https://api.github.com/repos/rbtcollins/interoperability-peps/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/rbtcollins/interoperability-peps/teams","hooks_url":"https://api.github.com/repos/rbtcollins/interoperability-peps/hooks","issue_events_url":"https://api.github.com/repos/rbtcollins/interoperability-peps/issues/events{/number}","events_url":"https://api.github.com/repos/rbtcollins/interoperability-peps/events","assignees_url":"https://api.github.com/repos/rbtcollins/interoperability-peps/assignees{/user}","branches_url":"https://api.github.com/repos/rbtcollins/interoperability-peps/branches{/branch}","tags_url":"https://api.github.com/repos/rbtcollins/interoperability-peps/tags","blobs_url":"https://api.github.com/repos/rbtcollins/interoperability-peps/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/rbtcollins/interoperability-peps/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/rbtcollins/interoperability-peps/git/refs{/sha}","trees_url":"https://api.github.com/repos/rbtcollins/interoperability-peps/git/trees{/sha}","statuses_url":"https://api.github.com/repos/rbtcollins/interoperability-peps/statuses/{sha}","languages_url":"https://api.github.com/repos/rbtcollins/interoperability-peps/languages","stargazers_url":"https://api.github.com/repos/rbtcollins/interoperability-peps/stargazers","contributors_url":"https://api.github.com/repos/rbtcollins/interoperability-peps/contributors","subscribers_url":"https://api.github.com/repos/rbtcollins/interoperability-peps/subscribers","subscription_url":"https://api.github.com/repos/rbtcollins/interoperability-peps/subscription","commits_url":"https://api.github.com/repos/rbtcollins/interoperability-peps/commits{/sha}","git_commits_url":"https://api.github.com/repos/rbtcollins/interoperability-peps/git/commits{/sha}","comments_url":"https://api.github.com/repos/rbtcollins/interoperability-peps/comments{/number}","issue_comment_url":"https://api.github.com/repos/rbtcollins/interoperability-peps/issues/comments{/number}","contents_url":"https://api.github.com/repos/rbtcollins/interoperability-peps/contents/{+path}","compare_url":"https://api.github.com/repos/rbtcollins/interoperability-peps/compare/{base}...{head}","merges_url":"https://api.github.com/repos/rbtcollins/interoperability-peps/merges","archive_url":"https://api.github.com/repos/rbtcollins/interoperability-peps/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/rbtcollins/interoperability-peps/downloads","issues_url":"https://api.github.com/repos/rbtcollins/interoperability-peps/issues{/number}","pulls_url":"https://api.github.com/repos/rbtcollins/interoperability-peps/pulls{/number}","milestones_url":"https://api.github.com/repos/rbtcollins/interoperability-peps/milestones{/number}","notifications_url":"https://api.github.com/repos/rbtcollins/interoperability-peps/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/rbtcollins/interoperability-peps/labels{/name}","releases_url":"https://api.github.com/repos/rbtcollins/interoperability-peps/releases{/id}","created_at":"2015-08-03T05:36:56Z","updated_at":"2015-08-03T05:36:56Z","pushed_at":"2015-11-17T23:21:20Z","git_url":"git://github.com/rbtcollins/interoperability-peps.git","ssh_url":"git@github.com:rbtcollins/interoperability-peps.git","clone_url":"https://github.com/rbtcollins/interoperability-peps.git","svn_url":"https://github.com/rbtcollins/interoperability-peps","homepage":null,"size":24520,"stargazers_count":0,"watchers_count":0,"language":"Python","has_issues":false,"has_downloads":true,"has_wiki":false,"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":"pypa:master","ref":"master","sha":"c7a900d5f8f7ef5a5e5b4b109219eb0ac37e562e","user":{"login":"pypa","id":647025,"avatar_url":"https://avatars.githubusercontent.com/u/647025?v=3","gravatar_id":"","url":"https://api.github.com/users/pypa","html_url":"https://github.com/pypa","followers_url":"https://api.github.com/users/pypa/followers","following_url":"https://api.github.com/users/pypa/following{/other_user}","gists_url":"https://api.github.com/users/pypa/gists{/gist_id}","starred_url":"https://api.github.com/users/pypa/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/pypa/subscriptions","organizations_url":"https://api.github.com/users/pypa/orgs","repos_url":"https://api.github.com/users/pypa/repos","events_url":"https://api.github.com/users/pypa/events{/privacy}","received_events_url":"https://api.github.com/users/pypa/received_events","type":"Organization","site_admin":false},"repo":{"id":28580365,"name":"interoperability-peps","full_name":"pypa/interoperability-peps","owner":{"login":"pypa","id":647025,"avatar_url":"https://avatars.githubusercontent.com/u/647025?v=3","gravatar_id":"","url":"https://api.github.com/users/pypa","html_url":"https://github.com/pypa","followers_url":"https://api.github.com/users/pypa/followers","following_url":"https://api.github.com/users/pypa/following{/other_user}","gists_url":"https://api.github.com/users/pypa/gists{/gist_id}","starred_url":"https://api.github.com/users/pypa/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/pypa/subscriptions","organizations_url":"https://api.github.com/users/pypa/orgs","repos_url":"https://api.github.com/users/pypa/repos","events_url":"https://api.github.com/users/pypa/events{/privacy}","received_events_url":"https://api.github.com/users/pypa/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/pypa/interoperability-peps","description":"Development repo for evolution of PyPA interoperability standards (released versions are published as PEPs on python.org)","fork":false,"url":"https://api.github.com/repos/pypa/interoperability-peps","forks_url":"https://api.github.com/repos/pypa/interoperability-peps/forks","keys_url":"https://api.github.com/repos/pypa/interoperability-peps/keys{/key_id}","collaborators_url":"https://api.github.com/repos/pypa/interoperability-peps/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/pypa/interoperability-peps/teams","hooks_url":"https://api.github.com/repos/pypa/interoperability-peps/hooks","issue_events_url":"https://api.github.com/repos/pypa/interoperability-peps/issues/events{/number}","events_url":"https://api.github.com/repos/pypa/interoperability-peps/events","assignees_url":"https://api.github.com/repos/pypa/interoperability-peps/assignees{/user}","branches_url":"https://api.github.com/repos/pypa/interoperability-peps/branches{/branch}","tags_url":"https://api.github.com/repos/pypa/interoperability-peps/tags","blobs_url":"https://api.github.com/repos/pypa/interoperability-peps/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/pypa/interoperability-peps/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/pypa/interoperability-peps/git/refs{/sha}","trees_url":"https://api.github.com/repos/pypa/interoperability-peps/git/trees{/sha}","statuses_url":"https://api.github.com/repos/pypa/interoperability-peps/statuses/{sha}","languages_url":"https://api.github.com/repos/pypa/interoperability-peps/languages","stargazers_url":"https://api.github.com/repos/pypa/interoperability-peps/stargazers","contributors_url":"https://api.github.com/repos/pypa/interoperability-peps/contributors","subscribers_url":"https://api.github.com/repos/pypa/interoperability-peps/subscribers","subscription_url":"https://api.github.com/repos/pypa/interoperability-peps/subscription","commits_url":"https://api.github.com/repos/pypa/interoperability-peps/commits{/sha}","git_commits_url":"https://api.github.com/repos/pypa/interoperability-peps/git/commits{/sha}","comments_url":"https://api.github.com/repos/pypa/interoperability-peps/comments{/number}","issue_comment_url":"https://api.github.com/repos/pypa/interoperability-peps/issues/comments{/number}","contents_url":"https://api.github.com/repos/pypa/interoperability-peps/contents/{+path}","compare_url":"https://api.github.com/repos/pypa/interoperability-peps/compare/{base}...{head}","merges_url":"https://api.github.com/repos/pypa/interoperability-peps/merges","archive_url":"https://api.github.com/repos/pypa/interoperability-peps/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/pypa/interoperability-peps/downloads","issues_url":"https://api.github.com/repos/pypa/interoperability-peps/issues{/number}","pulls_url":"https://api.github.com/repos/pypa/interoperability-peps/pulls{/number}","milestones_url":"https://api.github.com/repos/pypa/interoperability-peps/milestones{/number}","notifications_url":"https://api.github.com/repos/pypa/interoperability-peps/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/pypa/interoperability-peps/labels{/name}","releases_url":"https://api.github.com/repos/pypa/interoperability-peps/releases{/id}","created_at":"2014-12-29T04:35:09Z","updated_at":"2015-11-08T08:27:19Z","pushed_at":"2015-11-17T23:21:26Z","git_url":"git://github.com/pypa/interoperability-peps.git","ssh_url":"git@github.com:pypa/interoperability-peps.git","clone_url":"https://github.com/pypa/interoperability-peps.git","svn_url":"https://github.com/pypa/interoperability-peps","homepage":null,"size":24576,"stargazers_count":7,"watchers_count":7,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":8,"mirror_url":null,"open_issues_count":33,"forks":8,"open_issues":33,"watchers":7,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/pypa/interoperability-peps/pulls/56"},"html":{"href":"https://github.com/pypa/interoperability-peps/pull/56"},"issue":{"href":"https://api.github.com/repos/pypa/interoperability-peps/issues/56"},"comments":{"href":"https://api.github.com/repos/pypa/interoperability-peps/issues/56/comments"},"review_comments":{"href":"https://api.github.com/repos/pypa/interoperability-peps/pulls/56/comments"},"review_comment":{"href":"https://api.github.com/repos/pypa/interoperability-peps/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/pypa/interoperability-peps/pulls/56/commits"},"statuses":{"href":"https://api.github.com/repos/pypa/interoperability-peps/statuses/9beb2930707bf95433ef6f32c0e80e891fc10c5c"}}}}