Source code for edri.api.dataclass.range
from dataclasses import dataclass
__all__ = ["RangeSpec", "RangeValue"]
[docs]
@dataclass(slots=True)
class RangeSpec:
first: int | None = None
last: int | None = None
suffix_length: int | None = None
[docs]
@dataclass(slots=True)
class RangeValue:
unit: str
specs: tuple[RangeSpec, ...]
[docs]
def content_range(
self,
full_length: int | None,
start: int,
end: int,
) -> str:
"""
Build Content-Range for a *single* range response (206).
Args:
full_length: total representation length, or None if unknown.
start, end: inclusive byte positions of the payload actually served.
Returns:
e.g. ``bytes 0-99/1234`` or ``bytes 0-99/*``
"""
if self.unit != "bytes":
raise ValueError(f"Content-Range generation not implemented for unit={self.unit!r}")
if start < 0 or end < start:
raise ValueError("Invalid start/end")
if full_length is not None:
if full_length < 0:
raise ValueError("full_length must be >= 0")
# When length known, served range must be within it (end inclusive)
if full_length == 0:
raise ValueError("Cannot serve a non-empty range for full_length=0")
if end >= full_length:
raise ValueError("end must be < full_length when full_length is known")
return f"bytes {start}-{end}/{full_length}"
return f"bytes {start}-{end}/*"
[docs]
@staticmethod
def content_range_unsatisfied(*, unit: str = "bytes", full_length: int) -> str:
"""
Build Content-Range for 416 Range Not Satisfiable.
Returns:
e.g. ``bytes */1234``
"""
if full_length < 0:
raise ValueError("full_length must be >= 0")
return f"{unit} */{full_length}"
[docs]
def content_length(self, start: int, end: int) -> int:
"""
Content-Length for a *single* resolved range body (206).
"""
if self.unit != "bytes":
raise ValueError(f"Content-Length not implemented for unit={self.unit!r}")
if start < 0 or end < start:
raise ValueError("Invalid start/end")
return (end - start) + 1