From 02cf2d4595827ed55a629230b07e9d485a615fd2 Mon Sep 17 00:00:00 2001 From: iphydf Date: Mon, 8 Jan 2024 03:26:02 +0000 Subject: [PATCH 1/6] feat: Add stubgen to produce typings for cython modules. mypy's stubgen doesn't work, so I approximated one myself. --- .gitignore | 1 + BUILD.bazel | 19 - pytox/common.py | 8 +- pytox/toxav/toxav.pyi | 84 +++ pytox/toxav/toxav.pyx | 1 + pytox/toxcore/tox.pyi | 503 ++++++++++++++++++ pytox/toxcore/tox.pyx | 17 +- pytox/toxencryptsave/toxencryptsave.pyi | 41 ++ pytox/toxencryptsave/toxencryptsave.pyx | 5 +- .../auto_tests/self_connection_status_test.py | 4 +- test/tox_test.py | 16 +- test/toxav_test.py | 4 +- test/toxencryptsave_test.py | 2 +- tools/BUILD.bazel | 3 +- tools/gen-api | 1 + tools/stubgen.py | 137 ++++- 16 files changed, 798 insertions(+), 48 deletions(-) create mode 100644 pytox/toxav/toxav.pyi create mode 100644 pytox/toxcore/tox.pyi create mode 100644 pytox/toxencryptsave/toxencryptsave.pyi diff --git a/.gitignore b/.gitignore index cf5bf61..86290be 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,4 @@ .mypy_cache # TODO(iphydf): Remove once .gen is removed from the name. *.gen.pyx +__pycache__ diff --git a/BUILD.bazel b/BUILD.bazel index 9527ed2..aaec641 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -3,17 +3,6 @@ load("//tools/project:build_defs.bzl", "project") project(license = "gpl3-https") -#genrule( -# name = "pytox/core", -# srcs = [ -# "pytox/src/core.pyx", -# "//c-toxcore:tox/tox.h", -# ], -# outs = ["pytox/core.pyx"], -# cmd = "$(location //py_toxcore_c/tools:gen_api) $(location pytox/src/core.pyx) $(location //c-toxcore:tox/tox.h) > $@", -# tools = ["//py_toxcore_c/tools:gen_api"], -#) - pyx_library( name = "pytox", srcs = glob( @@ -34,11 +23,3 @@ pyx_library( tags = ["no-cross"], visibility = ["//visibility:public"], ) - -genrule( - name = "pytox_stubs", - outs = [mod[:-4] + ".pyi" for mod in glob(["pytox/**/*.pyx"])], - cmd = "$(location //py_toxcore_c/tools:stubgen) -o $(GENDIR)/py_toxcore_c" + " ".join([" -m %s" % mod[:-4].replace("/", ".") for mod in glob(["pytox/**/*.pyx"])]), - tags = ["manual"], - tools = ["//py_toxcore_c/tools:stubgen"], -) diff --git a/pytox/common.py b/pytox/common.py index 89589fa..83794d5 100644 --- a/pytox/common.py +++ b/pytox/common.py @@ -1,4 +1,4 @@ -from enum import Enum +import enum from typing import Sized from typing import TypeVar @@ -10,7 +10,7 @@ class PytoxException(Exception): class ApiException(PytoxException): - def __init__(self, err: Enum): + def __init__(self, err: enum.Enum): super().__init__(err.name) self.error = err @@ -20,13 +20,13 @@ class LengthException(PytoxException): class UseAfterFreeException(Exception): - def __init__(self): + def __init__(self) -> None: super().__init__( "object used after it was killed/freed (or it was never initialised)" ) -def _check_len(name: str, data: T, expected_length: int) -> T: +def check_len(name: str, data: T, expected_length: int) -> T: if len(data) < expected_length: raise LengthException( f"parameter '{name}' received bytes of invalid" diff --git a/pytox/toxav/toxav.pyi b/pytox/toxav/toxav.pyi new file mode 100644 index 0000000..f15fb0b --- /dev/null +++ b/pytox/toxav/toxav.pyi @@ -0,0 +1,84 @@ +# pytox.toxav.toxav +from array import array +from pytox.toxcore.tox import Tox_Ptr +from types import TracebackType +from typing import Any +from typing import Self +import enum +import pytox.common +class Tox_Conference_Number: ... +class Tox_Conference_Peer_Number: ... +class Tox_File_Number: ... +class Tox_Friend_Message_Id: ... +class Tox_Friend_Number: ... +class Tox_Group_Message_Id: ... +class Tox_Group_Number: ... +class Tox_Group_Peer_Number: ... +class ApiException(pytox.common.ApiException): ... +class Toxav_Call_Control(enum.Enum): ... +class Toxav_Err_Answer(enum.Enum): ... +class Toxav_Err_Bit_Rate_Set(enum.Enum): ... +class Toxav_Err_Call(enum.Enum): ... +class Toxav_Err_Call_Control(enum.Enum): ... +class Toxav_Err_New(enum.Enum): ... +class Toxav_Err_Send_Frame(enum.Enum): ... +class Toxav_Friend_Call_State(enum.Enum): ... +class Toxav_Ptr: + def __enter__(self) -> Self: ... + def __exit__(self, exc_type: type[BaseException] | None, exc_value: BaseException | None, exc_traceback: TracebackType | None) -> None: ... + def __init__(self, tox: Tox_Ptr) -> None: ... + def handle_audio_bit_rate(self, friend_number: int, audio_bit_rate: int) -> None: ... + def handle_audio_receive_frame(self, friend_number: int, pcm: array[Any], channels: int, sampling_rate: int) -> None: ... + def handle_call(self, friend_number: int, audio_enabled: bool, video_enabled: bool) -> None: ... + def handle_call_state(self, friend_number: int, state: int) -> None: ... + def handle_video_bit_rate(self, friend_number: int, video_bit_rate: int) -> None: ... + def handle_video_receive_frame(self, friend_number: int, width: int, height: int, y: bytes, u: bytes, v: bytes, ystride: int, ustride: int, vstride: int) -> None: ... +TOXAV_CALL_CONTROL_CANCEL: Toxav_Call_Control +TOXAV_CALL_CONTROL_HIDE_VIDEO: Toxav_Call_Control +TOXAV_CALL_CONTROL_MUTE_AUDIO: Toxav_Call_Control +TOXAV_CALL_CONTROL_PAUSE: Toxav_Call_Control +TOXAV_CALL_CONTROL_RESUME: Toxav_Call_Control +TOXAV_CALL_CONTROL_SHOW_VIDEO: Toxav_Call_Control +TOXAV_CALL_CONTROL_UNMUTE_AUDIO: Toxav_Call_Control +TOXAV_ERR_ANSWER_CODEC_INITIALIZATION: Toxav_Err_Answer +TOXAV_ERR_ANSWER_FRIEND_NOT_CALLING: Toxav_Err_Answer +TOXAV_ERR_ANSWER_FRIEND_NOT_FOUND: Toxav_Err_Answer +TOXAV_ERR_ANSWER_INVALID_BIT_RATE: Toxav_Err_Answer +TOXAV_ERR_ANSWER_OK: Toxav_Err_Answer +TOXAV_ERR_ANSWER_SYNC: Toxav_Err_Answer +TOXAV_ERR_BIT_RATE_SET_FRIEND_NOT_FOUND: Toxav_Err_Bit_Rate_Set +TOXAV_ERR_BIT_RATE_SET_FRIEND_NOT_IN_CALL: Toxav_Err_Bit_Rate_Set +TOXAV_ERR_BIT_RATE_SET_INVALID_BIT_RATE: Toxav_Err_Bit_Rate_Set +TOXAV_ERR_BIT_RATE_SET_OK: Toxav_Err_Bit_Rate_Set +TOXAV_ERR_BIT_RATE_SET_SYNC: Toxav_Err_Bit_Rate_Set +TOXAV_ERR_CALL_CONTROL_FRIEND_NOT_FOUND: Toxav_Err_Call +TOXAV_ERR_CALL_CONTROL_FRIEND_NOT_IN_CALL: Toxav_Err_Call +TOXAV_ERR_CALL_CONTROL_INVALID_TRANSITION: Toxav_Err_Call +TOXAV_ERR_CALL_CONTROL_OK: Toxav_Err_Call +TOXAV_ERR_CALL_CONTROL_SYNC: Toxav_Err_Call +TOXAV_ERR_CALL_FRIEND_ALREADY_IN_CALL: Toxav_Err_Call +TOXAV_ERR_CALL_FRIEND_NOT_CONNECTED: Toxav_Err_Call +TOXAV_ERR_CALL_FRIEND_NOT_FOUND: Toxav_Err_Call +TOXAV_ERR_CALL_INVALID_BIT_RATE: Toxav_Err_Call +TOXAV_ERR_CALL_MALLOC: Toxav_Err_Call +TOXAV_ERR_CALL_OK: Toxav_Err_Call +TOXAV_ERR_CALL_SYNC: Toxav_Err_Call +TOXAV_ERR_NEW_MALLOC: Toxav_Err_New +TOXAV_ERR_NEW_MULTIPLE: Toxav_Err_New +TOXAV_ERR_NEW_NULL: Toxav_Err_New +TOXAV_ERR_NEW_OK: Toxav_Err_New +TOXAV_ERR_SEND_FRAME_FRIEND_NOT_FOUND: Toxav_Err_Send_Frame +TOXAV_ERR_SEND_FRAME_FRIEND_NOT_IN_CALL: Toxav_Err_Send_Frame +TOXAV_ERR_SEND_FRAME_INVALID: Toxav_Err_Send_Frame +TOXAV_ERR_SEND_FRAME_NULL: Toxav_Err_Send_Frame +TOXAV_ERR_SEND_FRAME_OK: Toxav_Err_Send_Frame +TOXAV_ERR_SEND_FRAME_PAYLOAD_TYPE_DISABLED: Toxav_Err_Send_Frame +TOXAV_ERR_SEND_FRAME_RTP_FAILED: Toxav_Err_Send_Frame +TOXAV_ERR_SEND_FRAME_SYNC: Toxav_Err_Send_Frame +TOXAV_FRIEND_CALL_STATE_ACCEPTING_A: Toxav_Friend_Call_State +TOXAV_FRIEND_CALL_STATE_ACCEPTING_V: Toxav_Friend_Call_State +TOXAV_FRIEND_CALL_STATE_ERROR: Toxav_Friend_Call_State +TOXAV_FRIEND_CALL_STATE_FINISHED: Toxav_Friend_Call_State +TOXAV_FRIEND_CALL_STATE_NONE: Toxav_Friend_Call_State +TOXAV_FRIEND_CALL_STATE_SENDING_A: Toxav_Friend_Call_State +TOXAV_FRIEND_CALL_STATE_SENDING_V: Toxav_Friend_Call_State diff --git a/pytox/toxav/toxav.pyx b/pytox/toxav/toxav.pyx index f709c68..6458013 100644 --- a/pytox/toxav/toxav.pyx +++ b/pytox/toxav/toxav.pyx @@ -69,5 +69,6 @@ cdef class Toxav_Ptr: def handle_video_receive_frame(self, friend_number: int, width: int, height: int, y: bytes, u: bytes, v: bytes, ystride: int, ustride: int, vstride: int) -> None: pass def __init__(self, tox.Tox_Ptr tox): + """Create new Toxav object.""" self._ptr = self._new(tox) install_handlers(self, self._ptr) diff --git a/pytox/toxcore/tox.pyi b/pytox/toxcore/tox.pyi new file mode 100644 index 0000000..0f39f40 --- /dev/null +++ b/pytox/toxcore/tox.pyi @@ -0,0 +1,503 @@ +# pytox.toxcore.tox +from types import TracebackType +from typing import Any +from typing import Optional +from typing import Self +import enum +import pytox.common +class Tox_Conference_Number: ... +class Tox_Conference_Peer_Number: ... +class Tox_File_Number: ... +class Tox_Friend_Message_Id: ... +class Tox_Friend_Number: ... +class Tox_Group_Message_Id: ... +class Tox_Group_Number: ... +class Tox_Group_Peer_Number: ... +class ApiException(pytox.common.ApiException): ... +class Tox_Conference_Type(enum.Enum): ... +class Tox_Connection(enum.Enum): ... +class Tox_Err_Bootstrap(enum.Enum): ... +class Tox_Err_Conference_By_Id(enum.Enum): ... +class Tox_Err_Conference_By_Uid(enum.Enum): ... +class Tox_Err_Conference_Delete(enum.Enum): ... +class Tox_Err_Conference_Get_Type(enum.Enum): ... +class Tox_Err_Conference_Invite(enum.Enum): ... +class Tox_Err_Conference_Join(enum.Enum): ... +class Tox_Err_Conference_New(enum.Enum): ... +class Tox_Err_Conference_Peer_Query(enum.Enum): ... +class Tox_Err_Conference_Send_Message(enum.Enum): ... +class Tox_Err_Conference_Set_Max_Offline(enum.Enum): ... +class Tox_Err_Conference_Title(enum.Enum): ... +class Tox_Err_File_Control(enum.Enum): ... +class Tox_Err_File_Get(enum.Enum): ... +class Tox_Err_File_Seek(enum.Enum): ... +class Tox_Err_File_Send(enum.Enum): ... +class Tox_Err_File_Send_Chunk(enum.Enum): ... +class Tox_Err_Friend_Add(enum.Enum): ... +class Tox_Err_Friend_By_Public_Key(enum.Enum): ... +class Tox_Err_Friend_Custom_Packet(enum.Enum): ... +class Tox_Err_Friend_Delete(enum.Enum): ... +class Tox_Err_Friend_Get_Last_Online(enum.Enum): ... +class Tox_Err_Friend_Get_Public_Key(enum.Enum): ... +class Tox_Err_Friend_Query(enum.Enum): ... +class Tox_Err_Friend_Send_Message(enum.Enum): ... +class Tox_Err_Get_Port(enum.Enum): ... +class Tox_Err_Group_Disconnect(enum.Enum): ... +class Tox_Err_Group_Founder_Set_Password(enum.Enum): ... +class Tox_Err_Group_Founder_Set_Peer_Limit(enum.Enum): ... +class Tox_Err_Group_Founder_Set_Privacy_State(enum.Enum): ... +class Tox_Err_Group_Founder_Set_Topic_Lock(enum.Enum): ... +class Tox_Err_Group_Founder_Set_Voice_State(enum.Enum): ... +class Tox_Err_Group_Invite_Accept(enum.Enum): ... +class Tox_Err_Group_Invite_Friend(enum.Enum): ... +class Tox_Err_Group_Is_Connected(enum.Enum): ... +class Tox_Err_Group_Join(enum.Enum): ... +class Tox_Err_Group_Leave(enum.Enum): ... +class Tox_Err_Group_Mod_Kick_Peer(enum.Enum): ... +class Tox_Err_Group_Mod_Set_Role(enum.Enum): ... +class Tox_Err_Group_New(enum.Enum): ... +class Tox_Err_Group_Peer_Query(enum.Enum): ... +class Tox_Err_Group_Reconnect(enum.Enum): ... +class Tox_Err_Group_Self_Name_Set(enum.Enum): ... +class Tox_Err_Group_Self_Query(enum.Enum): ... +class Tox_Err_Group_Self_Status_Set(enum.Enum): ... +class Tox_Err_Group_Send_Custom_Packet(enum.Enum): ... +class Tox_Err_Group_Send_Custom_Private_Packet(enum.Enum): ... +class Tox_Err_Group_Send_Message(enum.Enum): ... +class Tox_Err_Group_Send_Private_Message(enum.Enum): ... +class Tox_Err_Group_Set_Ignore(enum.Enum): ... +class Tox_Err_Group_State_Queries(enum.Enum): ... +class Tox_Err_Group_Topic_Set(enum.Enum): ... +class Tox_Err_New(enum.Enum): ... +class Tox_Err_Options_New(enum.Enum): ... +class Tox_Err_Set_Info(enum.Enum): ... +class Tox_Err_Set_Typing(enum.Enum): ... +class Tox_File_Control(enum.Enum): ... +class Tox_File_Kind(enum.Enum): ... +class Tox_Group_Exit_Type(enum.Enum): ... +class Tox_Group_Join_Fail(enum.Enum): ... +class Tox_Group_Mod_Event(enum.Enum): ... +class Tox_Group_Privacy_State(enum.Enum): ... +class Tox_Group_Role(enum.Enum): ... +class Tox_Group_Topic_Lock(enum.Enum): ... +class Tox_Group_Voice_State(enum.Enum): ... +class Tox_Log_Level(enum.Enum): ... +class Tox_Message_Type(enum.Enum): ... +class Tox_Options_Ptr: + def __enter__(self) -> Self: ... + def __exit__(self, exc_type: type[BaseException] | None, exc_value: BaseException | None, exc_traceback: TracebackType | None) -> None: ... + def __init__(self) -> None: ... + dht_announcements_enabled: Any + end_port: Any + experimental_thread_safety: Any + hole_punching_enabled: Any + ipv6_enabled: Any + local_discovery_enabled: Any + proxy_host: Any + proxy_port: Any + proxy_type: Any + savedata_type: Any + start_port: Any + tcp_port: Any + udp_enabled: Any +class Tox_Proxy_Type(enum.Enum): ... +class Tox_Ptr: + def __enter__(self) -> Self: ... + def __exit__(self, exc_type: type[BaseException] | None, exc_value: BaseException | None, exc_traceback: TracebackType | None) -> None: ... + def __init__(self, options: Optional[Tox_Options_Ptr] = None) -> None: ... + address: Any + def bootstrap(self, host: str, port: int, public_key: bytes) -> bool: ... + connection_status: Any + def friend_add(self, address: bytes, message: bytes) -> None: ... + def friend_add_norequest(self, public_key: bytes) -> None: ... + def friend_delete(self, friend_number: int) -> None: ... + group_number_groups: Any + def handle_conference_connected(self, conference_number: Tox_Conference_Number) -> None: ... + def handle_conference_invite(self, friend_number: Tox_Friend_Number, type_: Tox_Conference_Type, cookie: bytes) -> None: ... + def handle_conference_message(self, conference_number: Tox_Conference_Number, peer_number: Tox_Conference_Peer_Number, type_: Tox_Message_Type, message: bytes) -> None: ... + def handle_conference_peer_list_changed(self, conference_number: Tox_Conference_Number) -> None: ... + def handle_conference_peer_name(self, conference_number: Tox_Conference_Number, peer_number: Tox_Conference_Peer_Number, name: bytes) -> None: ... + def handle_conference_title(self, conference_number: Tox_Conference_Number, peer_number: Tox_Conference_Peer_Number, title: bytes) -> None: ... + def handle_file_chunk_request(self, friend_number: Tox_Friend_Number, file_number: Tox_File_Number, position: int, length: int) -> None: ... + def handle_file_recv(self, friend_number: Tox_Friend_Number, file_number: Tox_File_Number, kind: int, file_size: int, filename: bytes) -> None: ... + def handle_file_recv_chunk(self, friend_number: Tox_Friend_Number, file_number: Tox_File_Number, position: int, data: bytes) -> None: ... + def handle_file_recv_control(self, friend_number: Tox_Friend_Number, file_number: Tox_File_Number, control: Tox_File_Control) -> None: ... + def handle_friend_connection_status(self, friend_number: Tox_Friend_Number, connection_status: Tox_Connection) -> None: ... + def handle_friend_lossless_packet(self, friend_number: Tox_Friend_Number, data: bytes) -> None: ... + def handle_friend_lossy_packet(self, friend_number: Tox_Friend_Number, data: bytes) -> None: ... + def handle_friend_message(self, friend_number: Tox_Friend_Number, type_: Tox_Message_Type, message: bytes) -> None: ... + def handle_friend_name(self, friend_number: Tox_Friend_Number, name: bytes) -> None: ... + def handle_friend_read_receipt(self, friend_number: Tox_Friend_Number, message_id: Tox_Friend_Message_Id) -> None: ... + def handle_friend_request(self, public_key: bytes, message: bytes) -> None: ... + def handle_friend_status(self, friend_number: Tox_Friend_Number, status: Tox_User_Status) -> None: ... + def handle_friend_status_message(self, friend_number: Tox_Friend_Number, message: bytes) -> None: ... + def handle_friend_typing(self, friend_number: Tox_Friend_Number, typing: bool) -> None: ... + def handle_group_custom_packet(self, group_number: Tox_Group_Number, peer_id: Tox_Group_Peer_Number, data: bytes) -> None: ... + def handle_group_custom_private_packet(self, group_number: Tox_Group_Number, peer_id: Tox_Group_Peer_Number, data: bytes) -> None: ... + def handle_group_invite(self, friend_number: Tox_Friend_Number, invite_data: bytes, group_name: bytes) -> None: ... + def handle_group_join_fail(self, group_number: Tox_Group_Number, fail_type: Tox_Group_Join_Fail) -> None: ... + def handle_group_message(self, group_number: Tox_Group_Number, peer_id: Tox_Group_Peer_Number, type_: Tox_Message_Type, message: bytes, message_id: Tox_Group_Message_Id) -> None: ... + def handle_group_moderation(self, group_number: Tox_Group_Number, source_peer_id: Tox_Group_Peer_Number, target_peer_id: Tox_Group_Peer_Number, mod_type: Tox_Group_Mod_Event) -> None: ... + def handle_group_password(self, group_number: Tox_Group_Number, password: bytes) -> None: ... + def handle_group_peer_exit(self, group_number: Tox_Group_Number, peer_id: Tox_Group_Peer_Number, exit_type: Tox_Group_Exit_Type, name: bytes, part_message: bytes) -> None: ... + def handle_group_peer_join(self, group_number: Tox_Group_Number, peer_id: Tox_Group_Peer_Number) -> None: ... + def handle_group_peer_limit(self, group_number: Tox_Group_Number, peer_limit: int) -> None: ... + def handle_group_peer_name(self, group_number: Tox_Group_Number, peer_id: Tox_Group_Peer_Number, name: bytes) -> None: ... + def handle_group_peer_status(self, group_number: Tox_Group_Number, peer_id: Tox_Group_Peer_Number, status: Tox_User_Status) -> None: ... + def handle_group_privacy_state(self, group_number: Tox_Group_Number, privacy_state: Tox_Group_Privacy_State) -> None: ... + def handle_group_private_message(self, group_number: Tox_Group_Number, peer_id: Tox_Group_Peer_Number, type_: Tox_Message_Type, message: bytes) -> None: ... + def handle_group_self_join(self, group_number: Tox_Group_Number) -> None: ... + def handle_group_topic(self, group_number: Tox_Group_Number, peer_id: Tox_Group_Peer_Number, topic: bytes) -> None: ... + def handle_group_topic_lock(self, group_number: Tox_Group_Number, topic_lock: Tox_Group_Topic_Lock) -> None: ... + def handle_group_voice_state(self, group_number: Tox_Group_Number, voice_state: Tox_Group_Voice_State) -> None: ... + def handle_self_connection_status(self, connection_status: Tox_Connection) -> None: ... + def iterate(self) -> None: ... + iteration_interval: Any + name: Any + nospam: Any + public_key: Any + savedata: Any + secret_key: Any + status: Any + status_message: Any +class Tox_Savedata_Type(enum.Enum): ... +class Tox_User_Status(enum.Enum): ... +ADDRESS_SIZE: int +CONFERENCE_ID_SIZE: int +CONFERENCE_UID_SIZE: int +FILE_ID_LENGTH: int +HASH_LENGTH: int +MAX_CUSTOM_PACKET_SIZE: int +MAX_FILENAME_LENGTH: int +MAX_FRIEND_REQUEST_LENGTH: int +MAX_HOSTNAME_LENGTH: int +MAX_MESSAGE_LENGTH: int +MAX_NAME_LENGTH: int +MAX_STATUS_MESSAGE_LENGTH: int +NOSPAM_SIZE: int +PUBLIC_KEY_SIZE: int +SECRET_KEY_SIZE: int +TOX_CONFERENCE_TYPE_AV: Tox_Conference_Type +TOX_CONFERENCE_TYPE_TEXT: Tox_Conference_Type +TOX_CONNECTION_NONE: Tox_Connection +TOX_CONNECTION_TCP: Tox_Connection +TOX_CONNECTION_UDP: Tox_Connection +TOX_ERR_BOOTSTRAP_BAD_HOST: Tox_Err_Bootstrap +TOX_ERR_BOOTSTRAP_BAD_PORT: Tox_Err_Bootstrap +TOX_ERR_BOOTSTRAP_NULL: Tox_Err_Bootstrap +TOX_ERR_BOOTSTRAP_OK: Tox_Err_Bootstrap +TOX_ERR_CONFERENCE_BY_ID_NOT_FOUND: Tox_Err_Conference_By_Id +TOX_ERR_CONFERENCE_BY_ID_NULL: Tox_Err_Conference_By_Id +TOX_ERR_CONFERENCE_BY_ID_OK: Tox_Err_Conference_By_Id +TOX_ERR_CONFERENCE_BY_UID_NOT_FOUND: Tox_Err_Conference_By_Uid +TOX_ERR_CONFERENCE_BY_UID_NULL: Tox_Err_Conference_By_Uid +TOX_ERR_CONFERENCE_BY_UID_OK: Tox_Err_Conference_By_Uid +TOX_ERR_CONFERENCE_DELETE_CONFERENCE_NOT_FOUND: Tox_Err_Conference_Delete +TOX_ERR_CONFERENCE_DELETE_OK: Tox_Err_Conference_Delete +TOX_ERR_CONFERENCE_GET_TYPE_CONFERENCE_NOT_FOUND: Tox_Err_Conference_Get_Type +TOX_ERR_CONFERENCE_GET_TYPE_OK: Tox_Err_Conference_Get_Type +TOX_ERR_CONFERENCE_INVITE_CONFERENCE_NOT_FOUND: Tox_Err_Conference_Invite +TOX_ERR_CONFERENCE_INVITE_FAIL_SEND: Tox_Err_Conference_Invite +TOX_ERR_CONFERENCE_INVITE_NO_CONNECTION: Tox_Err_Conference_Invite +TOX_ERR_CONFERENCE_INVITE_OK: Tox_Err_Conference_Invite +TOX_ERR_CONFERENCE_JOIN_DUPLICATE: Tox_Err_Conference_Join +TOX_ERR_CONFERENCE_JOIN_FAIL_SEND: Tox_Err_Conference_Join +TOX_ERR_CONFERENCE_JOIN_FRIEND_NOT_FOUND: Tox_Err_Conference_Join +TOX_ERR_CONFERENCE_JOIN_INIT_FAIL: Tox_Err_Conference_Join +TOX_ERR_CONFERENCE_JOIN_INVALID_LENGTH: Tox_Err_Conference_Join +TOX_ERR_CONFERENCE_JOIN_OK: Tox_Err_Conference_Join +TOX_ERR_CONFERENCE_JOIN_WRONG_TYPE: Tox_Err_Conference_Join +TOX_ERR_CONFERENCE_NEW_INIT: Tox_Err_Conference_New +TOX_ERR_CONFERENCE_NEW_OK: Tox_Err_Conference_New +TOX_ERR_CONFERENCE_PEER_QUERY_CONFERENCE_NOT_FOUND: Tox_Err_Conference_Peer_Query +TOX_ERR_CONFERENCE_PEER_QUERY_NO_CONNECTION: Tox_Err_Conference_Peer_Query +TOX_ERR_CONFERENCE_PEER_QUERY_OK: Tox_Err_Conference_Peer_Query +TOX_ERR_CONFERENCE_PEER_QUERY_PEER_NOT_FOUND: Tox_Err_Conference_Peer_Query +TOX_ERR_CONFERENCE_SEND_MESSAGE_CONFERENCE_NOT_FOUND: Tox_Err_Conference_Send_Message +TOX_ERR_CONFERENCE_SEND_MESSAGE_FAIL_SEND: Tox_Err_Conference_Send_Message +TOX_ERR_CONFERENCE_SEND_MESSAGE_NO_CONNECTION: Tox_Err_Conference_Send_Message +TOX_ERR_CONFERENCE_SEND_MESSAGE_OK: Tox_Err_Conference_Send_Message +TOX_ERR_CONFERENCE_SEND_MESSAGE_TOO_LONG: Tox_Err_Conference_Send_Message +TOX_ERR_CONFERENCE_SET_MAX_OFFLINE_CONFERENCE_NOT_FOUND: Tox_Err_Conference_Set_Max_Offline +TOX_ERR_CONFERENCE_SET_MAX_OFFLINE_OK: Tox_Err_Conference_Set_Max_Offline +TOX_ERR_CONFERENCE_TITLE_CONFERENCE_NOT_FOUND: Tox_Err_Conference_Title +TOX_ERR_CONFERENCE_TITLE_FAIL_SEND: Tox_Err_Conference_Title +TOX_ERR_CONFERENCE_TITLE_INVALID_LENGTH: Tox_Err_Conference_Title +TOX_ERR_CONFERENCE_TITLE_OK: Tox_Err_Conference_Title +TOX_ERR_FILE_CONTROL_ALREADY_PAUSED: Tox_Err_File_Control +TOX_ERR_FILE_CONTROL_DENIED: Tox_Err_File_Control +TOX_ERR_FILE_CONTROL_FRIEND_NOT_CONNECTED: Tox_Err_File_Control +TOX_ERR_FILE_CONTROL_FRIEND_NOT_FOUND: Tox_Err_File_Control +TOX_ERR_FILE_CONTROL_NOT_FOUND: Tox_Err_File_Control +TOX_ERR_FILE_CONTROL_NOT_PAUSED: Tox_Err_File_Control +TOX_ERR_FILE_CONTROL_OK: Tox_Err_File_Control +TOX_ERR_FILE_CONTROL_SENDQ: Tox_Err_File_Control +TOX_ERR_FILE_GET_FRIEND_NOT_FOUND: Tox_Err_File_Get +TOX_ERR_FILE_GET_NOT_FOUND: Tox_Err_File_Get +TOX_ERR_FILE_GET_NULL: Tox_Err_File_Get +TOX_ERR_FILE_GET_OK: Tox_Err_File_Get +TOX_ERR_FILE_SEEK_DENIED: Tox_Err_File_Seek +TOX_ERR_FILE_SEEK_FRIEND_NOT_CONNECTED: Tox_Err_File_Seek +TOX_ERR_FILE_SEEK_FRIEND_NOT_FOUND: Tox_Err_File_Seek +TOX_ERR_FILE_SEEK_INVALID_POSITION: Tox_Err_File_Seek +TOX_ERR_FILE_SEEK_NOT_FOUND: Tox_Err_File_Seek +TOX_ERR_FILE_SEEK_OK: Tox_Err_File_Seek +TOX_ERR_FILE_SEEK_SENDQ: Tox_Err_File_Seek +TOX_ERR_FILE_SEND_CHUNK_FRIEND_NOT_CONNECTED: Tox_Err_File_Send +TOX_ERR_FILE_SEND_CHUNK_FRIEND_NOT_FOUND: Tox_Err_File_Send +TOX_ERR_FILE_SEND_CHUNK_INVALID_LENGTH: Tox_Err_File_Send +TOX_ERR_FILE_SEND_CHUNK_NOT_FOUND: Tox_Err_File_Send +TOX_ERR_FILE_SEND_CHUNK_NOT_TRANSFERRING: Tox_Err_File_Send +TOX_ERR_FILE_SEND_CHUNK_NULL: Tox_Err_File_Send +TOX_ERR_FILE_SEND_CHUNK_OK: Tox_Err_File_Send +TOX_ERR_FILE_SEND_CHUNK_SENDQ: Tox_Err_File_Send +TOX_ERR_FILE_SEND_CHUNK_WRONG_POSITION: Tox_Err_File_Send +TOX_ERR_FILE_SEND_FRIEND_NOT_CONNECTED: Tox_Err_File_Send +TOX_ERR_FILE_SEND_FRIEND_NOT_FOUND: Tox_Err_File_Send +TOX_ERR_FILE_SEND_NAME_TOO_LONG: Tox_Err_File_Send +TOX_ERR_FILE_SEND_NULL: Tox_Err_File_Send +TOX_ERR_FILE_SEND_OK: Tox_Err_File_Send +TOX_ERR_FILE_SEND_TOO_MANY: Tox_Err_File_Send +TOX_ERR_FRIEND_ADD_ALREADY_SENT: Tox_Err_Friend_Add +TOX_ERR_FRIEND_ADD_BAD_CHECKSUM: Tox_Err_Friend_Add +TOX_ERR_FRIEND_ADD_MALLOC: Tox_Err_Friend_Add +TOX_ERR_FRIEND_ADD_NO_MESSAGE: Tox_Err_Friend_Add +TOX_ERR_FRIEND_ADD_NULL: Tox_Err_Friend_Add +TOX_ERR_FRIEND_ADD_OK: Tox_Err_Friend_Add +TOX_ERR_FRIEND_ADD_OWN_KEY: Tox_Err_Friend_Add +TOX_ERR_FRIEND_ADD_SET_NEW_NOSPAM: Tox_Err_Friend_Add +TOX_ERR_FRIEND_ADD_TOO_LONG: Tox_Err_Friend_Add +TOX_ERR_FRIEND_BY_PUBLIC_KEY_NOT_FOUND: Tox_Err_Friend_By_Public_Key +TOX_ERR_FRIEND_BY_PUBLIC_KEY_NULL: Tox_Err_Friend_By_Public_Key +TOX_ERR_FRIEND_BY_PUBLIC_KEY_OK: Tox_Err_Friend_By_Public_Key +TOX_ERR_FRIEND_CUSTOM_PACKET_EMPTY: Tox_Err_Friend_Custom_Packet +TOX_ERR_FRIEND_CUSTOM_PACKET_FRIEND_NOT_CONNECTED: Tox_Err_Friend_Custom_Packet +TOX_ERR_FRIEND_CUSTOM_PACKET_FRIEND_NOT_FOUND: Tox_Err_Friend_Custom_Packet +TOX_ERR_FRIEND_CUSTOM_PACKET_INVALID: Tox_Err_Friend_Custom_Packet +TOX_ERR_FRIEND_CUSTOM_PACKET_NULL: Tox_Err_Friend_Custom_Packet +TOX_ERR_FRIEND_CUSTOM_PACKET_OK: Tox_Err_Friend_Custom_Packet +TOX_ERR_FRIEND_CUSTOM_PACKET_SENDQ: Tox_Err_Friend_Custom_Packet +TOX_ERR_FRIEND_CUSTOM_PACKET_TOO_LONG: Tox_Err_Friend_Custom_Packet +TOX_ERR_FRIEND_DELETE_FRIEND_NOT_FOUND: Tox_Err_Friend_Delete +TOX_ERR_FRIEND_DELETE_OK: Tox_Err_Friend_Delete +TOX_ERR_FRIEND_GET_LAST_ONLINE_FRIEND_NOT_FOUND: Tox_Err_Friend_Get_Last_Online +TOX_ERR_FRIEND_GET_LAST_ONLINE_OK: Tox_Err_Friend_Get_Last_Online +TOX_ERR_FRIEND_GET_PUBLIC_KEY_FRIEND_NOT_FOUND: Tox_Err_Friend_Get_Public_Key +TOX_ERR_FRIEND_GET_PUBLIC_KEY_OK: Tox_Err_Friend_Get_Public_Key +TOX_ERR_FRIEND_QUERY_FRIEND_NOT_FOUND: Tox_Err_Friend_Query +TOX_ERR_FRIEND_QUERY_NULL: Tox_Err_Friend_Query +TOX_ERR_FRIEND_QUERY_OK: Tox_Err_Friend_Query +TOX_ERR_FRIEND_SEND_MESSAGE_EMPTY: Tox_Err_Friend_Send_Message +TOX_ERR_FRIEND_SEND_MESSAGE_FRIEND_NOT_CONNECTED: Tox_Err_Friend_Send_Message +TOX_ERR_FRIEND_SEND_MESSAGE_FRIEND_NOT_FOUND: Tox_Err_Friend_Send_Message +TOX_ERR_FRIEND_SEND_MESSAGE_NULL: Tox_Err_Friend_Send_Message +TOX_ERR_FRIEND_SEND_MESSAGE_OK: Tox_Err_Friend_Send_Message +TOX_ERR_FRIEND_SEND_MESSAGE_SENDQ: Tox_Err_Friend_Send_Message +TOX_ERR_FRIEND_SEND_MESSAGE_TOO_LONG: Tox_Err_Friend_Send_Message +TOX_ERR_GET_PORT_NOT_BOUND: Tox_Err_Get_Port +TOX_ERR_GET_PORT_OK: Tox_Err_Get_Port +TOX_ERR_GROUP_DISCONNECT_ALREADY_DISCONNECTED: Tox_Err_Group_Disconnect +TOX_ERR_GROUP_DISCONNECT_GROUP_NOT_FOUND: Tox_Err_Group_Disconnect +TOX_ERR_GROUP_DISCONNECT_OK: Tox_Err_Group_Disconnect +TOX_ERR_GROUP_FOUNDER_SET_PASSWORD_DISCONNECTED: Tox_Err_Group_Founder_Set_Password +TOX_ERR_GROUP_FOUNDER_SET_PASSWORD_FAIL_SEND: Tox_Err_Group_Founder_Set_Password +TOX_ERR_GROUP_FOUNDER_SET_PASSWORD_GROUP_NOT_FOUND: Tox_Err_Group_Founder_Set_Password +TOX_ERR_GROUP_FOUNDER_SET_PASSWORD_MALLOC: Tox_Err_Group_Founder_Set_Password +TOX_ERR_GROUP_FOUNDER_SET_PASSWORD_OK: Tox_Err_Group_Founder_Set_Password +TOX_ERR_GROUP_FOUNDER_SET_PASSWORD_PERMISSIONS: Tox_Err_Group_Founder_Set_Password +TOX_ERR_GROUP_FOUNDER_SET_PASSWORD_TOO_LONG: Tox_Err_Group_Founder_Set_Password +TOX_ERR_GROUP_FOUNDER_SET_PEER_LIMIT_DISCONNECTED: Tox_Err_Group_Founder_Set_Peer_Limit +TOX_ERR_GROUP_FOUNDER_SET_PEER_LIMIT_FAIL_SEND: Tox_Err_Group_Founder_Set_Peer_Limit +TOX_ERR_GROUP_FOUNDER_SET_PEER_LIMIT_FAIL_SET: Tox_Err_Group_Founder_Set_Peer_Limit +TOX_ERR_GROUP_FOUNDER_SET_PEER_LIMIT_GROUP_NOT_FOUND: Tox_Err_Group_Founder_Set_Peer_Limit +TOX_ERR_GROUP_FOUNDER_SET_PEER_LIMIT_OK: Tox_Err_Group_Founder_Set_Peer_Limit +TOX_ERR_GROUP_FOUNDER_SET_PEER_LIMIT_PERMISSIONS: Tox_Err_Group_Founder_Set_Peer_Limit +TOX_ERR_GROUP_FOUNDER_SET_PRIVACY_STATE_DISCONNECTED: Tox_Err_Group_Founder_Set_Privacy_State +TOX_ERR_GROUP_FOUNDER_SET_PRIVACY_STATE_FAIL_SEND: Tox_Err_Group_Founder_Set_Privacy_State +TOX_ERR_GROUP_FOUNDER_SET_PRIVACY_STATE_FAIL_SET: Tox_Err_Group_Founder_Set_Privacy_State +TOX_ERR_GROUP_FOUNDER_SET_PRIVACY_STATE_GROUP_NOT_FOUND: Tox_Err_Group_Founder_Set_Privacy_State +TOX_ERR_GROUP_FOUNDER_SET_PRIVACY_STATE_OK: Tox_Err_Group_Founder_Set_Privacy_State +TOX_ERR_GROUP_FOUNDER_SET_PRIVACY_STATE_PERMISSIONS: Tox_Err_Group_Founder_Set_Privacy_State +TOX_ERR_GROUP_FOUNDER_SET_TOPIC_LOCK_DISCONNECTED: Tox_Err_Group_Founder_Set_Topic_Lock +TOX_ERR_GROUP_FOUNDER_SET_TOPIC_LOCK_FAIL_SEND: Tox_Err_Group_Founder_Set_Topic_Lock +TOX_ERR_GROUP_FOUNDER_SET_TOPIC_LOCK_FAIL_SET: Tox_Err_Group_Founder_Set_Topic_Lock +TOX_ERR_GROUP_FOUNDER_SET_TOPIC_LOCK_GROUP_NOT_FOUND: Tox_Err_Group_Founder_Set_Topic_Lock +TOX_ERR_GROUP_FOUNDER_SET_TOPIC_LOCK_INVALID: Tox_Err_Group_Founder_Set_Topic_Lock +TOX_ERR_GROUP_FOUNDER_SET_TOPIC_LOCK_OK: Tox_Err_Group_Founder_Set_Topic_Lock +TOX_ERR_GROUP_FOUNDER_SET_TOPIC_LOCK_PERMISSIONS: Tox_Err_Group_Founder_Set_Topic_Lock +TOX_ERR_GROUP_FOUNDER_SET_VOICE_STATE_DISCONNECTED: Tox_Err_Group_Founder_Set_Voice_State +TOX_ERR_GROUP_FOUNDER_SET_VOICE_STATE_FAIL_SEND: Tox_Err_Group_Founder_Set_Voice_State +TOX_ERR_GROUP_FOUNDER_SET_VOICE_STATE_FAIL_SET: Tox_Err_Group_Founder_Set_Voice_State +TOX_ERR_GROUP_FOUNDER_SET_VOICE_STATE_GROUP_NOT_FOUND: Tox_Err_Group_Founder_Set_Voice_State +TOX_ERR_GROUP_FOUNDER_SET_VOICE_STATE_OK: Tox_Err_Group_Founder_Set_Voice_State +TOX_ERR_GROUP_FOUNDER_SET_VOICE_STATE_PERMISSIONS: Tox_Err_Group_Founder_Set_Voice_State +TOX_ERR_GROUP_INVITE_ACCEPT_BAD_INVITE: Tox_Err_Group_Invite_Accept +TOX_ERR_GROUP_INVITE_ACCEPT_CORE: Tox_Err_Group_Invite_Accept +TOX_ERR_GROUP_INVITE_ACCEPT_EMPTY: Tox_Err_Group_Invite_Accept +TOX_ERR_GROUP_INVITE_ACCEPT_FAIL_SEND: Tox_Err_Group_Invite_Accept +TOX_ERR_GROUP_INVITE_ACCEPT_INIT_FAILED: Tox_Err_Group_Invite_Accept +TOX_ERR_GROUP_INVITE_ACCEPT_OK: Tox_Err_Group_Invite_Accept +TOX_ERR_GROUP_INVITE_ACCEPT_PASSWORD: Tox_Err_Group_Invite_Accept +TOX_ERR_GROUP_INVITE_ACCEPT_TOO_LONG: Tox_Err_Group_Invite_Accept +TOX_ERR_GROUP_INVITE_FRIEND_DISCONNECTED: Tox_Err_Group_Invite_Friend +TOX_ERR_GROUP_INVITE_FRIEND_FAIL_SEND: Tox_Err_Group_Invite_Friend +TOX_ERR_GROUP_INVITE_FRIEND_FRIEND_NOT_FOUND: Tox_Err_Group_Invite_Friend +TOX_ERR_GROUP_INVITE_FRIEND_GROUP_NOT_FOUND: Tox_Err_Group_Invite_Friend +TOX_ERR_GROUP_INVITE_FRIEND_INVITE_FAIL: Tox_Err_Group_Invite_Friend +TOX_ERR_GROUP_INVITE_FRIEND_OK: Tox_Err_Group_Invite_Friend +TOX_ERR_GROUP_IS_CONNECTED_GROUP_NOT_FOUND: Tox_Err_Group_Is_Connected +TOX_ERR_GROUP_IS_CONNECTED_OK: Tox_Err_Group_Is_Connected +TOX_ERR_GROUP_JOIN_BAD_CHAT_ID: Tox_Err_Group_Join +TOX_ERR_GROUP_JOIN_CORE: Tox_Err_Group_Join +TOX_ERR_GROUP_JOIN_EMPTY: Tox_Err_Group_Join +TOX_ERR_GROUP_JOIN_INIT: Tox_Err_Group_Join +TOX_ERR_GROUP_JOIN_OK: Tox_Err_Group_Join +TOX_ERR_GROUP_JOIN_PASSWORD: Tox_Err_Group_Join +TOX_ERR_GROUP_JOIN_TOO_LONG: Tox_Err_Group_Join +TOX_ERR_GROUP_LEAVE_FAIL_SEND: Tox_Err_Group_Leave +TOX_ERR_GROUP_LEAVE_GROUP_NOT_FOUND: Tox_Err_Group_Leave +TOX_ERR_GROUP_LEAVE_OK: Tox_Err_Group_Leave +TOX_ERR_GROUP_LEAVE_TOO_LONG: Tox_Err_Group_Leave +TOX_ERR_GROUP_MOD_KICK_PEER_FAIL_ACTION: Tox_Err_Group_Mod_Kick_Peer +TOX_ERR_GROUP_MOD_KICK_PEER_FAIL_SEND: Tox_Err_Group_Mod_Kick_Peer +TOX_ERR_GROUP_MOD_KICK_PEER_GROUP_NOT_FOUND: Tox_Err_Group_Mod_Kick_Peer +TOX_ERR_GROUP_MOD_KICK_PEER_OK: Tox_Err_Group_Mod_Kick_Peer +TOX_ERR_GROUP_MOD_KICK_PEER_PEER_NOT_FOUND: Tox_Err_Group_Mod_Kick_Peer +TOX_ERR_GROUP_MOD_KICK_PEER_PERMISSIONS: Tox_Err_Group_Mod_Kick_Peer +TOX_ERR_GROUP_MOD_KICK_PEER_SELF: Tox_Err_Group_Mod_Kick_Peer +TOX_ERR_GROUP_MOD_SET_ROLE_ASSIGNMENT: Tox_Err_Group_Mod_Set_Role +TOX_ERR_GROUP_MOD_SET_ROLE_FAIL_ACTION: Tox_Err_Group_Mod_Set_Role +TOX_ERR_GROUP_MOD_SET_ROLE_GROUP_NOT_FOUND: Tox_Err_Group_Mod_Set_Role +TOX_ERR_GROUP_MOD_SET_ROLE_OK: Tox_Err_Group_Mod_Set_Role +TOX_ERR_GROUP_MOD_SET_ROLE_PEER_NOT_FOUND: Tox_Err_Group_Mod_Set_Role +TOX_ERR_GROUP_MOD_SET_ROLE_PERMISSIONS: Tox_Err_Group_Mod_Set_Role +TOX_ERR_GROUP_MOD_SET_ROLE_SELF: Tox_Err_Group_Mod_Set_Role +TOX_ERR_GROUP_NEW_ANNOUNCE: Tox_Err_Group_New +TOX_ERR_GROUP_NEW_EMPTY: Tox_Err_Group_New +TOX_ERR_GROUP_NEW_INIT: Tox_Err_Group_New +TOX_ERR_GROUP_NEW_OK: Tox_Err_Group_New +TOX_ERR_GROUP_NEW_STATE: Tox_Err_Group_New +TOX_ERR_GROUP_NEW_TOO_LONG: Tox_Err_Group_New +TOX_ERR_GROUP_PEER_QUERY_GROUP_NOT_FOUND: Tox_Err_Group_Peer_Query +TOX_ERR_GROUP_PEER_QUERY_OK: Tox_Err_Group_Peer_Query +TOX_ERR_GROUP_PEER_QUERY_PEER_NOT_FOUND: Tox_Err_Group_Peer_Query +TOX_ERR_GROUP_RECONNECT_CORE: Tox_Err_Group_Reconnect +TOX_ERR_GROUP_RECONNECT_GROUP_NOT_FOUND: Tox_Err_Group_Reconnect +TOX_ERR_GROUP_RECONNECT_OK: Tox_Err_Group_Reconnect +TOX_ERR_GROUP_SELF_NAME_SET_FAIL_SEND: Tox_Err_Group_Self_Name_Set +TOX_ERR_GROUP_SELF_NAME_SET_GROUP_NOT_FOUND: Tox_Err_Group_Self_Name_Set +TOX_ERR_GROUP_SELF_NAME_SET_INVALID: Tox_Err_Group_Self_Name_Set +TOX_ERR_GROUP_SELF_NAME_SET_OK: Tox_Err_Group_Self_Name_Set +TOX_ERR_GROUP_SELF_NAME_SET_TOO_LONG: Tox_Err_Group_Self_Name_Set +TOX_ERR_GROUP_SELF_QUERY_GROUP_NOT_FOUND: Tox_Err_Group_Self_Query +TOX_ERR_GROUP_SELF_QUERY_OK: Tox_Err_Group_Self_Query +TOX_ERR_GROUP_SELF_STATUS_SET_FAIL_SEND: Tox_Err_Group_Self_Status_Set +TOX_ERR_GROUP_SELF_STATUS_SET_GROUP_NOT_FOUND: Tox_Err_Group_Self_Status_Set +TOX_ERR_GROUP_SELF_STATUS_SET_OK: Tox_Err_Group_Self_Status_Set +TOX_ERR_GROUP_SEND_CUSTOM_PACKET_DISCONNECTED: Tox_Err_Group_Send_Custom_Packet +TOX_ERR_GROUP_SEND_CUSTOM_PACKET_EMPTY: Tox_Err_Group_Send_Custom_Packet +TOX_ERR_GROUP_SEND_CUSTOM_PACKET_GROUP_NOT_FOUND: Tox_Err_Group_Send_Custom_Packet +TOX_ERR_GROUP_SEND_CUSTOM_PACKET_OK: Tox_Err_Group_Send_Custom_Packet +TOX_ERR_GROUP_SEND_CUSTOM_PACKET_PERMISSIONS: Tox_Err_Group_Send_Custom_Packet +TOX_ERR_GROUP_SEND_CUSTOM_PACKET_TOO_LONG: Tox_Err_Group_Send_Custom_Packet +TOX_ERR_GROUP_SEND_CUSTOM_PRIVATE_PACKET_DISCONNECTED: Tox_Err_Group_Send_Custom_Private_Packet +TOX_ERR_GROUP_SEND_CUSTOM_PRIVATE_PACKET_EMPTY: Tox_Err_Group_Send_Custom_Private_Packet +TOX_ERR_GROUP_SEND_CUSTOM_PRIVATE_PACKET_FAIL_SEND: Tox_Err_Group_Send_Custom_Private_Packet +TOX_ERR_GROUP_SEND_CUSTOM_PRIVATE_PACKET_GROUP_NOT_FOUND: Tox_Err_Group_Send_Custom_Private_Packet +TOX_ERR_GROUP_SEND_CUSTOM_PRIVATE_PACKET_OK: Tox_Err_Group_Send_Custom_Private_Packet +TOX_ERR_GROUP_SEND_CUSTOM_PRIVATE_PACKET_PEER_NOT_FOUND: Tox_Err_Group_Send_Custom_Private_Packet +TOX_ERR_GROUP_SEND_CUSTOM_PRIVATE_PACKET_PERMISSIONS: Tox_Err_Group_Send_Custom_Private_Packet +TOX_ERR_GROUP_SEND_CUSTOM_PRIVATE_PACKET_TOO_LONG: Tox_Err_Group_Send_Custom_Private_Packet +TOX_ERR_GROUP_SEND_MESSAGE_BAD_TYPE: Tox_Err_Group_Send_Message +TOX_ERR_GROUP_SEND_MESSAGE_DISCONNECTED: Tox_Err_Group_Send_Message +TOX_ERR_GROUP_SEND_MESSAGE_EMPTY: Tox_Err_Group_Send_Message +TOX_ERR_GROUP_SEND_MESSAGE_FAIL_SEND: Tox_Err_Group_Send_Message +TOX_ERR_GROUP_SEND_MESSAGE_GROUP_NOT_FOUND: Tox_Err_Group_Send_Message +TOX_ERR_GROUP_SEND_MESSAGE_OK: Tox_Err_Group_Send_Message +TOX_ERR_GROUP_SEND_MESSAGE_PERMISSIONS: Tox_Err_Group_Send_Message +TOX_ERR_GROUP_SEND_MESSAGE_TOO_LONG: Tox_Err_Group_Send_Message +TOX_ERR_GROUP_SEND_PRIVATE_MESSAGE_BAD_TYPE: Tox_Err_Group_Send_Private_Message +TOX_ERR_GROUP_SEND_PRIVATE_MESSAGE_DISCONNECTED: Tox_Err_Group_Send_Private_Message +TOX_ERR_GROUP_SEND_PRIVATE_MESSAGE_EMPTY: Tox_Err_Group_Send_Private_Message +TOX_ERR_GROUP_SEND_PRIVATE_MESSAGE_FAIL_SEND: Tox_Err_Group_Send_Private_Message +TOX_ERR_GROUP_SEND_PRIVATE_MESSAGE_GROUP_NOT_FOUND: Tox_Err_Group_Send_Private_Message +TOX_ERR_GROUP_SEND_PRIVATE_MESSAGE_OK: Tox_Err_Group_Send_Private_Message +TOX_ERR_GROUP_SEND_PRIVATE_MESSAGE_PEER_NOT_FOUND: Tox_Err_Group_Send_Private_Message +TOX_ERR_GROUP_SEND_PRIVATE_MESSAGE_PERMISSIONS: Tox_Err_Group_Send_Private_Message +TOX_ERR_GROUP_SEND_PRIVATE_MESSAGE_TOO_LONG: Tox_Err_Group_Send_Private_Message +TOX_ERR_GROUP_SET_IGNORE_GROUP_NOT_FOUND: Tox_Err_Group_Set_Ignore +TOX_ERR_GROUP_SET_IGNORE_OK: Tox_Err_Group_Set_Ignore +TOX_ERR_GROUP_SET_IGNORE_PEER_NOT_FOUND: Tox_Err_Group_Set_Ignore +TOX_ERR_GROUP_SET_IGNORE_SELF: Tox_Err_Group_Set_Ignore +TOX_ERR_GROUP_STATE_QUERIES_GROUP_NOT_FOUND: Tox_Err_Group_State_Queries +TOX_ERR_GROUP_STATE_QUERIES_OK: Tox_Err_Group_State_Queries +TOX_ERR_GROUP_TOPIC_SET_DISCONNECTED: Tox_Err_Group_Topic_Set +TOX_ERR_GROUP_TOPIC_SET_FAIL_CREATE: Tox_Err_Group_Topic_Set +TOX_ERR_GROUP_TOPIC_SET_FAIL_SEND: Tox_Err_Group_Topic_Set +TOX_ERR_GROUP_TOPIC_SET_GROUP_NOT_FOUND: Tox_Err_Group_Topic_Set +TOX_ERR_GROUP_TOPIC_SET_OK: Tox_Err_Group_Topic_Set +TOX_ERR_GROUP_TOPIC_SET_PERMISSIONS: Tox_Err_Group_Topic_Set +TOX_ERR_GROUP_TOPIC_SET_TOO_LONG: Tox_Err_Group_Topic_Set +TOX_ERR_NEW_LOAD_BAD_FORMAT: Tox_Err_New +TOX_ERR_NEW_LOAD_ENCRYPTED: Tox_Err_New +TOX_ERR_NEW_MALLOC: Tox_Err_New +TOX_ERR_NEW_NULL: Tox_Err_New +TOX_ERR_NEW_OK: Tox_Err_New +TOX_ERR_NEW_PORT_ALLOC: Tox_Err_New +TOX_ERR_NEW_PROXY_BAD_HOST: Tox_Err_New +TOX_ERR_NEW_PROXY_BAD_PORT: Tox_Err_New +TOX_ERR_NEW_PROXY_BAD_TYPE: Tox_Err_New +TOX_ERR_NEW_PROXY_NOT_FOUND: Tox_Err_New +TOX_ERR_OPTIONS_NEW_MALLOC: Tox_Err_Options_New +TOX_ERR_OPTIONS_NEW_OK: Tox_Err_Options_New +TOX_ERR_SET_INFO_NULL: Tox_Err_Set_Info +TOX_ERR_SET_INFO_OK: Tox_Err_Set_Info +TOX_ERR_SET_INFO_TOO_LONG: Tox_Err_Set_Info +TOX_ERR_SET_TYPING_FRIEND_NOT_FOUND: Tox_Err_Set_Typing +TOX_ERR_SET_TYPING_OK: Tox_Err_Set_Typing +TOX_FILE_CONTROL_CANCEL: Tox_File_Control +TOX_FILE_CONTROL_PAUSE: Tox_File_Control +TOX_FILE_CONTROL_RESUME: Tox_File_Control +TOX_FILE_KIND_AVATAR: Tox_File_Kind +TOX_FILE_KIND_DATA: Tox_File_Kind +TOX_GROUP_EXIT_TYPE_DISCONNECTED: Tox_Group_Exit_Type +TOX_GROUP_EXIT_TYPE_KICK: Tox_Group_Exit_Type +TOX_GROUP_EXIT_TYPE_QUIT: Tox_Group_Exit_Type +TOX_GROUP_EXIT_TYPE_SELF_DISCONNECTED: Tox_Group_Exit_Type +TOX_GROUP_EXIT_TYPE_SYNC_ERROR: Tox_Group_Exit_Type +TOX_GROUP_EXIT_TYPE_TIMEOUT: Tox_Group_Exit_Type +TOX_GROUP_JOIN_FAIL_INVALID_PASSWORD: Tox_Group_Join_Fail +TOX_GROUP_JOIN_FAIL_PEER_LIMIT: Tox_Group_Join_Fail +TOX_GROUP_JOIN_FAIL_UNKNOWN: Tox_Group_Join_Fail +TOX_GROUP_MOD_EVENT_KICK: Tox_Group_Mod_Event +TOX_GROUP_MOD_EVENT_MODERATOR: Tox_Group_Mod_Event +TOX_GROUP_MOD_EVENT_OBSERVER: Tox_Group_Mod_Event +TOX_GROUP_MOD_EVENT_USER: Tox_Group_Mod_Event +TOX_GROUP_PRIVACY_STATE_PRIVATE: Tox_Group_Privacy_State +TOX_GROUP_PRIVACY_STATE_PUBLIC: Tox_Group_Privacy_State +TOX_GROUP_ROLE_FOUNDER: Tox_Group_Role +TOX_GROUP_ROLE_MODERATOR: Tox_Group_Role +TOX_GROUP_ROLE_OBSERVER: Tox_Group_Role +TOX_GROUP_ROLE_USER: Tox_Group_Role +TOX_GROUP_TOPIC_LOCK_DISABLED: Tox_Group_Topic_Lock +TOX_GROUP_TOPIC_LOCK_ENABLED: Tox_Group_Topic_Lock +TOX_GROUP_VOICE_STATE_ALL: Tox_Group_Voice_State +TOX_GROUP_VOICE_STATE_FOUNDER: Tox_Group_Voice_State +TOX_GROUP_VOICE_STATE_MODERATOR: Tox_Group_Voice_State +TOX_LOG_LEVEL_DEBUG: Tox_Log_Level +TOX_LOG_LEVEL_ERROR: Tox_Log_Level +TOX_LOG_LEVEL_INFO: Tox_Log_Level +TOX_LOG_LEVEL_TRACE: Tox_Log_Level +TOX_LOG_LEVEL_WARNING: Tox_Log_Level +TOX_MESSAGE_TYPE_ACTION: Tox_Message_Type +TOX_MESSAGE_TYPE_NORMAL: Tox_Message_Type +TOX_PROXY_TYPE_HTTP: Tox_Proxy_Type +TOX_PROXY_TYPE_NONE: Tox_Proxy_Type +TOX_PROXY_TYPE_SOCKS5: Tox_Proxy_Type +TOX_SAVEDATA_TYPE_NONE: Tox_Savedata_Type +TOX_SAVEDATA_TYPE_SECRET_KEY: Tox_Savedata_Type +TOX_SAVEDATA_TYPE_TOX_SAVE: Tox_Savedata_Type +TOX_USER_STATUS_AWAY: Tox_User_Status +TOX_USER_STATUS_BUSY: Tox_User_Status +TOX_USER_STATUS_NONE: Tox_User_Status +VERSION: str diff --git a/pytox/toxcore/tox.pyx b/pytox/toxcore/tox.pyx index 8f53196..631ae13 100644 --- a/pytox/toxcore/tox.pyx +++ b/pytox/toxcore/tox.pyx @@ -1,6 +1,7 @@ # cython: language_level=3, linetrace=True from array import array from pytox import common +from typing import Optional class ApiException(common.ApiException): pass @@ -331,6 +332,7 @@ cdef class Tox_Options_Ptr: self._ptr = NULL def __init__(self): + """Create new Tox_Options object.""" self._ptr = self._new() @@ -420,14 +422,15 @@ cdef class Tox_Ptr: def handle_group_join_fail(self, group_number: Tox_Group_Number, fail_type: Tox_Group_Join_Fail) -> None: pass def handle_group_moderation(self, group_number: Tox_Group_Number, source_peer_id: Tox_Group_Peer_Number, target_peer_id: Tox_Group_Peer_Number, mod_type: Tox_Group_Mod_Event) -> None: pass - def __init__(self, Tox_Options_Ptr options): - self._ptr = self._new(options) - install_handlers(self, self._ptr) - ############################################################ ########################## Manual ########################## ############################################################ + def __init__(self, options: Optional[Tox_Options_Ptr] = None): + """Create new Tox object.""" + self._ptr = self._new(options) + install_handlers(self, self._ptr) + @property def savedata(self) -> bytes: cdef size_t size = tox_get_savedata_size(self._get()) @@ -439,7 +442,7 @@ cdef class Tox_Ptr: free(data) def bootstrap(self, host: str, port: int, public_key: bytes) -> bool: - common._check_len("public_key", public_key, tox_public_key_size()) + common.check_len("public_key", public_key, tox_public_key_size()) cdef Tox_Err_Bootstrap err = TOX_ERR_BOOTSTRAP_OK return tox_bootstrap(self._get(), host.encode("utf-8"), port, public_key, &err) @@ -513,13 +516,13 @@ cdef class Tox_Ptr: if err: raise ApiException(Tox_Err_Set_Info(err)) def friend_add(self, address: bytes, message: bytes): - common._check_len("address", address, tox_address_size()) + common.check_len("address", address, tox_address_size()) cdef Tox_Err_Friend_Add err = TOX_ERR_FRIEND_ADD_OK tox_friend_add(self._get(), address, message, len(message), &err) if err: raise ApiException(Tox_Err_Friend_Add(err)) def friend_add_norequest(self, public_key: bytes): - common._check_len("public_key", public_key, tox_public_key_size()) + common.check_len("public_key", public_key, tox_public_key_size()) cdef Tox_Err_Friend_Add err = TOX_ERR_FRIEND_ADD_OK tox_friend_add_norequest(self._get(), public_key, &err) if err: raise ApiException(Tox_Err_Friend_Add(err)) diff --git a/pytox/toxencryptsave/toxencryptsave.pyi b/pytox/toxencryptsave/toxencryptsave.pyi new file mode 100644 index 0000000..42d6185 --- /dev/null +++ b/pytox/toxencryptsave/toxencryptsave.pyi @@ -0,0 +1,41 @@ +# pytox.toxencryptsave.toxencryptsave +from types import TracebackType +from typing import Optional +from typing import Self +import enum +import pytox.common +class Tox_Conference_Number: ... +class Tox_Conference_Peer_Number: ... +class Tox_File_Number: ... +class Tox_Friend_Message_Id: ... +class Tox_Friend_Number: ... +class Tox_Group_Message_Id: ... +class Tox_Group_Number: ... +class Tox_Group_Peer_Number: ... +class ApiException(pytox.common.ApiException): ... +class Tox_Err_Decryption(enum.Enum): ... +class Tox_Err_Encryption(enum.Enum): ... +class Tox_Err_Get_Salt(enum.Enum): ... +class Tox_Err_Key_Derivation(enum.Enum): ... +class Tox_Pass_Key_Ptr: + def __enter__(self) -> Self: ... + def __exit__(self, exc_type: type[BaseException] | None, exc_value: BaseException | None, exc_traceback: TracebackType | None) -> None: ... + def __init__(self, passphrase: bytes, salt: Optional[bytes] = None) -> None: ... + def decrypt(self, ciphertext: bytes) -> bytes: ... + def encrypt(self, plaintext: bytes) -> bytes: ... +TOX_ERR_DECRYPTION_BAD_FORMAT: Tox_Err_Decryption +TOX_ERR_DECRYPTION_FAILED: Tox_Err_Decryption +TOX_ERR_DECRYPTION_INVALID_LENGTH: Tox_Err_Decryption +TOX_ERR_DECRYPTION_KEY_DERIVATION_FAILED: Tox_Err_Decryption +TOX_ERR_DECRYPTION_NULL: Tox_Err_Decryption +TOX_ERR_DECRYPTION_OK: Tox_Err_Decryption +TOX_ERR_ENCRYPTION_FAILED: Tox_Err_Encryption +TOX_ERR_ENCRYPTION_KEY_DERIVATION_FAILED: Tox_Err_Encryption +TOX_ERR_ENCRYPTION_NULL: Tox_Err_Encryption +TOX_ERR_ENCRYPTION_OK: Tox_Err_Encryption +TOX_ERR_GET_SALT_BAD_FORMAT: Tox_Err_Get_Salt +TOX_ERR_GET_SALT_NULL: Tox_Err_Get_Salt +TOX_ERR_GET_SALT_OK: Tox_Err_Get_Salt +TOX_ERR_KEY_DERIVATION_FAILED: Tox_Err_Key_Derivation +TOX_ERR_KEY_DERIVATION_NULL: Tox_Err_Key_Derivation +TOX_ERR_KEY_DERIVATION_OK: Tox_Err_Key_Derivation diff --git a/pytox/toxencryptsave/toxencryptsave.pyx b/pytox/toxencryptsave/toxencryptsave.pyx index d1f1ee5..efa455b 100644 --- a/pytox/toxencryptsave/toxencryptsave.pyx +++ b/pytox/toxencryptsave/toxencryptsave.pyx @@ -29,7 +29,7 @@ cdef class Tox_Pass_Key_Ptr: cdef Tox_Pass_Key* _derive_with_salt(self, bytes passphrase, bytes salt): cdef Tox_Err_Key_Derivation error = TOX_ERR_KEY_DERIVATION_OK - cdef Tox_Pass_Key* ptr = tox_pass_key_derive_with_salt(passphrase, len(passphrase), common._check_len("salt", salt, tox_pass_salt_length()), &error) + cdef Tox_Pass_Key* ptr = tox_pass_key_derive_with_salt(passphrase, len(passphrase), common.check_len("salt", salt, tox_pass_salt_length()), &error) if error: raise ApiException(Tox_Err_Key_Derivation(error)) return ptr @@ -37,7 +37,8 @@ cdef class Tox_Pass_Key_Ptr: ########################## Manual ########################## ############################################################ - def __init__(self, passphrase: bytes, salt: bytes = None): + def __init__(self, passphrase: bytes, salt: Optional[bytes] = None): + """Create new Tox_Pass_Key object.""" if salt: self._ptr = self._derive_with_salt(passphrase, salt) else: diff --git a/test/auto_tests/self_connection_status_test.py b/test/auto_tests/self_connection_status_test.py index aaa95b5..e3115c0 100644 --- a/test/auto_tests/self_connection_status_test.py +++ b/test/auto_tests/self_connection_status_test.py @@ -23,8 +23,8 @@ def handle_self_connection_status(self, class AutoTest(unittest.TestCase): def test_connection_status_cb(self) -> None: - with TestTox(None) as tox1: - with TestTox(None) as tox2: + with TestTox() as tox1: + with TestTox() as tox2: # Test that exceptions can pass through C code. with self.assertRaises(TestException) as ex: while (tox1.connection_status == core.TOX_CONNECTION_NONE diff --git a/test/tox_test.py b/test/tox_test.py index 5db55f3..3ab13a9 100644 --- a/test/tox_test.py +++ b/test/tox_test.py @@ -40,11 +40,11 @@ def test_public_key_is_not_secret_key(self) -> None: self.assertNotEqual(tox.public_key, tox.secret_key) def test_savedata_contains_secret_key(self) -> None: - with c.Tox_Ptr(None) as tox: + with c.Tox_Ptr() as tox: self.assertIn(tox.secret_key, tox.savedata) def test_set_name(self) -> None: - with c.Tox_Ptr(None) as tox: + with c.Tox_Ptr() as tox: self.assertEqual(tox.name, b"") tox.name = b"iphy" self.assertEqual(tox.name, b"iphy") @@ -54,7 +54,7 @@ def test_set_name(self) -> None: tox.name = b"x" * (c.MAX_NAME_LENGTH + 1) def test_set_status_message(self) -> None: - with c.Tox_Ptr(None) as tox: + with c.Tox_Ptr() as tox: self.assertEqual(tox.status_message, b"") tox.status_message = b"pytox is cool now" self.assertEqual(tox.status_message, b"pytox is cool now") @@ -64,7 +64,7 @@ def test_set_status_message(self) -> None: tox.status_message = b"x" * (c.MAX_STATUS_MESSAGE_LENGTH + 1) def test_set_status(self) -> None: - with c.Tox_Ptr(None) as tox: + with c.Tox_Ptr() as tox: self.assertEqual(tox.status, c.TOX_USER_STATUS_NONE) tox.status = c.TOX_USER_STATUS_AWAY self.assertEqual(tox.status, c.TOX_USER_STATUS_AWAY) @@ -72,16 +72,16 @@ def test_set_status(self) -> None: self.assertEqual(tox.status, c.TOX_USER_STATUS_AWAY) def test_friend_add(self) -> None: - with c.Tox_Ptr(None) as tox1: - with c.Tox_Ptr(None) as tox2: + with c.Tox_Ptr() as tox1: + with c.Tox_Ptr() as tox2: tox1.friend_add(tox2.address, b"hello there!") tox2.friend_add_norequest(tox1.public_key) with self.assertRaises(common.LengthException): tox2.friend_add(tox1.public_key, b"oh no!") def test_friend_delete(self) -> None: - with c.Tox_Ptr(None) as tox1: - with c.Tox_Ptr(None) as tox2: + with c.Tox_Ptr() as tox1: + with c.Tox_Ptr() as tox2: tox1.friend_add(tox2.address, b"hello there!") tox1.friend_delete(0) with self.assertRaises(c.ApiException): diff --git a/test/toxav_test.py b/test/toxav_test.py index 46f4ac2..f91ddce 100644 --- a/test/toxav_test.py +++ b/test/toxav_test.py @@ -1,12 +1,14 @@ +from typing import cast import unittest +from pytox.toxcore import tox import pytox.toxav.toxav as av class AvTest(unittest.TestCase): def test_version(self) -> None: with self.assertRaises(av.ApiException) as ex: - av.Toxav_Ptr(None) + av.Toxav_Ptr(cast(tox.Tox_Ptr, None)) self.assertEqual(ex.exception.error, av.TOXAV_ERR_NEW_NULL) diff --git a/test/toxencryptsave_test.py b/test/toxencryptsave_test.py index 2d8e3f7..aad39ec 100644 --- a/test/toxencryptsave_test.py +++ b/test/toxencryptsave_test.py @@ -18,7 +18,7 @@ def test_encrypt_decrypt_with_correct_salt(self) -> None: b"hello world") def test_encrypt_decrypt_with_wrong_salt(self) -> None: - with c.Tox_Pass_Key_Ptr(b"hello", b"a" * 32) as pk1: + with c.Tox_Pass_Key_Ptr(passphrase=b"hello", salt=b"a" * 32) as pk1: with c.Tox_Pass_Key_Ptr(b"hello", b"b" * 32) as pk2: with self.assertRaises(c.ApiException) as ex: pk2.decrypt(pk1.encrypt(b"hello world")) diff --git a/tools/BUILD.bazel b/tools/BUILD.bazel index 637d38c..f8867bf 100644 --- a/tools/BUILD.bazel +++ b/tools/BUILD.bazel @@ -3,10 +3,9 @@ load("@rules_python//python:defs.bzl", "py_binary") py_binary( name = "stubgen", srcs = ["stubgen.py"], - tags = ["manual"], + tags = ["no-cross"], visibility = ["//visibility:public"], deps = [ "//py_toxcore_c:pytox", - "@mypy", ], ) diff --git a/tools/gen-api b/tools/gen-api index 2fde0de..21f518e 100755 --- a/tools/gen-api +++ b/tools/gen-api @@ -10,4 +10,5 @@ set -eux "$WORKSPACE_DIR/c-toxcore/toxav/toxav.h" \ "$WORKSPACE_DIR/c-toxcore/toxcore/tox.h" \ "$WORKSPACE_DIR/c-toxcore/toxencryptsave/toxencryptsave.h" +bazel run //py_toxcore_c/tools:stubgen -- "$REPO_DIR" bazel build //py_toxcore_c:pytox diff --git a/tools/stubgen.py b/tools/stubgen.py index 09f23f5..1305317 100644 --- a/tools/stubgen.py +++ b/tools/stubgen.py @@ -1,6 +1,139 @@ +import collections +import inspect +import os.path import sys -from mypy.stubgen import main +import pytox.common +import pytox.toxav.toxav +import pytox.toxcore.tox +import pytox.toxencryptsave.toxencryptsave + +PACKAGES = [ + pytox.toxav.toxav, + pytox.toxcore.tox, + pytox.toxencryptsave.toxencryptsave, +] + +def process_class(name: str, cls: list[str], imports: set[str], attr: object) -> None: + for mem in dir(attr): + mem_attr = getattr(attr, mem) + if mem == "__enter__": + imports.add("from typing import Self") + cls.append(f" def __enter__(self) -> Self: ...") + elif mem == "__exit__": + imports.add("from types import TracebackType") + cls.append(" def __exit__(self, exc_type: type[BaseException] | None, exc_value: BaseException | None, exc_traceback: TracebackType | None) -> None: ...") + elif mem == "__init__" or "cython_function_or_method" in mem_attr.__class__.__name__: + doc = mem_attr.__doc__.split('\n')[0] + if " -> " not in doc: + doc += " -> None" + if ": array" in doc: + imports.add("from array import array") + imports.add("from typing import Any") + doc = doc.replace(": array", ": array[Any]") + if ": Optional" in doc: + imports.add("from typing import Optional") + if ": Tox_Ptr" in doc and attr.__module__ != "tox": + imports.add("from pytox.toxcore.tox import Tox_Ptr") + cls.append(f" def {doc}: ...") + elif mem_attr.__class__.__name__ == "getset_descriptor": + imports.add("from typing import Any") + cls.append(f" {mem}: Any") + else: + if mem_attr.__doc__ and mem_attr.__doc__.startswith(mem): + raise Exception((mem, mem_attr.__doc__, mem_attr.__class__)) + + +def process_type(sym: str, attr: object, imports: set[str], classes: dict[str, list[str]]) -> None: + if not isinstance(attr, type): + return + + superclass = inspect.getclasstree([attr])[-1][0][1][0] + is_enum = False + if attr.__class__.__name__ == "EnumType": + imports.add("import enum") + inherit = "(enum.Enum)" + is_enum = True + elif superclass.__name__ == "object": + inherit = "" + else: + imports.add("import " + superclass.__module__) + inherit = f"({superclass.__module__}.{superclass.__name__})" + cls = classes[sym] = [ + f"class {sym}{inherit}:", + ] + if sym.endswith("Exception") or is_enum: + cls[0] += " ..." + else: + process_class(sym, cls, imports, attr) + + +def process_value(sym: str, attr: object, consts: list[str], classes: dict[str, list[str]]) -> None: + if isinstance(attr, int): + enum = tuple(c for c in classes.keys() if sym.startswith(c.upper())) + if enum: + consts.append(f"{sym}: {enum[0]}") + else: + consts.append(f"{sym}: int") + elif isinstance(attr, str): + consts.append(f"{sym}: str") + elif isinstance(attr, type): + pass # already done above + else: + raise Exception(f"nope {sym}: {type(attr)}") + + +def process_package(out_dir: str, pkg: object, prefix: str, name: str) -> None: + attrs: list[tuple[str, object]] = [] + for sym in dir(pkg): + attr = getattr(pkg, sym) + if sym.startswith("__"): + continue + if isinstance(attr, pytox.common.__class__): + continue + if hasattr(attr, "__module__") and f"{prefix}.{attr.__module__}" != name: + continue + attrs.append((sym, attr)) + + consts: list[str] = [] + classes: collections.OrderedDict[str, list[str]] = collections.OrderedDict() + imports: set[str] = set() + missing: set[str] = { + "Tox_Conference_Number", + "Tox_Conference_Peer_Number", + "Tox_File_Number", + "Tox_Friend_Number", + "Tox_Friend_Message_Id", + "Tox_Group_Number", + "Tox_Group_Peer_Number", + "Tox_Group_Message_Id", + } + + for sym, attr in attrs: + process_type(sym, attr, imports, classes) + + for sym, attr in attrs: + process_value(sym, attr, consts, classes) + + with open(os.path.join(out_dir, f"{name.replace('.', '/')}.pyi"), "w") as pyi: + pyi.write(f"# {name}\n") + for s in sorted(imports): + pyi.write(s + "\n") + for m in sorted(missing): + pyi.write(f"class {m}: ...\n") + for cls in classes.values(): + pyi.write('\n'.join(cls) + "\n") + for c in consts: + pyi.write(c + "\n") + + +def main() -> None: + out_dir = sys.argv[1] + for pkg in PACKAGES: + if not pkg.__package__: + raise Exception(f"{pkg} has no __package__") + process_package(out_dir, pkg, pkg.__package__, pkg.__name__) + if __name__ == "__main__": - sys.exit(main()) + main() From 8dbd06081d1b42eacd4a6cdd7ce37b7165552fb1 Mon Sep 17 00:00:00 2001 From: "Restyled.io" Date: Mon, 8 Jan 2024 03:45:00 +0000 Subject: [PATCH 2/6] Restyled by autopep8 --- tools/stubgen.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tools/stubgen.py b/tools/stubgen.py index 1305317..3439bf7 100644 --- a/tools/stubgen.py +++ b/tools/stubgen.py @@ -14,6 +14,7 @@ pytox.toxencryptsave.toxencryptsave, ] + def process_class(name: str, cls: list[str], imports: set[str], attr: object) -> None: for mem in dir(attr): mem_attr = getattr(attr, mem) @@ -22,7 +23,8 @@ def process_class(name: str, cls: list[str], imports: set[str], attr: object) -> cls.append(f" def __enter__(self) -> Self: ...") elif mem == "__exit__": imports.add("from types import TracebackType") - cls.append(" def __exit__(self, exc_type: type[BaseException] | None, exc_value: BaseException | None, exc_traceback: TracebackType | None) -> None: ...") + cls.append( + " def __exit__(self, exc_type: type[BaseException] | None, exc_value: BaseException | None, exc_traceback: TracebackType | None) -> None: ...") elif mem == "__init__" or "cython_function_or_method" in mem_attr.__class__.__name__: doc = mem_attr.__doc__.split('\n')[0] if " -> " not in doc: @@ -96,7 +98,8 @@ def process_package(out_dir: str, pkg: object, prefix: str, name: str) -> None: attrs.append((sym, attr)) consts: list[str] = [] - classes: collections.OrderedDict[str, list[str]] = collections.OrderedDict() + classes: collections.OrderedDict[str, + list[str]] = collections.OrderedDict() imports: set[str] = set() missing: set[str] = { "Tox_Conference_Number", From 232514e7d0049ef4bc783f6a623e3bb72d184d9b Mon Sep 17 00:00:00 2001 From: "Restyled.io" Date: Mon, 8 Jan 2024 03:45:03 +0000 Subject: [PATCH 3/6] Restyled by black --- pytox/common.py | 3 ++- .../auto_tests/self_connection_status_test.py | 18 ++++++++------- test/toxencryptsave_test.py | 13 ++++++----- tools/stubgen.py | 23 ++++++++++++------- 4 files changed, 34 insertions(+), 23 deletions(-) diff --git a/pytox/common.py b/pytox/common.py index 83794d5..ad6190d 100644 --- a/pytox/common.py +++ b/pytox/common.py @@ -30,5 +30,6 @@ def check_len(name: str, data: T, expected_length: int) -> T: if len(data) < expected_length: raise LengthException( f"parameter '{name}' received bytes of invalid" - f"length {len(data)}, expected at least {expected_length}") + f"length {len(data)}, expected at least {expected_length}" + ) return data diff --git a/test/auto_tests/self_connection_status_test.py b/test/auto_tests/self_connection_status_test.py index e3115c0..d5e1087 100644 --- a/test/auto_tests/self_connection_status_test.py +++ b/test/auto_tests/self_connection_status_test.py @@ -13,9 +13,9 @@ class TestException(Exception): class TestTox(core.Tox_Ptr): connection_status_from_cb = core.TOX_CONNECTION_NONE - def handle_self_connection_status(self, - connection_status: core.Tox_Connection - ) -> None: + def handle_self_connection_status( + self, connection_status: core.Tox_Connection + ) -> None: print(connection_status) self.connection_status_from_cb = connection_status raise TestException(connection_status) @@ -27,14 +27,16 @@ def test_connection_status_cb(self) -> None: with TestTox() as tox2: # Test that exceptions can pass through C code. with self.assertRaises(TestException) as ex: - while (tox1.connection_status == core.TOX_CONNECTION_NONE - or - tox2.connection_status == core.TOX_CONNECTION_NONE): + while ( + tox1.connection_status == core.TOX_CONNECTION_NONE + or tox2.connection_status == core.TOX_CONNECTION_NONE + ): tox1.iterate() tox2.iterate() time.sleep(tox1.iteration_interval / 1000) - self.assertEqual(tox1.connection_status, - tox1.connection_status_from_cb) + self.assertEqual( + tox1.connection_status, tox1.connection_status_from_cb + ) self.assertEqual(ex.exception.status, tox1.connection_status) diff --git a/test/toxencryptsave_test.py b/test/toxencryptsave_test.py index aad39ec..d6bc425 100644 --- a/test/toxencryptsave_test.py +++ b/test/toxencryptsave_test.py @@ -8,22 +8,23 @@ class ToxencryptsaveTest(unittest.TestCase): def test_encrypt_decrypt(self) -> None: with c.Tox_Pass_Key_Ptr(b"hello") as pk: self.assertNotEqual(pk.encrypt(b"hello world"), b"hello world") - self.assertEqual(pk.decrypt(pk.encrypt(b"hello world")), - b"hello world") + self.assertEqual(pk.decrypt(pk.encrypt(b"hello world")), b"hello world") def test_encrypt_decrypt_with_correct_salt(self) -> None: with c.Tox_Pass_Key_Ptr(b"hello", b"a" * 32) as pk1: with c.Tox_Pass_Key_Ptr(b"hello", b"a" * 32) as pk2: - self.assertEqual(pk2.decrypt(pk1.encrypt(b"hello world")), - b"hello world") + self.assertEqual( + pk2.decrypt(pk1.encrypt(b"hello world")), b"hello world" + ) def test_encrypt_decrypt_with_wrong_salt(self) -> None: with c.Tox_Pass_Key_Ptr(passphrase=b"hello", salt=b"a" * 32) as pk1: with c.Tox_Pass_Key_Ptr(b"hello", b"b" * 32) as pk2: with self.assertRaises(c.ApiException) as ex: pk2.decrypt(pk1.encrypt(b"hello world")) - self.assertEqual(ex.exception.error.name, - c.TOX_ERR_DECRYPTION_FAILED.name) + self.assertEqual( + ex.exception.error.name, c.TOX_ERR_DECRYPTION_FAILED.name + ) def test_salt_too_small(self) -> None: with self.assertRaises(common.LengthException): diff --git a/tools/stubgen.py b/tools/stubgen.py index 3439bf7..dffce99 100644 --- a/tools/stubgen.py +++ b/tools/stubgen.py @@ -24,9 +24,13 @@ def process_class(name: str, cls: list[str], imports: set[str], attr: object) -> elif mem == "__exit__": imports.add("from types import TracebackType") cls.append( - " def __exit__(self, exc_type: type[BaseException] | None, exc_value: BaseException | None, exc_traceback: TracebackType | None) -> None: ...") - elif mem == "__init__" or "cython_function_or_method" in mem_attr.__class__.__name__: - doc = mem_attr.__doc__.split('\n')[0] + " def __exit__(self, exc_type: type[BaseException] | None, exc_value: BaseException | None, exc_traceback: TracebackType | None) -> None: ..." + ) + elif ( + mem == "__init__" + or "cython_function_or_method" in mem_attr.__class__.__name__ + ): + doc = mem_attr.__doc__.split("\n")[0] if " -> " not in doc: doc += " -> None" if ": array" in doc: @@ -46,7 +50,9 @@ def process_class(name: str, cls: list[str], imports: set[str], attr: object) -> raise Exception((mem, mem_attr.__doc__, mem_attr.__class__)) -def process_type(sym: str, attr: object, imports: set[str], classes: dict[str, list[str]]) -> None: +def process_type( + sym: str, attr: object, imports: set[str], classes: dict[str, list[str]] +) -> None: if not isinstance(attr, type): return @@ -70,7 +76,9 @@ def process_type(sym: str, attr: object, imports: set[str], classes: dict[str, l process_class(sym, cls, imports, attr) -def process_value(sym: str, attr: object, consts: list[str], classes: dict[str, list[str]]) -> None: +def process_value( + sym: str, attr: object, consts: list[str], classes: dict[str, list[str]] +) -> None: if isinstance(attr, int): enum = tuple(c for c in classes.keys() if sym.startswith(c.upper())) if enum: @@ -98,8 +106,7 @@ def process_package(out_dir: str, pkg: object, prefix: str, name: str) -> None: attrs.append((sym, attr)) consts: list[str] = [] - classes: collections.OrderedDict[str, - list[str]] = collections.OrderedDict() + classes: collections.OrderedDict[str, list[str]] = collections.OrderedDict() imports: set[str] = set() missing: set[str] = { "Tox_Conference_Number", @@ -125,7 +132,7 @@ def process_package(out_dir: str, pkg: object, prefix: str, name: str) -> None: for m in sorted(missing): pyi.write(f"class {m}: ...\n") for cls in classes.values(): - pyi.write('\n'.join(cls) + "\n") + pyi.write("\n".join(cls) + "\n") for c in consts: pyi.write(c + "\n") From 63a28b6e80f3a8c9f4f1082563fb5de826cec859 Mon Sep 17 00:00:00 2001 From: "Restyled.io" Date: Mon, 8 Jan 2024 03:45:04 +0000 Subject: [PATCH 4/6] Restyled by isort --- pytox/common.py | 3 +-- test/toxav_test.py | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/pytox/common.py b/pytox/common.py index ad6190d..4994acd 100644 --- a/pytox/common.py +++ b/pytox/common.py @@ -1,6 +1,5 @@ import enum -from typing import Sized -from typing import TypeVar +from typing import Sized, TypeVar T = TypeVar("T", bytes, str, Sized) diff --git a/test/toxav_test.py b/test/toxav_test.py index f91ddce..685a545 100644 --- a/test/toxav_test.py +++ b/test/toxav_test.py @@ -1,8 +1,8 @@ -from typing import cast import unittest +from typing import cast -from pytox.toxcore import tox import pytox.toxav.toxav as av +from pytox.toxcore import tox class AvTest(unittest.TestCase): From 6b16ce372425b951ccaf637804c057e4d7f01488 Mon Sep 17 00:00:00 2001 From: "Restyled.io" Date: Mon, 8 Jan 2024 03:45:05 +0000 Subject: [PATCH 5/6] Restyled by reorder-python-imports --- pytox/common.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pytox/common.py b/pytox/common.py index 4994acd..ad6190d 100644 --- a/pytox/common.py +++ b/pytox/common.py @@ -1,5 +1,6 @@ import enum -from typing import Sized, TypeVar +from typing import Sized +from typing import TypeVar T = TypeVar("T", bytes, str, Sized) From 4db508f864034184c54784c678a467d69a4aaaac Mon Sep 17 00:00:00 2001 From: "Restyled.io" Date: Mon, 8 Jan 2024 03:45:10 +0000 Subject: [PATCH 6/6] Restyled by yapf --- pytox/common.py | 3 +- .../auto_tests/self_connection_status_test.py | 18 ++++++------ test/toxencryptsave_test.py | 13 ++++----- tools/stubgen.py | 28 +++++++++---------- 4 files changed, 29 insertions(+), 33 deletions(-) diff --git a/pytox/common.py b/pytox/common.py index ad6190d..83794d5 100644 --- a/pytox/common.py +++ b/pytox/common.py @@ -30,6 +30,5 @@ def check_len(name: str, data: T, expected_length: int) -> T: if len(data) < expected_length: raise LengthException( f"parameter '{name}' received bytes of invalid" - f"length {len(data)}, expected at least {expected_length}" - ) + f"length {len(data)}, expected at least {expected_length}") return data diff --git a/test/auto_tests/self_connection_status_test.py b/test/auto_tests/self_connection_status_test.py index d5e1087..e3115c0 100644 --- a/test/auto_tests/self_connection_status_test.py +++ b/test/auto_tests/self_connection_status_test.py @@ -13,9 +13,9 @@ class TestException(Exception): class TestTox(core.Tox_Ptr): connection_status_from_cb = core.TOX_CONNECTION_NONE - def handle_self_connection_status( - self, connection_status: core.Tox_Connection - ) -> None: + def handle_self_connection_status(self, + connection_status: core.Tox_Connection + ) -> None: print(connection_status) self.connection_status_from_cb = connection_status raise TestException(connection_status) @@ -27,16 +27,14 @@ def test_connection_status_cb(self) -> None: with TestTox() as tox2: # Test that exceptions can pass through C code. with self.assertRaises(TestException) as ex: - while ( - tox1.connection_status == core.TOX_CONNECTION_NONE - or tox2.connection_status == core.TOX_CONNECTION_NONE - ): + while (tox1.connection_status == core.TOX_CONNECTION_NONE + or + tox2.connection_status == core.TOX_CONNECTION_NONE): tox1.iterate() tox2.iterate() time.sleep(tox1.iteration_interval / 1000) - self.assertEqual( - tox1.connection_status, tox1.connection_status_from_cb - ) + self.assertEqual(tox1.connection_status, + tox1.connection_status_from_cb) self.assertEqual(ex.exception.status, tox1.connection_status) diff --git a/test/toxencryptsave_test.py b/test/toxencryptsave_test.py index d6bc425..aad39ec 100644 --- a/test/toxencryptsave_test.py +++ b/test/toxencryptsave_test.py @@ -8,23 +8,22 @@ class ToxencryptsaveTest(unittest.TestCase): def test_encrypt_decrypt(self) -> None: with c.Tox_Pass_Key_Ptr(b"hello") as pk: self.assertNotEqual(pk.encrypt(b"hello world"), b"hello world") - self.assertEqual(pk.decrypt(pk.encrypt(b"hello world")), b"hello world") + self.assertEqual(pk.decrypt(pk.encrypt(b"hello world")), + b"hello world") def test_encrypt_decrypt_with_correct_salt(self) -> None: with c.Tox_Pass_Key_Ptr(b"hello", b"a" * 32) as pk1: with c.Tox_Pass_Key_Ptr(b"hello", b"a" * 32) as pk2: - self.assertEqual( - pk2.decrypt(pk1.encrypt(b"hello world")), b"hello world" - ) + self.assertEqual(pk2.decrypt(pk1.encrypt(b"hello world")), + b"hello world") def test_encrypt_decrypt_with_wrong_salt(self) -> None: with c.Tox_Pass_Key_Ptr(passphrase=b"hello", salt=b"a" * 32) as pk1: with c.Tox_Pass_Key_Ptr(b"hello", b"b" * 32) as pk2: with self.assertRaises(c.ApiException) as ex: pk2.decrypt(pk1.encrypt(b"hello world")) - self.assertEqual( - ex.exception.error.name, c.TOX_ERR_DECRYPTION_FAILED.name - ) + self.assertEqual(ex.exception.error.name, + c.TOX_ERR_DECRYPTION_FAILED.name) def test_salt_too_small(self) -> None: with self.assertRaises(common.LengthException): diff --git a/tools/stubgen.py b/tools/stubgen.py index dffce99..f227611 100644 --- a/tools/stubgen.py +++ b/tools/stubgen.py @@ -15,7 +15,8 @@ ] -def process_class(name: str, cls: list[str], imports: set[str], attr: object) -> None: +def process_class(name: str, cls: list[str], imports: set[str], + attr: object) -> None: for mem in dir(attr): mem_attr = getattr(attr, mem) if mem == "__enter__": @@ -26,10 +27,8 @@ def process_class(name: str, cls: list[str], imports: set[str], attr: object) -> cls.append( " def __exit__(self, exc_type: type[BaseException] | None, exc_value: BaseException | None, exc_traceback: TracebackType | None) -> None: ..." ) - elif ( - mem == "__init__" - or "cython_function_or_method" in mem_attr.__class__.__name__ - ): + elif (mem == "__init__" + or "cython_function_or_method" in mem_attr.__class__.__name__): doc = mem_attr.__doc__.split("\n")[0] if " -> " not in doc: doc += " -> None" @@ -50,9 +49,8 @@ def process_class(name: str, cls: list[str], imports: set[str], attr: object) -> raise Exception((mem, mem_attr.__doc__, mem_attr.__class__)) -def process_type( - sym: str, attr: object, imports: set[str], classes: dict[str, list[str]] -) -> None: +def process_type(sym: str, attr: object, imports: set[str], + classes: dict[str, list[str]]) -> None: if not isinstance(attr, type): return @@ -76,9 +74,8 @@ def process_type( process_class(sym, cls, imports, attr) -def process_value( - sym: str, attr: object, consts: list[str], classes: dict[str, list[str]] -) -> None: +def process_value(sym: str, attr: object, consts: list[str], + classes: dict[str, list[str]]) -> None: if isinstance(attr, int): enum = tuple(c for c in classes.keys() if sym.startswith(c.upper())) if enum: @@ -101,12 +98,14 @@ def process_package(out_dir: str, pkg: object, prefix: str, name: str) -> None: continue if isinstance(attr, pytox.common.__class__): continue - if hasattr(attr, "__module__") and f"{prefix}.{attr.__module__}" != name: + if hasattr(attr, + "__module__") and f"{prefix}.{attr.__module__}" != name: continue attrs.append((sym, attr)) consts: list[str] = [] - classes: collections.OrderedDict[str, list[str]] = collections.OrderedDict() + classes: collections.OrderedDict[str, list[str]] = collections.OrderedDict( + ) imports: set[str] = set() missing: set[str] = { "Tox_Conference_Number", @@ -125,7 +124,8 @@ def process_package(out_dir: str, pkg: object, prefix: str, name: str) -> None: for sym, attr in attrs: process_value(sym, attr, consts, classes) - with open(os.path.join(out_dir, f"{name.replace('.', '/')}.pyi"), "w") as pyi: + with open(os.path.join(out_dir, f"{name.replace('.', '/')}.pyi"), + "w") as pyi: pyi.write(f"# {name}\n") for s in sorted(imports): pyi.write(s + "\n")