Skip to content

Python: [Bug]: pytest.raises wrong usage (dead code and unexpected behaviour) #5115

@Serjbory

Description

@Serjbory

Description

Problem Summary

Multiple with pytest.raises(...) blocks contain more than one statement. Because pytest.raises exits immediately after the first exception, all subsequent statements are dead code that never execute. This creates a false sense of test coverage — assertions appear to pass but are never actually tested.

# BAD: second call is dead code
with pytest.raises(ValueError):
    function_that_raises()       # raises here, block exits
    another_function_that_raises()  # NEVER RUNS

Affected Locations

1. test_types.py — "Invalid base64" block (line 194)

Original code:

with pytest.raises(ValueError, match="Invalid base64 data provided."):
    detect_media_type_from_base64(data_str="invalid_base64!")  # raises → block exits
    detect_media_type_from_base64(data_str="")                 # DEAD CODE

What actually happens with data_str="":

>>> detect_media_type_from_base64(data_str="")
None  # Does NOT raise — base64.b64decode("") succeeds, returns b"", no magic bytes match

base64.b64decode("") is valid and returns b"". The function then checks magic bytes, finds no match, and returns None.

⚠️ Maintainer decision needed:

The original test implied data_str="" should raise ValueError. Two interpretations:

Option A: Empty string is valid input — base64.b64decode("") succeeds, the function returns None. The test was simply wrong.

Option B: Empty string should be rejected as invalid input. This requires a code change in detect_media_type_from_base64() to add an explicit check:

if data_str is not None:
    if not data_str:
        raise ValueError("Invalid base64 data provided.")

If Option B is chosen, the test should remain as two separate pytest.raises blocks.


2. test_types.py — "Provide exactly one" block (line 198)

Original code:

with pytest.raises(ValueError, match="Provide exactly one of data_bytes, data_str, or data_uri."):
    detect_media_type_from_base64()                                              # raises → block exits
    detect_media_type_from_base64(data_bytes=b"data", data_str="data", data_uri="data:...;base64,AAA")  # DEAD
    detect_media_type_from_base64(data_bytes=b"data", data_str="data")           # DEAD
    detect_media_type_from_base64(data_bytes=b"data", data_uri="data:...;base64,AAA")  # DEAD
    detect_media_type_from_base64(data_str="data", data_uri="data:...;base64,AAA")     # DEAD

Suggested Patch: Split into 5 individual with pytest.raises blocks.

Hidden issue here (I've tried to split and noticed inconsistency):
The last case (data_str + data_uri) raises "Invalid base64 data provided." instead of "Provide exactly one...".
This happens because:

  1. data_uri is processed first → extracts base64 payload → overwrites data_str
  2. data is still None (no data_bytes was set)
  3. The data_str is not None check passes, but the mutual-exclusion guard (if data is not None) doesn't trigger
  4. base64.b64decode() fails on the extracted payload → raises "Invalid base64"

So the original data_str parameter is silently discarded. The function still raises ValueError, just with a different message.

⚠️ Maintainer decision needed:

Option A: Accept that data_str + data_uri raises a different error message. The function still rejects the input, just via a different code path.

Option B: Fix detect_media_type_from_base64() to check mutual exclusion upfront before any processing:

provided = sum(x is not None for x in (data_bytes, data_str, data_uri))
if provided != 1:
    raise ValueError("Provide exactly one of data_bytes, data_str, or data_uri.")

This would make all combinations produce the same clear error message. The test could then use the strict match= pattern for all 5 cases.

I haven't introduce the PR yet, because first we have to define the desired behaviour. But once decision is made I would like to handle this bug in order to help the community and project :)

Code Sample

# BAD: second call is dead code
with pytest.raises(ValueError):
    function_that_raises()       # raises here, block exits
    another_function_that_raises()  # NEVER RUNS

Error Messages / Stack Traces

Package Versions

agent-framework-core v1.0.0

Python Version

Python3.14, Python3.13

Additional Context

No response

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

Projects

Status

No status

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions