From 638202c4a88702f229d257d48cd1284cefe8d07e Mon Sep 17 00:00:00 2001 From: matytsyn <71841191+matytsyn@users.noreply.github.com> Date: Sun, 16 Aug 2026 13:15:00 +0300 Subject: [PATCH 1/2] =?UTF-8?q?fix:=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B0=20=D0=BE=D0=B1=D1=80=D0=B0=D0=B1=D0=BE=D1=82?= =?UTF-8?q?=D0=BA=D0=B0=20PureError=20=D0=B2=20upload=5Ffile=5Fbuffer()?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- maxapi/connection/base.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/maxapi/connection/base.py b/maxapi/connection/base.py index 870b9d2..aa16f49 100644 --- a/maxapi/connection/base.py +++ b/maxapi/connection/base.py @@ -20,6 +20,7 @@ ClientSession, FormData, ) +from puremagic.main import PureError from ..client.ssl import connector_kwargs from ..enums.api_path import ApiPath @@ -298,7 +299,7 @@ async def upload_file_buffer( else: mime_type = f"{type.value}/*" ext = "" - except (OSError, ValueError, AttributeError): + except (OSError, ValueError, AttributeError, PureError): mime_type = f"{type.value}/*" ext = "" From 13e56349425170ed44c5b864145a7ea503d7176d Mon Sep 17 00:00:00 2001 From: matytsyn <71841191+matytsyn@users.noreply.github.com> Date: Sun, 16 Aug 2026 15:17:04 +0300 Subject: [PATCH 2/2] =?UTF-8?q?test:=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=20=D1=82=D0=B5=D1=81=D1=82=20=D0=BF=D0=BE?= =?UTF-8?q?=D0=BA=D1=80=D1=8B=D1=82=D0=B8=D1=8F=20=D0=B2=D0=B5=D1=82=D0=BA?= =?UTF-8?q?=D0=B8=20PureError=20=D0=B2=20upload=5Ffile=5Fbuffer?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/test_coverage_gaps.py | 46 +++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/tests/test_coverage_gaps.py b/tests/test_coverage_gaps.py index c0bfe38..8f4497f 100644 --- a/tests/test_coverage_gaps.py +++ b/tests/test_coverage_gaps.py @@ -616,3 +616,49 @@ async def test_upload_file_buffer_uses_temp_session_when_session_is_none( assert result == '{"token":"buf"}' mock_session_instance.post.assert_called_once() mock_cm.__aenter__.assert_called_once() + + async def test_upload_file_buffer_puremagic_pureerror_fallback(self, bot): + """upload_file_buffer перехватывает PureError из puremagic + и использует fallback-имя/MIME для файлов без magic bytes + (например, .txt).""" + from unittest.mock import AsyncMock, MagicMock, patch + + from maxapi.connection.base import BaseConnection + from maxapi.enums.upload_type import UploadType + from puremagic.main import PureError + + conn = BaseConnection() + conn.bot = bot + + some_buffer = b"plain text content without magic bytes" + + mock_response = MagicMock() + mock_response.text = AsyncMock(return_value='{"token":"txt"}') + + mock_context = AsyncMock() + mock_context.__aenter__.return_value = mock_response + mock_context.__aexit__.return_value = None + + bot.session = MagicMock() + bot.session.closed = False + bot.session.post = MagicMock(return_value=mock_context) + + with patch( + "maxapi.connection.base.puremagic.magic_string", + side_effect=PureError("Could not identify file"), + ): + result = await conn.upload_file_buffer( + filename="document", + url="https://upload.example.com", + buffer=some_buffer, + type=UploadType.FILE, + ) + + assert result == '{"token":"txt"}' + bot.session.post.assert_called_once() + form = bot.session.post.call_args.kwargs["data"] + # FormData хранит поля в ._fields как кортежи: + # (MultiDict с name/filename, заголовки dict, значение bytes). + field = next(f for f in form._fields if f[0].get("name") == "data") + assert field[0].get("filename") == "document" # без расширения + assert field[1]["Content-Type"] == "file/*" # fallback MIME