From 9e814860ae3d75c87539345fbc642df81256a17a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Helleu?= Date: Sun, 7 Dec 2025 09:22:34 +0100 Subject: [PATCH] ci: switch from bandit/flake8/pylint to ruff in CI for Python scripts --- .github/workflows/ci.yml | 5 +- ruff.toml | 15 + src/plugins/python/weechat.pyi | 8 +- tests/unit/scripts/python/testapi.py | 1126 +++++++++++++---------- tests/unit/scripts/python/testapigen.py | 409 ++++---- tests/unit/scripts/python/unparse.py | 1020 ++++++++++---------- tools/check_curl_symbols.py | 82 +- tools/check_scripts.sh | 6 +- tools/generate_python_stub.py | 50 +- 9 files changed, 1419 insertions(+), 1302 deletions(-) create mode 100644 ruff.toml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 491b31d46..970fdebee 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,7 +18,6 @@ env: curl devscripts equivs - flake8 gem2deb guile-3.0-dev lcov @@ -40,8 +39,6 @@ env: php-dev pipx pkgconf - pylint - python3-bandit python3-dev ruby-pygments.rb shellcheck @@ -158,7 +155,7 @@ jobs: sudo apt-get --yes --no-install-recommends install ${{ env.WEECHAT_DEPS_UBUNTU }} # uninstall php imagick as is causes a crash when loading php plugin (see #2009) sudo apt-get --yes purge php8.3-imagick - pipx install msgcheck schemathesis + pipx install msgcheck ruff schemathesis - name: Check gettext files run: msgcheck po/*.po diff --git a/ruff.toml b/ruff.toml new file mode 100644 index 000000000..bc25cbdb1 --- /dev/null +++ b/ruff.toml @@ -0,0 +1,15 @@ +# SPDX-FileCopyrightText: 2025 Sébastien Helleu +# +# SPDX-License-Identifier: GPL-3.0-or-later + +line-length = 120 + +[lint] +select = ["ALL"] +ignore = [ + "D203", # incorrect-blank-line-before-class + "D213", # multi-line-summary-second-line +] + +[lint.pylint] +max-args = 10 diff --git a/src/plugins/python/weechat.pyi b/src/plugins/python/weechat.pyi index d96701f9b..0c669ccd4 100644 --- a/src/plugins/python/weechat.pyi +++ b/src/plugins/python/weechat.pyi @@ -7,6 +7,8 @@ # DO NOT EDIT BY HAND! # +# ruff: noqa: A002,D400,D205,D301,D415,E501,PIE790,PYI021,PYI048,UP006,UP007,UP035 + from typing import Dict, Union WEECHAT_RC_OK: int = 0 @@ -55,8 +57,7 @@ WEECHAT_HOOK_SIGNAL_POINTER: str = "pointer" def register(name: str, author: str, version: str, license: str, description: str, shutdown_function: str, charset: str) -> int: - """`register in WeeChat plugin API reference `_ - """ + """`register in WeeChat plugin API reference `_""" ... @@ -1981,8 +1982,7 @@ def window_get_integer(window: str, property: str) -> int: def window_get_string(window: str, property: str) -> str: - """`window_get_string in WeeChat plugin API reference `_ - """ + """`window_get_string in WeeChat plugin API reference `_""" ... diff --git a/tests/unit/scripts/python/testapi.py b/tests/unit/scripts/python/testapi.py index 5099ad027..ab8ab817d 100644 --- a/tests/unit/scripts/python/testapi.py +++ b/tests/unit/scripts/python/testapi.py @@ -16,30 +16,36 @@ # along with this program. If not, see . # -""" -This script contains WeeChat scripting API tests -(it cannot be run directly and cannot be loaded in WeeChat). +"""WeeChat scripting API tests. + +It cannot be run directly and cannot be loaded in WeeChat. It is parsed by testapigen.py, using Python AST (Abstract Syntax Trees), to generate scripts in all supported languages (Python, Perl, Ruby, ...). The resulting scripts can be loaded in WeeChat to test the scripting API. """ -# pylint: disable=line-too-long,no-value-for-parameter,too-many-locals -# pylint: disable=too-many-statements +# ruff: noqa: ANN001,ANN201,ARG001,COM812,INP001,ISC003,PLR2004,PLR0915 -import weechat # pylint: disable=import-error +import weechat def check(result, condition, lineno): """Display the result of a test.""" if result: - weechat.prnt('', ' TEST OK: ' + condition) + weechat.prnt("", " TEST OK: " + condition) else: - weechat.prnt('', - '{SCRIPT_SOURCE}' + ':' + lineno + ':1: ' + - 'ERROR: [' + '{SCRIPT_NAME}' + '] condition is false: ' + - condition) + weechat.prnt( + "", + "{SCRIPT_SOURCE}" + + ":" + + lineno + + ":1: " + + "ERROR: [" + + "{SCRIPT_NAME}" + + "] condition is false: " + + condition, + ) def test_constants(): @@ -61,13 +67,13 @@ def test_constants(): check(weechat.WEECHAT_CONFIG_OPTION_UNSET_OK_RESET == 1) check(weechat.WEECHAT_CONFIG_OPTION_UNSET_OK_REMOVED == 2) check(weechat.WEECHAT_CONFIG_OPTION_UNSET_ERROR == -1) - check(weechat.WEECHAT_LIST_POS_SORT == 'sort') - check(weechat.WEECHAT_LIST_POS_BEGINNING == 'beginning') - check(weechat.WEECHAT_LIST_POS_END == 'end') - check(weechat.WEECHAT_HOTLIST_LOW == '0') - check(weechat.WEECHAT_HOTLIST_MESSAGE == '1') - check(weechat.WEECHAT_HOTLIST_PRIVATE == '2') - check(weechat.WEECHAT_HOTLIST_HIGHLIGHT == '3') + check(weechat.WEECHAT_LIST_POS_SORT == "sort") + check(weechat.WEECHAT_LIST_POS_BEGINNING == "beginning") + check(weechat.WEECHAT_LIST_POS_END == "end") + check(weechat.WEECHAT_HOTLIST_LOW == "0") + check(weechat.WEECHAT_HOTLIST_MESSAGE == "1") + check(weechat.WEECHAT_HOTLIST_PRIVATE == "2") + check(weechat.WEECHAT_HOTLIST_HIGHLIGHT == "3") check(weechat.WEECHAT_HOOK_PROCESS_RUNNING == -1) check(weechat.WEECHAT_HOOK_PROCESS_ERROR == -2) check(weechat.WEECHAT_HOOK_CONNECT_IPV6_DISABLE == 0) @@ -84,110 +90,108 @@ def test_constants(): check(weechat.WEECHAT_HOOK_CONNECT_MEMORY_ERROR == 8) check(weechat.WEECHAT_HOOK_CONNECT_TIMEOUT == 9) check(weechat.WEECHAT_HOOK_CONNECT_SOCKET_ERROR == 10) - check(weechat.WEECHAT_HOOK_SIGNAL_STRING == 'string') - check(weechat.WEECHAT_HOOK_SIGNAL_INT == 'int') - check(weechat.WEECHAT_HOOK_SIGNAL_POINTER == 'pointer') + check(weechat.WEECHAT_HOOK_SIGNAL_STRING == "string") + check(weechat.WEECHAT_HOOK_SIGNAL_INT == "int") + check(weechat.WEECHAT_HOOK_SIGNAL_POINTER == "pointer") def test_plugins(): """Test plugins functions.""" - check(weechat.plugin_get_name('') == 'core') - check(weechat.plugin_get_name( - weechat.buffer_get_pointer( - weechat.buffer_search_main(), 'plugin')) == 'core') + check(weechat.plugin_get_name("") == "core") + check(weechat.plugin_get_name(weechat.buffer_get_pointer(weechat.buffer_search_main(), "plugin")) == "core") def test_strings(): """Test string functions.""" - check(weechat.charset_set('iso-8859-15') == 1) - check(weechat.charset_set('') == 1) - check(weechat.iconv_to_internal('iso-8859-15', 'abc') == 'abc') - check(weechat.iconv_from_internal('iso-8859-15', 'abcd') == 'abcd') - check(weechat.gettext('abcdef') == 'abcdef') - check(weechat.ngettext('file', 'files', 1) == 'file') - check(weechat.ngettext('file', 'files', 2) == 'files') - check(weechat.strlen_screen('abcd') == 4) - check(weechat.string_match('abcdef', 'abc*', 0) == 1) - check(weechat.string_match('abcdef', 'abc*', 1) == 1) - check(weechat.string_match('ABCDEF', 'abc*', 1) == 0) - check(weechat.string_match_list('abcdef', '*,!abc*', 0) == 0) - check(weechat.string_match_list('ABCDEF', '*,!abc*', 1) == 1) - check(weechat.string_match_list('def', '*,!abc*', 0) == 1) - check(weechat.string_eval_path_home('test ${abc}', {}, {'abc': '123'}, {}) == 'test 123') - check(weechat.string_mask_to_regex('test*mask') == 'test.*mask') - check(weechat.string_has_highlight('my test string', 'test,word2') == 1) - check(weechat.string_has_highlight_regex('my test string', 'test|word2') == 1) - check(weechat.string_format_size(0) == '0 bytes') - check(weechat.string_format_size(1) == '1 byte') - check(weechat.string_format_size(2097152) == '2.10 MB') - check(weechat.string_format_size(420000000) == '420.00 MB') - check(weechat.string_parse_size('') == 0) - check(weechat.string_parse_size('*') == 0) - check(weechat.string_parse_size('z') == 0) - check(weechat.string_parse_size('1ba') == 0) - check(weechat.string_parse_size('1') == 1) - check(weechat.string_parse_size('12b') == 12) - check(weechat.string_parse_size('123 b') == 123) - check(weechat.string_parse_size('120k') == 120000) - check(weechat.string_parse_size('1500m') == 1500000000) - check(weechat.string_parse_size('2g') == 2000000000) - check(weechat.string_color_code_size('') == 0) - check(weechat.string_color_code_size('test') == 0) - str_color = weechat.color('yellow,red') + check(weechat.charset_set("iso-8859-15") == 1) + check(weechat.charset_set("") == 1) + check(weechat.iconv_to_internal("iso-8859-15", "abc") == "abc") + check(weechat.iconv_from_internal("iso-8859-15", "abcd") == "abcd") + check(weechat.gettext("abcdef") == "abcdef") + check(weechat.ngettext("file", "files", 1) == "file") + check(weechat.ngettext("file", "files", 2) == "files") + check(weechat.strlen_screen("abcd") == 4) + check(weechat.string_match("abcdef", "abc*", 0) == 1) + check(weechat.string_match("abcdef", "abc*", 1) == 1) + check(weechat.string_match("ABCDEF", "abc*", 1) == 0) + check(weechat.string_match_list("abcdef", "*,!abc*", 0) == 0) + check(weechat.string_match_list("ABCDEF", "*,!abc*", 1) == 1) + check(weechat.string_match_list("def", "*,!abc*", 0) == 1) + check(weechat.string_eval_path_home("test ${abc}", {}, {"abc": "123"}, {}) == "test 123") + check(weechat.string_mask_to_regex("test*mask") == "test.*mask") + check(weechat.string_has_highlight("my test string", "test,word2") == 1) + check(weechat.string_has_highlight_regex("my test string", "test|word2") == 1) + check(weechat.string_format_size(0) == "0 bytes") + check(weechat.string_format_size(1) == "1 byte") + check(weechat.string_format_size(2097152) == "2.10 MB") + check(weechat.string_format_size(420000000) == "420.00 MB") + check(weechat.string_parse_size("") == 0) + check(weechat.string_parse_size("*") == 0) + check(weechat.string_parse_size("z") == 0) + check(weechat.string_parse_size("1ba") == 0) + check(weechat.string_parse_size("1") == 1) + check(weechat.string_parse_size("12b") == 12) + check(weechat.string_parse_size("123 b") == 123) + check(weechat.string_parse_size("120k") == 120000) + check(weechat.string_parse_size("1500m") == 1500000000) + check(weechat.string_parse_size("2g") == 2000000000) + check(weechat.string_color_code_size("") == 0) + check(weechat.string_color_code_size("test") == 0) + str_color = weechat.color("yellow,red") check(weechat.string_color_code_size(str_color) == 7) - check(weechat.string_remove_color('test', '?') == 'test') - check(weechat.string_is_command_char('/test') == 1) - check(weechat.string_is_command_char('test') == 0) - check(weechat.string_input_for_buffer('test') == 'test') - check(weechat.string_input_for_buffer('/test') == '') - check(weechat.string_input_for_buffer('//test') == '/test') - check(weechat.string_eval_expression("100 > 50", {}, {}, {"type": "condition"}) == '1') - check(weechat.string_eval_expression("-50 < 100", {}, {}, {"type": "condition"}) == '1') - check(weechat.string_eval_expression("18.2 > 5", {}, {}, {"type": "condition"}) == '1') - check(weechat.string_eval_expression("0xA3 > 2", {}, {}, {"type": "condition"}) == '1') - check(weechat.string_eval_expression("${buffer.full_name}", {}, {}, {}) == 'core.weechat') + check(weechat.string_remove_color("test", "?") == "test") + check(weechat.string_is_command_char("/test") == 1) + check(weechat.string_is_command_char("test") == 0) + check(weechat.string_input_for_buffer("test") == "test") + check(weechat.string_input_for_buffer("/test") == "") + check(weechat.string_input_for_buffer("//test") == "/test") + check(weechat.string_eval_expression("100 > 50", {}, {}, {"type": "condition"}) == "1") + check(weechat.string_eval_expression("-50 < 100", {}, {}, {"type": "condition"}) == "1") + check(weechat.string_eval_expression("18.2 > 5", {}, {}, {"type": "condition"}) == "1") + check(weechat.string_eval_expression("0xA3 > 2", {}, {}, {"type": "condition"}) == "1") + check(weechat.string_eval_expression("${buffer.full_name}", {}, {}, {}) == "core.weechat") def test_lists(): """Test list functions.""" ptr_list = weechat.list_new() - check(ptr_list != '') + check(ptr_list != "") check(weechat.list_size(ptr_list) == 0) - item_def = weechat.list_add(ptr_list, 'def', weechat.WEECHAT_LIST_POS_SORT, '') + item_def = weechat.list_add(ptr_list, "def", weechat.WEECHAT_LIST_POS_SORT, "") check(weechat.list_size(ptr_list) == 1) - item_abc = weechat.list_add(ptr_list, 'abc', weechat.WEECHAT_LIST_POS_SORT, '') + item_abc = weechat.list_add(ptr_list, "abc", weechat.WEECHAT_LIST_POS_SORT, "") check(weechat.list_size(ptr_list) == 2) - check(weechat.list_search(ptr_list, 'abc') == item_abc) - check(weechat.list_search(ptr_list, 'def') == item_def) - check(weechat.list_search(ptr_list, 'ghi') == '') - check(weechat.list_search_pos(ptr_list, 'abc') == 0) - check(weechat.list_search_pos(ptr_list, 'def') == 1) - check(weechat.list_search_pos(ptr_list, 'ghi') == -1) - check(weechat.list_casesearch(ptr_list, 'abc') == item_abc) - check(weechat.list_casesearch(ptr_list, 'def') == item_def) - check(weechat.list_casesearch(ptr_list, 'ghi') == '') - check(weechat.list_casesearch(ptr_list, 'ABC') == item_abc) - check(weechat.list_casesearch(ptr_list, 'DEF') == item_def) - check(weechat.list_casesearch(ptr_list, 'GHI') == '') - check(weechat.list_casesearch_pos(ptr_list, 'abc') == 0) - check(weechat.list_casesearch_pos(ptr_list, 'def') == 1) - check(weechat.list_casesearch_pos(ptr_list, 'ghi') == -1) - check(weechat.list_casesearch_pos(ptr_list, 'ABC') == 0) - check(weechat.list_casesearch_pos(ptr_list, 'DEF') == 1) - check(weechat.list_casesearch_pos(ptr_list, 'GHI') == -1) + check(weechat.list_search(ptr_list, "abc") == item_abc) + check(weechat.list_search(ptr_list, "def") == item_def) + check(weechat.list_search(ptr_list, "ghi") == "") + check(weechat.list_search_pos(ptr_list, "abc") == 0) + check(weechat.list_search_pos(ptr_list, "def") == 1) + check(weechat.list_search_pos(ptr_list, "ghi") == -1) + check(weechat.list_casesearch(ptr_list, "abc") == item_abc) + check(weechat.list_casesearch(ptr_list, "def") == item_def) + check(weechat.list_casesearch(ptr_list, "ghi") == "") + check(weechat.list_casesearch(ptr_list, "ABC") == item_abc) + check(weechat.list_casesearch(ptr_list, "DEF") == item_def) + check(weechat.list_casesearch(ptr_list, "GHI") == "") + check(weechat.list_casesearch_pos(ptr_list, "abc") == 0) + check(weechat.list_casesearch_pos(ptr_list, "def") == 1) + check(weechat.list_casesearch_pos(ptr_list, "ghi") == -1) + check(weechat.list_casesearch_pos(ptr_list, "ABC") == 0) + check(weechat.list_casesearch_pos(ptr_list, "DEF") == 1) + check(weechat.list_casesearch_pos(ptr_list, "GHI") == -1) check(weechat.list_get(ptr_list, 0) == item_abc) check(weechat.list_get(ptr_list, 1) == item_def) - check(weechat.list_get(ptr_list, 2) == '') - weechat.list_set(item_def, 'def2') - check(weechat.list_string(item_def) == 'def2') + check(weechat.list_get(ptr_list, 2) == "") + weechat.list_set(item_def, "def2") + check(weechat.list_string(item_def) == "def2") check(weechat.list_next(item_abc) == item_def) - check(weechat.list_next(item_def) == '') - check(weechat.list_prev(item_abc) == '') + check(weechat.list_next(item_def) == "") + check(weechat.list_prev(item_abc) == "") check(weechat.list_prev(item_def) == item_abc) weechat.list_remove(ptr_list, item_abc) check(weechat.list_size(ptr_list) == 1) check(weechat.list_get(ptr_list, 0) == item_def) - check(weechat.list_get(ptr_list, 1) == '') + check(weechat.list_get(ptr_list, 1) == "") weechat.list_remove_all(ptr_list) check(weechat.list_size(ptr_list) == 0) weechat.list_free(ptr_list) @@ -235,48 +239,66 @@ def option_check_value_cb(data, option, value): def option_change_cb(data, option): """Option change callback.""" - pass # pylint: disable=unnecessary-pass + pass # noqa: PIE790 def option_delete_cb(data, option): """Option delete callback.""" - pass # pylint: disable=unnecessary-pass + pass # noqa: PIE790 def test_config(): """Test config functions.""" # config - ptr_config = weechat.config_new('test_config_' + '{SCRIPT_LANGUAGE}', - 'config_reload_cb', 'config_reload_data') - check(ptr_config != '') + ptr_config = weechat.config_new("test_config_" + "{SCRIPT_LANGUAGE}", "config_reload_cb", "config_reload_data") + check(ptr_config != "") # set version - weechat.config_set_version(ptr_config, 2, - 'config_update_cb', 'config_update_data') + weechat.config_set_version(ptr_config, 2, "config_update_cb", "config_update_data") # section ptr_section = weechat.config_new_section( - ptr_config, 'section1', 0, 0, - 'section_read_cb', '', - 'section_write_cb', '', - 'section_write_default_cb', '', - 'section_create_option_cb', '', - 'section_delete_option_cb', '', + ptr_config, + "section1", + 0, + 0, + "section_read_cb", + "", + "section_write_cb", + "", + "section_write_default_cb", + "", + "section_create_option_cb", + "", + "section_delete_option_cb", + "", ) - check(ptr_section != '') + check(ptr_section != "") # search section - ptr_section2 = weechat.config_search_section(ptr_config, 'section1') + ptr_section2 = weechat.config_search_section(ptr_config, "section1") check(ptr_section2 == ptr_section) # boolean option ptr_opt_bool = weechat.config_new_option( - ptr_config, ptr_section, 'option_bool', 'boolean', 'bool option', - '', 0, 0, 'on', 'on', 0, - 'option_check_value_cb', '', - 'option_change_cb', '', - 'option_delete_cb', '', + ptr_config, + ptr_section, + "option_bool", + "boolean", + "bool option", + "", + 0, + 0, + "on", + "on", + 0, + "option_check_value_cb", + "", + "option_change_cb", + "", + "option_delete_cb", + "", ) - check(ptr_opt_bool != '') + check(ptr_opt_bool != "") check(weechat.config_boolean(ptr_opt_bool) == 1) - check(weechat.config_option_set(ptr_opt_bool, 'off', 1) == 2) # SET_OK_CHANGED - check(weechat.config_option_set(ptr_opt_bool, 'off', 1) == 1) # SET_OK_SAME_VALUE + check(weechat.config_option_set(ptr_opt_bool, "off", 1) == 2) # SET_OK_CHANGED + check(weechat.config_option_set(ptr_opt_bool, "off", 1) == 1) # SET_OK_SAME_VALUE check(weechat.config_boolean(ptr_opt_bool) == 0) check(weechat.config_boolean_default(ptr_opt_bool) == 1) check(weechat.config_option_reset(ptr_opt_bool, 1) == 2) # SET_OK_CHANGED @@ -284,28 +306,51 @@ def test_config(): check(weechat.config_boolean(ptr_opt_bool) == 1) # boolean option with parent option ptr_opt_bool_child = weechat.config_new_option( - ptr_config, ptr_section, - 'option_bool_child << test_config_' + '{SCRIPT_LANGUAGE}' + '.section1.option_bool', - 'boolean', 'bool option', '', 0, 0, None, None, 1, - 'option_check_value_cb', '', - 'option_change_cb', '', - 'option_delete_cb', '', + ptr_config, + ptr_section, + "option_bool_child << test_config_" + "{SCRIPT_LANGUAGE}" + ".section1.option_bool", + "boolean", + "bool option", + "", + 0, + 0, + None, + None, + 1, + "option_check_value_cb", + "", + "option_change_cb", + "", + "option_delete_cb", + "", ) - check(ptr_opt_bool_child != '') + check(ptr_opt_bool_child != "") check(weechat.config_boolean(ptr_opt_bool_child) == 0) check(weechat.config_boolean_inherited(ptr_opt_bool_child) == 1) # integer option ptr_opt_int = weechat.config_new_option( - ptr_config, ptr_section, 'option_int', 'integer', 'int option', - '', 0, 256, '2', '2', 0, - 'option_check_value_cb', '', - 'option_change_cb', '', - 'option_delete_cb', '', + ptr_config, + ptr_section, + "option_int", + "integer", + "int option", + "", + 0, + 256, + "2", + "2", + 0, + "option_check_value_cb", + "", + "option_change_cb", + "", + "option_delete_cb", + "", ) - check(ptr_opt_int != '') + check(ptr_opt_int != "") check(weechat.config_integer(ptr_opt_int) == 2) - check(weechat.config_option_set(ptr_opt_int, '15', 1) == 2) # SET_OK_CHANGED - check(weechat.config_option_set(ptr_opt_int, '15', 1) == 1) # SET_OK_SAME_VALUE + check(weechat.config_option_set(ptr_opt_int, "15", 1) == 2) # SET_OK_CHANGED + check(weechat.config_option_set(ptr_opt_int, "15", 1) == 1) # SET_OK_SAME_VALUE check(weechat.config_integer(ptr_opt_int) == 15) check(weechat.config_integer_default(ptr_opt_int) == 2) check(weechat.config_option_reset(ptr_opt_int, 1) == 2) # SET_OK_CHANGED @@ -313,172 +358,273 @@ def test_config(): check(weechat.config_integer(ptr_opt_int) == 2) # integer option with parent option ptr_opt_int_child = weechat.config_new_option( - ptr_config, ptr_section, - 'option_int_child << test_config_' + '{SCRIPT_LANGUAGE}' + '.section1.option_int', - 'integer', 'int option', '', 0, 256, None, None, 1, - 'option_check_value_cb', '', - 'option_change_cb', '', - 'option_delete_cb', '', + ptr_config, + ptr_section, + "option_int_child << test_config_" + "{SCRIPT_LANGUAGE}" + ".section1.option_int", + "integer", + "int option", + "", + 0, + 256, + None, + None, + 1, + "option_check_value_cb", + "", + "option_change_cb", + "", + "option_delete_cb", + "", ) - check(ptr_opt_int_child != '') + check(ptr_opt_int_child != "") check(weechat.config_integer(ptr_opt_int_child) == 0) check(weechat.config_integer_inherited(ptr_opt_int_child) == 2) # integer option (with string values: enum with WeeChat >= 4.1.0) ptr_opt_int_str = weechat.config_new_option( - ptr_config, ptr_section, 'option_int_str', 'integer', 'int option str', - 'val1|val2|val3', 0, 0, 'val2', 'val2', 0, - 'option_check_value_cb', '', - 'option_change_cb', '', - 'option_delete_cb', '', + ptr_config, + ptr_section, + "option_int_str", + "integer", + "int option str", + "val1|val2|val3", + 0, + 0, + "val2", + "val2", + 0, + "option_check_value_cb", + "", + "option_change_cb", + "", + "option_delete_cb", + "", ) - check(ptr_opt_int_str != '') + check(ptr_opt_int_str != "") check(weechat.config_integer(ptr_opt_int_str) == 1) - check(weechat.config_string(ptr_opt_int_str) == 'val2') - check(weechat.config_option_set(ptr_opt_int_str, 'val1', 1) == 2) # SET_OK_CHANGED - check(weechat.config_option_set(ptr_opt_int_str, 'val1', 1) == 1) # SET_OK_SAME_VALUE + check(weechat.config_string(ptr_opt_int_str) == "val2") + check(weechat.config_option_set(ptr_opt_int_str, "val1", 1) == 2) # SET_OK_CHANGED + check(weechat.config_option_set(ptr_opt_int_str, "val1", 1) == 1) # SET_OK_SAME_VALUE check(weechat.config_integer(ptr_opt_int_str) == 0) - check(weechat.config_string(ptr_opt_int_str) == 'val1') + check(weechat.config_string(ptr_opt_int_str) == "val1") check(weechat.config_integer_default(ptr_opt_int_str) == 1) - check(weechat.config_string_default(ptr_opt_int_str) == 'val2') + check(weechat.config_string_default(ptr_opt_int_str) == "val2") check(weechat.config_option_reset(ptr_opt_int_str, 1) == 2) # SET_OK_CHANGED check(weechat.config_option_reset(ptr_opt_int_str, 1) == 1) # SET_OK_SAME_VALUE check(weechat.config_integer(ptr_opt_int_str) == 1) - check(weechat.config_string(ptr_opt_int_str) == 'val2') + check(weechat.config_string(ptr_opt_int_str) == "val2") # integer option with parent option (with string values: enum with WeeChat >= 4.1.0) ptr_opt_int_str_child = weechat.config_new_option( - ptr_config, ptr_section, - 'option_int_str_child << test_config_' + '{SCRIPT_LANGUAGE}' + '.section1.option_int_str', - 'integer', 'int option str', - 'val1|val2|val3', 0, 0, None, None, 1, - 'option_check_value_cb', '', - 'option_change_cb', '', - 'option_delete_cb', '', + ptr_config, + ptr_section, + "option_int_str_child << test_config_" + "{SCRIPT_LANGUAGE}" + ".section1.option_int_str", + "integer", + "int option str", + "val1|val2|val3", + 0, + 0, + None, + None, + 1, + "option_check_value_cb", + "", + "option_change_cb", + "", + "option_delete_cb", + "", ) - check(ptr_opt_int_str_child != '') + check(ptr_opt_int_str_child != "") check(weechat.config_integer(ptr_opt_int_str_child) == 0) check(weechat.config_integer_inherited(ptr_opt_int_str_child) == 1) # string option ptr_opt_str = weechat.config_new_option( - ptr_config, ptr_section, 'option_str', 'string', 'str option', - '', 0, 0, 'value', 'value', 1, - 'option_check_value_cb', '', - 'option_change_cb', '', - 'option_delete_cb', '', + ptr_config, + ptr_section, + "option_str", + "string", + "str option", + "", + 0, + 0, + "value", + "value", + 1, + "option_check_value_cb", + "", + "option_change_cb", + "", + "option_delete_cb", + "", ) - check(ptr_opt_str != '') - check(weechat.config_string(ptr_opt_str) == 'value') - check(weechat.config_option_set(ptr_opt_str, 'value2', 1) == 2) # SET_OK_CHANGED - check(weechat.config_option_set(ptr_opt_str, 'value2', 1) == 1) # SET_OK_SAME_VALUE - check(weechat.config_string(ptr_opt_str) == 'value2') - check(weechat.config_string_default(ptr_opt_str) == 'value') + check(ptr_opt_str != "") + check(weechat.config_string(ptr_opt_str) == "value") + check(weechat.config_option_set(ptr_opt_str, "value2", 1) == 2) # SET_OK_CHANGED + check(weechat.config_option_set(ptr_opt_str, "value2", 1) == 1) # SET_OK_SAME_VALUE + check(weechat.config_string(ptr_opt_str) == "value2") + check(weechat.config_string_default(ptr_opt_str) == "value") check(weechat.config_option_reset(ptr_opt_str, 1) == 2) # SET_OK_CHANGED check(weechat.config_option_reset(ptr_opt_str, 1) == 1) # SET_OK_SAME_VALUE - check(weechat.config_string(ptr_opt_str) == 'value') + check(weechat.config_string(ptr_opt_str) == "value") check(weechat.config_option_is_null(ptr_opt_str) == 0) check(weechat.config_option_set_null(ptr_opt_str, 1) == 2) # SET_OK_CHANGED check(weechat.config_option_set_null(ptr_opt_str, 1) == 1) # SET_OK_SAME_VALUE check(weechat.config_option_is_null(ptr_opt_str) == 1) - check(weechat.config_string(ptr_opt_str) == '') + check(weechat.config_string(ptr_opt_str) == "") check(weechat.config_option_unset(ptr_opt_str) == 1) # UNSET_OK_RESET check(weechat.config_option_unset(ptr_opt_str) == 0) # UNSET_OK_NO_RESET - check(weechat.config_string(ptr_opt_str) == 'value') + check(weechat.config_string(ptr_opt_str) == "value") check(weechat.config_option_default_is_null(ptr_opt_str) == 0) # string option with parent option ptr_opt_str_child = weechat.config_new_option( - ptr_config, ptr_section, - 'option_str_child << test_config_' + '{SCRIPT_LANGUAGE}' + '.section1.option_str', - 'string', 'str option', '', 0, 0, None, None, 1, - 'option_check_value_cb', '', - 'option_change_cb', '', - 'option_delete_cb', '', + ptr_config, + ptr_section, + "option_str_child << test_config_" + "{SCRIPT_LANGUAGE}" + ".section1.option_str", + "string", + "str option", + "", + 0, + 0, + None, + None, + 1, + "option_check_value_cb", + "", + "option_change_cb", + "", + "option_delete_cb", + "", ) - check(ptr_opt_str_child != '') - check(weechat.config_string(ptr_opt_str_child) == '') - check(weechat.config_string_inherited(ptr_opt_str_child) == 'value') + check(ptr_opt_str_child != "") + check(weechat.config_string(ptr_opt_str_child) == "") + check(weechat.config_string_inherited(ptr_opt_str_child) == "value") # color option ptr_opt_col = weechat.config_new_option( - ptr_config, ptr_section, 'option_col', 'color', 'col option', - '', 0, 0, 'lightgreen', 'lightgreen', 0, - 'option_check_value_cb', '', - 'option_change_cb', '', - 'option_delete_cb', '', + ptr_config, + ptr_section, + "option_col", + "color", + "col option", + "", + 0, + 0, + "lightgreen", + "lightgreen", + 0, + "option_check_value_cb", + "", + "option_change_cb", + "", + "option_delete_cb", + "", ) - check(ptr_opt_col != '') - check(weechat.config_color(ptr_opt_col) == 'lightgreen') - check(weechat.config_option_set(ptr_opt_col, 'red', 1) == 2) # SET_OK_CHANGED - check(weechat.config_option_set(ptr_opt_col, 'red', 1) == 1) # SET_OK_SAME_VALUE - check(weechat.config_color(ptr_opt_col) == 'red') - check(weechat.config_color_default(ptr_opt_col) == 'lightgreen') + check(ptr_opt_col != "") + check(weechat.config_color(ptr_opt_col) == "lightgreen") + check(weechat.config_option_set(ptr_opt_col, "red", 1) == 2) # SET_OK_CHANGED + check(weechat.config_option_set(ptr_opt_col, "red", 1) == 1) # SET_OK_SAME_VALUE + check(weechat.config_color(ptr_opt_col) == "red") + check(weechat.config_color_default(ptr_opt_col) == "lightgreen") check(weechat.config_option_reset(ptr_opt_col, 1) == 2) # SET_OK_CHANGED check(weechat.config_option_reset(ptr_opt_col, 1) == 1) # SET_OK_SAME_VALUE - check(weechat.config_color(ptr_opt_col) == 'lightgreen') + check(weechat.config_color(ptr_opt_col) == "lightgreen") # color option with parent option ptr_opt_col_child = weechat.config_new_option( - ptr_config, ptr_section, - 'option_col_child << test_config_' + '{SCRIPT_LANGUAGE}' + '.section1.option_col', - 'color', 'col option', '', 0, 0, None, None, 1, - 'option_check_value_cb', '', - 'option_change_cb', '', - 'option_delete_cb', '', + ptr_config, + ptr_section, + "option_col_child << test_config_" + "{SCRIPT_LANGUAGE}" + ".section1.option_col", + "color", + "col option", + "", + 0, + 0, + None, + None, + 1, + "option_check_value_cb", + "", + "option_change_cb", + "", + "option_delete_cb", + "", ) - check(ptr_opt_col_child != '') - check(weechat.config_color(ptr_opt_col_child) == '') - check(weechat.config_color_inherited(ptr_opt_col_child) == 'lightgreen') + check(ptr_opt_col_child != "") + check(weechat.config_color(ptr_opt_col_child) == "") + check(weechat.config_color_inherited(ptr_opt_col_child) == "lightgreen") # enum option ptr_opt_enum = weechat.config_new_option( - ptr_config, ptr_section, 'option_enum', 'enum', 'enum option', - 'val1|val2|val3', 0, 0, 'val2', 'val2', 0, - 'option_check_value_cb', '', - 'option_change_cb', '', - 'option_delete_cb', '', + ptr_config, + ptr_section, + "option_enum", + "enum", + "enum option", + "val1|val2|val3", + 0, + 0, + "val2", + "val2", + 0, + "option_check_value_cb", + "", + "option_change_cb", + "", + "option_delete_cb", + "", ) - check(ptr_opt_enum != '') + check(ptr_opt_enum != "") check(weechat.config_enum(ptr_opt_enum) == 1) check(weechat.config_integer(ptr_opt_enum) == 1) - check(weechat.config_string(ptr_opt_enum) == 'val2') - check(weechat.config_option_set(ptr_opt_enum, 'val1', 1) == 2) # SET_OK_CHANGED - check(weechat.config_option_set(ptr_opt_enum, 'val1', 1) == 1) # SET_OK_SAME_VALUE + check(weechat.config_string(ptr_opt_enum) == "val2") + check(weechat.config_option_set(ptr_opt_enum, "val1", 1) == 2) # SET_OK_CHANGED + check(weechat.config_option_set(ptr_opt_enum, "val1", 1) == 1) # SET_OK_SAME_VALUE check(weechat.config_enum(ptr_opt_enum) == 0) check(weechat.config_integer(ptr_opt_enum) == 0) - check(weechat.config_string(ptr_opt_enum) == 'val1') + check(weechat.config_string(ptr_opt_enum) == "val1") check(weechat.config_enum_default(ptr_opt_enum) == 1) check(weechat.config_integer_default(ptr_opt_enum) == 1) - check(weechat.config_string_default(ptr_opt_enum) == 'val2') + check(weechat.config_string_default(ptr_opt_enum) == "val2") check(weechat.config_option_reset(ptr_opt_enum, 1) == 2) # SET_OK_CHANGED check(weechat.config_option_reset(ptr_opt_enum, 1) == 1) # SET_OK_SAME_VALUE check(weechat.config_enum(ptr_opt_enum) == 1) check(weechat.config_integer(ptr_opt_enum) == 1) - check(weechat.config_string(ptr_opt_enum) == 'val2') + check(weechat.config_string(ptr_opt_enum) == "val2") # enum option with parent option ptr_opt_enum_child = weechat.config_new_option( - ptr_config, ptr_section, - 'option_enum_child << test_config_' + '{SCRIPT_LANGUAGE}' + '.section1.option_enum', - 'enum', 'enum option', 'val1|val2|val3', 0, 0, None, None, 1, - 'option_check_value_cb', '', - 'option_change_cb', '', - 'option_delete_cb', '', + ptr_config, + ptr_section, + "option_enum_child << test_config_" + "{SCRIPT_LANGUAGE}" + ".section1.option_enum", + "enum", + "enum option", + "val1|val2|val3", + 0, + 0, + None, + None, + 1, + "option_check_value_cb", + "", + "option_change_cb", + "", + "option_delete_cb", + "", ) - check(ptr_opt_enum_child != '') + check(ptr_opt_enum_child != "") check(weechat.config_enum(ptr_opt_enum_child) == 0) check(weechat.config_enum_inherited(ptr_opt_enum_child) == 1) # search option - ptr_opt_bool2 = weechat.config_search_option(ptr_config, ptr_section, - 'option_bool') + ptr_opt_bool2 = weechat.config_search_option(ptr_config, ptr_section, "option_bool") check(ptr_opt_bool2 == ptr_opt_bool) # string to boolean - check(weechat.config_string_to_boolean('') == 0) - check(weechat.config_string_to_boolean('off') == 0) - check(weechat.config_string_to_boolean('0') == 0) - check(weechat.config_string_to_boolean('on') == 1) - check(weechat.config_string_to_boolean('1') == 1) + check(weechat.config_string_to_boolean("") == 0) + check(weechat.config_string_to_boolean("off") == 0) + check(weechat.config_string_to_boolean("0") == 0) + check(weechat.config_string_to_boolean("on") == 1) + check(weechat.config_string_to_boolean("1") == 1) # rename option - weechat.config_option_rename(ptr_opt_bool, 'option_bool_renamed') + weechat.config_option_rename(ptr_opt_bool, "option_bool_renamed") # get string property of option - check(weechat.config_option_get_string(ptr_opt_bool, 'type') == 'boolean') - check(weechat.config_option_get_string(ptr_opt_bool, 'name') == 'option_bool_renamed') + check(weechat.config_option_get_string(ptr_opt_bool, "type") == "boolean") + check(weechat.config_option_get_string(ptr_opt_bool, "name") == "option_bool_renamed") # get pointer property of option - check(weechat.config_option_get_pointer(ptr_opt_bool, 'config_file') == ptr_config) - check(weechat.config_option_get_pointer(ptr_opt_bool, 'section') == ptr_section) + check(weechat.config_option_get_pointer(ptr_opt_bool, "config_file") == ptr_config) + check(weechat.config_option_get_pointer(ptr_opt_bool, "section") == ptr_section) # read config (create it because it does not exist yet) check(weechat.config_read(ptr_config) == 0) # CONFIG_READ_OK # write config @@ -494,33 +640,35 @@ def test_config(): # free config weechat.config_free(ptr_config) # config_get - ptr_option = weechat.config_get('weechat.look.item_time_format') - check(ptr_option != '') - check(weechat.config_string(ptr_option) == '%H:%M') + ptr_option = weechat.config_get("weechat.look.item_time_format") + check(ptr_option != "") + check(weechat.config_string(ptr_option) == "%H:%M") # config plugin - check(weechat.config_get_plugin('option') == '') - check(weechat.config_is_set_plugin('option') == 0) - check(weechat.config_set_plugin('option', 'value') == 1) # SET_OK_SAME_VALUE - weechat.config_set_desc_plugin('option', 'description of option') - check(weechat.config_get_plugin('option') == 'value') - check(weechat.config_is_set_plugin('option') == 1) - check(weechat.config_unset_plugin('option') == 2) # UNSET_OK_REMOVED - check(weechat.config_unset_plugin('option') == -1) # UNSET_ERROR + check(weechat.config_get_plugin("option") == "") + check(weechat.config_is_set_plugin("option") == 0) + check(weechat.config_set_plugin("option", "value") == 1) # SET_OK_SAME_VALUE + weechat.config_set_desc_plugin("option", "description of option") + check(weechat.config_get_plugin("option") == "value") + check(weechat.config_is_set_plugin("option") == 1) + check(weechat.config_unset_plugin("option") == 2) # UNSET_OK_REMOVED + check(weechat.config_unset_plugin("option") == -1) # UNSET_ERROR def test_key(): """Test key functions.""" check( weechat.key_bind( - 'mouse', + "mouse", { - '@chat(plugin.test):button1': 'hsignal:test_mouse', - '@chat(plugin.test):wheelup': '/mycommand up', - '@chat(plugin.test):wheeldown': '/mycommand down', - '__quiet': '', - } - ) == 3) - check(weechat.key_unbind('mouse', 'quiet:area:chat(plugin.test)') == 3) + "@chat(plugin.test):button1": "hsignal:test_mouse", + "@chat(plugin.test):wheelup": "/mycommand up", + "@chat(plugin.test):wheeldown": "/mycommand down", + "__quiet": "", + }, + ) + == 3 + ) + check(weechat.key_unbind("mouse", "quiet:area:chat(plugin.test)") == 3) def buffer_input_cb(data, buffer, input_data): @@ -535,81 +683,76 @@ def buffer_close_cb(data, buffer): def test_display(): """Test display functions.""" - check(weechat.prefix('action') != '') - check(weechat.prefix('error') != '') - check(weechat.prefix('join') != '') - check(weechat.prefix('network') != '') - check(weechat.prefix('quit') != '') - check(weechat.prefix('unknown') == '') - check(weechat.color('green') != '') - check(weechat.color('unknown') == '') - weechat.prnt('', '## test print core buffer') - weechat.prnt_date_tags('', 946681200, 'tag1,tag2', - '## test print_date_tags core buffer') - weechat.prnt_datetime_tags('', 2146383600, 123456, 'tag1,tag2', - '## test print_date_tags core buffer, January, 6th 2038') - hdata_buffer = weechat.hdata_get('buffer') - hdata_lines = weechat.hdata_get('lines') - hdata_line = weechat.hdata_get('line') - hdata_line_data = weechat.hdata_get('line_data') + check(weechat.prefix("action") != "") + check(weechat.prefix("error") != "") + check(weechat.prefix("join") != "") + check(weechat.prefix("network") != "") + check(weechat.prefix("quit") != "") + check(weechat.prefix("unknown") == "") + check(weechat.color("green") != "") + check(weechat.color("unknown") == "") + weechat.prnt("", "## test print core buffer") + weechat.prnt_date_tags("", 946681200, "tag1,tag2", "## test print_date_tags core buffer") + weechat.prnt_datetime_tags( + "", 2146383600, 123456, "tag1,tag2", "## test print_date_tags core buffer, January, 6th 2038" + ) + hdata_buffer = weechat.hdata_get("buffer") + hdata_lines = weechat.hdata_get("lines") + hdata_line = weechat.hdata_get("line") + hdata_line_data = weechat.hdata_get("line_data") buffer = weechat.buffer_search_main() - own_lines = weechat.hdata_pointer(hdata_buffer, buffer, 'own_lines') - line = weechat.hdata_pointer(hdata_lines, own_lines, 'last_line') - data = weechat.hdata_pointer(hdata_line, line, 'data') - check(weechat.hdata_time(hdata_line_data, data, 'date') == 2146383600) - check(weechat.hdata_integer(hdata_line_data, data, 'date_usec') == 123456) - buffer = weechat.buffer_new('test_formatted', - 'buffer_input_cb', '', 'buffer_close_cb', '') - check(buffer != '') - check(weechat.buffer_get_integer(buffer, 'type') == 0) - weechat.prnt(buffer, '## test print formatted buffer') - weechat.prnt_date_tags(buffer, 946681200, 'tag1,tag2', - '## test print_date_tags formatted buffer') + own_lines = weechat.hdata_pointer(hdata_buffer, buffer, "own_lines") + line = weechat.hdata_pointer(hdata_lines, own_lines, "last_line") + data = weechat.hdata_pointer(hdata_line, line, "data") + check(weechat.hdata_time(hdata_line_data, data, "date") == 2146383600) + check(weechat.hdata_integer(hdata_line_data, data, "date_usec") == 123456) + buffer = weechat.buffer_new("test_formatted", "buffer_input_cb", "", "buffer_close_cb", "") + check(buffer != "") + check(weechat.buffer_get_integer(buffer, "type") == 0) + weechat.prnt(buffer, "## test print formatted buffer") + weechat.prnt_date_tags(buffer, 946681200, "tag1,tag2", "## test print_date_tags formatted buffer") weechat.buffer_close(buffer) - buffer = weechat.buffer_new_props('test_free', {'type': 'free'}, - 'buffer_input_cb', '', 'buffer_close_cb', '') - check(weechat.buffer_get_integer(buffer, 'type') == 1) - check(buffer != '') - weechat.prnt_y(buffer, 0, '## test print_y free buffer') - weechat.prnt_y_date_tags(buffer, 0, 946681200, 'tag1,tag2', - '## test print_y_date_tags free buffer') - weechat.prnt_y_datetime_tags(buffer, 1, 2146383600, 123456, 'tag1,tag2', - '## test print_y_date_tags free buffer, January, 6th 2038') + buffer = weechat.buffer_new_props("test_free", {"type": "free"}, "buffer_input_cb", "", "buffer_close_cb", "") + check(weechat.buffer_get_integer(buffer, "type") == 1) + check(buffer != "") + weechat.prnt_y(buffer, 0, "## test print_y free buffer") + weechat.prnt_y_date_tags(buffer, 0, 946681200, "tag1,tag2", "## test print_y_date_tags free buffer") + weechat.prnt_y_datetime_tags( + buffer, 1, 2146383600, 123456, "tag1,tag2", "## test print_y_date_tags free buffer, January, 6th 2038" + ) weechat.buffer_close(buffer) def completion1_cb(data, completion_item, buf, completion): """Completion callback.""" - check(data == 'completion_data') - check(completion_item == '{SCRIPT_NAME}1') - check(weechat.completion_get_string(completion, 'args') == 'w') - weechat.completion_set(completion, 'add_space', '0') - weechat.completion_list_add(completion, 'word_completed', - 0, weechat.WEECHAT_LIST_POS_END) + check(data == "completion_data") + check(completion_item == "{SCRIPT_NAME}1") + check(weechat.completion_get_string(completion, "args") == "w") + weechat.completion_set(completion, "add_space", "0") + weechat.completion_list_add(completion, "word_completed", 0, weechat.WEECHAT_LIST_POS_END) return weechat.WEECHAT_RC_OK def completion2_cb(data, completion_item, buf, completion): """Completion callback.""" - check(data == 'completion_data') - check(completion_item == '{SCRIPT_NAME}2') - check(weechat.completion_get_string(completion, 'args') == 'w') - weechat.completion_list_add(completion, 'word_completed', - 0, weechat.WEECHAT_LIST_POS_END) + check(data == "completion_data") + check(completion_item == "{SCRIPT_NAME}2") + check(weechat.completion_get_string(completion, "args") == "w") + weechat.completion_list_add(completion, "word_completed", 0, weechat.WEECHAT_LIST_POS_END) return weechat.WEECHAT_RC_OK def command_cb(data, buf, args): """Command callback.""" - check(data == 'command_data') - check(args == 'word_completed') + check(data == "command_data") + check(args == "word_completed") return weechat.WEECHAT_RC_OK def command_run_cb(data, buf, command): """Command_run callback.""" - check(data == 'command_run_data') - check(command == '/cmd2' + '{SCRIPT_NAME}' + ' word_completed') + check(data == "command_run_data") + check(command == "/cmd2" + "{SCRIPT_NAME}" + " word_completed") return weechat.WEECHAT_RC_OK @@ -622,91 +765,96 @@ def test_hooks(): """Test hook functions.""" buffer = weechat.buffer_search_main() # hook_completion / hook_completion_args / and hook_command - hook_cmplt1 = weechat.hook_completion('{SCRIPT_NAME}1', 'description', - 'completion1_cb', 'completion_data') - hook_cmd1 = weechat.hook_command('cmd1' + '{SCRIPT_NAME}', 'description', - 'arguments', 'description arguments', - '%(' + '{SCRIPT_NAME}1' + ')', - 'command_cb', 'command_data') - hook_cmplt2 = weechat.hook_completion('{SCRIPT_NAME}2', 'description', - 'completion2_cb', 'completion_data') - hook_cmd2 = weechat.hook_command('cmd2' + '{SCRIPT_NAME}', 'description', - 'arguments', 'description arguments', - '%(' + '{SCRIPT_NAME}2' + ')', - 'command_cb', 'command_data') - weechat.command('', '/input insert /cmd1' + '{SCRIPT_NAME}' + ' w') - weechat.command('', '/input complete_next') - buffer_input = weechat.buffer_get_string(buffer, 'input') - check(buffer_input == '/cmd1' + '{SCRIPT_NAME}' + ' word_completed') - weechat.command('', '/input delete_line') - weechat.command('', '/input insert /cmd2' + '{SCRIPT_NAME}' + ' w') - weechat.command('', '/input complete_next') - buffer_input = weechat.buffer_get_string(buffer, 'input') - check(buffer_input == '/cmd2' + '{SCRIPT_NAME}' + ' word_completed ') + hook_cmplt1 = weechat.hook_completion("{SCRIPT_NAME}1", "description", "completion1_cb", "completion_data") + hook_cmd1 = weechat.hook_command( + "cmd1" + "{SCRIPT_NAME}", + "description", + "arguments", + "description arguments", + "%(" + "{SCRIPT_NAME}1" + ")", + "command_cb", + "command_data", + ) + hook_cmplt2 = weechat.hook_completion("{SCRIPT_NAME}2", "description", "completion2_cb", "completion_data") + hook_cmd2 = weechat.hook_command( + "cmd2" + "{SCRIPT_NAME}", + "description", + "arguments", + "description arguments", + "%(" + "{SCRIPT_NAME}2" + ")", + "command_cb", + "command_data", + ) + weechat.command("", "/input insert /cmd1" + "{SCRIPT_NAME}" + " w") + weechat.command("", "/input complete_next") + buffer_input = weechat.buffer_get_string(buffer, "input") + check(buffer_input == "/cmd1" + "{SCRIPT_NAME}" + " word_completed") + weechat.command("", "/input delete_line") + weechat.command("", "/input insert /cmd2" + "{SCRIPT_NAME}" + " w") + weechat.command("", "/input complete_next") + buffer_input = weechat.buffer_get_string(buffer, "input") + check(buffer_input == "/cmd2" + "{SCRIPT_NAME}" + " word_completed ") # hook_command_run - hook_cmd_run = weechat.hook_command_run('/cmd2' + '{SCRIPT_NAME}' + '*', - 'command_run_cb', 'command_run_data') - weechat.command('', '/input return') + hook_cmd_run = weechat.hook_command_run("/cmd2" + "{SCRIPT_NAME}" + "*", "command_run_cb", "command_run_data") + weechat.command("", "/input return") weechat.unhook(hook_cmd_run) weechat.unhook(hook_cmd1) weechat.unhook(hook_cmplt1) weechat.unhook(hook_cmd2) weechat.unhook(hook_cmplt2) - # weechat.unhook(hook_cmplt2) # hook_timer - hook_timer = weechat.hook_timer(2000111000, 0, 1, - 'timer_cb', 'timer_cb_data') - ptr_infolist = weechat.infolist_get('hook', hook_timer, '') - check(ptr_infolist != '') + hook_timer = weechat.hook_timer(2000111000, 0, 1, "timer_cb", "timer_cb_data") + ptr_infolist = weechat.infolist_get("hook", hook_timer, "") + check(ptr_infolist != "") check(weechat.infolist_next(ptr_infolist) == 1) - check(weechat.infolist_string(ptr_infolist, 'interval') == '2000111000') + check(weechat.infolist_string(ptr_infolist, "interval") == "2000111000") weechat.infolist_free(ptr_infolist) weechat.unhook(hook_timer) def test_buffers(): """Test buffer functions.""" - buffer1 = weechat.buffer_new('test1', 'buffer_input_cb', '', 'buffer_close_cb', '') - check(buffer1 != '') - check(weechat.buffer_get_integer(buffer1, 'number') == 2) - check(weechat.buffer_get_string(buffer1, 'short_name') == 'test1') + buffer1 = weechat.buffer_new("test1", "buffer_input_cb", "", "buffer_close_cb", "") + check(buffer1 != "") + check(weechat.buffer_get_integer(buffer1, "number") == 2) + check(weechat.buffer_get_string(buffer1, "short_name") == "test1") props = { - 'short_name': 't2', + "short_name": "t2", } - buffer2 = weechat.buffer_new_props('test2', props, 'buffer_input_cb', '', 'buffer_close_cb', '') - check(buffer2 != '') - check(weechat.buffer_get_integer(buffer2, 'number') == 3) - check(weechat.buffer_get_string(buffer2, 'short_name') == 't2') - check(weechat.buffer_get_integer(buffer2, 'next_line_id') == 0) - weechat.prnt(buffer2, '## test line 1') - check(weechat.buffer_get_integer(buffer2, 'next_line_id') == 1) + buffer2 = weechat.buffer_new_props("test2", props, "buffer_input_cb", "", "buffer_close_cb", "") + check(buffer2 != "") + check(weechat.buffer_get_integer(buffer2, "number") == 3) + check(weechat.buffer_get_string(buffer2, "short_name") == "t2") + check(weechat.buffer_get_integer(buffer2, "next_line_id") == 0) + weechat.prnt(buffer2, "## test line 1") + check(weechat.buffer_get_integer(buffer2, "next_line_id") == 1) weechat.buffer_clear(buffer2) weechat.buffer_merge(buffer2, buffer1) - check(weechat.buffer_get_integer(buffer1, 'number') == 2) - check(weechat.buffer_get_integer(buffer2, 'number') == 2) + check(weechat.buffer_get_integer(buffer1, "number") == 2) + check(weechat.buffer_get_integer(buffer2, "number") == 2) weechat.buffer_unmerge(buffer2, 3) - check(weechat.buffer_get_integer(buffer1, 'number') == 2) - check(weechat.buffer_get_integer(buffer2, 'number') == 3) - check(weechat.current_buffer() != '') - check(weechat.buffer_get_integer(buffer1, 'hidden') == 0) - weechat.buffer_set(buffer1, 'hidden', '1') - check(weechat.buffer_get_integer(buffer1, 'hidden') == 1) - weechat.buffer_set(buffer1, 'hidden', '0') - check(weechat.buffer_get_integer(buffer1, 'hidden') == 0) - weechat.buffer_set(buffer1, 'localvar_set_var1', 'value1') - check(weechat.buffer_string_replace_local_var(buffer1, 'test $var1') == 'test value1') + check(weechat.buffer_get_integer(buffer1, "number") == 2) + check(weechat.buffer_get_integer(buffer2, "number") == 3) + check(weechat.current_buffer() != "") + check(weechat.buffer_get_integer(buffer1, "hidden") == 0) + weechat.buffer_set(buffer1, "hidden", "1") + check(weechat.buffer_get_integer(buffer1, "hidden") == 1) + weechat.buffer_set(buffer1, "hidden", "0") + check(weechat.buffer_get_integer(buffer1, "hidden") == 0) + weechat.buffer_set(buffer1, "localvar_set_var1", "value1") + check(weechat.buffer_string_replace_local_var(buffer1, "test $var1") == "test value1") buffer = weechat.buffer_search_main() - buffer_id = weechat.buffer_get_string(buffer, 'id') - check(weechat.buffer_search('xxx', 'yyy') == '') - check(weechat.buffer_search('==', 'xxx') == '') - check(weechat.buffer_search('==id', '0') == '') - check(weechat.buffer_search('core', 'weechat') == buffer) - check(weechat.buffer_search('==', 'core.weechat') == buffer) - check(weechat.buffer_search('==id', buffer_id) == buffer) - check(weechat.buffer_match_list(buffer, '') == 0) - check(weechat.buffer_match_list(buffer, '*') == 1) - check(weechat.buffer_match_list(buffer, 'core.weechat') == 1) - check(weechat.buffer_match_list(buffer, '*,!core.weechat') == 0) + buffer_id = weechat.buffer_get_string(buffer, "id") + check(weechat.buffer_search("xxx", "yyy") == "") + check(weechat.buffer_search("==", "xxx") == "") + check(weechat.buffer_search("==id", "0") == "") + check(weechat.buffer_search("core", "weechat") == buffer) + check(weechat.buffer_search("==", "core.weechat") == buffer) + check(weechat.buffer_search("==id", buffer_id) == buffer) + check(weechat.buffer_match_list(buffer, "") == 0) + check(weechat.buffer_match_list(buffer, "*") == 1) + check(weechat.buffer_match_list(buffer, "core.weechat") == 1) + check(weechat.buffer_match_list(buffer, "*,!core.weechat") == 0) weechat.buffer_close(buffer1) weechat.buffer_close(buffer2) @@ -714,63 +862,61 @@ def test_buffers(): def test_lines(): """Test line functions.""" buffer = weechat.buffer_search_main() - check(weechat.line_search_by_id(buffer, -1) == '') - check(weechat.line_search_by_id(buffer, 1234567) == '') - check(weechat.line_search_by_id(buffer, 0) != '') + check(weechat.line_search_by_id(buffer, -1) == "") + check(weechat.line_search_by_id(buffer, 1234567) == "") + check(weechat.line_search_by_id(buffer, 0) != "") def test_windows(): """Test window functions.""" window = weechat.current_window() - check(window != '') + check(window != "") buffer = weechat.buffer_search_main() - check(weechat.window_search_with_buffer(buffer) != '') - buffer1 = weechat.buffer_new('test1', 'buffer_input_cb', '', 'buffer_close_cb', '') - check(buffer1 != '') - check(weechat.window_search_with_buffer(buffer1) == '') + check(weechat.window_search_with_buffer(buffer) != "") + buffer1 = weechat.buffer_new("test1", "buffer_input_cb", "", "buffer_close_cb", "") + check(buffer1 != "") + check(weechat.window_search_with_buffer(buffer1) == "") weechat.buffer_close(buffer1) - check(weechat.window_get_integer(window, 'number') == 1) - check(weechat.window_get_string(window, 'xxx') == '') + check(weechat.window_get_integer(window, "number") == 1) + check(weechat.window_get_string(window, "xxx") == "") def test_command(): """Test command functions.""" - check(weechat.command('', '/mute') == 0) - check(weechat.command_options('', '/mute', {'commands': '*,!print'}) == 0) - check(weechat.command_options('', '/mute', {'commands': '*,!mute'}) == -1) + check(weechat.command("", "/mute") == 0) + check(weechat.command_options("", "/mute", {"commands": "*,!print"}) == 0) + check(weechat.command_options("", "/mute", {"commands": "*,!mute"}) == -1) def infolist_cb(data, infolist_name, pointer, arguments): """Infolist callback.""" infolist = weechat.infolist_new() - check(infolist != '') + check(infolist != "") item = weechat.infolist_new_item(infolist) - check(item != '') - check(weechat.infolist_new_var_integer(item, 'integer', 123) != '') - check(weechat.infolist_new_var_string(item, 'string', 'test string') != '') - check(weechat.infolist_new_var_pointer(item, 'pointer', '0xabcdef') != '') + check(item != "") + check(weechat.infolist_new_var_integer(item, "integer", 123) != "") + check(weechat.infolist_new_var_string(item, "string", "test string") != "") + check(weechat.infolist_new_var_pointer(item, "pointer", "0xabcdef") != "") # Tue Jan 06 2009 08:40:30 GMT+0000 - check(weechat.infolist_new_var_time(item, 'time1', 1231231230) != '') + check(weechat.infolist_new_var_time(item, "time1", 1231231230) != "") # Wed Jan 06 2038 09:40:00 GMT+0000 - check(weechat.infolist_new_var_time(item, 'time2', 2146383600) != '') + check(weechat.infolist_new_var_time(item, "time2", 2146383600) != "") return infolist def test_infolist(): """Test infolist functions.""" - hook_infolist = weechat.hook_infolist('infolist_test_script', - 'description', '', '', - 'infolist_cb', '') - check(weechat.infolist_get('infolist_does_not_exist', '', '') == '') - ptr_infolist = weechat.infolist_get('infolist_test_script', '', '') - check(ptr_infolist != '') + hook_infolist = weechat.hook_infolist("infolist_test_script", "description", "", "", "infolist_cb", "") + check(weechat.infolist_get("infolist_does_not_exist", "", "") == "") + ptr_infolist = weechat.infolist_get("infolist_test_script", "", "") + check(ptr_infolist != "") check(weechat.infolist_next(ptr_infolist) == 1) - check(weechat.infolist_integer(ptr_infolist, 'integer') == 123) - check(weechat.infolist_string(ptr_infolist, 'string') == 'test string') - check(weechat.infolist_pointer(ptr_infolist, 'pointer') == '0xabcdef') - check(weechat.infolist_time(ptr_infolist, 'time1') == 1231231230) - check(weechat.infolist_time(ptr_infolist, 'time2') == 2146383600) - check(weechat.infolist_fields(ptr_infolist) == 'i:integer,s:string,p:pointer,t:time1,t:time2') + check(weechat.infolist_integer(ptr_infolist, "integer") == 123) + check(weechat.infolist_string(ptr_infolist, "string") == "test string") + check(weechat.infolist_pointer(ptr_infolist, "pointer") == "0xabcdef") + check(weechat.infolist_time(ptr_infolist, "time1") == 1231231230) + check(weechat.infolist_time(ptr_infolist, "time2") == 2146383600) + check(weechat.infolist_fields(ptr_infolist) == "i:integer,s:string,p:pointer,t:time1,t:time2") check(weechat.infolist_next(ptr_infolist) == 0) weechat.infolist_free(ptr_infolist) weechat.unhook(hook_infolist) @@ -780,57 +926,58 @@ def test_hdata(): """Test hdata functions.""" buffer = weechat.buffer_search_main() # get hdata - hdata_buffer = weechat.hdata_get('buffer') - check(hdata_buffer != '') - hdata_lines = weechat.hdata_get('lines') - check(hdata_lines != '') - hdata_line = weechat.hdata_get('line') - check(hdata_line != '') - hdata_line_data = weechat.hdata_get('line_data') - check(hdata_line_data != '') - hdata_key = weechat.hdata_get('key') - check(hdata_key != '') - hdata_hotlist = weechat.hdata_get('hotlist') - check(hdata_hotlist != '') - hdata_irc_server = weechat.hdata_get('irc_server') - check(hdata_irc_server != '') + hdata_buffer = weechat.hdata_get("buffer") + check(hdata_buffer != "") + hdata_lines = weechat.hdata_get("lines") + check(hdata_lines != "") + hdata_line = weechat.hdata_get("line") + check(hdata_line != "") + hdata_line_data = weechat.hdata_get("line_data") + check(hdata_line_data != "") + hdata_key = weechat.hdata_get("key") + check(hdata_key != "") + hdata_hotlist = weechat.hdata_get("hotlist") + check(hdata_hotlist != "") + hdata_irc_server = weechat.hdata_get("irc_server") + check(hdata_irc_server != "") # create a test buffer with 3 messages - buffer2 = weechat.buffer_new('test', 'buffer_input_cb', '', 'buffer_close_cb', '') - weechat.prnt_date_tags(buffer2, 2146383600, 'tag1,tag2', 'prefix1\t## msg1') - weechat.prnt_date_tags(buffer2, 2146383601, 'tag3,tag4', 'prefix2\t## msg2') - weechat.prnt_date_tags(buffer2, 2146383602, 'tag5,tag6', 'prefix3\t## msg3') - own_lines = weechat.hdata_pointer(hdata_buffer, buffer2, 'own_lines') - line1 = weechat.hdata_pointer(hdata_lines, own_lines, 'first_line') - line1_data = weechat.hdata_pointer(hdata_line, line1, 'data') - line2 = weechat.hdata_pointer(hdata_line, line1, 'next_line') - line3 = weechat.hdata_pointer(hdata_line, line2, 'next_line') + buffer2 = weechat.buffer_new("test", "buffer_input_cb", "", "buffer_close_cb", "") + weechat.prnt_date_tags(buffer2, 2146383600, "tag1,tag2", "prefix1\t## msg1") + weechat.prnt_date_tags(buffer2, 2146383601, "tag3,tag4", "prefix2\t## msg2") + weechat.prnt_date_tags(buffer2, 2146383602, "tag5,tag6", "prefix3\t## msg3") + own_lines = weechat.hdata_pointer(hdata_buffer, buffer2, "own_lines") + line1 = weechat.hdata_pointer(hdata_lines, own_lines, "first_line") + line1_data = weechat.hdata_pointer(hdata_line, line1, "data") + line2 = weechat.hdata_pointer(hdata_line, line1, "next_line") + line3 = weechat.hdata_pointer(hdata_line, line2, "next_line") # hdata_get_var_offset - check(weechat.hdata_get_var_offset(hdata_buffer, 'id') == 0) - check(weechat.hdata_get_var_offset(hdata_buffer, 'plugin') > 0) + check(weechat.hdata_get_var_offset(hdata_buffer, "id") == 0) + check(weechat.hdata_get_var_offset(hdata_buffer, "plugin") > 0) # hdata_get_var_type_string - check(weechat.hdata_get_var_type_string(hdata_buffer, 'plugin') == 'pointer') - check(weechat.hdata_get_var_type_string(hdata_buffer, 'number') == 'integer') - check(weechat.hdata_get_var_type_string(hdata_buffer, 'name') == 'string') - check(weechat.hdata_get_var_type_string(hdata_buffer, 'local_variables') == 'hashtable') - check(weechat.hdata_get_var_type_string(hdata_line_data, 'displayed') == 'char') - check(weechat.hdata_get_var_type_string(hdata_line_data, 'prefix') == 'shared_string') - check(weechat.hdata_get_var_type_string(hdata_line_data, 'date') == 'time') - check(weechat.hdata_get_var_type_string(hdata_hotlist, 'time') == 'time') - check(weechat.hdata_get_var_type_string(hdata_hotlist, 'time_usec') == 'long') - check(weechat.hdata_get_var_type_string(hdata_irc_server, 'sasl_scram_salted_pwd') == 'other') + check(weechat.hdata_get_var_type_string(hdata_buffer, "plugin") == "pointer") + check(weechat.hdata_get_var_type_string(hdata_buffer, "number") == "integer") + check(weechat.hdata_get_var_type_string(hdata_buffer, "name") == "string") + check(weechat.hdata_get_var_type_string(hdata_buffer, "local_variables") == "hashtable") + check(weechat.hdata_get_var_type_string(hdata_line_data, "displayed") == "char") + check(weechat.hdata_get_var_type_string(hdata_line_data, "prefix") == "shared_string") + check(weechat.hdata_get_var_type_string(hdata_line_data, "date") == "time") + check(weechat.hdata_get_var_type_string(hdata_hotlist, "time") == "time") + check(weechat.hdata_get_var_type_string(hdata_hotlist, "time_usec") == "long") + check(weechat.hdata_get_var_type_string(hdata_irc_server, "sasl_scram_salted_pwd") == "other") # hdata_get_var_array_size - check(weechat.hdata_get_var_array_size(hdata_buffer, buffer2, 'name') == -1) - check(weechat.hdata_get_var_array_size(hdata_buffer, buffer2, 'highlight_tags_array') >= 0) + check(weechat.hdata_get_var_array_size(hdata_buffer, buffer2, "name") == -1) + check(weechat.hdata_get_var_array_size(hdata_buffer, buffer2, "highlight_tags_array") >= 0) # hdata_get_var_array_size_string - check(weechat.hdata_get_var_array_size_string(hdata_buffer, buffer2, 'name') == '') - check(weechat.hdata_get_var_array_size_string( - hdata_buffer, buffer2, 'highlight_tags_array') == 'highlight_tags_count') + check(weechat.hdata_get_var_array_size_string(hdata_buffer, buffer2, "name") == "") + check( + weechat.hdata_get_var_array_size_string(hdata_buffer, buffer2, "highlight_tags_array") == "highlight_tags_count" + ) # hdata_get_var_hdata - check(weechat.hdata_get_var_hdata(hdata_buffer, 'plugin') == 'plugin') - check(weechat.hdata_get_var_hdata(hdata_buffer, 'own_lines') == 'lines') - check(weechat.hdata_get_var_hdata(hdata_buffer, 'name') == '') + check(weechat.hdata_get_var_hdata(hdata_buffer, "plugin") == "plugin") + check(weechat.hdata_get_var_hdata(hdata_buffer, "own_lines") == "lines") + check(weechat.hdata_get_var_hdata(hdata_buffer, "name") == "") # hdata_get_list - check(weechat.hdata_get_list(hdata_buffer, 'gui_buffers') == buffer) + check(weechat.hdata_get_list(hdata_buffer, "gui_buffers") == buffer) # hdata_check_pointer check(weechat.hdata_check_pointer(hdata_buffer, buffer, buffer) == 1) check(weechat.hdata_check_pointer(hdata_buffer, buffer, buffer2) == 1) @@ -840,60 +987,60 @@ def test_hdata(): check(weechat.hdata_move(hdata_line, line1, 2) == line3) check(weechat.hdata_move(hdata_line, line3, -1) == line2) check(weechat.hdata_move(hdata_line, line3, -2) == line1) - check(weechat.hdata_move(hdata_line, line1, -1) == '') + check(weechat.hdata_move(hdata_line, line1, -1) == "") # hdata_search - check(weechat.hdata_search(hdata_buffer, buffer, '${name} == test', {}, {}, {}, 1) == buffer2) - check(weechat.hdata_search(hdata_buffer, buffer, '${name} == xxx', {}, {}, {}, 1) == '') + check(weechat.hdata_search(hdata_buffer, buffer, "${name} == test", {}, {}, {}, 1) == buffer2) + check(weechat.hdata_search(hdata_buffer, buffer, "${name} == xxx", {}, {}, {}, 1) == "") # hdata_char - check(weechat.hdata_char(hdata_line_data, line1_data, 'displayed') == 1) + check(weechat.hdata_char(hdata_line_data, line1_data, "displayed") == 1) # hdata_integer - check(weechat.hdata_integer(hdata_buffer, buffer2, 'number') == 2) + check(weechat.hdata_integer(hdata_buffer, buffer2, "number") == 2) # hdata_long - weechat.buffer_set(buffer, 'hotlist', weechat.WEECHAT_HOTLIST_MESSAGE) - gui_hotlist = weechat.hdata_get_list(hdata_hotlist, 'gui_hotlist') - check(weechat.hdata_long(hdata_hotlist, gui_hotlist, 'creation_time.tv_usec') >= 0) + weechat.buffer_set(buffer, "hotlist", weechat.WEECHAT_HOTLIST_MESSAGE) + gui_hotlist = weechat.hdata_get_list(hdata_hotlist, "gui_hotlist") + check(weechat.hdata_long(hdata_hotlist, gui_hotlist, "creation_time.tv_usec") >= 0) # hdata_longlong - check(weechat.hdata_longlong(hdata_buffer, buffer2, 'id') > 1708874542000000) + check(weechat.hdata_longlong(hdata_buffer, buffer2, "id") > 1708874542000000) # hdata_string - check(weechat.hdata_string(hdata_buffer, buffer2, 'name') == 'test') + check(weechat.hdata_string(hdata_buffer, buffer2, "name") == "test") # hdata_pointer - check(weechat.hdata_pointer(hdata_buffer, buffer2, 'own_lines') == own_lines) + check(weechat.hdata_pointer(hdata_buffer, buffer2, "own_lines") == own_lines) # hdata_time - check(weechat.hdata_time(hdata_line_data, line1_data, 'date') > 1659430030) + check(weechat.hdata_time(hdata_line_data, line1_data, "date") > 1659430030) # hdata_hashtable - local_vars = weechat.hdata_hashtable(hdata_buffer, buffer2, 'local_variables') - value = local_vars['name'] - check(value == 'test') + local_vars = weechat.hdata_hashtable(hdata_buffer, buffer2, "local_variables") + value = local_vars["name"] + check(value == "test") # hdata_compare - check(weechat.hdata_compare(hdata_buffer, buffer, buffer2, 'name', 0) > 0) - check(weechat.hdata_compare(hdata_buffer, buffer2, buffer, 'name', 0) < 0) - check(weechat.hdata_compare(hdata_buffer, buffer, buffer, 'name', 0) == 0) + check(weechat.hdata_compare(hdata_buffer, buffer, buffer2, "name", 0) > 0) + check(weechat.hdata_compare(hdata_buffer, buffer2, buffer, "name", 0) < 0) + check(weechat.hdata_compare(hdata_buffer, buffer, buffer, "name", 0) == 0) # hdata_update - check(weechat.hdata_time(hdata_line_data, line1_data, 'date') == 2146383600) - check(weechat.hdata_string(hdata_line_data, line1_data, 'prefix') == 'prefix1') - check(weechat.hdata_string(hdata_line_data, line1_data, 'message') == '## msg1') + check(weechat.hdata_time(hdata_line_data, line1_data, "date") == 2146383600) + check(weechat.hdata_string(hdata_line_data, line1_data, "prefix") == "prefix1") + check(weechat.hdata_string(hdata_line_data, line1_data, "message") == "## msg1") update = { - 'date': '2146383605', - 'prefix': 'new_prefix1', - 'message': 'new_message1' + "date": "2146383605", + "prefix": "new_prefix1", + "message": "new_message1", } check(weechat.hdata_update(hdata_line_data, line1_data, update) == 3) - check(weechat.hdata_time(hdata_line_data, line1_data, 'date') == 2146383605) - check(weechat.hdata_string(hdata_line_data, line1_data, 'prefix') == 'new_prefix1') - check(weechat.hdata_string(hdata_line_data, line1_data, 'message') == 'new_message1') + check(weechat.hdata_time(hdata_line_data, line1_data, "date") == 2146383605) + check(weechat.hdata_string(hdata_line_data, line1_data, "prefix") == "new_prefix1") + check(weechat.hdata_string(hdata_line_data, line1_data, "message") == "new_message1") # hdata_get_string - check(weechat.hdata_get_string(hdata_line, 'var_prev') == 'prev_line') - check(weechat.hdata_get_string(hdata_line, 'var_next') == 'next_line') + check(weechat.hdata_get_string(hdata_line, "var_prev") == "prev_line") + check(weechat.hdata_get_string(hdata_line, "var_next") == "next_line") # destroy test buffer weechat.buffer_close(buffer2) def cmd_test_cb(data, buf, args): """Run all the tests.""" - weechat.prnt('', '>>>') - weechat.prnt('', '>>> ------------------------------') - weechat.prnt('', '>>> Testing ' + '{SCRIPT_LANGUAGE}' + ' API') - weechat.prnt('', ' > TESTS: ' + '{SCRIPT_TESTS}') + weechat.prnt("", ">>>") + weechat.prnt("", ">>> ------------------------------") + weechat.prnt("", ">>> Testing " + "{SCRIPT_LANGUAGE}" + " API") + weechat.prnt("", " > TESTS: " + "{SCRIPT_TESTS}") test_constants() test_plugins() test_strings() @@ -908,12 +1055,13 @@ def cmd_test_cb(data, buf, args): test_command() test_infolist() test_hdata() - weechat.prnt('', ' > TESTS END') + weechat.prnt("", " > TESTS END") return weechat.WEECHAT_RC_OK def weechat_init(): - """Main function.""" - weechat.register('{SCRIPT_NAME}', '{SCRIPT_AUTHOR}', '{SCRIPT_VERSION}', - '{SCRIPT_LICENSE}', '{SCRIPT_DESCRIPTION}', '', '') - weechat.hook_command('{SCRIPT_NAME}', '', '', '', '', 'cmd_test_cb', '') + """Initialize script.""" + weechat.register( + "{SCRIPT_NAME}", "{SCRIPT_AUTHOR}", "{SCRIPT_VERSION}", "{SCRIPT_LICENSE}", "{SCRIPT_DESCRIPTION}", "", "" + ) + weechat.hook_command("{SCRIPT_NAME}", "", "", "", "", "cmd_test_cb", "") diff --git a/tests/unit/scripts/python/testapigen.py b/tests/unit/scripts/python/testapigen.py index 2cebaed6b..bb046208c 100755 --- a/tests/unit/scripts/python/testapigen.py +++ b/tests/unit/scripts/python/testapigen.py @@ -18,9 +18,9 @@ # along with this program. If not, see . # -""" -Scripts generator for WeeChat: build source of scripts in all languages to -test the scripting API. +"""Test script generator for WeeChat. + +Build source of scripts in all languages to test the scripting API. This script can be run in WeeChat or as a standalone script (during automatic tests, it is loaded as a WeeChat script). @@ -30,36 +30,33 @@ It uses the following scripts: - testapi.py: the WeeChat scripting API tests """ -# pylint: disable=wrong-import-order,wrong-import-position -# pylint: disable=useless-object-inheritance -# pylint: disable=consider-using-f-string -# pylint: disable=super-with-arguments -# pylint: disable=consider-using-with -# pylint: disable=unspecified-encoding +# ruff: noqa: T201,UP006,UP007,UP035 -from __future__ import print_function import argparse import ast -from datetime import datetime +import datetime import inspect -from io import StringIO +import io import os import sys import traceback +from pathlib import Path +from typing import Tuple, Type, Union sys.dont_write_bytecode = True -SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) -sys.path.append(SCRIPT_DIR) +SCRIPT_DIR = Path(__file__).resolve().parent +sys.path.append(str(SCRIPT_DIR)) from unparse import ( # noqa: E402 - UnparsePython, - UnparsePerl, - UnparseRuby, - UnparseLua, - UnparseTcl, + Unparse, UnparseGuile, UnparseJavaScript, + UnparseLua, + UnparsePerl, UnparsePhp, + UnparsePython, + UnparseRuby, + UnparseTcl, ) RUNNING_IN_WEECHAT = True @@ -69,315 +66,328 @@ except ImportError: RUNNING_IN_WEECHAT = False -SCRIPT_NAME = 'testapigen' -SCRIPT_AUTHOR = 'Sébastien Helleu ' -SCRIPT_VERSION = '0.1' -SCRIPT_LICENSE = 'GPL3' -SCRIPT_DESC = 'Generate scripting API test scripts' +SCRIPT_NAME = "testapigen" +SCRIPT_AUTHOR = "Sébastien Helleu " +SCRIPT_VERSION = "0.1" +SCRIPT_LICENSE = "GPL3" +SCRIPT_DESC = "Generate scripting API test scripts" -SCRIPT_COMMAND = 'testapigen' +SCRIPT_COMMAND = "testapigen" -class WeechatScript(object): # pylint: disable=too-many-instance-attributes - """ - A generic WeeChat script. +class WeechatScript: + """A generic WeeChat script. This class must NOT be instantiated directly, use subclasses instead: PythonScript, PerlScript, ... """ - def __init__(self, unparse_class, tree, source_script, output_dir, - language, extension, comment_char='#', - weechat_module='weechat'): - # pylint: disable=too-many-arguments + def __init__( + self, + unparse_class: Type[Unparse], + tree: ast.AST, + source_script: str, + output_dir: str, + language: str, + extension: str, + comment_char: str = "#", + weechat_module: str = "weechat", + ) -> None: + """Initialize a WeeChat script generator.""" self.unparse_class = unparse_class self.tree = tree self.source_script = os.path.realpath(source_script) self.output_dir = os.path.realpath(output_dir) self.language = language self.extension = extension - self.script_name = 'weechat_testapi.%s' % extension - self.script_path = os.path.join(self.output_dir, self.script_name) + self.script_name = f"weechat_testapi.{extension}" + self.script_path = Path(self.output_dir) / self.script_name self.comment_char = comment_char self.weechat_module = weechat_module self.update_tree() - def comment(self, string): + def comment(self, string: str) -> str: """Get a commented line.""" - return '%s %s' % (self.comment_char, string) + return f"{self.comment_char} {string}" - def update_tree(self): + def update_tree(self) -> None: """Make changes in AST tree.""" functions = { - 'prnt': 'print', - 'prnt_date_tags': 'print_date_tags', - 'prnt_datetime_tags': 'print_datetime_tags', - 'prnt_y': 'print_y', - 'prnt_y_date_tags': 'print_y_date_tags', - 'prnt_y_datetime_tags': 'print_y_datetime_tags', + "prnt": "print", + "prnt_date_tags": "print_date_tags", + "prnt_datetime_tags": "print_datetime_tags", + "prnt_y": "print_y", + "prnt_y_date_tags": "print_y_date_tags", + "prnt_y_datetime_tags": "print_y_datetime_tags", } tests_count = 0 for node in ast.walk(self.tree): # rename some API functions - if self.language != 'python' and \ - isinstance(node, ast.Call) and \ - isinstance(node.func, ast.Attribute) and \ - node.func.value.id == 'weechat': + if ( + self.language != "python" + and isinstance(node, ast.Call) + and isinstance(node.func, ast.Attribute) + and node.func.value.id == "weechat" + ): node.func.attr = functions.get(node.func.attr, node.func.attr) # count number of tests - if isinstance(node, ast.Call) and \ - isinstance(node.func, ast.Name) and \ - node.func.id == 'check': + if isinstance(node, ast.Call) and isinstance(node.func, ast.Name) and node.func.id == "check": tests_count += 1 # replace script variables in string values variables = { - '{SCRIPT_SOURCE}': self.source_script, - '{SCRIPT_NAME}': self.script_name, - '{SCRIPT_PATH}': self.script_path, - '{SCRIPT_AUTHOR}': 'Sebastien Helleu', - '{SCRIPT_VERSION}': '1.0', - '{SCRIPT_LICENSE}': 'GPL3', - '{SCRIPT_DESCRIPTION}': ('%s scripting API test' % - self.language.capitalize()), - '{SCRIPT_LANGUAGE}': self.language, - '{SCRIPT_TESTS}': str(tests_count), + "{SCRIPT_SOURCE}": self.source_script, + "{SCRIPT_NAME}": self.script_name, + "{SCRIPT_PATH}": str(self.script_path), + "{SCRIPT_AUTHOR}": "Sebastien Helleu", + "{SCRIPT_VERSION}": "1.0", + "{SCRIPT_LICENSE}": "GPL3", + "{SCRIPT_DESCRIPTION}": f"{self.language.capitalize()} scripting API test", + "{SCRIPT_LANGUAGE}": self.language, + "{SCRIPT_TESTS}": str(tests_count), } # replace variables for node in ast.walk(self.tree): if isinstance(node, ast.Constant) and node.value in variables: node.value = variables[node.value] - def write_header(self, output): + def write_header(self, output: io.TextIOBase) -> None: """Generate script header (just comments by default).""" comments = ( - '', - '%s -- WeeChat %s scripting API testing' % ( - self.script_name, self.language.capitalize()), - '', - 'WeeChat script automatically generated by testapigen.py.', - 'DO NOT EDIT BY HAND!', - '', - 'Date: %s' % datetime.now(), - '', + "", + f"{self.script_name} -- WeeChat {self.language.capitalize()} scripting API testing", + "", + "WeeChat script automatically generated by testapigen.py.", + "DO NOT EDIT BY HAND!", + "", + f"Date: {datetime.datetime.now(tz=datetime.timezone.utc)}", + "", ) - for line in comments: - output.write(self.comment(line).rstrip() + '\n') + output.writelines(f"{self.comment(line)}\n" for line in comments) - def write(self): + def write(self) -> None: """Write script on disk.""" - print('Writing script %s... ' % self.script_path, end='') - with open(self.script_path, 'w') as output: + print(f"Writing script {self.script_path}... ", end="") + with self.script_path.open("w") as output: self.write_header(output) self.unparse_class(output).add(self.tree) - output.write('\n') + output.write("\n") self.write_footer(output) - print('OK') + print("OK") - def write_footer(self, output): + def write_footer(self, output: io.TextIOBase) -> None: """Write footer (nothing by default).""" - pass # pylint: disable=unnecessary-pass class WeechatPythonScript(WeechatScript): """A WeeChat script written in Python.""" - def __init__(self, tree, source_script, output_dir): - super(WeechatPythonScript, self).__init__( - UnparsePython, tree, source_script, output_dir, 'python', 'py') + def __init__(self, tree: ast.AST, source_script: str, output_dir: str) -> None: + """Initialize Python script.""" + super().__init__(UnparsePython, tree, source_script, output_dir, "python", "py") - def write_header(self, output): - super(WeechatPythonScript, self).write_header(output) - output.write('\n' - 'import weechat') + def write_header(self, output: io.TextIOBase) -> None: + """Write header of Python script.""" + super().write_header(output) + output.write("\nimport weechat") - def write_footer(self, output): - output.write('\n' - '\n' - 'if __name__ == "__main__":\n' - ' weechat_init()\n') + def write_footer(self, output: io.TextIOBase) -> None: + """Write footer of Python script.""" + super().write_footer(output) + output.write('\n\nif __name__ == "__main__":\n weechat_init()\n') class WeechatPerlScript(WeechatScript): """A WeeChat script written in Perl.""" - def __init__(self, tree, source_script, output_dir): - super(WeechatPerlScript, self).__init__( - UnparsePerl, tree, source_script, output_dir, 'perl', 'pl') + def __init__(self, tree: ast.AST, source_script: str, output_dir: str) -> None: + """Initialize Perl script.""" + super().__init__(UnparsePerl, tree, source_script, output_dir, "perl", "pl") - def write_footer(self, output): - output.write('\n' - 'weechat_init();\n') + def write_footer(self, output: io.TextIOBase) -> None: + """Write footer of Perl script.""" + super().write_footer(output) + output.write("\nweechat_init();\n") class WeechatRubyScript(WeechatScript): """A WeeChat script written in Ruby.""" - def __init__(self, tree, source_script, output_dir): - super(WeechatRubyScript, self).__init__( - UnparseRuby, tree, source_script, output_dir, 'ruby', 'rb') + def __init__(self, tree: ast.AST, source_script: str, output_dir: str) -> None: + """Initialize Ruby script.""" + super().__init__(UnparseRuby, tree, source_script, output_dir, "ruby", "rb") - def update_tree(self): - super(WeechatRubyScript, self).update_tree() + def update_tree(self) -> None: + """Make changes in AST tree of Ruby script.""" + super().update_tree() for node in ast.walk(self.tree): - if isinstance(node, ast.Attribute) and \ - node.value.id == 'weechat': - node.value.id = 'Weechat' - if isinstance(node, ast.Call) \ - and isinstance(node.func, ast.Attribute) \ - and node.func.attr == 'config_new_option': + if isinstance(node, ast.Attribute) and node.value.id == "weechat": + node.value.id = "Weechat" + if ( + isinstance(node, ast.Call) + and isinstance(node.func, ast.Attribute) + and node.func.attr == "config_new_option" + ): node.args = [*node.args[:11], ast.List(node.args[11:])] class WeechatLuaScript(WeechatScript): """A WeeChat script written in Lua.""" - def __init__(self, tree, source_script, output_dir): - super(WeechatLuaScript, self).__init__( - UnparseLua, tree, source_script, output_dir, 'lua', 'lua', - comment_char='--') + def __init__(self, tree: ast.AST, source_script: str, output_dir: str) -> None: + """Initialize Lua script.""" + super().__init__(UnparseLua, tree, source_script, output_dir, "lua", "lua", comment_char="--") - def write_footer(self, output): - output.write('\n' - 'weechat_init()\n') + def write_footer(self, output: io.TextIOBase) -> None: + """Write footer of Lua script.""" + super().write_footer(output) + output.write("\nweechat_init()\n") class WeechatTclScript(WeechatScript): """A WeeChat script written in Tcl.""" - def __init__(self, tree, source_script, output_dir): - super(WeechatTclScript, self).__init__( - UnparseTcl, tree, source_script, output_dir, 'tcl', 'tcl') + def __init__(self, tree: ast.AST, source_script: str, output_dir: str) -> None: + """Initialize Tcl script.""" + super().__init__(UnparseTcl, tree, source_script, output_dir, "tcl", "tcl") - def write_footer(self, output): - output.write('\n' - 'weechat_init\n') + def write_footer(self, output: io.TextIOBase) -> None: + """Write footer of Tcl script.""" + super().write_footer(output) + output.write("\nweechat_init\n") class WeechatGuileScript(WeechatScript): """A WeeChat script written in Guile (Scheme).""" - def __init__(self, tree, source_script, output_dir): - super(WeechatGuileScript, self).__init__( - UnparseGuile, tree, source_script, output_dir, 'guile', 'scm', - comment_char=';') + def __init__(self, tree: ast.AST, source_script: str, output_dir: str) -> None: + """Initialize Guile script.""" + super().__init__(UnparseGuile, tree, source_script, output_dir, "guile", "scm", comment_char=";") - def update_tree(self): - super(WeechatGuileScript, self).update_tree() + def update_tree(self) -> None: + """Make changes in AST tree of Guile script.""" + super().update_tree() functions_with_list = ( - 'config_new_section', - 'config_new_option', + "config_new_section", + "config_new_option", ) for node in ast.walk(self.tree): - if isinstance(node, ast.Call) \ - and isinstance(node.func, ast.Attribute) \ - and node.func.attr in functions_with_list: - node.args = [ast.Call('list', node.args)] + if ( + isinstance(node, ast.Call) + and isinstance(node.func, ast.Attribute) + and node.func.attr in functions_with_list + ): + node.args = [ast.Call("list", node.args)] - def write_footer(self, output): - output.write('\n' - '(weechat_init)\n') + def write_footer(self, output: io.TextIOBase) -> None: + """Write footer of Guile script.""" + super().write_footer(output) + output.write("\n(weechat_init)\n") class WeechatJavaScriptScript(WeechatScript): """A WeeChat script written in JavaScript.""" - def __init__(self, tree, source_script, output_dir): - super(WeechatJavaScriptScript, self).__init__( - UnparseJavaScript, tree, source_script, output_dir, - 'javascript', 'js', comment_char='//') + def __init__(self, tree: ast.AST, source_script: str, output_dir: str) -> None: + """Initialize JavaScript script.""" + super().__init__(UnparseJavaScript, tree, source_script, output_dir, "javascript", "js", comment_char="//") - def write_footer(self, output): - output.write('\n' - 'weechat_init()\n') + def write_footer(self, output: io.TextIOBase) -> None: + """Writer footer of JavaScript script.""" + super().write_footer(output) + output.write("\nweechat_init()\n") class WeechatPhpScript(WeechatScript): """A WeeChat script written in PHP.""" - def __init__(self, tree, source_script, output_dir): - super(WeechatPhpScript, self).__init__( - UnparsePhp, tree, source_script, output_dir, 'php', 'php', - comment_char='//') + def __init__(self, tree: ast.AST, source_script: str, output_dir: str) -> None: + """Initialize PHP script.""" + super().__init__(UnparsePhp, tree, source_script, output_dir, "php", "php", comment_char="//") - def write_header(self, output): - output.write(' None: + """Writer header of PHP script.""" + output.write(" None: + """Write footer of PHP script.""" + super().write_footer(output) + output.write("\nweechat_init();\n") - def write_footer(self, output): - output.write('\n' - 'weechat_init();\n') # ============================================================================ -def update_nodes(tree): - """ - Update the tests AST tree (in-place): +def update_nodes(tree: ast.AST) -> None: + """Update the tests AST tree (in-place). + + Actions performed: 1. add a print message in each test_* function 2. add arguments in calls to check() function """ for node in ast.walk(tree): - if isinstance(node, ast.FunctionDef) and \ - node.name.startswith('test_'): + if isinstance(node, ast.FunctionDef) and node.name.startswith("test_"): # add a print at the beginning of each test function - node.body.insert( - 0, ast.parse('weechat.prnt("", " > %s");' % node.name)) - elif isinstance(node, ast.Call) and \ - isinstance(node.func, ast.Name) and \ - node.func.id == 'check': + node.body.insert(0, ast.parse(f'weechat.prnt("", " > {node.name}");')) + elif isinstance(node, ast.Call) and isinstance(node.func, ast.Name) and node.func.id == "check": # add two arguments in the call to "check" function: # 1. the string representation of the test # 2. the line number in source (as string) # for example if this test is on line 50: - # check(weechat.test() == 123) + # >>> check(weechat.test() == 123) # it becomes: - # check(weechat.test() == 123, 'weechat.test() == 123', '50') - output = StringIO() + # >>> check(weechat.test() == 123, 'weechat.test() == 123', '50') + output = io.StringIO() unparsed = UnparsePython(output=output) unparsed.add(node.args[0]) node.args.append(ast.Constant(output.getvalue())) node.args.append(ast.Constant(str(node.func.lineno))) -def get_tests(path): +def get_tests(path: str) -> ast.AST: """Parse the source with tests and return the AST node.""" - test_script = open(path).read() - tests = ast.parse(test_script) - update_nodes(tests) - return tests + with Path(path).open() as f: + test_script = f.read() + tests = ast.parse(test_script) + update_nodes(tests) + return tests -def generate_scripts(source_script, output_dir): +def generate_scripts(source_script: str, output_dir: str) -> Tuple[int, Union[str, None]]: """Generate scripts in all languages to test the API.""" ret_code = 0 error = None try: for name, obj in inspect.getmembers(sys.modules[__name__]): - if inspect.isclass(obj) and name != 'WeechatScript' and \ - name.startswith('Weechat') and name.endswith('Script'): + if ( + inspect.isclass(obj) + and name != "WeechatScript" + and name.startswith("Weechat") + and name.endswith("Script") + ): tests = get_tests(source_script) obj(tests, source_script, output_dir).write() - except Exception as exc: # pylint: disable=broad-except + except Exception as exc: # noqa: BLE001 ret_code = 1 - error = 'ERROR: %s\n\n%s' % (str(exc), traceback.format_exc()) + error = f"ERROR: {exc}\n\n{traceback.format_exc()}" return ret_code, error -def testapigen_cmd_cb(data, buf, args): +def testapigen_cmd_cb(data: str, buf: str, args: str) -> int: # noqa: ARG001 """Callback for WeeChat command /testapigen.""" - def print_error(msg): + def print_error(msg: str) -> None: """Print an error message on core buffer.""" - weechat.prnt('', '%s%s' % (weechat.prefix('error'), msg)) + weechat.prnt("", f"{weechat.prefix('error')}{msg}") try: source_script, output_dir = args.split() except ValueError: - print_error('ERROR: invalid arguments for /testapigen') + print_error("ERROR: invalid arguments for /testapigen") return weechat.WEECHAT_RC_OK if not weechat.mkdir_parents(output_dir, 0o755): - print_error('ERROR: invalid directory: %s' % output_dir) + print_error("ERROR: invalid directory: {output_dir}") return weechat.WEECHAT_RC_OK ret_code, error = generate_scripts(source_script, output_dir) if error: @@ -385,23 +395,16 @@ def testapigen_cmd_cb(data, buf, args): return weechat.WEECHAT_RC_OK if ret_code == 0 else weechat.WEECHAT_RC_ERROR -def get_parser_args(): +def get_parser_args() -> argparse.Namespace: """Get parser arguments.""" - parser = argparse.ArgumentParser( - description=('Generate WeeChat scripts in all languages ' - 'to test the API.')) - parser.add_argument( - 'script', - help='the path to Python script with tests') - parser.add_argument( - '-o', '--output-dir', - default='.', - help='output directory (defaults to current directory)') + parser = argparse.ArgumentParser(description=("Generate WeeChat scripts in all languages to test the API.")) + parser.add_argument("script", help="the path to Python script with tests") + parser.add_argument("-o", "--output-dir", default=".", help="output directory (defaults to current directory)") return parser.parse_args() -def main(): - """Main function (when script is not loaded in WeeChat).""" +def main() -> None: + """Generate all scripts (when script is not loaded in WeeChat).""" args = get_parser_args() ret_code, error = generate_scripts(args.script, args.output_dir) if error: @@ -409,17 +412,17 @@ def main(): sys.exit(ret_code) -if __name__ == '__main__': +if __name__ == "__main__": if RUNNING_IN_WEECHAT: - weechat.register(SCRIPT_NAME, SCRIPT_AUTHOR, SCRIPT_VERSION, - SCRIPT_LICENSE, SCRIPT_DESC, '', '') + weechat.register(SCRIPT_NAME, SCRIPT_AUTHOR, SCRIPT_VERSION, SCRIPT_LICENSE, SCRIPT_DESC, "", "") weechat.hook_command( SCRIPT_COMMAND, - 'Generate scripting API test scripts', - 'source_script output_dir', - 'source_script: path to source script (testapi.py)\n' - ' output_dir: output directory for scripts', - '', - 'testapigen_cmd_cb', '') + "Generate scripting API test scripts", + "source_script output_dir", + "source_script: path to source script (testapi.py)\n output_dir: output directory for scripts", + "", + "testapigen_cmd_cb", + "", + ) else: main() diff --git a/tests/unit/scripts/python/unparse.py b/tests/unit/scripts/python/unparse.py index f741cd5b1..b69abd3ec 100755 --- a/tests/unit/scripts/python/unparse.py +++ b/tests/unit/scripts/python/unparse.py @@ -18,30 +18,31 @@ # along with this program. If not, see . # -""" -Unparse AST tree to generate scripts in all supported languages -(Python, Perl, Ruby, ...). +"""Unparse AST tree to generate script. + +All languages supported by WeeChat can be used: Python, Perl, Ruby, etc. """ -# pylint: disable=too-many-lines,unnecessary-pass,useless-object-inheritance -# pylint: disable=consider-using-f-string -# pylint: disable=super-with-arguments +# ruff: noqa: B905,T201,UP006,UP007,UP035 -from __future__ import print_function import argparse import ast import inspect +import io import os import select -from io import StringIO import sys +from typing import Any, List, Union sys.dont_write_bytecode = True -class UnparsePython(object): - """ - Unparse AST to generate Python script code. +class Unparse: + """Unparse AST to generate script code.""" + + +class UnparsePython(Unparse): + """Unparse AST to generate Python script code. This class is inspired from _Unparser class in cpython: https://github.com/python/cpython/blob/main/Lib/ast.py @@ -52,65 +53,66 @@ class UnparsePython(object): __lineno__ = inspect.currentframe().f_lineno - def __init__(self, output=sys.stdout): + def __init__(self, output: io.TextIOBase = sys.stdout) -> None: + """Initialize Python parser.""" self.output = output - self.indent_string = ' ' * 4 + self.indent_string = " " * 4 self._indent_level = 0 self._prefix = [] # not used in Python, only in other languages self.binop = { - 'Add': '+', - 'Sub': '-', - 'Mult': '*', - 'MatMult': '@', - 'Div': '/', - 'Mod': '%', - 'LShift': '<<', - 'RShift': '>>', - 'BitOr': '|', - 'BitXor': '^', - 'BitAnd': '&', - 'FloorDiv': '//', - 'Pow': '**', + "Add": "+", + "Sub": "-", + "Mult": "*", + "MatMult": "@", + "Div": "/", + "Mod": "%", + "LShift": "<<", + "RShift": ">>", + "BitOr": "|", + "BitXor": "^", + "BitAnd": "&", + "FloorDiv": "//", + "Pow": "**", } self.unaryop = { - 'Invert': '~', - 'Not': 'not ', - 'UAdd': '+', - 'USub': '-', + "Invert": "~", + "Not": "not ", + "UAdd": "+", + "USub": "-", } self.cmpop = { - 'Eq': '==', - 'NotEq': '!=', - 'Lt': '<', - 'LtE': '<=', - 'Gt': '>', - 'GtE': '>=', - 'Is': 'is', - 'IsNot': 'is not', - 'In': 'in', - 'NotIn': 'not in', + "Eq": "==", + "NotEq": "!=", + "Lt": "<", + "LtE": "<=", + "Gt": ">", + "GtE": ">=", + "Is": "is", + "IsNot": "is not", + "In": "in", + "NotIn": "not in", } - def fill(self, string=''): + def fill(self, string: str = "") -> None: """Add a new line and an indented string.""" - self.add('\n%s%s' % (self.indent_string * self._indent_level, string)) + self.add(f"\n{self.indent_string * self._indent_level}{string}") - def indent(self): + def indent(self) -> None: """Indent code.""" self._indent_level += 1 - def unindent(self): + def unindent(self) -> None: """Unindent code.""" self._indent_level -= 1 - def prefix(self, prefix): + def prefix(self, prefix: Union[str, None]) -> None: """Add or remove a prefix from list.""" if prefix: self._prefix.append(prefix) else: self._prefix.pop() - def add(self, *args): + def add(self, *args) -> None: # noqa: ANN002 """Add string/node(s) to the output file.""" for arg in args: if callable(arg): @@ -121,9 +123,7 @@ class UnparsePython(object): for item in arg: self.add(item) elif isinstance(arg, ast.AST): - method = getattr( - self, '_ast_%s' % arg.__class__.__name__.lower(), - None) + method = getattr(self, f"_ast_{arg.__class__.__name__.lower()}", None) if method is None: raise NotImplementedError(arg) method(arg) @@ -131,7 +131,7 @@ class UnparsePython(object): self.output.write(arg) @staticmethod - def make_list(values, sep=', '): + def make_list(values: List[Any], sep: str = ", ") -> list: """Add multiple values using a custom method and separator.""" result = [] for value in values: @@ -141,79 +141,78 @@ class UnparsePython(object): return result @staticmethod - def is_bool(node): + def is_bool(node: ast.AST) -> bool: """Check if the node is a boolean.""" - return isinstance(node, ast.Name) and node.id in ('False', 'True') + return isinstance(node, ast.Name) and node.id in ("False", "True") @staticmethod - def is_number(node): + def is_number(node: ast.AST) -> bool: """Check if the node is a number.""" - return ((isinstance(node, ast.Constant) and isinstance(node.value, int)) or - (isinstance(node, ast.UnaryOp) and - isinstance(node.op, (ast.UAdd, ast.USub)))) + return (isinstance(node, ast.Constant) and isinstance(node.value, int)) or ( + isinstance(node, ast.UnaryOp) and isinstance(node.op, (ast.UAdd, ast.USub)) + ) - def _ast_alias(self, node): + def _ast_alias(self, node: ast.AST) -> None: """Add an AST alias in output.""" # ignore alias - pass + pass # noqa: PIE790 - def _ast_arg(self, node): + def _ast_arg(self, node: ast.AST) -> None: """Add an AST arg in output.""" - self.add('%s%s' % (self._prefix[-1] if self._prefix else '', - node.arg)) + prefix = self._prefix[-1] if self._prefix else "" + self.add(f"{prefix}{node.arg}") - def _ast_assign(self, node): + def _ast_assign(self, node: ast.Assign) -> None: """Add an AST Assign in output.""" self.add( self.fill, - [[target, ' = '] for target in node.targets], + [[target, " = "] for target in node.targets], node.value, ) - def _ast_attribute(self, node): + def _ast_attribute(self, node: ast.Attribute) -> None: """Add an AST Attribute in output.""" - self.add(node.value, '.', node.attr) + self.add(node.value, ".", node.attr) - def _ast_binop(self, node): + def _ast_binop(self, node: ast.BinOp) -> None: """Add an AST BinOp in output.""" self.add( node.left, - ' %s ' % self.binop[node.op.__class__.__name__], + f" {self.binop[node.op.__class__.__name__]} ", node.right, ) - def _ast_call(self, node): + def _ast_call(self, node: ast.Call) -> None: """Add an AST Call in output.""" self.add( node.func, - '(', + "(", self.make_list(node.args), - ')', + ")", ) - def _ast_compare(self, node): + def _ast_compare(self, node: ast.Compare) -> None: """Add an AST Compare in output.""" self.add(node.left) for operator, comparator in zip(node.ops, node.comparators): self.add( - ' %s ' % self.cmpop[operator.__class__.__name__], + f" {self.cmpop[operator.__class__.__name__]} ", comparator, ) - def _ast_constant(self, node): + def _ast_constant(self, node: ast.Constant) -> None: """Add an AST Constant in output.""" self.add(repr(node.value)) - def _ast_dict(self, node): + def _ast_dict(self, node: ast.Dict) -> None: """Add an AST Dict in output.""" self.add( - '{', - self.make_list([[key, ': ', value] - for key, value in zip(node.keys, node.values)]), - '}', + "{", + self.make_list([[key, ": ", value] for key, value in zip(node.keys, node.values)]), + "}", ) - def _ast_expr(self, node): + def _ast_expr(self, node: ast.Expr) -> None: """Add an AST Expr in output.""" if not isinstance(node.value, ast.Constant): # ignore docstrings self.add( @@ -221,27 +220,27 @@ class UnparsePython(object): node.value, ) - def _ast_functiondef(self, node): + def _ast_functiondef(self, node: ast.FunctionDef) -> None: """Add an AST FunctionDef in output.""" self.add( self.fill, self.fill, self.fill if self._indent_level == 0 else None, - 'def %s(' % node.name, + f"def {node.name}(", self.make_list(node.args.args), - '):', + "):", self.indent, node.body, self.unindent, ) - def _ast_if(self, node): + def _ast_if(self, node: ast.If) -> None: """Add an AST If in output.""" self.add( self.fill, - 'if ', + "if ", node.test, - ':', + ":", self.indent, node.body, self.unindent, @@ -249,76 +248,76 @@ class UnparsePython(object): if node.orelse: self.add( self.fill, - 'else:', + "else:", self.indent, node.orelse, self.unindent, ) - def _ast_index(self, node): + def _ast_index(self, node: ast.Index) -> None: """Add an AST Subscript in output.""" # note: deprecated since Python 3.9 self.add(node.value) - def _ast_import(self, node): + def _ast_import(self, node: ast.AST) -> None: """Add an AST Import in output.""" # ignore import - pass + pass # noqa: PIE790 - def _ast_list(self, node): + def _ast_list(self, node: ast.AST) -> None: """Add an AST List in output.""" self.add( - '[', + "[", self.make_list(node.elts), - ']', + "]", ) - def _ast_module(self, node): + def _ast_module(self, node: ast.Module) -> None: """Add an AST Module in output.""" self.add(node.body) - def _ast_name(self, node): + def _ast_name(self, node: ast.Name) -> None: """Add an AST Name in output.""" - self.add('%s%s' % (self._prefix[-1] if self._prefix else '', - node.id)) + prefix = self._prefix[-1] if self._prefix else "" + self.add(f"{prefix}{node.id}") - def _ast_num(self, node): + def _ast_num(self, node: ast.Num) -> None: """Add an AST Num in output.""" self.add(repr(node.n)) - def _ast_pass(self, node): # pylint: disable=unused-argument + def _ast_pass(self, node: ast.Pass) -> None: # noqa: ARG002 """Add an AST Pass in output.""" - self.fill('pass') + self.fill("pass") - def _ast_return(self, node): + def _ast_return(self, node: ast.Return) -> None: """Add an AST Return in output.""" - self.fill('return') + self.fill("return") if node.value: - self.add(' ', node.value) + self.add(" ", node.value) - def _ast_str(self, node): + def _ast_str(self, node: ast.Str) -> None: """Add an AST Str in output.""" self._ast_constant(node) - def _ast_subscript(self, node): + def _ast_subscript(self, node: ast.Subscript) -> None: """Add an AST Subscript in output.""" self.add( node.value, - '[', + "[", node.slice, - ']', + "]", ) - def _ast_tuple(self, node): + def _ast_tuple(self, node: ast.Tuple) -> None: """Add an AST Tuple in output.""" self.add( - '(', + "(", self.make_list(node.elts), - ',' if len(node.elts) == 1 else None, - ')', + "," if len(node.elts) == 1 else None, + ")", ) - def _ast_unaryop(self, node): + def _ast_unaryop(self, node: ast.UnaryOp) -> None: """Add an AST UnaryOp in output.""" self.add( self.unaryop[node.op.__class__.__name__], @@ -327,8 +326,7 @@ class UnparsePython(object): class UnparsePerl(UnparsePython): - """ - Unparse AST to generate Perl script code. + """Unparse AST to generate Perl script code. Note: only part of AST types are supported (just the types used by the script to test WeeChat scripting API). @@ -336,198 +334,196 @@ class UnparsePerl(UnparsePython): __lineno__ = inspect.currentframe().f_lineno - def _ast_assign(self, node): + def _ast_assign(self, node: ast.Assign) -> None: """Add an AST Assign in output.""" self.add( self.fill, - (self.prefix, '$'), - [[target, ' = '] for target in node.targets], + (self.prefix, "$"), + [[target, " = "] for target in node.targets], (self.prefix, None), node.value, - ';', + ";", ) - def _ast_attribute(self, node): + def _ast_attribute(self, node: ast.Attribute) -> None: """Add an AST Attribute in output.""" saved_prefix = self._prefix self._prefix = [] - self.add(node.value, '::', node.attr) + self.add(node.value, "::", node.attr) self._prefix = saved_prefix - def _ast_binop(self, node): + def _ast_binop(self, node: ast.BinOp) -> None: """Add an AST BinOp in output.""" - if isinstance(node.op, ast.Add) and \ - (not self.is_number(node.left) or - not self.is_number(node.right)): - str_op = '.' + if isinstance(node.op, ast.Add) and (not self.is_number(node.left) or not self.is_number(node.right)): + str_op = "." else: str_op = self.binop[node.op.__class__.__name__] self.add( - (self.prefix, '$'), + (self.prefix, "$"), node.left, - ' %s ' % str_op, + f" {str_op} ", node.right, (self.prefix, None), ) - def _ast_call(self, node): + def _ast_call(self, node: ast.Call) -> None: """Add an AST Call in output.""" self.add( node.func, - '(', - (self.prefix, '$'), + "(", + (self.prefix, "$"), self.make_list(node.args), (self.prefix, None), - ')', + ")", ) - def _ast_compare(self, node): + def _ast_compare(self, node: ast.Compare) -> None: """Add an AST Compare in output.""" self.add(node.left) for operator, comparator in zip(node.ops, node.comparators): - if isinstance(operator, (ast.Eq, ast.NotEq)) and \ - not self.is_number(node.left) and \ - not self.is_bool(node.left) and \ - not self.is_number(comparator) and \ - not self.is_bool(comparator): + if ( + isinstance(operator, (ast.Eq, ast.NotEq)) + and not self.is_number(node.left) + and not self.is_bool(node.left) + and not self.is_number(comparator) + and not self.is_bool(comparator) + ): custom_cmpop = { - 'Eq': 'eq', - 'NotEq': 'ne', + "Eq": "eq", + "NotEq": "ne", } else: custom_cmpop = self.cmpop self.add( - ' %s ' % custom_cmpop[operator.__class__.__name__], + f" {custom_cmpop[operator.__class__.__name__]} ", comparator, ) - def _ast_constant(self, node): + def _ast_constant(self, node: ast.Constant) -> None: """Add an AST Constant in output.""" if isinstance(node.value, str): - self.add('"%s"' % node.value.replace('$', '\\$').replace('@', '\\@')) + str_node = node.value.replace("$", "\\$").replace("@", "\\@") + self.add(f'"{str_node}"') elif node.value is None: - self.add('undef') + self.add("undef") else: self.add(repr(node.value)) - def _ast_dict(self, node): + def _ast_dict(self, node: ast.Dict) -> None: """Add an AST Dict in output.""" self.add( - '{', - self.make_list([[key, ' => ', value] - for key, value in zip(node.keys, node.values)]), - '}', + "{", + self.make_list([[key, " => ", value] for key, value in zip(node.keys, node.values)]), + "}", ) - def _ast_expr(self, node): + def _ast_expr(self, node: ast.Expr) -> None: """Add an AST Expr in output.""" if not isinstance(node.value, ast.Constant): # ignore docstrings self.add( self.fill, node.value, - ';', + ";", ) - def _ast_functiondef(self, node): + def _ast_functiondef(self, node: ast.FunctionDef) -> None: """Add an AST FunctionDef in output.""" self.add( self.fill, self.fill, - 'sub %s' % node.name, + f"sub {node.name}", self.fill, - '{', + "{", self.indent, ) if node.args.args: self.add( self.fill, - 'my (', - (self.prefix, '$'), + "my (", + (self.prefix, "$"), self.make_list(node.args.args), (self.prefix, None), - ') = @_;', + ") = @_;", ) self.add( node.body, self.unindent, self.fill, - '}', + "}", ) - def _ast_if(self, node): + def _ast_if(self, node: ast.If) -> None: """Add an AST If in output.""" self.add( self.fill, - 'if (', - (self.prefix, '$'), + "if (", + (self.prefix, "$"), node.test, (self.prefix, None), - ')', + ")", self.fill, - '{', + "{", self.indent, node.body, self.unindent, self.fill, - '}', + "}", ) if node.orelse: self.add( self.fill, - 'else', + "else", self.fill, - '{', + "{", self.indent, node.orelse, self.unindent, self.fill, - '}', + "}", ) - def _ast_list(self, node): + def _ast_list(self, node: ast.List) -> None: """Add an AST List in output.""" self.add( - '(', + "(", self.make_list(node.elts), - ')', + ")", ) - def _ast_pass(self, node): + def _ast_pass(self, node: ast.Pass) -> None: """Add an AST Pass in output.""" - pass + pass # noqa: PIE790 - def _ast_return(self, node): + def _ast_return(self, node: ast.Return) -> None: """Add an AST Return in output.""" - self.fill('return') + self.fill("return") if node.value: self.add( - ' ', - (self.prefix, - '%' if isinstance(node.value, ast.Dict) else '$'), + " ", + (self.prefix, "%" if isinstance(node.value, ast.Dict) else "$"), node.value, (self.prefix, None), - ';', + ";", ) - def _ast_str(self, node): + def _ast_str(self, node: ast.Str) -> None: """Add an AST Str in output.""" self._ast_constant(node) - def _ast_subscript(self, node): + def _ast_subscript(self, node: ast.Subscript) -> None: """Add an AST Subscript in output.""" self.add( - (self.prefix, '$'), + (self.prefix, "$"), node.value, (self.prefix, None), - '->{', + "->{", node.slice, - '}', + "}", ) class UnparseRuby(UnparsePython): - """ - Unparse AST to generate Ruby script code. + """Unparse AST to generate Ruby script code. Note: only part of AST types are supported (just the types used by the script to test WeeChat scripting API). @@ -535,58 +531,58 @@ class UnparseRuby(UnparsePython): __lineno__ = inspect.currentframe().f_lineno - def _ast_attribute(self, node): + def _ast_attribute(self, node: ast.Attribute) -> None: """Add an AST Attribute in output.""" self.add( node.value, - '::' if node.attr.startswith('WEECHAT_') else '.', + "::" if node.attr.startswith("WEECHAT_") else ".", node.attr, ) - def _ast_constant(self, node): + def _ast_constant(self, node: ast.Constant) -> None: """Add an AST Constant in output.""" if isinstance(node.value, str): - self.add('"%s"' % node.value.replace('#{', '\\#{')) + str_node = node.value.replace("#{", "\\#{") + self.add(f'"{str_node}"') elif node.value is None: - self.add('nil') + self.add("nil") else: self.add(repr(node.value)) - def _ast_dict(self, node): + def _ast_dict(self, node: ast.Dict) -> None: """Add an AST Dict in output.""" self.add( - 'Hash[', - self.make_list([[key, ' => ', value] - for key, value in zip(node.keys, node.values)]), - ']', + "Hash[", + self.make_list([[key, " => ", value] for key, value in zip(node.keys, node.values)]), + "]", ) - def _ast_functiondef(self, node): + def _ast_functiondef(self, node: ast.FunctionDef) -> None: """Add an AST FunctionDef in output.""" self.add( self.fill, self.fill, - 'def %s' % node.name, + f"def {node.name}", ) if node.args.args: self.add( - '(', + "(", self.make_list(node.args.args), - ')', + ")", ) self.add( self.indent, node.body, self.unindent, self.fill, - 'end', + "end", ) - def _ast_if(self, node): + def _ast_if(self, node: ast.If) -> None: """Add an AST If in output.""" self.add( self.fill, - 'if ', + "if ", node.test, self.indent, node.body, @@ -595,34 +591,33 @@ class UnparseRuby(UnparsePython): if node.orelse: self.add( self.fill, - 'else', + "else", self.indent, node.orelse, self.unindent, self.fill, - 'end', + "end", ) - def _ast_list(self, node): + def _ast_list(self, node: ast.List) -> None: """Add an AST List in output.""" self.add( - 'Array[', + "Array[", self.make_list(node.elts), - ']', + "]", ) - def _ast_pass(self, node): + def _ast_pass(self, node: ast.Pass) -> None: """Add an AST Pass in output.""" - pass + pass # noqa: PIE790 - def _ast_str(self, node): + def _ast_str(self, node: ast.Str) -> None: """Add an AST Str in output.""" self._ast_constant(node) class UnparseLua(UnparsePython): - """ - Unparse AST to generate Lua script code. + """Unparse AST to generate Lua script code. Note: only part of AST types are supported (just the types used by the script to test WeeChat scripting API). @@ -630,73 +625,70 @@ class UnparseLua(UnparsePython): __lineno__ = inspect.currentframe().f_lineno - def __init__(self, *args, **kwargs): - super(UnparseLua, self).__init__(*args, **kwargs) + def __init__(self, *args, **kwargs) -> None: # noqa: ANN002,ANN003 + """Initialize Lua parser.""" + super().__init__(*args, **kwargs) self.cmpop = { - 'Eq': '==', - 'NotEq': '~=', - 'Lt': '<', - 'LtE': '<=', - 'Gt': '>', - 'GtE': '>=', + "Eq": "==", + "NotEq": "~=", + "Lt": "<", + "LtE": "<=", + "Gt": ">", + "GtE": ">=", } - def _ast_binop(self, node): + def _ast_binop(self, node: ast.BinOp) -> None: """Add an AST BinOp in output.""" - if isinstance(node.op, ast.Add) and \ - (not self.is_number(node.left) or - not self.is_number(node.right)): - str_op = '..' + if isinstance(node.op, ast.Add) and (not self.is_number(node.left) or not self.is_number(node.right)): + str_op = ".." else: str_op = self.binop[node.op.__class__.__name__] self.add( node.left, - ' %s ' % str_op, + f" {str_op} ", node.right, ) - def _ast_constant(self, node): + def _ast_constant(self, node: ast.Constant) -> None: """Add an AST Constant in output.""" if node.value is None: - self.add('nil') + self.add("nil") else: self.add(repr(node.value)) - def _ast_dict(self, node): + def _ast_dict(self, node: ast.Dict) -> None: """Add an AST Dict in output.""" self.add( - '{', - self.make_list([ - ['[', key, ']', '=', value] - for key, value in zip(node.keys, node.values)]), - '}', + "{", + self.make_list([["[", key, "]", "=", value] for key, value in zip(node.keys, node.values)]), + "}", ) - def _ast_functiondef(self, node): + def _ast_functiondef(self, node: ast.FunctionDef) -> None: """Add an AST FunctionDef in output.""" self.add( self.fill, self.fill, - 'function %s' % node.name, + f"function {node.name}", ) self.add( - '(', + "(", self.make_list(node.args.args), - ')', + ")", self.indent, node.body, self.unindent, self.fill, - 'end', + "end", ) - def _ast_if(self, node): + def _ast_if(self, node: ast.If) -> None: """Add an AST If in output.""" self.add( self.fill, - 'if ', + "if ", node.test, - ' then', + " then", self.indent, node.body, self.unindent, @@ -704,30 +696,29 @@ class UnparseLua(UnparsePython): if node.orelse: self.add( self.fill, - 'else', + "else", self.indent, node.orelse, self.unindent, self.fill, - 'end', + "end", ) - def _ast_list(self, node): + def _ast_list(self, node: ast.List) -> None: """Add an AST List in output.""" self.add( - '{', + "{", self.make_list(node.elts), - '}', + "}", ) - def _ast_pass(self, node): + def _ast_pass(self, node: ast.Pass) -> None: """Add an AST Pass in output.""" - pass + pass # noqa: PIE790 class UnparseTcl(UnparsePython): - """ - Unparse AST to generate Tcl script code. + """Unparse AST to generate Tcl script code. Note: only part of AST types are supported (just the types used by the script to test WeeChat scripting API). @@ -735,189 +726,189 @@ class UnparseTcl(UnparsePython): __lineno__ = inspect.currentframe().f_lineno - def __init__(self, *args, **kwargs): - super(UnparseTcl, self).__init__(*args, **kwargs) + def __init__(self, *args, **kwargs) -> None: # noqa: ANN002,ANN003 + """Initialize Tcl parser.""" + super().__init__(*args, **kwargs) self._call = 0 - def _ast_assign(self, node): + def _ast_assign(self, node: ast.Assign) -> None: """Add an AST Assign in output.""" exclude_types = (ast.Dict, ast.List, ast.Constant, ast.Subscript) self.add( self.fill, - 'set ', + "set ", node.targets[0], - ' ', - '[' if not isinstance(node.value, exclude_types) else '', + " ", + "[" if not isinstance(node.value, exclude_types) else "", node.value, - ']' if not isinstance(node.value, exclude_types) else '', + "]" if not isinstance(node.value, exclude_types) else "", ) - def _ast_attribute(self, node): + def _ast_attribute(self, node: ast.Attribute) -> None: """Add an AST Attribute in output.""" saved_prefix = self._prefix self._prefix = [] - if node.attr.startswith('WEECHAT_'): - self.add('$::') - self.add(node.value, '::', node.attr) + if node.attr.startswith("WEECHAT_"): + self.add("$::") + self.add(node.value, "::", node.attr) self._prefix = saved_prefix - def _ast_binop(self, node): + def _ast_binop(self, node: ast.BinOp) -> None: """Add an AST BinOp in output.""" self.add( - '[join [list ', - (self.prefix, '$'), + "[join [list ", + (self.prefix, "$"), node.left, - ' ', + " ", node.right, (self.prefix, None), '] ""]', ) - def _ast_call(self, node): + def _ast_call(self, node: ast.Call) -> None: """Add an AST Call in output.""" if self._call: - self.add('[') + self.add("[") self._call += 1 self.add( node.func, - ' ' if node.args else None, - (self.prefix, '$'), - self.make_list(node.args, sep=' '), + " " if node.args else None, + (self.prefix, "$"), + self.make_list(node.args, sep=" "), (self.prefix, None), ) self._call -= 1 if self._call: - self.add(']') + self.add("]") - def _ast_compare(self, node): + def _ast_compare(self, node: ast.Compare) -> None: """Add an AST Compare in output.""" - self.prefix('$') + self.prefix("$") if self._call: - self.add('[expr {') + self.add("[expr {") self.add(node.left) for operator, comparator in zip(node.ops, node.comparators): - if isinstance(operator, (ast.Eq, ast.NotEq)) and \ - not self.is_number(node.left) and \ - not self.is_bool(node.left) and \ - not self.is_number(comparator) and \ - not self.is_bool(comparator): + if ( + isinstance(operator, (ast.Eq, ast.NotEq)) + and not self.is_number(node.left) + and not self.is_bool(node.left) + and not self.is_number(comparator) + and not self.is_bool(comparator) + ): custom_cmpop = { - 'Eq': 'eq', - 'NotEq': 'ne', + "Eq": "eq", + "NotEq": "ne", } else: custom_cmpop = self.cmpop self.add( - ' %s ' % custom_cmpop[operator.__class__.__name__], + f" {custom_cmpop[operator.__class__.__name__]} ", comparator, ) if self._call: - self.add('}]') + self.add("}]") self.prefix(None) - def _ast_constant(self, node): + def _ast_constant(self, node: ast.Constant) -> None: """Add an AST Constant in output.""" if isinstance(node.value, str): - self.add('"%s"' % node.value.replace('$', '\\$')) + str_node = node.value.replace("$", "\\$") + self.add(f'"{str_node}"') elif node.value is None: - self.add('$::weechat::WEECHAT_NULL') + self.add("$::weechat::WEECHAT_NULL") else: self.add(repr(node.value)) - def _ast_dict(self, node): + def _ast_dict(self, node: ast.Dict) -> None: """Add an AST Dict in output.""" self.add( - '[dict create ', - self.make_list([[key, ' ', value] - for key, value in zip(node.keys, node.values)], - sep=' '), - ']', + "[dict create ", + self.make_list([[key, " ", value] for key, value in zip(node.keys, node.values)], sep=" "), + "]", ) - def _ast_functiondef(self, node): + def _ast_functiondef(self, node: ast.FunctionDef) -> None: """Add an AST FunctionDef in output.""" self.add( self.fill, self.fill, - 'proc %s {' % node.name, - (self.make_list(node.args.args, sep=' ') - if node.args.args else None), - '} {', + f"proc {node.name} {{", + (self.make_list(node.args.args, sep=" ") if node.args.args else None), + "} {", self.indent, node.body, self.unindent, self.fill, - '}', + "}", ) - def _ast_if(self, node): + def _ast_if(self, node: ast.If) -> None: """Add an AST If in output.""" self.add( self.fill, - 'if {', - (self.prefix, '$'), + "if {", + (self.prefix, "$"), node.test, (self.prefix, None), - '} {', + "} {", self.indent, node.body, self.unindent, self.fill, - '}', + "}", ) if node.orelse: self.add( - ' else {', + " else {", self.indent, node.orelse, self.unindent, self.fill, - '}', + "}", ) - def _ast_list(self, node): + def _ast_list(self, node: ast.List) -> None: """Add an AST List in output.""" self.add( - '[', - self.make_list(node.elts, sep=' '), - ']', + "[", + self.make_list(node.elts, sep=" "), + "]", ) - def _ast_pass(self, node): + def _ast_pass(self, node: ast.Pass) -> None: """Add an AST Pass in output.""" - pass + pass # noqa: PIE790 - def _ast_return(self, node): + def _ast_return(self, node: ast.Return) -> None: """Add an AST Return in output.""" - self.fill('return') + self.fill("return") if node.value: self.add( - ' ', - (self.prefix, '$'), + " ", + (self.prefix, "$"), node.value, (self.prefix, None), ) - def _ast_str(self, node): + def _ast_str(self, node: ast.Str) -> None: """Add an AST Str in output.""" self._ast_constant(node) - def _ast_subscript(self, node): + def _ast_subscript(self, node: ast.Subscript) -> None: """Add an AST Subscript in output.""" self.add( - '[dict get ', - (self.prefix, '$'), + "[dict get ", + (self.prefix, "$"), node.value, (self.prefix, None), - ' ', + " ", node.slice, - ']', + "]", ) class UnparseGuile(UnparsePython): - """ - Unparse AST to generate Guile script code. + """Unparse AST to generate Guile script code. Note: only part of AST types are supported (just the types used by the script to test WeeChat scripting API). @@ -925,118 +916,120 @@ class UnparseGuile(UnparsePython): __lineno__ = inspect.currentframe().f_lineno - def __init__(self, *args, **kwargs): - super(UnparseGuile, self).__init__(*args, **kwargs) + def __init__(self, *args, **kwargs) -> None: # noqa: ANN002,ANN003 + """Initialize Guile parser.""" + super().__init__(*args, **kwargs) self.cmpop = { - 'Eq': '=', - 'NotEq': '<>', - 'Lt': '<', - 'LtE': '<=', - 'Gt': '>', - 'GtE': '>=', + "Eq": "=", + "NotEq": "<>", + "Lt": "<", + "LtE": "<=", + "Gt": ">", + "GtE": ">=", } self._call = 0 self._let = 0 - def _ast_assign(self, node): + def _ast_assign(self, node: ast.Assign) -> None: """Add an AST Assign in output.""" self.add( self.fill, - '(let ((', + "(let ((", node.targets[0], - ' ', + " ", node.value, - '))', + "))", self.indent, self.fill, - '(begin', + "(begin", self.indent, ) self._let += 1 - def _ast_attribute(self, node): + def _ast_attribute(self, node: ast.Attribute) -> None: """Add an AST Attribute in output.""" - self.add(node.value, ':', node.attr) + self.add(node.value, ":", node.attr) - def _ast_binop(self, node): + def _ast_binop(self, node: ast.BinOp) -> None: """Add an AST BinOp in output.""" - if isinstance(node.op, ast.Add) and \ - (isinstance(node.left, (ast.Name, ast.Constant)) or - isinstance(node.right, (ast.Name, ast.Constant))): + if isinstance(node.op, ast.Add) and ( + isinstance(node.left, (ast.Name, ast.Constant)) or isinstance(node.right, (ast.Name, ast.Constant)) + ): self.add( - '(string-append ', + "(string-append ", node.left, - ' ', + " ", node.right, - ')', + ")", ) else: self.add( node.left, - ' %s ' % self.binop[node.op.__class__.__name__], + f" {self.binop[node.op.__class__.__name__]} ", node.right, ) - def _ast_call(self, node): + def _ast_call(self, node: ast.Call) -> None: """Add an AST Call in output.""" self._call += 1 self.add( - '(', + "(", node.func, - ' ' if node.args else None, - self.make_list(node.args, sep=' '), - ')', + " " if node.args else None, + self.make_list(node.args, sep=" "), + ")", ) self._call -= 1 - def _ast_compare(self, node): + def _ast_compare(self, node: ast.Compare) -> None: """Add an AST Compare in output.""" for operator, comparator in zip(node.ops, node.comparators): - if isinstance(operator, (ast.Eq, ast.NotEq)) and \ - not self.is_number(node.left) and \ - not self.is_bool(node.left) and \ - not self.is_number(comparator) and \ - not self.is_bool(comparator): - prefix = 'string' + if ( + isinstance(operator, (ast.Eq, ast.NotEq)) + and not self.is_number(node.left) + and not self.is_bool(node.left) + and not self.is_number(comparator) + and not self.is_bool(comparator) + ): + prefix = "string" else: - prefix = '' + prefix = "" self.add( - '(%s%s ' % (prefix, self.cmpop[operator.__class__.__name__]), + f"({prefix}{self.cmpop[operator.__class__.__name__]} ", node.left, - ' ', + " ", comparator, - ')', + ")", ) - def _ast_constant(self, node): + def _ast_constant(self, node: ast.Constant) -> None: """Add an AST Constant in output.""" if isinstance(node.value, str): - self.add('"%s"' % node.value) + self.add(f'"{node.value}"') elif node.value is None: - self.add('#nil') + self.add("#nil") else: self.add(repr(node.value)) - def _ast_dict(self, node): + def _ast_dict(self, node: ast.Dict) -> None: """Add an AST Dict in output.""" self.add( - '\'(', - self.make_list([['(', key, ' ', value, ')'] - for key, value in zip(node.keys, node.values)], - sep=' '), - ')', + "'(", + self.make_list( + [["(", key, " ", value, ")"] for key, value in zip(node.keys, node.values)], sep=" ", + ), + ")", ) - def _ast_functiondef(self, node): + def _ast_functiondef(self, node: ast.FunctionDef) -> None: """Add an AST FunctionDef in output.""" self.add( self.fill, self.fill, - '(define (%s' % node.name, - ' ' if node.args.args else None, - (self.make_list(node.args.args, sep=' ') - if node.args.args else None), - ')', + f"(define ({node.name}", + " " if node.args.args else None, + (self.make_list(node.args.args, sep=" ") if node.args.args else None), + ")", self.indent, node.body, ) @@ -1044,85 +1037,83 @@ class UnparseGuile(UnparsePython): self.add( self.unindent, self.fill, - ')', + ")", self.unindent, self.fill, - ')', + ")", ) self._let -= 1 self.add( self.unindent, self.fill, - ')', + ")", ) - def _ast_if(self, node): + def _ast_if(self, node: ast.If) -> None: """Add an AST If in output.""" self.add( self.fill, - '(if ' - '' if isinstance(node.test, ast.Name) else '(', + "(if " if isinstance(node.test, ast.Name) else "(", node.test, - '' if isinstance(node.test, ast.Name) else ')', + "" if isinstance(node.test, ast.Name) else ")", self.indent, self.fill, - '(begin', + "(begin", self.indent, node.body, self.unindent, self.fill, - ')', + ")", self.unindent, ) if node.orelse: self.add( self.indent, self.fill, - '(begin', + "(begin", self.indent, node.orelse, self.unindent, self.fill, - ')', + ")", self.unindent, ) - self.add(self.fill, ')') + self.add(self.fill, ")") - def _ast_list(self, node): + def _ast_list(self, node: ast.List) -> None: """Add an AST List in output.""" self.add( - '\'(', - self.make_list(node.elts, sep=' '), - ')', + "'(", + self.make_list(node.elts, sep=" "), + ")", ) - def _ast_pass(self, node): + def _ast_pass(self, node: ast.Pass) -> None: # noqa: ARG002 """Add an AST Pass in output.""" - self.add('#t') + self.add("#t") - def _ast_return(self, node): + def _ast_return(self, node: ast.Return) -> None: """Add an AST Return in output.""" if node.value: self.add(self.fill, node.value) - def _ast_str(self, node): + def _ast_str(self, node: ast.Str) -> None: """Add an AST Str in output.""" self._ast_constant(node) - def _ast_subscript(self, node): + def _ast_subscript(self, node: ast.Subscript) -> None: """Add an AST Subscript in output.""" self.add( - '(assoc-ref ', + "(assoc-ref ", node.value, - ' ', + " ", node.slice, - ')', + ")", ) class UnparseJavaScript(UnparsePython): - """ - Unparse AST to generate JavaScript script code. + """Unparse AST to generate JavaScript script code. Note: only part of AST types are supported (just the types used by the script to test WeeChat scripting API). @@ -1130,68 +1121,66 @@ class UnparseJavaScript(UnparsePython): __lineno__ = inspect.currentframe().f_lineno - def _ast_dict(self, node): + def _ast_dict(self, node: ast.Dict) -> None: """Add an AST Dict in output.""" self.add( - '{', - self.make_list([[key, ': ', value] - for key, value in zip(node.keys, node.values)]), - '}', + "{", + self.make_list([[key, ": ", value] for key, value in zip(node.keys, node.values)]), + "}", ) - def _ast_constant(self, node): + def _ast_constant(self, node: ast.Constant) -> None: """Add an AST Constant in output.""" if node.value is None: - self.add('null') + self.add("null") else: self.add(repr(node.value)) - def _ast_functiondef(self, node): + def _ast_functiondef(self, node: ast.FunctionDef) -> None: """Add an AST FunctionDef in output.""" self.add( self.fill, self.fill, - 'function %s(' % node.name, + f"function {node.name}(", self.make_list(node.args.args), - ') {', + ") {", self.indent, node.body, self.unindent, self.fill, - '}', + "}", ) - def _ast_if(self, node): + def _ast_if(self, node: ast.If) -> None: """Add an AST If in output.""" self.add( self.fill, - 'if (', + "if (", node.test, - ') {', + ") {", self.indent, node.body, self.unindent, self.fill, - '}', + "}", ) if node.orelse: self.add( - ' else {', + " else {", self.indent, node.orelse, self.unindent, self.fill, - '}', + "}", ) - def _ast_pass(self, node): + def _ast_pass(self, node: ast.Pass) -> None: """Add an AST Pass in output.""" - pass + pass # noqa: PIE790 class UnparsePhp(UnparsePython): - """ - Unparse AST to generate PHP script code. + """Unparse AST to generate PHP script code. Note: only part of AST types are supported (just the types used by the script to test WeeChat scripting API). @@ -1199,218 +1188,213 @@ class UnparsePhp(UnparsePython): __lineno__ = inspect.currentframe().f_lineno - def _ast_assign(self, node): + def _ast_assign(self, node: ast.Assign) -> None: """Add an AST Assign in output.""" self.add( self.fill, - (self.prefix, '$'), - [[target, ' = '] for target in node.targets], + (self.prefix, "$"), + [[target, " = "] for target in node.targets], (self.prefix, None), node.value, - ';', + ";", ) - def _ast_attribute(self, node): + def _ast_attribute(self, node: ast.Attribute) -> None: """Add an AST Attribute in output.""" saved_prefix = self._prefix self._prefix = [] - if not node.attr.startswith('WEECHAT_'): - self.add(node.value, '_') + if not node.attr.startswith("WEECHAT_"): + self.add(node.value, "_") self.add(node.attr) self._prefix = saved_prefix - def _ast_binop(self, node): + def _ast_binop(self, node: ast.BinOp) -> None: """Add an AST BinOp in output.""" - if isinstance(node.op, ast.Add) and \ - (isinstance(node.left, (ast.Name, ast.Constant)) or - isinstance(node.right, (ast.Name, ast.Constant))): - str_op = '.' + if isinstance(node.op, ast.Add) and ( + isinstance(node.left, (ast.Name, ast.Constant)) or isinstance(node.right, (ast.Name, ast.Constant)) + ): + str_op = "." else: str_op = self.binop[node.op.__class__.__name__] self.add( - (self.prefix, '$'), + (self.prefix, "$"), node.left, - ' %s ' % str_op, + f" {str_op} ", node.right, (self.prefix, None), ) - def _ast_call(self, node): + def _ast_call(self, node: ast.Call) -> None: """Add an AST Call in output.""" self.add( node.func, - '(', - (self.prefix, '$'), + "(", + (self.prefix, "$"), self.make_list(node.args), (self.prefix, None), - ')', + ")", ) - def _ast_constant(self, node): + def _ast_constant(self, node: ast.Constant) -> None: """Add an AST Constant in output.""" if isinstance(node.value, str): - self.add('"%s"' % node.value.replace('$', '\\$')) + str_node = node.value.replace("$", "\\$") + self.add(f'"{str_node}"') elif node.value is None: - self.add('NULL') + self.add("NULL") else: self.add(repr(node.value)) - def _ast_dict(self, node): + def _ast_dict(self, node: ast.Dict) -> None: """Add an AST Dict in output.""" self.add( - 'array(', - self.make_list([[key, ' => ', value] - for key, value in zip(node.keys, node.values)]), - ')', + "array(", + self.make_list([[key, " => ", value] for key, value in zip(node.keys, node.values)]), + ")", ) - def _ast_expr(self, node): + def _ast_expr(self, node: ast.Expr) -> None: """Add an AST Expr in output.""" if not isinstance(node.value, ast.Constant): # ignore docstrings self.add( self.fill, node.value, - ';', + ";", ) - def _ast_functiondef(self, node): + def _ast_functiondef(self, node: ast.FunctionDef) -> None: """Add an AST FunctionDef in output.""" self.add( self.fill, self.fill, - 'function %s(' % node.name, - (self.prefix, '$'), + f"function {node.name}(", + (self.prefix, "$"), self.make_list(node.args.args), (self.prefix, None), - ')', + ")", self.fill, - '{', + "{", self.indent, node.body, self.unindent, self.fill, - '}', + "}", ) - def _ast_list(self, node): + def _ast_list(self, node: ast.List) -> None: """Add an AST List in output.""" self.add( - 'array(', + "array(", self.make_list(node.elts), - ')', + ")", ) - def _ast_if(self, node): + def _ast_if(self, node: ast.If) -> None: """Add an AST If in output.""" self.add( self.fill, - 'if (', - (self.prefix, '$'), + "if (", + (self.prefix, "$"), node.test, (self.prefix, None), - ')', + ")", self.fill, - '{', + "{", self.indent, node.body, self.unindent, self.fill, - '}', + "}", ) if node.orelse: self.add( self.fill, - 'else', + "else", self.fill, - '{', + "{", self.indent, node.orelse, self.unindent, self.fill, - '}', + "}", ) - def _ast_pass(self, node): + def _ast_pass(self, node: ast.Pass) -> None: """Add an AST Pass in output.""" - pass + pass # noqa: PIE790 - def _ast_return(self, node): + def _ast_return(self, node: ast.Return) -> None: """Add an AST Return in output.""" - self.fill('return') + self.fill("return") if node.value: self.add( - ' ', - (self.prefix, '$'), + " ", + (self.prefix, "$"), node.value, (self.prefix, None), - ';', + ";", ) - def _ast_str(self, node): + def _ast_str(self, node: ast.Str) -> None: """Add an AST Str in output.""" self._ast_constant(node) - def _ast_subscript(self, node): + def _ast_subscript(self, node: ast.Subscript) -> None: """Add an AST Subscript in output.""" self.add( - '$', + "$", node.value, - '[', + "[", node.slice, - ']', + "]", ) -def get_languages(): +def get_languages() -> List[str]: """Return a list of supported languages: ['python', 'perl', ...].""" - members = [ member - for member in inspect.getmembers(sys.modules[__name__], - predicate=inspect.isclass) - if inspect.isclass(member[1]) and member[0].startswith('Unparse') + for member in inspect.getmembers(sys.modules[__name__], predicate=inspect.isclass) + if inspect.isclass(member[1]) and member[0].startswith("Unparse") and member[0] != "Unparse" ] - - languages = [ - name[7:].lower() - for name, _ in sorted(members, - key=lambda member: member[1].__lineno__) - ] - - return languages + return [name[7:].lower() for name, _ in sorted(members, key=lambda member: member[1].__lineno__)] LANGUAGES = get_languages() -def get_parser(): +def get_parser() -> argparse.ArgumentParser: """Get parser arguments.""" - all_languages = [*LANGUAGES, 'all'] + all_languages = [*LANGUAGES, "all"] default_language = LANGUAGES[0] parser = argparse.ArgumentParser( - description=('Unparse Python code from stdin and generate code in ' - 'another language (to stdout).\n\n' - 'The code is read from stdin and generated code is ' - 'written on stdout.')) + description=( + "Unparse Python code from stdin and generate code in " + "another language (to stdout).\n\n" + "The code is read from stdin and generated code is " + "written on stdout." + ), + ) parser.add_argument( - '-l', '--language', + "-l", + "--language", default=default_language, choices=all_languages, - help='output language (default: %s)' % default_language) + help="output language (default: {default_language})", + ) return parser -def get_stdin(): - """ - Return data from standard input. +def get_stdin() -> str: + """Return data from standard input. If there is nothing in stdin, wait for data until ctrl-d (EOF) is received. """ - data = '' + data = "" inr = select.select([sys.stdin], [], [], 0)[0] if not inr: - print('Enter the code to convert (Enter + ctrl-d to end)') + print("Enter the code to convert (Enter + ctrl-d to end)") while True: inr = select.select([sys.stdin], [], [], 0.1)[0] if not inr: @@ -1418,38 +1402,38 @@ def get_stdin(): new_data = os.read(sys.stdin.fileno(), 4096) if not new_data: # EOF? break - data += new_data.decode('utf-8') + data += new_data.decode("utf-8") return data -def convert_to_language(code, language, prefix=''): +def convert_to_language(code: str, language: str, prefix: str = "") -> None: """Convert Python code to a language.""" - class_name = 'Unparse%s' % language.capitalize() + class_name = f"Unparse{language.capitalize()}" unparse_class = getattr(sys.modules[__name__], class_name) if prefix: print(prefix) - output = StringIO() + output = io.StringIO() unparse_class(output=output).add(ast.parse(code)) print(output.getvalue().lstrip()) -def convert(code, language): +def convert(code: str, language: str) -> None: """Convert Python code to one or all languages.""" - if language == 'all': + if language == "all": for lang in LANGUAGES: - convert_to_language(code, lang, '\n%s:' % lang) + convert_to_language(code, lang, "\n{lang}:") else: convert_to_language(code, language) -def main(): - """Main function.""" +def main() -> None: + """Generate scripts.""" parser = get_parser() args = parser.parse_args() code = get_stdin() if not code: - print('ERROR: missing input') + print("ERROR: missing input") print() parser.print_help() sys.exit(1) @@ -1459,5 +1443,5 @@ def main(): sys.exit(0) -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/tools/check_curl_symbols.py b/tools/check_curl_symbols.py index 10532947b..589f97bf8 100755 --- a/tools/check_curl_symbols.py +++ b/tools/check_curl_symbols.py @@ -18,7 +18,8 @@ # along with this program. If not, see . # -""" +"""Check Curl symbols defined in WeeChat source code. + Check if Curl symbols defined in src/core/core-url.c are matching symbols defined in Curl (introduced/deprecated/last versions), using this file: https://github.com/curl/curl/blob/master/docs/libcurl/symbols-in-versions. @@ -41,16 +42,15 @@ Or with Curl repository cloned locally: This script requires Python 3.7+. """ -from dataclasses import dataclass -from pathlib import Path -from typing import Dict, List, TextIO, Tuple +# ruff: noqa: COM812,T201 +import io import re import sys +from dataclasses import dataclass +from pathlib import Path -SRC_PATH = ( - Path(__file__).resolve().parent.parent / "src" / "core" / "core-url.c" -) +SRC_PATH = Path(__file__).resolve().parent.parent / "src" / "core" / "core-url.c" # NOTE: keep version in sync with CMakeLists.txt CURL_MIN_VERSION_STR = "7.68.0" @@ -72,13 +72,10 @@ WEECHAT_CURL_MIN_MAX_VERSION_RE = ( r"(?P[0-9][0-9.]+) \*/" ) WEECHAT_ENDIF_RE = r"#endif" -WEECHAT_CURL_CONSTANT_RE = ( - r" URL_DEF_CONST\((?P[A-Z0-9_]+), (?P[A-Z0-9_]+)\)," -) -WEECHAT_CURL_OPTION_RE = ( - r" URL_DEF_OPTION\((?P[A-Z0-9_]+), .*\)," -) +WEECHAT_CURL_CONSTANT_RE = r" URL_DEF_CONST\((?P[A-Z0-9_]+), (?P[A-Z0-9_]+)\)," +WEECHAT_CURL_OPTION_RE = r" URL_DEF_OPTION\((?P[A-Z0-9_]+), .*\)," CURL_SYMBOL_RE = r"[A-Z][A-Z0-9_]" +CURL_VERSION_ITEMS = 3 @dataclass @@ -92,8 +89,7 @@ class WeechatCurlSymbol: def curl_version_to_int(version: str) -> int: - """ - Convert Curl version as string to integer. + """Convert Curl version as string to integer. :param version: version as string (eg: "7.87.0") :return: version as integer, eg: 481024 (== 0x075700, 0x57 == 87) @@ -102,7 +98,7 @@ def curl_version_to_int(version: str) -> int: return 0 result = 0 items = version.split(".") - if len(items) < 3: + while len(items) < CURL_VERSION_ITEMS: items.append("0") factor = 0 for item in reversed(items): @@ -112,8 +108,7 @@ def curl_version_to_int(version: str) -> int: def curl_version_to_str(version: int) -> str: - """ - Convert Curl version as integer to string. + """Convert Curl version as integer to string. :param version: version as integer, eg: 481024 (0x075700) :return: version as string, eg: "7.87.0" @@ -127,15 +122,14 @@ def curl_version_to_str(version: int) -> str: return result.rstrip(".") -def get_curl_symbols(symbols_file: TextIO) -> Dict[str, Tuple[int, int]]: - """ - Parse file docs/libcurl/symbols-in-versions from Curl repository. +def get_curl_symbols(symbols_file: io.TextIOBase) -> dict[str, tuple[int, int]]: + """Parse file docs/libcurl/symbols-in-versions from Curl repository. :param symbols_file: file with Curl symbols :return: Curl symbols as dict: {name: (version_min, version_max)} """ curl_symbol_pattern = re.compile(CURL_SYMBOL_RE) - symbols: Dict[str, Tuple[int, int]] = {} + symbols: dict[str, tuple[int, int]] = {} if symbols_file.isatty(): return symbols for line in symbols_file: @@ -150,10 +144,8 @@ def get_curl_symbols(symbols_file: TextIO) -> Dict[str, Tuple[int, int]]: return symbols -def check_req_symbols(symbols: List[WeechatCurlSymbol]) -> int: - """ - Checks the symbols' min/max version, relative to minimum Curl version that - we require. +def check_req_symbols(symbols: list[WeechatCurlSymbol]) -> int: + """Check the symbols' min/max version, relative to min Curl version required. :return: errors """ @@ -177,13 +169,11 @@ def check_req_symbols(symbols: List[WeechatCurlSymbol]) -> int: return errors -def get_weechat_curl_symbols() -> Tuple[List[WeechatCurlSymbol], int]: - """ - Parse Curl symbols declared in src/core/core-url.c. +def get_weechat_curl_symbols() -> tuple[list[WeechatCurlSymbol], int]: # noqa: C901,PLR0915 + """Parse Curl symbols declared in src/core/core-url.c. :return: tuple (list_symbols, errors) """ - # pylint: disable=too-many-locals,too-many-statements min_version_pattern = re.compile(WEECHAT_CURL_MIN_VERSION_RE) max_version_pattern = re.compile(WEECHAT_CURL_MAX_VERSION_RE) min_max_version_pattern = re.compile(WEECHAT_CURL_MIN_MAX_VERSION_RE) @@ -192,10 +182,10 @@ def get_weechat_curl_symbols() -> Tuple[List[WeechatCurlSymbol], int]: option_pattern = re.compile(WEECHAT_CURL_OPTION_RE) v_min: int = 0 v_max: int = 0 - symbols: List[WeechatCurlSymbol] = [] + symbols: list[WeechatCurlSymbol] = [] errors: int = 0 line_no: int = 0 - with open(SRC_PATH, encoding="utf-8") as src_file: + with Path(SRC_PATH).open(encoding="utf-8") as src_file: for line in src_file: line_no += 1 # min Curl version @@ -207,9 +197,7 @@ def get_weechat_curl_symbols() -> Tuple[List[WeechatCurlSymbol], int]: comment_min = curl_version_to_int(str_min_vers) if v_min != comment_min: print( - f"{SRC_PATH}:{line_no}: min version not matching " - f"the comment: " - f"{hex_min_vers} != {str_min_vers}" + f"{SRC_PATH}:{line_no}: min version not matching the comment: {hex_min_vers} != {str_min_vers}" ) errors += 1 continue @@ -222,9 +210,7 @@ def get_weechat_curl_symbols() -> Tuple[List[WeechatCurlSymbol], int]: comment_max = curl_version_to_int(str_max_vers) if v_max != comment_max: print( - f"{SRC_PATH}:{line_no}: max version not matching " - f"the comment: " - f"{hex_max_vers} != {str_max_vers}" + f"{SRC_PATH}:{line_no}: max version not matching the comment: {hex_max_vers} != {str_max_vers}" ) errors += 1 continue @@ -240,16 +226,12 @@ def get_weechat_curl_symbols() -> Tuple[List[WeechatCurlSymbol], int]: comment_max = curl_version_to_int(str_max_vers) if v_min != comment_min: print( - f"{SRC_PATH}:{line_no}: min version not matching " - f"the comment: " - f"{hex_min_vers} != {str_min_vers}" + f"{SRC_PATH}:{line_no}: min version not matching the comment: {hex_min_vers} != {str_min_vers}" ) errors += 1 if v_max != comment_max: print( - f"{SRC_PATH}:{line_no}: max version not matching " - f"the comment: " - f"{hex_max_vers} != {str_max_vers}" + f"{SRC_PATH}:{line_no}: max version not matching the comment: {hex_max_vers} != {str_max_vers}" ) errors += 1 continue @@ -276,11 +258,10 @@ def get_weechat_curl_symbols() -> Tuple[List[WeechatCurlSymbol], int]: def check_symbols( - weechat_curl_symbols: List[WeechatCurlSymbol], - curl_symbols: Dict[str, Tuple[int, int]], + weechat_curl_symbols: list[WeechatCurlSymbol], + curl_symbols: dict[str, tuple[int, int]], ) -> int: - """ - Check that symbols declared are matching Curl symbols. + """Check that symbols declared are matching Curl symbols. :param weechat_curl_symbols: list of Curl symbols in WeeChat :param curl_symbols: list of all Curl symbols @@ -291,10 +272,7 @@ def check_symbols( for symbol in weechat_curl_symbols: curl_symbol = curl_symbols.get(symbol.name) if not curl_symbol: - print( - f"{SRC_PATH}:{symbol.line_no}: symbol {symbol.name} " - f"not found in Curl" - ) + print(f"{SRC_PATH}:{symbol.line_no}: symbol {symbol.name} not found in Curl") errors += 1 continue if curl_symbol[0] > req_curl and symbol.min_curl != curl_symbol[0]: diff --git a/tools/check_scripts.sh b/tools/check_scripts.sh index cf0a1f9cf..936ded922 100755 --- a/tools/check_scripts.sh +++ b/tools/check_scripts.sh @@ -23,7 +23,7 @@ # # Check shell and Python scripts in WeeChat git repository using these tools: # - shell scripts: shellcheck -# - Python scripts: flake8 + pylint + bandit +# - Python scripts: ruff # set -o errexit @@ -45,7 +45,5 @@ done # check Python scripts for script in ${python_scripts}; do - flake8 --max-line-length=100 --builtins=_ "${root_dir}/$script" - pylint --additional-builtins=_ "${root_dir}/$script" - bandit "${root_dir}/$script" + ruff check "${root_dir}/$script" done diff --git a/tools/generate_python_stub.py b/tools/generate_python_stub.py index 21f53da01..6278ba3eb 100755 --- a/tools/generate_python_stub.py +++ b/tools/generate_python_stub.py @@ -19,16 +19,16 @@ # along with this program. If not, see . # -""" -Generate Python stub: API constants and functions, with type annotations. +"""Generate Python stub with API constants and functions. -This script requires Python 3.6+. +This script requires Python 3.10+. """ -from pathlib import Path -from textwrap import indent +# ruff: noqa: T201 import re +from pathlib import Path +from textwrap import indent DOC_DIR = Path(__file__).resolve().parent.parent / "doc" / "en" SRC_DIR = Path(__file__).resolve().parent.parent / "src" @@ -43,12 +43,12 @@ STUB_HEADER = """\ # DO NOT EDIT BY HAND! # +# ruff: noqa: A002,D400,D205,D301,D415,E501,PIE790,PYI021,PYI048,UP006,UP007,UP035 + from typing import Dict, Union """ -CONSTANT_RE = ( - r"WEECHAT_SCRIPT_CONST_(?P(INT|STR))\((?PWEECHAT_[A-Z0-9_]+)\)" -) +CONSTANT_RE = r"WEECHAT_SCRIPT_CONST_(?P(INT|STR))\((?PWEECHAT_[A-Z0-9_]+)\)" FUNCTION_RE = r"""\[source,python\] ---- @@ -60,40 +60,34 @@ def (?P\w+)(?P[^)]*)(?P\) -> [^:]+:) \.\.\.(?P. def print_stub_constants() -> None: """Print constants, extracted from the plugin-script.c.""" constant_pattern = re.compile(CONSTANT_RE) - with open( - SRC_DIR / "plugins" / "plugin-script.c", encoding="utf-8" - ) as plugin_script_file, open( - SRC_DIR / "plugins" / "weechat-plugin.h", encoding="utf-8" - ) as plugin_public_header_file: + plugin_script_c = Path(SRC_DIR / "plugins" / "plugin-script.c") + weechat_plugin_h = Path(SRC_DIR / "plugins" / "weechat-plugin.h") + with ( + plugin_script_c.open(encoding="utf-8") as plugin_script_file, + weechat_plugin_h.open(encoding="utf-8") as plugin_public_header_file, + ): plugin_script = plugin_script_file.read() plugin_public_header = plugin_public_header_file.read() for match in constant_pattern.finditer(plugin_script): value_re = rf'^#define {match["constant"]} +(?P[\w"-]+)$' value_match = re.search(value_re, plugin_public_header, re.MULTILINE) - value = f' = {value_match["value"]}' if value_match else "" - print(f'{match["constant"]}: {match["type"].lower()}{value}') + value = f" = {value_match['value']}" if value_match else "" + print(f"{match['constant']}: {match['type'].lower()}{value}") def print_stub_functions() -> None: """Print function prototypes, extracted from the Plugin API reference.""" function_pattern = re.compile(FUNCTION_RE, re.DOTALL) - with open(DOC_DIR / "weechat_plugin_api.en.adoc", - encoding="utf-8") as api_doc_file: + with Path(DOC_DIR / "weechat_plugin_api.en.adoc").open(encoding="utf-8") as api_doc_file: api_doc = api_doc_file.read() for match in function_pattern.finditer(api_doc): - url = f'https://weechat.org/doc/weechat/api/#_{match["function"]}' - example = ( - f'\n ::\n\n{indent(match["example"].lstrip(), " " * 8)}' - if match["example"] - else "" - ) - print( - f"""\n + url = f"https://weechat.org/doc/weechat/api/#_{match['function']}" + example = f"\n ::\n\n{indent(match['example'].lstrip(), ' ' * 8)}\n " if match["example"] else "" + str_func = f"""\n def {match["function"]}{match["args"]}{match["return"]} - \"""`{match["function"]} in WeeChat plugin API reference <{url}>`_{example} - \""" + \"""`{match["function"]} in WeeChat plugin API reference <{url}>`_{example}\""" ...""" - ) + print(str_func) def stub_api() -> None: