Skip to Content
ReferencePythonopentele2._native

opentele2._native

The extension module compiled from the Rust core; every module of the package computes through it. It is typed by its _native.pyi stub. Its names are lower-level than the modules above; the guides load folders and print string sessions with them.

from opentele2._native import TData, mtcute_string_session, telethon_string_session

The signatures below come from _native.pyi, with read-only properties shown as attributes; _Bytes is bytes | bytearray, _Passcode is bytes | bytearray | str and _Path is str | os.PathLike[str].

Errors

opentele2/_native.pyi
class CoreError(Exception): code: str message: str legacy_message: str detail_code: str | None def __init__(self, code: str, message: str, legacy_message: str | None = None) -> None: ... def core_error_classes() -> dict[str, str]: ...

Every failure of the module raises CoreError. code is the stable SCREAMING_SNAKE code (for example TDATA_WRONG_PASSCODE or SRP_BAD_B), message the human-readable text, which may change between releases, legacy_message the stable message of the matching opentele2.exception class, and detail_code the code of a context raised differently from the rest of code, such as BAD_ACCOUNTS_COUNT. core_error_classes() maps each code to the class name raised for it.

tdata

opentele2/_native.pyi
SAVE_FAILED_MESSAGE: str MAX_ACCOUNT_LIMIT_MESSAGE: str TDF_MAGIC: bytes @final class Account: def __new__(cls, index: int, user_id: int, main_dc: int, keys: Iterable[tuple[int, _Bytes]], config: _Bytes | None = None) -> Account: ... index: int # read only user_id: int main_dc: int auth_key: bytes keys: list[tuple[int, bytes]] config: bytes | None @final class TData: MAX_ACCOUNTS: int @staticmethod def load(path: _Path, passcode: _Passcode = b"", key_file: str | None = None) -> TData: ... @staticmethod def new(accounts: Sequence[Account], passcode: _Passcode = b"", performance_mode: bool = True, active_index: int = -1, draws: Iterable[_Bytes] | None = None) -> TData: ... def save(self, path: _Path, performance_mode: bool | None = None, draws: Iterable[_Bytes] | None = None) -> None: ... def migrate(self, draws: Iterable[_Bytes] | None = None) -> bool: ... def add_account(self, user_id: int, main_dc: int, auth_key: _Bytes) -> int: ... accounts: list[Account] # settable active_index: int # settable performance_mode: bool # settable app_version: int local_key: bytes passcode_key: bytes main_account: Account | None key_file: str # settable legacy_key_file: bool def load_many(requests: Iterable[_LoadRequest], threads: int | None = None) -> list[TData | CoreError]: ... def draw_plan(operation: Literal["new", "migrate", "save"], target: TData | DrawPlanParams) -> list[int]: ...
NameDescription
TData.load(path, passcode, key_file)Loads a folder; a wrong passcode raises TDATA_BAD_DECRYPT_KEY, a missing key file TFILE_NOT_FOUND.
TData.new(accounts, ...)A new folder for accounts, with keys from the OS random source (fixed keys in performance mode without a passcode).
TData.save(path, ...)Writes the folder; with performance mode on no configs files are written.
TData.migrate()Installs 7.3 key data in place of a pre-7.3 key file and returns whether it did.
TData.add_account(user_id, main_dc, auth_key)Adds an account at the lowest free index and returns it; a full folder raises MAX_ACCOUNT_LIMIT.
TData.main_accountThe account at the active index, else the first one.
load_many(requests, threads)Loads many folders on a thread pool and returns, in input order, a TData or the CoreError of each; a request is a path or a (path, passcode, key_file) tuple.
draw_plan(operation, target)The sizes of the random draws "new", "migrate" or "save" would make, for replaying recorded draws through draws.

repr() of Account and TData never shows key bytes.

MTP config

opentele2/_native.pyi
MTP_FLAG_IPV6: int MTP_FLAG_MEDIA_ONLY: int MTP_FLAG_TCPO_ONLY: int MTP_FLAG_CDN: int MTP_FLAG_STATIC: int MTP_FLAG_THIS_PORT_ONLY: int MTP_FLAG_SECRET: int def account_mtp_config(account: Account | None = None) -> MtpConfig: ... def account_endpoints(account: Account | None = None, dc_id: int | None = None) -> Endpoints | None: ...

account_mtp_config is the account’s stored config parsed, or the production default; its dict has environment, dcs, cdn_public_keys and fields. account_endpoints gives the endpoints of a DC (the main DC by default) by family and protocol, None for a DC the config does not list. The flags are the endpoint bits Telegram Desktop stores. Account.MtpConfig in opentele2.td wraps both.

Sessions

opentele2/_native.pyi
def telethon_string_session(account: Account, ipv6: bool = False) -> str: ... def mtcute_string_session(account: Account) -> str: ... TELETHON_SESSION_VERSION: int # 8 TELETHON_SESSION_SUFFIX: str # ".session" TELETHON_JSON_SUFFIX: str # ".json" def telethon_schema() -> list[TelethonTable]: ... def telethon_session_rows(account: Account, ipv6: bool = False) -> TelethonSessionRows: ... def session_pair_paths(base: _Path) -> tuple[str, str]: ... def session_path(path: _Path) -> str: ... def session_companion_json(profile: ApiProfile, extra: dict[str, Any] | None = None) -> dict[str, Any]: ... def read_session_companion(text: str) -> tuple[ApiProfile | None, dict[str, Any]]: ... def write_session_file(path: _Path, dc_id: int, server_address: str, port: int, auth_key: _Bytes, takeout_id: int | None = None) -> str: ... def read_session_file(path: _Path) -> TelethonSessionRows: ... def py_json_text(obj: object) -> str: ...
FunctionDescription
telethon_string_session(account, ipv6)The Telethon string session (version 1) of the account’s main DC.
mtcute_string_session(account)The mtcute v3 string session of the account.
telethon_schema()The tables of the version 8 .session layout, with their DDL and columns.
telethon_session_rows(account, ipv6)The sessions row a .session file stores for the account.
session_pair_paths(base)The .session and .json paths of a pair: one trailing .session, then one .json, is removed and each suffix added back.
session_path(path)path with .session appended unless it ends with it.
session_companion_json(profile, extra)The .json companion object for a profile.
read_session_companion(text)The profile (None when its keys are not in strict form) and the whole object of companion text; raises INVALID_INPUT for text that is not a session JSON.
write_session_file(...)Writes a version 8 .session file over the bundled SQLite and returns its path.
read_session_file(path)Reads the sessions row of a version 8 file.
py_json_text(obj)json.dumps(obj, indent=2, ensure_ascii=False), the companion’s text form.

Profiles and devices

opentele2/_native.pyi
def profile(client: _Client, versions: _VersionsArg | None = None) -> ApiProfile: ... def generate(client: _Client, seed: str | int | None = None, system: _DesktopSystem | None = None, versions: _VersionsArg | None = None) -> ApiProfile: ... def profile_from_session_json(json: str | dict[str, Any]) -> ApiProfile: ... def profile_to_session_json(profile: ApiProfile, extra: dict[str, Any] | None = None) -> dict[str, Any]: ... def profiles_equal(a: ApiProfile, b: ApiProfile) -> bool: ... def format_app_version(version: int) -> str: ... SESSION_JSON_FIELDS: list[tuple[str, str, str | None, str | None]] DEFAULT_EXTRA_FIELDS: list[tuple[str, str | bool | None]] def catalog_entries(platform: _Platform) -> list[CatalogEntry]: ... def device_models(platform: _Platform) -> list[str]: ... def system_versions(platform: _Platform) -> list[str]: ... WEB_BROWSER_WEIGHTS: dict[str, int]

_Client is one of "TelegramDesktop", "TelegramAndroid", "TelegramAndroidX", "TelegramIOS", "TelegramMacOS", "TelegramWeb_A", "TelegramWeb_K" and "Webogram"; _DesktopSystem is "windows", "macos" or "linux"; _Platform is "windows", "linux", "macos", "android", "ios", "web_a" or "web_k". An ApiProfile is a dict with api_id, api_hash, device_model, system_version, app_version, lang_code, system_lang_code and lang_pack.

FunctionDescription
profile(client, versions)The default profile of a client, with versions overriding the offline versions.
generate(client, seed, system, versions)The profile API.<client>.Generate returns for seed.
profile_from_session_json(json) / profile_to_session_json(profile, extra)APIData.from_json and APIData.to_json on dicts.
profiles_equal(a, b)Equality on api_id, api_hash, device_model, system_version and app_version.
format_app_version(version)A packed desktop version as text: 7003001 is "7.3.1".
SESSION_JSON_FIELDS / DEFAULT_EXTRA_FIELDSThe profile keys of the session JSON as (key, attribute, default, fallback), and the account keys as (key, default).
catalog_entries, device_models, system_versionsA catalog’s weighted pairs, models and system versions.

Versions

opentele2/_native.pyi
DEFAULT_TIMEOUT: float def platform_versions(overrides: _VersionsArg | None = None) -> PlatformVersions: ... def fetch_versions(timeout: float = ...) -> dict[str, str | int]: ... def apply_versions_patch(versions: _VersionsArg | None, patch: VersionsPatch | Mapping[str, str | int | None]) -> PlatformVersions: ...

platform_versions is the offline set with overrides applied. fetch_versions queries the release feeds (each request bounded by timeout seconds, DEFAULT_TIMEOUT by default) and returns the fields that answered; it never raises for the network. apply_versions_patch writes a patch onto a version set, leaving desktop_app_version bound to the tdata version.

Fingerprint checks

opentele2/_native.pyi
LAYER: int STRICT_MODES: tuple[StrictMode, ...] FINGERPRINT_CONFIG_DEFAULTS: FingerprintConfigDefaults MSG_ID_OFFSET_MAX: int def tz_offset(offset_seconds: int) -> float: ... def validate_init_params(profile: ApiProfile, versions: _VersionsArg | None = None, mode: StrictMode = "warn") -> list[Issue]: ... def check_versions(profile: ApiProfile, versions: _VersionsArg | None = None) -> list[Issue]: ... def issues_message(issues: Iterable[Issue]) -> str: ... def msg_id_offset() -> int: ... def is_valid_msg_id(msg_id: int, from_client: bool, now_unix: float) -> bool: ... def fingerprint_config(*, strict_mode: StrictMode | None = None, auto_validate: bool | None = None, preferred_transport: str | None = None, warn_on_layer_mismatch: bool | None = None, layer_override: int | None = None, randomize_msg_id_offset: bool | None = None, msg_id_offset: int | None = None) -> FingerprintConfig: ... def validate_fingerprint(config: FingerprintConfig, profile: ApiProfile, versions: _VersionsArg | None = None) -> list[Issue]: ... def effective_layer(config: FingerprintConfig) -> int: ... def layer_mismatch_warning(library_layer: int) -> str | None: ...

An Issue is a dict with kind (UnknownLangPack, ShortLangCode, MissingRegion, EmptyDeviceModel, EmptySystemVersion, EmptyAppVersion, ApiIdMismatch, AppVersionMajor, AndroidSdkRange), severity (note, warning, error) and message. validate_init_params checks a profile under a mode; check_versions is the strict version check alone; issues_message is the text FingerprintConfig.validate_params warns or raises with. The opentele2.fingerprint module wraps these.

Browser

opentele2/_native.pyi
SUPPORTED_BROWSERS: tuple[str, ...] SUPPORTED_OPERATING_SYSTEMS: tuple[str, ...] SUPPORTED_DEVICES: tuple[str, ...] SUPPORTED_HTTP_VERSIONS: tuple[Literal["1", "2"], ...] def generate_headers(options: HeaderOptions | None = None, *, seed: str | int | None = None, **kwargs: Unpack[HeaderOptions]) -> dict[str, str]: ... def generate_fingerprint(options: FingerprintOptions | None = None, *, seed: str | int | None = None, **kwargs: Unpack[FingerprintOptions]) -> FingerprintData: ...

The dict forms of opentele2.browser: HeaderOptions has browser, os, device, locale, http_version, strict, user_agent and request_dependent_headers; FingerprintOptions has screen, strict, mock_webrtc, slim and header. Unsatisfiable or invalid options raise ValueError, an unknown key TypeError.

Crypto

opentele2/_native.pyi
def key_id(auth_key: _Bytes) -> int: ... def prepare_aes_oldmtp(auth_key: _Bytes, msg_key: _Bytes, send: bool = False) -> tuple[bytes, bytes]: ... def aes_ige_encrypt(data: _Bytes, key: _Bytes, iv: _Bytes) -> bytes: ... def aes_ige_decrypt(data: _Bytes, key: _Bytes, iv: _Bytes) -> bytes: ... def encrypt_local(data: _Bytes, local_key: _Bytes) -> bytes: ... def decrypt_local(encrypted: _Bytes, local_key: _Bytes) -> bytes: ... def create_local_key(passcode: _Passcode, salt: _Bytes) -> bytes: ... def create_legacy_local_key(passcode: _Passcode, salt: _Bytes) -> bytes: ... def argon2id(passcode: _Passcode, salt: _Bytes, memory_kib: int, time: int, lanes: int) -> bytes: ... def sha1(data: _Bytes) -> bytes: ... def sha256(data: _Bytes) -> bytes: ... def hmac_sha256(key: _Bytes, data: _Bytes) -> bytes: ... def pbkdf2(password: _Passcode, salt: _Bytes, iterations: int, key_len: int = 64, digest: str = "sha512") -> bytes: ... def factorize_pq(pq: _Bytes) -> tuple[bytes, bytes]: ... def random_bytes(size: int) -> bytes: ... def gzip(data: _Bytes, max_size: int | None = None) -> bytes | None: ... def gunzip(data: _Bytes) -> bytes: ... @final class AesCtr: def __new__(cls, key: _Bytes, iv: _Bytes) -> AesCtr: ... def process(self, data: _Bytes) -> bytes: ... cryptg: _Cryptg # encrypt_ige(data, key, iv), decrypt_ige(data, key, iv)

Bad lengths raise CoreError BAD_LENGTH; pbkdf2 with zero iterations or a digest other than sha1, sha256 and sha512 raises INVALID_INPUT. factorize_pq takes 1 to 8 big-endian bytes and returns p <= q. AesCtr keeps its keystream across process calls. cryptg is the cryptg 0.6.0 interface, also importable as opentele2._native.cryptg, which import opentele2 registers as the top-level cryptg when no real one is installed.

Login, session admin and consistency

opentele2/_native.pyi
def qr_login_url(token: _Bytes) -> str: ... def srp_inputs(srp_id: int | None = None, srp_b: _Bytes | None = None) -> tuple[int, bytes]: ... def srp_check(params: SrpParams, password: str, exponents: Iterable[_Bytes] | None = None) -> SrpCheck: ... def post_login_steps(lang_pack: str) -> list[PostLoginStep]: ... def random_delay_ms(min_ms: int, max_ms: int) -> int: ... def session_row(authorization: _Authorization) -> SessionRow: ... def format_sessions(rows: Iterable[SessionRow]) -> str: ... def format_table(headers: Sequence[str], rows: Sequence[Sequence[str]], add_split: Sequence[int] | None = None) -> str: ... def is_official_api_id(api_id: int) -> bool: ... def consistency_checks() -> list[str]: ... def consistency_expectations(profile: ApiProfile, versions: _VersionsArg | None = None) -> ConsistencyExpectations: ... def consistency_report(outcomes: Iterable[CheckOutcome]) -> ConsistencyReport: ... def consistency_summary(results: Iterable[CheckResult]) -> str: ... def layer_result(library_layer: int, advertised_layer: int | None = None) -> CheckResult: ... OFFICIAL_API_IDS: tuple[int, ...] SESSION_COLUMNS: tuple[str, ...] LAYER_TOLERANCE: int QR_LOGIN_ATTEMPTS: int QR_EXPIRE_SAFETY_SECONDS: int POST_LOGIN_STEPS: tuple[PostLoginStep, ...]
NameDescription
qr_login_url(token)tg://login?token= and the token in URL-safe base64 without padding, as Telethon’s QRLogin.url.
srp_inputs / srp_checkThe srp_id and srp_B rule and the inputCheckPasswordSRP values of Telethon’s password.compute_check; refusals raise SRP_BAD_PRIME_OR_GENERATOR, SRP_BAD_B or SRP_NO_GOOD_RANDOM.
post_login_steps(lang_pack)The requests an official client sends after login, with the sleep range before each.
session_row, format_sessions, format_tableThe row PrintSessions shows for an authorization, and the table it prints.
is_official_api_id(api_id)Whether api_id is one of OFFICIAL_API_IDS (2040, 6, 21724, 10840, 2834, 2496).
consistency_checks()The names of the seven checks, in order.
consistency_expectations(profile)What the seven checks expect from a session with profile.
consistency_report(outcomes) / consistency_summary(results)The report and its text from one outcome per check.
layer_result(library_layer)The layer_match result: passes within LAYER_TOLERANCE (15) of LAYER.

The module also carries the message constants and detail builders of these flows (NO_PASSWORD_PROVIDED, FRESH_RESET_FORBIDDEN, HASH_INVALID, QR_LOGIN_TIMEOUT, EXISTING_SESSION_KEPT, EXISTING_SESSION_REPLACED, get_config_detail, lang_pack_detail and the rest), which the Python modules use to word their warnings and errors.

Last updated on