Skip to content

feat: возможность для пользователя передавать тип загружаемого файла как строку#119

Open
someqst wants to merge 4 commits intolove-apples:mainfrom
someqst:feat/allow-str-upload-type-while-upload_media
Open

feat: возможность для пользователя передавать тип загружаемого файла как строку#119
someqst wants to merge 4 commits intolove-apples:mainfrom
someqst:feat/allow-str-upload-type-while-upload_media

Conversation

@someqst
Copy link
Copy Markdown

@someqst someqst commented Apr 18, 2026

Столкнулся с проблемой, что тип загружаемого файла нельзя передать строкой.
Думаю, стоит позволить пользователю передавать строку.

Также сделал небольшой рефакторинг функционала определения типа файла на основе содержимого во избежание дублирования кода.

@someqst someqst force-pushed the feat/allow-str-upload-type-while-upload_media branch from e042e8a to ad07ed4 Compare April 18, 2026 21:51
@Olegt0rr Olegt0rr requested a review from Copilot April 19, 2026 17:45
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

PR добавляет возможность передавать тип загружаемого файла как строку (в дополнение к UploadType) и выносит определение типа по содержимому в общий хелпер, чтобы убрать дублирование.

Changes:

  • Расширен API InputMedia для приема type как UploadType | str.
  • Вынесена логика определения типа файла по содержимому в функцию detect_file_type.
  • Унифицирована валидация type с выдачей понятной ошибки при неверном значении.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Определяет тип файла на основе его содержимого (MIME-типа).

Args:
data (bytes): Буфер с содержимым файла.
Copy link

Copilot AI Apr 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

В detect_file_type докстринг описывает аргументы, но не документирует возвращаемое значение (и возможные исключения). В этом репозитории обычно указываются секции Returns: (и часто Raises:) — стоит добавить их, чтобы поведение функции было однозначно описано.

Suggested change
data (bytes): Буфер с содержимым файла.
data (bytes): Буфер с содержимым файла.
Returns:
UploadType: Определенный тип файла. Если MIME-тип не удалось
определить или при определении произошла ошибка, возвращается
``UploadType.FILE``.

Copilot uses AI. Check for mistakes.
Comment thread maxapi/types/input_media.py Outdated
Comment on lines +110 to +114
if type is not None:
try:
self.type = UploadType(type)
except ValueError as e:
allowed = ", ".join(item.value for item in UploadType)
Copy link

Copilot AI Apr 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Сигнатура InputMediaBuffer.__init__ по-прежнему аннотирует type как UploadType | None, но ниже вы явно поддерживаете строки через UploadType(type). Это делает новый публичный API несогласованным (и ухудшает опыт статической типизации). Обновите аннотацию параметра до UploadType | str | None (и синхронизируйте описание аргумента в докстринге).

Copilot uses AI. Check for mistakes.
Comment thread maxapi/types/input_media.py Outdated
Comment on lines +62 to +69
if type is not None:
try:
self.type = UploadType(type)
except ValueError as e:
allowed = ", ".join(item.value for item in UploadType)
raise ValueError(
f"Неверный тип загружаемого файла: {type!r}. Ожидается: {allowed}" # noqa: E501
) from e
Copy link

Copilot AI Apr 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Логика приведения/валидации type (через UploadType(type) + формирование списка allowed) продублирована в InputMedia и InputMediaBuffer. Лучше вынести её в общий хелпер (например, модульную функцию), чтобы в будущем не разъехались формат ошибки/правила валидации.

Copilot uses AI. Check for mistakes.
Comment on lines +50 to +71
def __init__(self, path: str, type: UploadType | str | None = None):
"""
Инициализирует объект медиафайла.

Args:
path (str): Путь к файлу.
type (UploadType, optional): Тип файла. Если не указан,
type (UploadType, str, optional): Тип файла. Если не указан,
определяется автоматически.
"""

self.path = path
self.type = type or self.__detect_file_type(path)

def __detect_file_type(self, path: str) -> UploadType:
"""
Определяет тип файла на основе его содержимого (MIME-типа).

Args:
path (str): Путь к файлу.

Returns:
UploadType: Тип файла (VIDEO, IMAGE, AUDIO или FILE).
"""
if type is not None:
try:
self.type = UploadType(type)
except ValueError as e:
allowed = ", ".join(item.value for item in UploadType)
raise ValueError(
f"Неверный тип загружаемого файла: {type!r}. Ожидается: {allowed}" # noqa: E501
) from e
else:
self.type = detect_file_type(InputMedia._read_file_sample(path))
Copy link

Copilot AI Apr 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Добавлена новая функциональность: принимать type как строку и выбрасывать ValueError с перечислением допустимых значений. В тестах сейчас нет проверок этого сценария (особенно: строка валидная → корректный UploadType, строка невалидная → ожидаемое сообщение ошибки). Стоит добавить/расширить тесты для InputMedia и InputMediaBuffer, чтобы зафиксировать контракт.

Copilot uses AI. Check for mistakes.
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 20, 2026

Codecov Report

❌ Patch coverage is 72.22222% with 10 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
maxapi/types/input_media.py 72.22% 10 Missing ⚠️

📢 Thoughts on this report? Let us know!

Copy link
Copy Markdown
Collaborator

@Olegt0rr Olegt0rr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Хорошая работа. Рефакторинг детекции типа в detect_file_type — правильное решение, убирает дублирование между InputMedia и InputMediaBuffer. Логика валидации с понятным сообщением об ошибке тоже на месте.

Тесты покрывают основные сценарии, включая проверку что при явно переданном типе автодетект не вызывается — именно то, что нужно.

