add stubs for m3u8 (#12683)

This commit is contained in:
DinhHuy2010
2024-10-01 19:05:59 +07:00
committed by GitHub
parent 302e83f003
commit 1c96234848
11 changed files with 628 additions and 0 deletions

View File

@@ -59,6 +59,7 @@
"stubs/jsonschema",
"stubs/jwcrypto",
"stubs/ldap3",
"stubs/m3u8",
"stubs/Markdown",
"stubs/mysqlclient",
"stubs/netaddr/netaddr/core.pyi",

View File

@@ -0,0 +1,17 @@
# type check only
m3u8.httpclient.HTTPSHandler.__new__
# internal functions and attributes
m3u8.M3U8.simple_attributes
m3u8.model.M3U8.simple_attributes
m3u8.model.denormalize_attribute
m3u8.model.find_key
m3u8.model.number_to_string
m3u8.model.quoted
m3u8.parser.cast_date_time
m3u8.parser.format_date_time
m3u8.parser.get_segment_custom_value
m3u8.parser.normalize_attribute
m3u8.parser.remove_quotes
m3u8.parser.remove_quotes_parser
m3u8.parser.save_segment_custom_value
m3u8.parser.string_to_lines

2
stubs/m3u8/METADATA.toml Normal file
View File

@@ -0,0 +1,2 @@
version = "6.0.*"
upstream_repository = "https://github.com/globocom/m3u8"

View File

@@ -0,0 +1,74 @@
from _typeshed import Incomplete
from collections.abc import Callable, Mapping
from typing import Any
from typing_extensions import TypeAlias
from m3u8.httpclient import _HTTPClientProtocol
from m3u8.model import (
M3U8,
ContentSteering,
DateRange,
DateRangeList,
IFramePlaylist,
ImagePlaylist,
Key,
Media,
MediaList,
PartialSegment,
PartialSegmentList,
PartInformation,
Playlist,
PlaylistList,
PreloadHint,
RenditionReport,
RenditionReportList,
Segment,
SegmentList,
ServerControl,
Skip,
Start,
Tiles,
)
from m3u8.parser import ParseError, parse
__all__ = (
"M3U8",
"Segment",
"SegmentList",
"PartialSegment",
"PartialSegmentList",
"Key",
"Playlist",
"IFramePlaylist",
"Media",
"MediaList",
"PlaylistList",
"Start",
"RenditionReport",
"RenditionReportList",
"ServerControl",
"Skip",
"PartInformation",
"PreloadHint",
"DateRange",
"DateRangeList",
"ContentSteering",
"ImagePlaylist",
"Tiles",
"loads",
"load",
"parse",
"ParseError",
)
_CustomTagsParser: TypeAlias = Callable[[str, int, dict[str, Any], dict[str, Any]], object]
def loads(content: str, uri: str | None = None, custom_tags_parser: _CustomTagsParser | None = None) -> M3U8: ...
def load(
uri: str,
timeout: Incomplete | None = None,
headers: Mapping[str, Any] = {},
custom_tags_parser: _CustomTagsParser | None = None,
http_client: _HTTPClientProtocol = ...,
verify_ssl: bool = True,
) -> M3U8: ...

View File

@@ -0,0 +1,19 @@
import urllib.request
from typing import Any, Protocol, type_check_only
@type_check_only
class _HTTPClientProtocol(Protocol): # noqa: Y046
def download(
self, uri: str, timeout: float | None = None, headers: dict[str, Any] = {}, verify_ssl: bool = True
) -> tuple[str, str]: ...
class DefaultHTTPClient:
proxies: dict[str, str] | None
def __init__(self, proxies: dict[str, str] | None = None) -> None: ...
def download(
self, uri: str, timeout: float | None = None, headers: dict[str, Any] = {}, verify_ssl: bool = True
) -> tuple[str, str]: ...
class HTTPSHandler:
def __new__(cls, verify_ssl: bool = True) -> urllib.request.HTTPSHandler: ... # type: ignore

View File

@@ -0,0 +1,25 @@
from abc import ABCMeta
from collections.abc import Iterable
from typing import TypeVar
_T = TypeVar("_T")
class BasePathMixin:
uri: str | None
@property
def absolute_uri(self) -> str: ...
@property
def base_path(self) -> str: ...
@base_path.setter
def base_path(self, newbase_path: str) -> None: ...
def get_path_from_uri(self) -> str: ...
class GroupedBasePathMixin(Iterable[_T], metaclass=ABCMeta):
@property
def base_uri(self) -> str: ...
@base_uri.setter
def base_uri(self, __new_url: str, /) -> None: ...
@property
def base_path(self) -> str: ...
@base_path.setter
def base_path(self, __new_url: str, /) -> None: ...

406
stubs/m3u8/m3u8/model.pyi Normal file
View File

@@ -0,0 +1,406 @@
import datetime as dt
from _typeshed import Incomplete, StrOrBytesPath
from collections.abc import Callable, Mapping
from typing import ClassVar, Literal, Protocol, TypeVar, type_check_only
from typing_extensions import TypeAlias
from m3u8.mixins import BasePathMixin, GroupedBasePathMixin
from m3u8.protocol import ext_x_map, ext_x_session_key
_T = TypeVar("_T")
_CustomTagsParser: TypeAlias = Callable[[str, int, dict[str, Incomplete], dict[str, Incomplete]], object]
@type_check_only
class _PlaylistProtocol(Protocol):
base_uri: str | None
uri: str | None
@property
def absolute_uri(self) -> str: ...
@property
def base_path(self) -> str: ...
@base_path.setter
def base_path(self, newbase_path: str) -> None: ...
def get_path_from_uri(self) -> str: ...
_PlaylistAnyT = TypeVar("_PlaylistAnyT", bound=_PlaylistProtocol)
class MalformedPlaylistError(Exception): ...
class M3U8:
simple_attributes: list[tuple[str, str]]
data: dict[str, Incomplete]
keys: list[Key]
segment_map: list[InitializationSection]
segments: SegmentList
files: list[str | None]
media: MediaList
playlists: PlaylistList[Playlist]
iframe_playlists: PlaylistList[IFramePlaylist]
image_playlists: PlaylistList[ImagePlaylist]
start: Start
server_control: ServerControl
part_inf: PartInformation
skip: Skip
rendition_reports: RenditionReportList
session_data: SessionDataList
session_keys: list[SessionKey | None]
preload_hint: PreloadHint
content_steering: ContentSteering
# inserted via setattr()
is_variant: bool | None
is_endlist: bool | None
is_i_frames_only: bool | None
target_duration: float | None
media_sequence: int | None
program_date_time: str | None
is_independent_segments: bool | None
version: str | None
allow_cache: str | None
playlist_type: str | None
discontinuity_sequence: Incomplete | None # undocmented
is_images_only: bool | None
def __init__(
self,
content: str | None = None,
base_path: str | None = None,
base_uri: str | None = None,
strict: bool = False,
custom_tags_parser: _CustomTagsParser | None = None,
) -> None: ...
@property
def base_uri(self) -> str | None: ...
@base_uri.setter
def base_uri(self, new_base_uri: str) -> None: ...
@property
def base_path(self) -> str | None: ...
@base_path.setter
def base_path(self, newbase_path: str) -> None: ...
def add_playlist(self, playlist: Playlist) -> None: ...
def add_iframe_playlist(self, iframe_playlist: IFramePlaylist) -> None: ...
def add_image_playlist(self, image_playlist: ImagePlaylist) -> None: ...
def add_media(self, media: Media) -> None: ...
def add_segment(self, segment: Segment) -> None: ...
def add_rendition_report(self, report: RenditionReport) -> None: ...
def dumps(self, timespec: str = "milliseconds", infspec: str = "auto") -> str: ...
def dump(self, filename: StrOrBytesPath) -> None: ...
def __unicode__(self) -> str: ...
class Segment(BasePathMixin):
media_sequence: int | None
uri: str | None
duration: float | None
title: str
bitrate: int | None
byterange: str | None
program_date_time: dt.datetime | None
current_program_date_time: dt.datetime | None
discontinuity: bool
cue_out_start: bool
cue_out_explicitly_duration: bool
cue_out: bool
cue_in: bool
scte35: str | None
oatcls_scte35: str | None
scte35_duration: float | None
scte35_elapsedtime: Incomplete | None
asset_metadata: dict[str, Incomplete] | None
key: Key | None
parts: PartialSegmentList
init_section: InitializationSection | None
dateranges: DateRangeList
gap_tag: Incomplete | None
custom_parser_values: dict[str, Incomplete]
def __init__(
self,
uri: str | None = None,
base_uri: str | None = None,
program_date_time: dt.datetime | None = None,
current_program_date_time=None,
duration: float | None = None,
title: str | None = None,
bitrate=None,
byterange=None,
cue_out: bool = False,
cue_out_start: bool = False,
cue_out_explicitly_duration: bool = False,
cue_in: bool = False,
discontinuity: bool = False,
key=None,
scte35=None,
oatcls_scte35: str | None = None,
scte35_duration=None,
scte35_elapsedtime=None,
asset_metadata: Mapping[str, str] | None = None,
keyobject: Key | None = None,
parts: list[Mapping[str, Incomplete]] | None = None,
init_section: Mapping[str, Incomplete] | None = None,
dateranges=None,
gap_tag: list[Mapping[str, Incomplete]] | None = None,
media_sequence: int | None = None,
custom_parser_values=None,
) -> None: ...
def add_part(self, part: PartialSegment) -> None: ...
def dumps(self, last_segment: PartialSegment | None, timespec: str = "milliseconds", infspec: str = "auto") -> str: ...
@property
def base_path(self) -> str: ...
@base_path.setter
def base_path(self, newbase_path: str) -> None: ...
@property
def base_uri(self) -> str: ...
@base_uri.setter
def base_uri(self, newbase_uri: str) -> None: ...
class SegmentList(list[Segment], GroupedBasePathMixin[Segment]):
def dumps(self, timespec: str = "milliseconds", infspec: str = "auto") -> str: ...
@property
def uri(self) -> list[str | None]: ...
def by_key(self, key: Key) -> list[Segment]: ...
class PartialSegment(BasePathMixin):
base_uri: str
uri: str | None
duration: float | None
program_date_time: dt.datetime | None
current_program_date_time: dt.datetime | None
byterange: str | None
independent: bool
gap: str | None
dateranges: DateRangeList
gap_tag: str | None
def __init__(
self,
base_uri: str,
uri: str | None,
duration: float | None,
program_date_time: dt.datetime | None = None,
current_program_date_time: Incomplete | None = None,
byterange: Incomplete | None = None,
independent: Incomplete | None = None,
gap: Incomplete | None = None,
dateranges: list[Mapping[str, Incomplete]] | None = None,
gap_tag: Incomplete | None = None,
) -> None: ...
def dumps(self, last_segment) -> str: ...
class PartialSegmentList(list[PartialSegment], GroupedBasePathMixin[PartialSegment]): ...
class Key(BasePathMixin):
tag: ClassVar[str] = ...
method: str
base_uri: str
uri: str | None
iv: str | None
keyformat: str | None
keyformatversions: str | None
def __init__(
self,
method: str,
base_uri: str,
uri: str | None = None,
iv: str | None = None,
keyformat: str | None = None,
keyformatversions: str | None = None,
**kwargs,
) -> None: ...
def __eq__(self, other: object) -> bool: ...
def __ne__(self, other: object) -> bool: ...
class InitializationSection(BasePathMixin):
tag = ext_x_map
base_uri: str
uri: str | None
byterange: str | None
def __init__(self, base_uri: str, uri: str | None, byterange: str | None = None) -> None: ...
def __eq__(self, other: object) -> bool: ...
def __ne__(self, other: object) -> bool: ...
class SessionKey(Key):
tag = ext_x_session_key
class Playlist(_PlaylistProtocol):
base_uri: str | None
uri: str | None
stream_info: StreamInfo
media: MediaList
def __init__(self, uri: str | None, stream_info: Mapping[str, Incomplete], media: MediaList, base_uri: str) -> None: ...
class IFramePlaylist(_PlaylistProtocol):
uri: str | None
base_uri: str | None
iframe_stream_info: StreamInfo
def __init__(self, base_uri: str, uri: str | None, iframe_stream_info: Mapping[str, Incomplete]) -> None: ...
class StreamInfo:
bandwidth: int | None
closed_captions: Incomplete | None
average_bandwidth: int | None
program_id: int | None
resolution: tuple[int, int] | None
codecs: str | None
audio: str | None
video: str | None
subtitles: str | None
frame_rate: float | None
video_range: str | None
hdcp_level: str | None
pathway_id: str | None
stable_variant_id: str | None
req_video_layout: str | None
def __init__(self, **kwargs) -> None: ...
class Media(BasePathMixin):
base_uri: str | None
uri: str | None
type: str | None
group_id: str | None
language: str | None
name: str | None
default: str | None
autoselect: str | None
forced: str | None
assoc_language: str | None
instream_id: str | None
characteristics: str | None
channels: str | None
stable_rendition_id: str | None
extras: dict[str, Incomplete]
def __init__(
self,
uri: str | None = None,
type: str | None = None,
group_id: str | None = None,
language: str | None = None,
name: str | None = None,
default: str | None = None,
autoselect: str | None = None,
forced: str | None = None,
characteristics: str | None = None,
channels: str | None = None,
stable_rendition_id: str | None = None,
assoc_language: str | None = None,
instream_id: str | None = None,
base_uri: str | None = None,
**extras,
) -> None: ...
def dumps(self) -> str: ...
class TagList(list[_T]): ...
class MediaList(TagList[Media], list[Media], GroupedBasePathMixin[Media]):
@property
def uri(self) -> list[str | None]: ...
class PlaylistList(TagList[_PlaylistAnyT], list[_PlaylistAnyT], GroupedBasePathMixin[_PlaylistAnyT]): ...
class SessionDataList(TagList[SessionData], list[SessionData]): ...
class Start:
time_offset: float
precise: Literal["YES", "NO"]
def __init__(self, time_offset: float, precise: Literal["YES", "NO"] | None = None) -> None: ...
class RenditionReport(BasePathMixin):
base_uri: str | None
uri: str | None
last_msn: int
last_part: int | None
def __init__(self, base_uri: str | None, uri: str | None, last_msn: int, last_part: int | None = None) -> None: ...
def dumps(self) -> str: ...
class RenditionReportList(list[RenditionReport], GroupedBasePathMixin[RenditionReport]): ...
class ServerControl:
can_skip_until: float | None
can_block_reload: str | None
hold_back: float | None
part_hold_back: float | None
can_skip_dateranges: str | None
def __init__(
self,
can_skip_until: float | None = None,
can_block_reload: str | None = None,
hold_back: float | None = None,
part_hold_back: float | None = None,
can_skip_dateranges: str | None = None,
) -> None: ...
def __getitem__(self, item: str): ...
def dumps(self) -> str: ...
class Skip:
skipped_segments: int | None
recently_removed_dateranges: str | None
def __init__(self, skipped_segments: int, recently_removed_dateranges: str | None = None) -> None: ...
def dumps(self) -> str: ...
class PartInformation:
part_target: float | None
def __init__(self, part_target: float | None = None) -> None: ...
def dumps(self) -> str: ...
class PreloadHint(BasePathMixin):
hint_type: str | None
base_uri: str | None
uri: str | None
byterange_start: int | None
byterange_length: int | None
def __init__(
self,
type: str | None,
base_uri: str | None,
uri: str | None,
byterange_start: int | None = None,
byterange_length: int | None = None,
) -> None: ...
def __getitem__(self, item: str) -> str: ...
def dumps(self) -> str: ...
class SessionData:
data_id: str
value: str | None
uri: str | None
language: str | None
def __init__(self, data_id: str, value: str | None = None, uri: str | None = None, language: str | None = None) -> None: ...
def dumps(self) -> str: ...
class DateRangeList(TagList[DateRange]): ...
class DateRange:
id: str
start_date: str | None
class_: str | None
end_date: str | None
duration: float | None
planned_duration: float | None
scte35_cmd: str | None
scte35_out: str | None
scte35_in: str | None
end_on_next: Incomplete
x_client_attrs: list[tuple[str, str]]
def __init__(self, **kwargs) -> None: ...
def dumps(self) -> str: ...
class ContentSteering(BasePathMixin):
base_uri: str | None
uri: str | None
pathway_id: str | None
def __init__(self, base_uri: str | None, server_uri: str | None, pathway_id: str | None = None) -> None: ...
def dumps(self) -> str: ...
class ImagePlaylist(_PlaylistProtocol):
uri: str | None
base_uri: str | None
image_stream_info: StreamInfo
def __init__(self, base_uri: str | None, uri: str | None, image_stream_info: Mapping[str, Incomplete]) -> None: ...
class Tiles(BasePathMixin): # this is unused in runtime, so this is (temporary) has incomplete
uri: str | None
resolution: Incomplete
layout: Incomplete
duration: Incomplete
def __init__(self, resolution, layout, duration) -> None: ...
def dumps(self) -> str: ...

View File

@@ -0,0 +1,14 @@
from collections.abc import Callable
from re import Pattern
from typing import Any
from typing_extensions import TypeAlias
ATTRIBUTELISTPATTERN: Pattern[str]
_CustomTagsParser: TypeAlias = Callable[[str, int, dict[str, Any], dict[str, Any]], object]
class ParseError(Exception):
lineno: int
line: str
def __init__(self, lineno: int, line: str) -> None: ...
def parse(content: str, strict: bool = False, custom_tags_parser: _CustomTagsParser | None = None) -> dict[str, Any]: ...

View File

@@ -0,0 +1,41 @@
ext_m3u: str
ext_x_targetduration: str
ext_x_media_sequence: str
ext_x_discontinuity_sequence: str
ext_x_program_date_time: str
ext_x_media: str
ext_x_playlist_type: str
ext_x_key: str
ext_x_stream_inf: str
ext_x_version: str
ext_x_allow_cache: str
ext_x_endlist: str
extinf: str
ext_i_frames_only: str
ext_x_asset: str
ext_x_bitrate: str
ext_x_byterange: str
ext_x_i_frame_stream_inf: str
ext_x_discontinuity: str
ext_x_cue_out: str
ext_x_cue_out_cont: str
ext_x_cue_in: str
ext_x_cue_span: str
ext_oatcls_scte35: str
ext_is_independent_segments: str
ext_x_map: str
ext_x_start: str
ext_x_server_control: str
ext_x_part_inf: str
ext_x_part: str
ext_x_rendition_report: str
ext_x_skip: str
ext_x_session_data: str
ext_x_session_key: str
ext_x_preload_hint: str
ext_x_daterange: str
ext_x_gap: str
ext_x_content_steering: str
ext_x_image_stream_inf: str
ext_x_images_only: str
ext_x_tiles: str

View File

@@ -0,0 +1,5 @@
from m3u8.version_matching_rules import VersionMatchingError
def get_version(file_lines: list[str]) -> float | None: ...
def valid_in_all_rules(line_number: int, line: str, version: float) -> list[VersionMatchingError]: ...
def validate(file_lines: list[str]) -> list[VersionMatchingError]: ...

View File

@@ -0,0 +1,24 @@
from dataclasses import dataclass
@dataclass
class VersionMatchingError(Exception):
line_number: int
line: str
how_to_fix: str = ...
description: str = ...
class VersionMatchRuleBase:
description: str
how_to_fix: str
version: float
line_number: int
line: str
def __init__(self, version: float, line_number: int, line: str) -> None: ...
def validate(self) -> bool: ...
def get_error(self) -> VersionMatchingError: ...
class ValidIVInEXTXKEY(VersionMatchRuleBase): ...
class ValidFloatingPointEXTINF(VersionMatchRuleBase): ...
class ValidEXTXBYTERANGEOrEXTXIFRAMESONLY(VersionMatchRuleBase): ...
available_rules: list[type[VersionMatchRuleBase]]