Summary
Stream.disposition is typed as Disposition in av/stream.pyi, but assigning a Disposition member at runtime raises TypeError. The user must assign Disposition.X.value (an int) to make the runtime accept it, which then fails static type-checking against the stub. There is no value that satisfies both the static type and the runtime.
Root cause: Disposition extends enum.Flag (not enum.IntFlag), so its members are not int subclasses; the Cython setter assigns to a C int field, and the auto-conversion int(value) fails for plain Flag members.
Environment
- PyAV: 17.0.1 (latest on PyPI)
- ffmpeg: 8.0.1 (Homebrew)
- Python: 3.12.11
- OS: macOS 26.4.1 (Darwin 25)
Reproducer
import av
from av.stream import Disposition
w = av.open("/tmp/repro.mp3", mode="w", format="mp3")
w.add_stream("mp3", rate=44100)
video = w.add_stream("png", rate=1)
video.width = 1
video.height = 1
video.pix_fmt = "rgba"
# A) Assign the enum member (matches the stub `disposition: Disposition`).
# Runtime: TypeError.
video.disposition = Disposition.attached_pic
# TypeError: int() argument must be a string, a bytes-like object or a real
# number, not 'Disposition'
# B) Assign the underlying int via .value (runtime works, static check fails).
video.disposition = Disposition.attached_pic.value
| Assignment |
Runtime |
Static type-check |
video.disposition = Disposition.attached_pic |
TypeError |
OK |
video.disposition = Disposition.attached_pic.value |
OK |
error: int is not assignable to Disposition |
Expected
Assigning the value declared by the stub (Disposition.attached_pic) should succeed at runtime.
Root cause
Disposition is declared as a plain Flag, whose members are not int subclasses:
>>> from av.stream import Disposition
>>> [c.__name__ for c in type(Disposition.attached_pic).__mro__]
['Disposition', 'Flag', 'Enum', 'object']
>>> isinstance(Disposition.attached_pic, int)
False
>>> int(Disposition.attached_pic)
TypeError: int() argument must be a string, a bytes-like object or a real number, not 'Disposition'
The setter for disposition in av/stream.py assigns to a C int field on the underlying AVStream:
def __setattr__(self, name, value):
...
if name == "disposition":
self.ptr.disposition = value
return
Cython auto-converts the right-hand side via int(value) for the C int target. Since plain Flag does not implement __int__, this raises TypeError. The user must pass .value (an int) for the conversion to succeed — but that contradicts the stub, which declares disposition: Disposition.
Suggested fix
Change Disposition to inherit from enum.IntFlag instead of enum.Flag. IntFlag members are int subclasses, so int(member) works and the Cython setter's conversion succeeds. Bitwise operations and membership behavior are preserved. Two lines in av/stream.py (and the matching two in av/stream.pyi).
I'm happy to send a PR if helpful.
Observed downstream impact
External code that sets disposition = Disposition.attached_pic.value (the only form runtime accepts) cannot pass a static type check without a suppression marker (# type: ignore[invalid-assignment], an explicit cast, or a rule downgrade in the type-checker config).
Summary
Stream.dispositionis typed asDispositioninav/stream.pyi, but assigning aDispositionmember at runtime raisesTypeError. The user must assignDisposition.X.value(anint) to make the runtime accept it, which then fails static type-checking against the stub. There is no value that satisfies both the static type and the runtime.Root cause:
Dispositionextendsenum.Flag(notenum.IntFlag), so its members are notintsubclasses; the Cython setter assigns to a Cintfield, and the auto-conversionint(value)fails for plainFlagmembers.Environment
Reproducer
video.disposition = Disposition.attached_picTypeErrorvideo.disposition = Disposition.attached_pic.valueintis not assignable toDispositionExpected
Assigning the value declared by the stub (
Disposition.attached_pic) should succeed at runtime.Root cause
Dispositionis declared as a plainFlag, whose members are notintsubclasses:The setter for
dispositioninav/stream.pyassigns to a Cintfield on the underlyingAVStream:Cython auto-converts the right-hand side via
int(value)for the Cinttarget. Since plainFlagdoes not implement__int__, this raisesTypeError. The user must pass.value(anint) for the conversion to succeed — but that contradicts the stub, which declaresdisposition: Disposition.Suggested fix
Change
Dispositionto inherit fromenum.IntFlaginstead ofenum.Flag.IntFlagmembers areintsubclasses, soint(member)works and the Cython setter's conversion succeeds. Bitwise operations and membership behavior are preserved. Two lines inav/stream.py(and the matching two inav/stream.pyi).I'm happy to send a PR if helpful.
Observed downstream impact
External code that sets
disposition = Disposition.attached_pic.value(the only form runtime accepts) cannot pass a static type check without a suppression marker (# type: ignore[invalid-assignment], an explicitcast, or a rule downgrade in the type-checker config).