diff --git a/src/dstack/_internal/server/routers/repos.py b/src/dstack/_internal/server/routers/repos.py index 3c5b59857d..32e59f6317 100644 --- a/src/dstack/_internal/server/routers/repos.py +++ b/src/dstack/_internal/server/routers/repos.py @@ -1,7 +1,6 @@ from typing import List, Tuple from fastapi import APIRouter, Depends, Request, UploadFile -from humanize import naturalsize from sqlalchemy.ext.asyncio import AsyncSession from dstack._internal.core.errors import ResourceNotExistsError, ServerClientError @@ -20,6 +19,7 @@ get_base_api_additional_responses, get_request_size, ) +from dstack._internal.utils.common import sizeof_fmt router = APIRouter( prefix="/api/project/{project_name}/repos", @@ -98,10 +98,15 @@ async def upload_code( ): request_size = get_request_size(request) if SERVER_CODE_UPLOAD_LIMIT > 0 and request_size > SERVER_CODE_UPLOAD_LIMIT: + diff_size_fmt = sizeof_fmt(request_size) + limit_fmt = sizeof_fmt(SERVER_CODE_UPLOAD_LIMIT) + if diff_size_fmt == limit_fmt: + diff_size_fmt = f"{request_size}B" + limit_fmt = f"{SERVER_CODE_UPLOAD_LIMIT}B" raise ServerClientError( - f"Repo diff size is {naturalsize(request_size)}, which exceeds the limit of " - f"{naturalsize(SERVER_CODE_UPLOAD_LIMIT)}. Use .gitignore to exclude large files from the repo. This " - f"limit can be modified by setting the DSTACK_SERVER_CODE_UPLOAD_LIMIT environment variable" + f"Repo diff size is {diff_size_fmt}, which exceeds the limit of {limit_fmt}." + " Use .gitignore to exclude large files from the repo." + " This limit can be modified by setting the DSTACK_SERVER_CODE_UPLOAD_LIMIT environment variable." ) _, project = user_project await repos.upload_code( diff --git a/src/tests/_internal/utils/test_common.py b/src/tests/_internal/utils/test_common.py index a10e3f7a3a..ed9ef99168 100644 --- a/src/tests/_internal/utils/test_common.py +++ b/src/tests/_internal/utils/test_common.py @@ -11,6 +11,7 @@ make_proxy_url, parse_memory, pretty_date, + sizeof_fmt, split_chunks, ) @@ -211,3 +212,26 @@ def test_concat_url_path(a: str, b: str, result: str) -> None: ) def test_make_proxy_url(server_url, proxy_url, expected_url): assert make_proxy_url(server_url, proxy_url) == expected_url + + +class TestSizeofFmt: + @pytest.mark.parametrize( + ("num", "suffix", "expected"), + [ + (0, "B", "0.0B"), + (1023, "B", "1023.0B"), + (1024, "B", "1.0KiB"), + (1536, "B", "1.5KiB"), + (1048576, "B", "1.0MiB"), + (1073741824, "B", "1.0GiB"), + (1099511627776, "B", "1.0TiB"), + (1125899906842624, "B", "1.0PiB"), + (1152921504606846976, "B", "1.0EiB"), + (1180591620717411303424, "B", "1.0ZiB"), + (1208925819614629174706176, "B", "1.0YiB"), + (2000, "", "2.0Ki"), + (3000000, "Hz", "2.9MiHz"), + ], + ) + def test_sizeof_fmt(self, num: int, suffix: str, expected: str) -> None: + assert sizeof_fmt(num, suffix) == expected