Судя по боту coverage - где-то пропущено покрытие.
По комментариям Copilot хорошо бы пробежаться внимательно. Если не актуально - напишите, позакрываю.

Косметический момент: в docstring InputMediaBuffer.init порядок типов записан как type (UploadType, optional, str) — немного странно, лучше UploadType | str | None как в сигнатуре. Не блокирует.

@someqst
Copy link
Copy Markdown
Author

someqst commented Apr 23, 2026

@Olegt0rr
По замечаниям copilot я прошелся, docstring изменил. Дописал тесты на которые, вроде бы, ругался codecov

…как строку

вынесена валидация типа медиа

обновлен docstring detect_file_type

исправлены аннотации

добавлены тесты на проверку InputMedia и InputMediaBuffer

исправлена ошибка ruff

fix: исправлены замечания ruff

fix: исправлены docstring

feat: дополнены тесты mime_type=None

fix: исправлена логика validate_uploading_type

исправлены замечания ruff

fix: formatting
@someqst someqst force-pushed the feat/allow-str-upload-type-while-upload_media branch from 16f82ef to 413abae Compare April 23, 2026 08:29
@Olegt0rr Olegt0rr requested a review from Copilot April 26, 2026 07:26
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 6 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

try:
matches = puremagic.magic_string(data)
if matches:
mime_type = matches[0].mime_type
Copy link

Copilot AI Apr 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

puremagic.magic_string() results are treated as tuples elsewhere in the codebase (e.g. maxapi/connection/base.py:265-268 uses matches[0][1] for MIME). Here matches[0].mime_type will raise AttributeError when matches[0] is a tuple. Please extract MIME consistently (e.g. tuple indexing) or normalize the result before accessing it.

Suggested change
mime_type = matches[0].mime_type
match = matches[0]
if isinstance(match, (tuple, list)) and len(match) > 1:
mime_type = match[1]
else:
mime_type = getattr(match, "mime_type", None)

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Здесь matches - это list из namedtuple. Луче обратиться по атрибуту. Исправил поведение в maxapi/connection/base.py, там обращение в принципе было не к mime_type по индексу элемента в кортеже.

Comment thread maxapi/types/input_media.py Outdated
Comment on lines +61 to +65
Attributes:
path (str): Путь к файлу.
type (UploadType): Тип файла, определенный на основе содержимого
type (UploadType | str | None): Тип файла, определенный на основе содержимого
(MIME-типа).
"""
""" # noqa: E501
Copy link

Copilot AI Apr 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

InputMedia.type is always set to an UploadType instance (either via validate_uploading_type() or detect_file_type()), but the docstring/types currently describe the attribute as UploadType | str | None. Consider keeping the constructor parameter as UploadType | str | None but tightening the stored attribute annotation/docstring to UploadType to avoid misleading users and type-checkers.

Copilot uses AI. Check for mistakes.
Comment on lines 96 to 99
Attributes:
buffer (bytes): Буфер с содержимым файла.
type (UploadType): Тип файла, определенный по содержимому.
type (UploadType | str | None): Тип файла, определенный по содержимому.
"""
Copy link

Copilot AI Apr 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

InputMediaBuffer.type is always set to an UploadType instance after initialization, but the docstring/types currently describe the attribute as UploadType | str | None. Consider documenting/annotating the attribute as UploadType (while keeping the constructor parameter as UploadType | str | None) so consumers and type-checkers don't assume str/None are possible post-init.

Copilot uses AI. Check for mistakes.
Comment thread tests/test_upload_file.py Outdated
Comment on lines +336 to +348
@pytest.mark.asyncio
async def test_default_upload_type_input_media_buffer(self, tmp_path):
"""
Если mimetype не определился (None),
для файла должен вернуться тип UploadType.FILE
"""
media = InputMediaBuffer(
buffer=b"fake-bytes",
filename="sample.bin",
)

assert media.type == UploadType.FILE

Copy link

Copilot AI Apr 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These tests are marked async/@pytest.mark.asyncio but don't await anything. Making them synchronous (def ...) and dropping the asyncio marker will reduce overhead and avoid implying async behavior where there is none.

Copilot uses AI. Check for mistakes.
Comment thread tests/test_upload_file.py Outdated
Comment on lines +349 to +360
@pytest.mark.asyncio
async def test_default_upload_type_input_media(self, tmp_path):
"""
Если mimetype не определился (None),
для файла должен вернуться тип UploadType.FILE
"""
test_file = tmp_path / "sample.bin"
test_file.write_bytes(b"fake-data")

media = InputMedia(path=test_file)

assert media.type == UploadType.FILE
Copy link

Copilot AI Apr 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test is marked async/@pytest.mark.asyncio but doesn't await anything. Converting it to a normal synchronous test (def ...) and dropping the asyncio marker will make intent clearer and avoid unnecessary event-loop setup.

Copilot uses AI. Check for mistakes.
Comment thread maxapi/types/input_media.py Outdated
Args:
path (str): Путь к файлу.
type (UploadType, optional): Тип файла. Если не указан,
type (UploadType | str |None): Тип файла. Если не указан,
Copy link

Copilot AI Apr 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Docstring type annotation has a formatting typo: UploadType | str |None is missing a space before None (| None). This is minor but it makes the generated docs/type hints harder to read.

Suggested change
type (UploadType | str |None): Тип файла. Если не указан,
type (UploadType | str | None): Тип файла. Если не указан,

Copilot uses AI. Check for mistakes.
@someqst
Copy link
Copy Markdown
Author

someqst commented Apr 26, 2026

@Olegt0rr
Классно, что получилось найти баг благодаря копилоту. В maxapi/connection/base на 267 строке был бажок, обращение по факту не к mime_type происходило, а к offset.
Замечания copilot я исправил.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants