Repository: pypi/warehouse

Issue:
File size limit error message should include size of the limit
Since we don't document the file size limit for uploads anywhere, it'd be nice if the error message when an upload is over the limit includes what the limit is, especially considering that the limits might be different for various projects.

Currently the message is something like:

```
HTTPError: 400 Client Error: File too large. for url: https://upload.pypi.org/legacy/
```

It'd be nice if this was something like:

```
HTTPError: 400 Client Error: File too large (limit for <project_name> is <limit>) for url: https://upload.pypi.org/legacy/
```


Discussion:
In our [meeting today](https://wiki.python.org/psf/PackagingWG/2017-12-19-Warehouse) we decided this belongs in [the first milestone, the MVP for package maintainers](https://github.com/pypa/warehouse/milestone/8).

@Miserlou is working on implementing it in #2487.
I closed #2487, so this issue is still open and available for someone else to pick up as their first contribution.
@di 

https://github.com/pypa/warehouse/blob/d12b7c1ff792942b6ba8c91793e4fa6e1f1cf137/warehouse/forklift/legacy.py#L878

It's just the matter of formatting the project name and file size limit from local variables here into the message; correct?

@pradyunsg Yep! Something like:

> File is too large. Limit for project 'foobar' is 60MB.

Resolving patch:
diff --git a/warehouse/forklift/legacy.py b/warehouse/forklift/legacy.py
--- a/warehouse/forklift/legacy.py
+++ b/warehouse/forklift/legacy.py
@@ -875,7 +875,13 @@ def file_upload(request):
                     lambda: request.POST["content"].file.read(8096), b""):
                 file_size += len(chunk)
                 if file_size > file_size_limit:
-                    raise _exc_with_message(HTTPBadRequest, "File too large.")
+                    raise _exc_with_message(
+                        HTTPBadRequest,
+                        "File too large. " +
+                        "Limit for project {name!r} is {limit}MB".format(
+                            name=project.name,
+                            limit=file_size_limit // (1024 * 1024),
+                        ))
                 fp.write(chunk)
                 for hasher in file_hashes.values():
                     hasher.update(chunk)


Test patch:
diff --git a/tests/unit/forklift/test_legacy.py b/tests/unit/forklift/test_legacy.py
--- a/tests/unit/forklift/test_legacy.py
+++ b/tests/unit/forklift/test_legacy.py
@@ -1371,7 +1371,10 @@ def test_upload_fails_with_too_large_file(self, pyramid_config,
         pyramid_config.testing_securitypolicy(userid=1)
 
         user = UserFactory.create()
-        project = ProjectFactory.create()
+        project = ProjectFactory.create(
+            name='foobar',
+            upload_limit=(60 * 1024 * 1024),  # 60MB
+        )
         release = ReleaseFactory.create(project=project, version="1.0")
         RoleFactory.create(user=user, project=project)
 
@@ -1385,7 +1388,7 @@ def test_upload_fails_with_too_large_file(self, pyramid_config,
             "md5_digest": "nope!",
             "content": pretend.stub(
                 filename=filename,
-                file=io.BytesIO(b"a" * (legacy.MAX_FILESIZE + 1)),
+                file=io.BytesIO(b"a" * (project.upload_limit + 1)),
                 type="application/tar",
             ),
         })
@@ -1396,7 +1399,9 @@ def test_upload_fails_with_too_large_file(self, pyramid_config,
         resp = excinfo.value
 
         assert resp.status_code == 400
-        assert resp.status == "400 File too large."
+        assert resp.status == (
+            "400 File too large. Limit for project 'foobar' is 60MB"
+        )
 
     def test_upload_fails_with_too_large_signature(self, pyramid_config,
                                                    db_request):