From bb956aadf315cc1edc89966741a6ea1c919417aa Mon Sep 17 00:00:00 2001 From: nutti Date: Sat, 28 Sep 2024 16:19:39 +0900 Subject: [PATCH] Update: Strategy to find 'never none' and 'accept none' (#254) --- src/fake_bpy_module/analyzer/directives.py | 7 +- .../transformer/data_type_refiner.py | 23 +++- .../transformer/mod_applier.py | 8 ++ .../common/analyzer/append/bpy.types.mod.rst | 18 ++- .../common/analyzer/update/bpy.types.mod.rst | 14 ++- .../base_analyzer_test/expect/option.xml | 32 +++++ .../base_analyzer_test/input/option.rst | 10 ++ .../fake_bpy_module_test/transformer_test.py | 41 ++++++- .../expect/option_non_rna_based.xml | 18 +++ .../option_non_rna_based_transformed.xml | 18 +++ .../expect/option_rna_based.xml | 16 ++- .../expect/option_rna_based_transformed.xml | 16 ++- .../input/option_non_rna_based.rst | 5 + .../input/option_rna_based.rst | 8 +- ...date_function_update_argument_type.mod.xml | 22 ++++ .../update_function_update_argument_type.xml | 109 ++++++++++++++++++ ...date_function_update_argument_type.mod.rst | 7 ++ 17 files changed, 362 insertions(+), 10 deletions(-) create mode 100644 tests/python/fake_bpy_module_test/fake_bpy_module_test/transformer_test_data/mod_applier_test/expect/update_function_update_argument_type.mod.xml create mode 100644 tests/python/fake_bpy_module_test/fake_bpy_module_test/transformer_test_data/mod_applier_test/expect/update_function_update_argument_type.xml create mode 100644 tests/python/fake_bpy_module_test/fake_bpy_module_test/transformer_test_data/mod_applier_test/input/update_function_update_argument_type.mod.rst diff --git a/src/fake_bpy_module/analyzer/directives.py b/src/fake_bpy_module/analyzer/directives.py index 464001ad..80f2ff7f 100644 --- a/src/fake_bpy_module/analyzer/directives.py +++ b/src/fake_bpy_module/analyzer/directives.py @@ -460,8 +460,11 @@ def _parse_arg_option(self, arg_list_node: ArgumentListNode, arg_node = n.parent break if arg_node: - for dtype_node in arg_node.findall(DataTypeNode): - dtype_node.attributes[option_type] = option_body.astext() + if option_body.astext() == "update-argument-type": + arg_node.attributes[option_type] = option_body.astext() + else: + for dtype_node in arg_node.findall(DataTypeNode): + dtype_node.attributes[option_type] = option_body.astext() def _parse_return_option(self, return_node: FunctionReturnNode, option_type: str, diff --git a/src/fake_bpy_module/transformer/data_type_refiner.py b/src/fake_bpy_module/transformer/data_type_refiner.py index 1f90dbc8..e1fc725e 100644 --- a/src/fake_bpy_module/transformer/data_type_refiner.py +++ b/src/fake_bpy_module/transformer/data_type_refiner.py @@ -664,20 +664,39 @@ def _get_refined_data_type( dtype_str_changed, module_name, variable_kind, additional_info=additional_info) + def is_cls_attr_in_never_none_blacklist( + class_full_name: str, attr_name: str) -> bool: + blacklist = ( + "bpy.types.ID.library" + ) + return f"{class_full_name}.{attr_name}" in blacklist + # Add options. for r in result: option_results = original_options.copy() option_results.extend(options.copy()) if "option" in r.attributes: option_results.extend(r.attributes["option"].split(",")) + # list object will not be None. if (variable_kind in ('CLS_ATTR', 'CONST') and "never none" not in option_results): if _REGEX_DATA_TYPE_STARTS_WITH_COLLECTION.match(r.to_string()): option_results.append("never none") - # If data type is bpy.types.Context, it will be never None. + + # If data type is bpy.types.Context, it will accept None. if r.to_string() == "bpy.types.Context": - option_results.append("never none") + while "never none" in option_results: + option_results.remove("never none") + option_results.append("accept none") + + if variable_kind == 'CLS_ATTR': + if is_cls_attr_in_never_none_blacklist( + additional_info["self_class"], + additional_info["data_name"]): + option_results.append("never none") + + option_results = sorted(set(option_results)) r.attributes["option"] = ",".join(option_results) output_log( diff --git a/src/fake_bpy_module/transformer/mod_applier.py b/src/fake_bpy_module/transformer/mod_applier.py index fd0bd5c0..6fbdf791 100644 --- a/src/fake_bpy_module/transformer/mod_applier.py +++ b/src/fake_bpy_module/transformer/mod_applier.py @@ -84,6 +84,14 @@ def _mod_update_function_arguments( arg_name = arg_node.element(NameNode).astext() if arg_name == mod_arg_name: + mod_options = [] + node_attrs = mod_arg_node.attributes + if "mod-option" in node_attrs: + mod_options = node_attrs["mod-option"].split(",") + if "update-argument-type" in mod_options: + arg_node.attributes["argument_type"] = \ + node_attrs["argument_type"] + mod_desc_node = mod_arg_node.element(DescriptionNode) if not mod_desc_node.empty(): arg_node.replace_node(mod_desc_node) diff --git a/src/mods/common/analyzer/append/bpy.types.mod.rst b/src/mods/common/analyzer/append/bpy.types.mod.rst index ea40a9dd..a7ea7f60 100644 --- a/src/mods/common/analyzer/append/bpy.types.mod.rst +++ b/src/mods/common/analyzer/append/bpy.types.mod.rst @@ -52,12 +52,28 @@ :mod-option rtype: skip-refine :option function: overload + .. method:: __setitem__(key, value) + + :type key: int | str + :mod-option arg key: skip-refine + :type value: GenericType1 | None + :mod-option arg value: skip-refine + .. method:: __setitem__(key, value) :type key: int :mod-option arg key: skip-refine + :type value: _GenericType1 | None + :mod-option arg value: skip-refine + :option function: overload + + .. method:: __setitem__(key, value) + + :type key: str + :mod-option arg key: skip-refine :type value: _GenericType1 :mod-option arg value: skip-refine + :option function: overload .. method:: __iter__() @@ -76,7 +92,7 @@ .. method:: __contains__(key) - :type key: str | tuple[str, ...] + :type key: str | tuple[str, ...] | _GenericType1 :mod-option arg key: skip-refine :rtype: bool :mod-option rtype: skip-refine diff --git a/src/mods/common/analyzer/update/bpy.types.mod.rst b/src/mods/common/analyzer/update/bpy.types.mod.rst index c6044fa8..83bce99a 100644 --- a/src/mods/common/analyzer/update/bpy.types.mod.rst +++ b/src/mods/common/analyzer/update/bpy.types.mod.rst @@ -14,11 +14,16 @@ .. method:: values() - :rtype: list[_GenericType1] + :rtype: list[_GenericType1 | None] :mod-option rtype: skip-refine + .. method:: find(key) + + :type key: str (never None) + .. method:: get(key, default=None) + :type key: str (never None) :type default: _GenericType2 :mod-option arg default: skip-refine :generic-types: _GenericType2 @@ -147,3 +152,10 @@ .. attribute:: node_tree :type: :class:`bpy.types.TextureNodeTree` + +.. class:: IDMaterials + + .. method:: pop(*, index=-1) + + :type index: int (never None) + :mod-option arg index: update-argument-type diff --git a/tests/python/fake_bpy_module_test/fake_bpy_module_test/analyzer_test_data/base_analyzer_test/expect/option.xml b/tests/python/fake_bpy_module_test/fake_bpy_module_test/analyzer_test_data/base_analyzer_test/expect/option.xml index c4eae94c..30b24ece 100644 --- a/tests/python/fake_bpy_module_test/fake_bpy_module_test/analyzer_test_data/base_analyzer_test/expect/option.xml +++ b/tests/python/fake_bpy_module_test/fake_bpy_module_test/analyzer_test_data/base_analyzer_test/expect/option.xml @@ -20,3 +20,35 @@ + + + method_2 + + + + + arg_1 + + + + + method_2 arg_1 type + + + + + + method_3 + + + + + arg_1 + + + + + method_3 arg_1 type + + + diff --git a/tests/python/fake_bpy_module_test/fake_bpy_module_test/analyzer_test_data/base_analyzer_test/input/option.rst b/tests/python/fake_bpy_module_test/fake_bpy_module_test/analyzer_test_data/base_analyzer_test/input/option.rst index 5961f8c5..7aea1d2b 100644 --- a/tests/python/fake_bpy_module_test/fake_bpy_module_test/analyzer_test_data/base_analyzer_test/input/option.rst +++ b/tests/python/fake_bpy_module_test/fake_bpy_module_test/analyzer_test_data/base_analyzer_test/input/option.rst @@ -5,3 +5,13 @@ .. method:: method_1() :option function: overload + + .. method:: method_2(arg_1) + + :type arg_1: method_2 arg_1 type + :mod-option arg arg_1: update-argument-type + + .. method:: method_3(arg_1) + + :type arg_1: method_3 arg_1 type + :mod-option arg arg_1: skip-refine diff --git a/tests/python/fake_bpy_module_test/fake_bpy_module_test/transformer_test.py b/tests/python/fake_bpy_module_test/fake_bpy_module_test/transformer_test.py index 4aa35bf0..6bba4997 100644 --- a/tests/python/fake_bpy_module_test/fake_bpy_module_test/transformer_test.py +++ b/tests/python/fake_bpy_module_test/fake_bpy_module_test/transformer_test.py @@ -754,11 +754,21 @@ def test_option(self) -> None: analyzer = BaseAnalyzer() documents = analyzer.analyze(rst_files) + entry_points = [] + entry_point = EntryPoint("bpy.types", "Context", "class") + entry_points.append(entry_point) + entry_point = EntryPoint("bpy.types", "ID", "class") + entry_points.append(entry_point) + self.assertEqual(len(documents), len(expect_files)) for doc, expect in zip(documents, expect_files, strict=True): self.compare_with_file_contents(doc.pformat(), expect) - transformer = Transformer(["data_type_refiner"], {}) + transformer = Transformer(["data_type_refiner"], { + "data_type_refiner": { + "entry_points": entry_points, + } + }) transformed = transformer.transform(documents) self.assertEqual(len(transformed), len(expect_transformed_files)) @@ -1210,6 +1220,35 @@ def test_update_function(self) -> None: for doc, expect_file in zip(transformed, expect_files, strict=True): self.compare_with_file_contents(doc.pformat(), expect_file) + def test_update_function_update_argument_type(self) -> None: + rst_files = ["base.rst"] + mod_files = ["update_function_update_argument_type.mod.rst"] + expect_mod_files = ["update_function_update_argument_type.mod.xml"] + expect_files = ["update_function_update_argument_type.xml"] + rst_files = [f"{self.data_dir}/input/{f}" for f in rst_files] + mod_files = [f"{self.data_dir}/input/{f}" for f in mod_files] + expect_mod_files = [f"{self.data_dir}/expect/{f}" + for f in expect_mod_files] + expect_files = [f"{self.data_dir}/expect/{f}" for f in expect_files] + + analyzer = BaseAnalyzer() + documents = analyzer.analyze(rst_files) + + transformer = Transformer(["mod_applier"], + {"mod_applier": {"mod_files": mod_files}}) + transformed = transformer.transform(documents) + self.assertEqual(len(transformer.get_transformers()), 1) + mod_documents = transformer.get_transformers()[0].get_mod_documents() + + self.assertEqual(len(mod_documents), len(expect_mod_files)) + for mod_doc, expect_file in zip(mod_documents, expect_mod_files, + strict=True): + self.compare_with_file_contents(mod_doc.pformat(), expect_file) + + self.assertEqual(len(transformed), len(rst_files)) + for doc, expect_file in zip(transformed, expect_files, strict=True): + self.compare_with_file_contents(doc.pformat(), expect_file) + def test_update_class(self) -> None: rst_files = ["base.rst"] mod_files = ["update_class.mod.rst"] diff --git a/tests/python/fake_bpy_module_test/fake_bpy_module_test/transformer_test_data/data_type_refiner_test/expect/option_non_rna_based.xml b/tests/python/fake_bpy_module_test/fake_bpy_module_test/transformer_test_data/data_type_refiner_test/expect/option_non_rna_based.xml index edc9e3ea..ea629c99 100644 --- a/tests/python/fake_bpy_module_test/fake_bpy_module_test/transformer_test_data/data_type_refiner_test/expect/option_non_rna_based.xml +++ b/tests/python/fake_bpy_module_test/fake_bpy_module_test/transformer_test_data/data_type_refiner_test/expect/option_non_rna_based.xml @@ -86,3 +86,21 @@ + + + function_3 + + + + + arg_accept_none + + function_3 arg_accept_none description + + + + + bpy.types.Context + + + diff --git a/tests/python/fake_bpy_module_test/fake_bpy_module_test/transformer_test_data/data_type_refiner_test/expect/option_non_rna_based_transformed.xml b/tests/python/fake_bpy_module_test/fake_bpy_module_test/transformer_test_data/data_type_refiner_test/expect/option_non_rna_based_transformed.xml index b47c7deb..3b0930d9 100644 --- a/tests/python/fake_bpy_module_test/fake_bpy_module_test/transformer_test_data/data_type_refiner_test/expect/option_non_rna_based_transformed.xml +++ b/tests/python/fake_bpy_module_test/fake_bpy_module_test/transformer_test_data/data_type_refiner_test/expect/option_non_rna_based_transformed.xml @@ -86,3 +86,21 @@ + + + function_3 + + + + + arg_accept_none + + function_3 arg_accept_none description + + + + + bpy.types.Context + + + diff --git a/tests/python/fake_bpy_module_test/fake_bpy_module_test/transformer_test_data/data_type_refiner_test/expect/option_rna_based.xml b/tests/python/fake_bpy_module_test/fake_bpy_module_test/transformer_test_data/data_type_refiner_test/expect/option_rna_based.xml index 1407cd59..1090b148 100644 --- a/tests/python/fake_bpy_module_test/fake_bpy_module_test/transformer_test_data/data_type_refiner_test/expect/option_rna_based.xml +++ b/tests/python/fake_bpy_module_test/fake_bpy_module_test/transformer_test_data/data_type_refiner_test/expect/option_rna_based.xml @@ -3,7 +3,7 @@ option_rna_based.rst - bpy.type + bpy.types @@ -71,6 +71,20 @@ int + + + ID + + + + + + library + + + + int + active_data diff --git a/tests/python/fake_bpy_module_test/fake_bpy_module_test/transformer_test_data/data_type_refiner_test/expect/option_rna_based_transformed.xml b/tests/python/fake_bpy_module_test/fake_bpy_module_test/transformer_test_data/data_type_refiner_test/expect/option_rna_based_transformed.xml index d7455d26..9456c44b 100644 --- a/tests/python/fake_bpy_module_test/fake_bpy_module_test/transformer_test_data/data_type_refiner_test/expect/option_rna_based_transformed.xml +++ b/tests/python/fake_bpy_module_test/fake_bpy_module_test/transformer_test_data/data_type_refiner_test/expect/option_rna_based_transformed.xml @@ -3,7 +3,7 @@ option_rna_based.rst - bpy.type + bpy.types @@ -71,6 +71,20 @@ int + + + ID + + + + + + library + + + + int + active_data diff --git a/tests/python/fake_bpy_module_test/fake_bpy_module_test/transformer_test_data/data_type_refiner_test/input/option_non_rna_based.rst b/tests/python/fake_bpy_module_test/fake_bpy_module_test/transformer_test_data/data_type_refiner_test/input/option_non_rna_based.rst index d864c25c..28c0b505 100644 --- a/tests/python/fake_bpy_module_test/fake_bpy_module_test/transformer_test_data/data_type_refiner_test/input/option_non_rna_based.rst +++ b/tests/python/fake_bpy_module_test/fake_bpy_module_test/transformer_test_data/data_type_refiner_test/input/option_non_rna_based.rst @@ -19,3 +19,8 @@ :type arg_accept_none_4: int :arg arg_never_none: Optional function_2 arg_never_none description :type arg_never_none: str + +.. function:: function_3(arg_accept_none) + + :arg arg_accept_none: function_3 arg_accept_none description + :type arg_accept_none: :class:`bpy.types.Context` diff --git a/tests/python/fake_bpy_module_test/fake_bpy_module_test/transformer_test_data/data_type_refiner_test/input/option_rna_based.rst b/tests/python/fake_bpy_module_test/fake_bpy_module_test/transformer_test_data/data_type_refiner_test/input/option_rna_based.rst index 4f775e80..e7ab7687 100644 --- a/tests/python/fake_bpy_module_test/fake_bpy_module_test/transformer_test_data/data_type_refiner_test/input/option_rna_based.rst +++ b/tests/python/fake_bpy_module_test/fake_bpy_module_test/transformer_test_data/data_type_refiner_test/input/option_rna_based.rst @@ -1,4 +1,4 @@ -.. module:: bpy.type +.. module:: bpy.types .. function:: function_1(arg_optional, arg_readonly, arg_never_none) @@ -20,6 +20,12 @@ :type: int +.. class:: ID + + .. attribute:: library + + :type: int + .. data:: active_data :type: int diff --git a/tests/python/fake_bpy_module_test/fake_bpy_module_test/transformer_test_data/mod_applier_test/expect/update_function_update_argument_type.mod.xml b/tests/python/fake_bpy_module_test/fake_bpy_module_test/transformer_test_data/mod_applier_test/expect/update_function_update_argument_type.mod.xml new file mode 100644 index 00000000..d84065ba --- /dev/null +++ b/tests/python/fake_bpy_module_test/fake_bpy_module_test/transformer_test_data/mod_applier_test/expect/update_function_update_argument_type.mod.xml @@ -0,0 +1,22 @@ + + + update + + + module_1 + + + + function_2 + + + + + arg_1 + + + 123 + + + + diff --git a/tests/python/fake_bpy_module_test/fake_bpy_module_test/transformer_test_data/mod_applier_test/expect/update_function_update_argument_type.xml b/tests/python/fake_bpy_module_test/fake_bpy_module_test/transformer_test_data/mod_applier_test/expect/update_function_update_argument_type.xml new file mode 100644 index 00000000..dee79219 --- /dev/null +++ b/tests/python/fake_bpy_module_test/fake_bpy_module_test/transformer_test_data/mod_applier_test/expect/update_function_update_argument_type.xml @@ -0,0 +1,109 @@ + + + base.rst + + + module_1 + + + + DATA_1 + + DATA_1 description + + + DATA_1 type + + + function_1 + + function_1 description + + + + arg_1 + + function_1 arg_1 description + + + + function_1 arg_1 type + + + function_1 return description + + + function_1 return type + + + function_2 + + function_2 description + + + + arg_1 + + function_2 arg_1 description + + 123 + + + function_2 arg_1 type + + + + + + ClassA + + ClassA description + + + + + attr_1 + + attr_1 description + + + attr_1 type + + + + method_1 + + method_1 description + + + + arg_1 + + method_1 arg_1 description + + + + method_1 arg_1 type + + + method_1 return description + + + method_1 return type + + + method_2 + + + + + arg_1 + + method_2 arg_1 description + + + + method_2 arg_1 type + + + diff --git a/tests/python/fake_bpy_module_test/fake_bpy_module_test/transformer_test_data/mod_applier_test/input/update_function_update_argument_type.mod.rst b/tests/python/fake_bpy_module_test/fake_bpy_module_test/transformer_test_data/mod_applier_test/input/update_function_update_argument_type.mod.rst new file mode 100644 index 00000000..4ff32f7f --- /dev/null +++ b/tests/python/fake_bpy_module_test/fake_bpy_module_test/transformer_test_data/mod_applier_test/input/update_function_update_argument_type.mod.rst @@ -0,0 +1,7 @@ +.. mod-type:: update + +.. module:: module_1 + +.. function:: function_2(*, arg_1=123) + + :mod-option arg arg_1: update-argument-type