diff options
Diffstat (limited to 'po/update_msg.py')
-rw-r--r-- | po/update_msg.py | 380 |
1 files changed, 0 insertions, 380 deletions
diff --git a/po/update_msg.py b/po/update_msg.py deleted file mode 100644 index 21d727922d4..00000000000 --- a/po/update_msg.py +++ /dev/null @@ -1,380 +0,0 @@ -# ***** BEGIN GPL LICENSE BLOCK ***** -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software Foundation, -# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# ***** END GPL LICENSE BLOCK ***** - -# <pep8-80 compliant> - -# Write out messages.txt from blender - -# Execite: -# blender --background --python po/update_msg.py - -import os - -CURRENT_DIR = os.path.abspath(os.path.dirname(__file__)) -SOURCE_DIR = os.path.normpath(os.path.abspath(os.path.join(CURRENT_DIR, ".."))) - -FILE_NAME_MESSAGES = os.path.join(CURRENT_DIR, "messages.txt") -COMMENT_PREFIX = "#~ " - - -def dump_messages_rna(messages): - import bpy - - def classBlackList(): - blacklist_rna_class = [ - # core classes - "Context", "Event", "Function", "UILayout", - "BlendData", - # registerable classes - "Panel", "Menu", "Header", "RenderEngine", - "Operator", "OperatorMacro", "Macro", - "KeyingSetInfo", "UnknownType", - # window classes - "WindowManager", "Window" - ] - - # --------------------------------------------------------------------- - # Collect internal operators - - # extend with all internal operators - # note that this uses internal api introspection functions - # all possible operator names - op_names = list(sorted(set( - [cls.bl_rna.identifier for cls in - bpy.types.OperatorProperties.__subclasses__()] + - [cls.bl_rna.identifier for cls in - bpy.types.Operator.__subclasses__()] + - [cls.bl_rna.identifier for cls in - bpy.types.OperatorMacro.__subclasses__()] - ))) - - get_inatance = __import__("_bpy").ops.get_instance - path_resolve = type(bpy.context).__base__.path_resolve - for idname in op_names: - op = get_inatance(idname) - if 'INTERNAL' in path_resolve(op, "bl_options"): - blacklist_rna_class.append(idname) - - # --------------------------------------------------------------------- - # Collect builtin classes we dont need to doc - blacklist_rna_class.append("Property") - blacklist_rna_class.extend( - [cls.__name__ for cls in - bpy.types.Property.__subclasses__()]) - - # --------------------------------------------------------------------- - # Collect classes which are attached to collections, these are api - # access only. - collection_props = set() - for cls_id in dir(bpy.types): - cls = getattr(bpy.types, cls_id) - for prop in cls.bl_rna.properties: - if prop.type == 'COLLECTION': - prop_cls = prop.srna - if prop_cls is not None: - collection_props.add(prop_cls.identifier) - blacklist_rna_class.extend(sorted(collection_props)) - - return blacklist_rna_class - - blacklist_rna_class = classBlackList() - - def filterRNA(bl_rna): - id = bl_rna.identifier - if id in blacklist_rna_class: - print(" skipping", id) - return True - return False - - # ------------------------------------------------------------------------- - # Function definitions - - def walkProperties(bl_rna): - import bpy - - # get our parents properties not to export them multiple times - bl_rna_base = bl_rna.base - if bl_rna_base: - bl_rna_base_props = bl_rna_base.properties.values() - else: - bl_rna_base_props = () - - for prop in bl_rna.properties: - # only write this property is our parent hasn't got it. - if prop in bl_rna_base_props: - continue - if prop.identifier == "rna_type": - continue - - msgsrc = "bpy.types.%s.%s" % (bl_rna.identifier, prop.identifier) - if prop.name and prop.name != prop.identifier: - messages.setdefault(prop.name, []).append(msgsrc) - if prop.description: - messages.setdefault(prop.description, []).append(msgsrc) - - if isinstance(prop, bpy.types.EnumProperty): - for item in prop.enum_items: - msgsrc = "bpy.types.%s.%s, '%s'" % (bl_rna.identifier, - prop.identifier, - item.identifier, - ) - # Here identifier and name can be the same! - if item.name: # and item.name != item.identifier: - messages.setdefault(item.name, - []).append(msgsrc) - if item.description: - messages.setdefault(item.description, - []).append(msgsrc) - - def walkRNA(bl_rna): - - if filterRNA(bl_rna): - return - - msgsrc = "bpy.types.%s" % bl_rna.identifier - - if bl_rna.name and bl_rna.name != bl_rna.identifier: - messages.setdefault(bl_rna.name, []).append(msgsrc) - - if bl_rna.description: - messages.setdefault(bl_rna.description, []).append(msgsrc) - - if hasattr(bl_rna, 'bl_label') and bl_rna.bl_label: - messages.setdefault(bl_rna.bl_label, []).append(msgsrc) - - walkProperties(bl_rna) - - def walkClass(cls): - walkRNA(cls.bl_rna) - - def walk_keymap_hierarchy(hier, msgsrc_prev): - for lvl in hier: - msgsrc = "%s.%s" % (msgsrc_prev, lvl[1]) - messages.setdefault(lvl[0], []).append(msgsrc) - - if lvl[3]: - walk_keymap_hierarchy(lvl[3], msgsrc) - - # ------------------------------------------------------------------------- - # Dump Messages - - def full_class_id(cls): - """ gives us 'ID.Lamp.AreaLamp' which is best for sorting. - """ - cls_id = "" - bl_rna = cls.bl_rna - while bl_rna: - cls_id = "%s.%s" % (bl_rna.identifier, cls_id) - bl_rna = bl_rna.base - return cls_id - - cls_list = type(bpy.context).__base__.__subclasses__() - cls_list.sort(key=full_class_id) - for cls in cls_list: - walkClass(cls) - - cls_list = bpy.types.Space.__subclasses__() - cls_list.sort(key=full_class_id) - for cls in cls_list: - walkClass(cls) - - cls_list = bpy.types.Operator.__subclasses__() - cls_list.sort(key=full_class_id) - for cls in cls_list: - walkClass(cls) - - cls_list = bpy.types.OperatorProperties.__subclasses__() - cls_list.sort(key=full_class_id) - for cls in cls_list: - walkClass(cls) - - cls_list = bpy.types.Menu.__subclasses__() - cls_list.sort(key=full_class_id) - for cls in cls_list: - walkClass(cls) - - from bpy_extras.keyconfig_utils import KM_HIERARCHY - - walk_keymap_hierarchy(KM_HIERARCHY, "KM_HIERARCHY") - - -def dump_messages_pytext(messages): - """ dumps text inlined in the python user interface: eg. - - layout.prop("someprop", text="My Name") - """ - import ast - - # ------------------------------------------------------------------------- - # Gather function names - - import bpy - # key: func_id - # val: [(arg_kw, arg_pos), (arg_kw, arg_pos), ...] - func_translate_args = {} - - # so far only 'text' keywords, but we may want others translated later - translate_kw = ("text", ) - - for func_id, func in bpy.types.UILayout.bl_rna.functions.items(): - # check it has a 'text' argument - for (arg_pos, (arg_kw, arg)) in enumerate(func.parameters.items()): - if ((arg_kw in translate_kw) and - (arg.is_output == False) and - (arg.type == 'STRING')): - - func_translate_args.setdefault(func_id, []).append((arg_kw, - arg_pos)) - # print(func_translate_args) - - # ------------------------------------------------------------------------- - # Function definitions - - def extract_strings(fp_rel, node_container): - """ Recursively get strings, needed incase we have "Blah" + "Blah", - passed as an argument in that case it wont evaluate to a string. - """ - - for node in ast.walk(node_container): - if type(node) == ast.Str: - eval_str = ast.literal_eval(node) - if eval_str: - # print("%s:%d: %s" % (fp, node.lineno, eval_str)) - msgsrc = "%s:%s" % (fp_rel, node.lineno) - messages.setdefault(eval_str, []).append(msgsrc) - - def extract_strings_from_file(fp): - filedata = open(fp, 'r', encoding="utf8") - root_node = ast.parse(filedata.read(), fp, 'exec') - filedata.close() - - fp_rel = os.path.relpath(fp, SOURCE_DIR) - - for node in ast.walk(root_node): - if type(node) == ast.Call: - # print("found function at") - # print("%s:%d" % (fp, node.lineno)) - - # lambda's - if type(node.func) == ast.Name: - continue - - # getattr(self, con.type)(context, box, con) - if not hasattr(node.func, "attr"): - continue - - translate_args = func_translate_args.get(node.func.attr, ()) - - # do nothing if not found - for arg_kw, arg_pos in translate_args: - if arg_pos < len(node.args): - extract_strings(fp_rel, node.args[arg_pos]) - else: - for kw in node.keywords: - if kw.arg == arg_kw: - extract_strings(fp_rel, kw.value) - - # ------------------------------------------------------------------------- - # Dump Messages - - mod_dir = os.path.join(SOURCE_DIR, - "release", - "scripts", - "startup", - "bl_ui") - - files = [os.path.join(mod_dir, fn) - for fn in sorted(os.listdir(mod_dir)) - if not fn.startswith("_") - if fn.endswith("py") - ] - - for fp in files: - extract_strings_from_file(fp) - - -def dump_messages(): - - def filter_message(msg): - - # check for strings like ": %d" - msg_test = msg - for ignore in ("%d", "%s", "%r", # string formatting - "*", ".", "(", ")", "-", "/", "\\", "+", ":", "#", "%" - "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", - "x", # used on its own eg: 100x200 - "X", "Y", "Z", # used alone. no need to include - ): - msg_test = msg_test.replace(ignore, "") - msg_test = msg_test.strip() - if not msg_test: - # print("Skipping: '%s'" % msg) - return True - - # we could filter out different strings here - - return False - - if 1: - import collections - messages = collections.OrderedDict() - else: - messages = {} - - messages[""] = [] - - # get strings from RNA - dump_messages_rna(messages) - - # get strings from UI layout definitions text="..." args - dump_messages_pytext(messages) - - del messages[""] - - message_file = open(FILE_NAME_MESSAGES, 'w', encoding="utf8") - # message_file.writelines("\n".join(sorted(messages))) - - for key, value in messages.items(): - - # filter out junk values - if filter_message(key): - continue - - for msgsrc in value: - message_file.write("%s%s\n" % (COMMENT_PREFIX, msgsrc)) - message_file.write("%s\n" % key) - - message_file.close() - - print("Written %d messages to: %r" % (len(messages), FILE_NAME_MESSAGES)) - - -def main(): - - try: - import bpy - except ImportError: - print("This script must run from inside blender") - return - - dump_messages() - - -if __name__ == "__main__": - print("\n\n *** Running %r *** \n" % __file__) - main() |