Repository: pypi/warehouse

Issue:
[Request] Package documentation link(s)
I'm following up [this issue on ReadTheDocs about browsing docs offline with 3rd party apps](https://github.com/rtfd/readthedocs.org/issues/662) - it looks like no one asked anyone here for help, but the issue is still outstanding.

There's currently no way to map from here to documentation in a format other applications can use. Details of why this would be useful are in the above ticket, but essentially there are examples of documentation names being different to the package names.

`pypi-legacy` accepts three URLs from a user, `Home page`, `Download URL` and `Bugtrack url`. `warehouse` only takes `url`, meant for the homepage.

Is there room for optional documentation URLs (plural as docs may be in multiple places and a user can choose which they prefer)?

[Also on pypi-legacy here](https://github.com/pypa/pypi-legacy/issues/501), as I'm not sure if this would be applied to `pypi-legacy` or kept for `warehouse`.



Discussion:
Well warehouse takes Home page and download URL both currently. Both Warehouse and legacy also support arbitrary "Project URLs" which are essentially Name: URL pairs like: `"Documentation", "https://docs.pypi.org/"`, however setuptools doesn't currently expose a way to add those.

I may be wrong, but I think leaving it to a custom Project URL means developers won't include a documentation URL - there's no habit formed for including docs in Legacy, and there's no field there to serve as a reminder or indication that this could now be done, so few will know to, and even if they do it's still very easy to forget.

Also, @ewdurbin is happy to do this on Legacy, but if you decide a Product URL covers this then I don't think that can be done with Legacy.

What do you think?

I've proposed setuptools support for Project-URL metadata at https://github.com/pypa/setuptools/pull/1205 though my uploads to testpypi don't put the links anywhere obvious and the PKG-INFO link seems to present a munged metadata set with the Project-URL list stripped out (if you download the files however you can see it's present in both mudpy-0.0.1.dev231.dist-info/METADATA and mudpy-0.0.1.dev231/PKG-INFO files therein):

    https://test.pypi.org/project/mudpy/
    https://testpypi.python.org/pypi/mudpy/

The pkginfo library is able to find it in distributions downloaded from testpypi:

    >>> pkginfo.SDist('mudpy-0.0.1.dev231.tar.gz').project_urls
    [u'Bug Tracker, http://mudpy.org/contact/ Documentation, http://mudpy.org/documentation/ Source Code, http://mudpy.org/gitweb/mudpy.git']

The format of the list also seems to match the core metadata spec which in turn matches the design from PEP 345, so I'm not sure if I'm missing something or whether there's a bug in warehouse/cheeseshop.
There might be missing support for it, though I thought I added it.
Ahh, pouring back over the specs, I believe I've misinterpreted the described format. Multi-use means multiple lines beginning with "Project-URL:" rather than one with multiple indented Title,URL pairs on distinct lines. I'll rejigger the PR and do another test soon.
The respun Project-URL support for setuptools is now up for review as https://github.com/pypa/setuptools/pull/1210 and it's working for https://testpypi.python.org/pypi/mudpy/0.0.1.dev232/ but https://test.pypi.org/project/mudpy/0.0.1.dev232/ doesn't seem to provide the same links... leading me to suspect that implementation in Warehouse is not yet completed?
FWIW. I've the same problem with PyObjC: The wheels contain "Project-URL" metadata, but that doesn't show up on warehouse while pkginfo can extract the information.

Resolving patch:
diff --git a/warehouse/packaging/models.py b/warehouse/packaging/models.py
--- a/warehouse/packaging/models.py
+++ b/warehouse/packaging/models.py
@@ -338,7 +338,7 @@ def urls(self):
             _urls["Homepage"] = self.home_page
 
         for urlspec in self.project_urls:
-            name, url = urlspec.split(",", 1)
+            name, url = [x.strip() for x in urlspec.split(",", 1)]
             _urls[name] = url
 
         if self.download_url and "Download" not in _urls:


Test patch:
diff --git a/tests/unit/packaging/test_models.py b/tests/unit/packaging/test_models.py
--- a/tests/unit/packaging/test_models.py
+++ b/tests/unit/packaging/test_models.py
@@ -159,6 +159,14 @@ def test_has_meta_false(self, db_session):
                     ("Source Code", "https://example.com/source-code/"),
                 ]),
             ),
+            (
+                None,
+                None,
+                ["Source Code, https://example.com/source-code/"],
+                OrderedDict([
+                    ("Source Code", "https://example.com/source-code/"),
+                ]),
+            ),
             (
                 "https://example.com/home/",
                 "https://example.com/download/",