diff options
Diffstat (limited to 'python')
| -rw-r--r-- | python/architecture.py | 6 | ||||
| -rw-r--r-- | python/binaryview.py | 113 | ||||
| -rw-r--r-- | python/callingconvention.py | 23 | ||||
| -rw-r--r-- | python/databuffer.py | 22 | ||||
| -rw-r--r-- | python/function.py | 6 | ||||
| -rw-r--r-- | python/highlevelil.py | 24 | ||||
| -rw-r--r-- | python/mediumlevelil.py | 2 | ||||
| -rw-r--r-- | python/metadata.py | 4 | ||||
| -rw-r--r-- | python/scriptingprovider.py | 3 | ||||
| -rw-r--r-- | python/types.py | 7 |
10 files changed, 94 insertions, 116 deletions
diff --git a/python/architecture.py b/python/architecture.py index 0b46c8ff..bbed133a 100644 --- a/python/architecture.py +++ b/python/architecture.py @@ -116,7 +116,7 @@ class IntrinsicInfo: class InstructionBranch: type:BranchType target:int - arch:'Architecture' + arch:Optional['Architecture'] def __repr__(self): if self.arch is not None: @@ -131,7 +131,7 @@ class InstructionInfo: branch_delay:bool = False branches:List[InstructionBranch] = field(default_factory=list) - def add_branch(self, branch_type, target = 0, arch = None): + def add_branch(self, branch_type:BranchType, target:int = 0, arch:Optional['Architecture'] = None) -> None: self.branches.append(InstructionBranch(branch_type, target, arch)) def __len__(self): @@ -2663,7 +2663,7 @@ class ArchitectureHook(CoreArchitecture): self._cb.getIntrinsicOutputs = self._cb.getIntrinsicOutputs.__class__() self._cb.freeTypeList = self._cb.freeTypeList.__class__() - def register(self): + def register(self) -> None: self.__class__._registered_cb = self._cb self.handle = core.BNRegisterArchitectureHook(self._base_arch.handle, self._cb) core.BNFinalizeArchitectureHook(self._base_arch.handle) diff --git a/python/binaryview.py b/python/binaryview.py index f33224cb..246af295 100644 --- a/python/binaryview.py +++ b/python/binaryview.py @@ -74,7 +74,6 @@ NotificationType = Mapping['BinaryDataNotification', 'BinaryDataNotificationCall ProgressFuncType = Callable[[int, int], bool] DataMatchCallbackType = Callable[[int, 'databuffer.DataBuffer'], bool] LineMatchCallbackType = Callable[[int, 'lineardisassembly.LinearDisassemblyLine'], bool] -SomeName = Union['_types.QualifiedName', str] @dataclass(frozen=True) @@ -3553,7 +3552,7 @@ class BinaryView: core.BNFreeDataReferences(refs, count.value) - def get_data_refs_for_type_field(self, name:SomeName, offset:int) -> List[int]: + def get_data_refs_for_type_field(self, name:'_types.QualifiedNameType', offset:int) -> List[int]: """ ``get_data_refs_for_type_field`` returns a list of virtual addresses of data which references the type ``name``. Note, the returned addresses are the actual start of the queried type field. For example, suppose there is a @@ -3584,7 +3583,7 @@ class BinaryView: core.BNFreeDataReferences(refs, count.value) - def get_type_refs_for_type(self, name:SomeName) -> List['_types.TypeReferenceSource']: + def get_type_refs_for_type(self, name:'_types.QualifiedNameType') -> List['_types.TypeReferenceSource']: """ ``get_type_refs_for_type`` returns a list of TypeReferenceSource objects (xrefs or cross-references) that reference the provided QualifiedName. @@ -3613,7 +3612,7 @@ class BinaryView: core.BNFreeTypeReferences(refs, count.value) - def get_type_refs_for_type_field(self, name:SomeName, offset:int) -> List['_types.TypeReferenceSource']: + def get_type_refs_for_type_field(self, name:'_types.QualifiedNameType', offset:int) -> List['_types.TypeReferenceSource']: """ ``get_type_refs_for_type`` returns a list of TypeReferenceSource objects (xrefs or cross-references) that reference the provided type field. @@ -3737,7 +3736,7 @@ class BinaryView: core.BNRemoveUserDataReference(self.handle, from_addr, to_addr) - def get_all_fields_referenced(self, name:SomeName) -> List[int]: + def get_all_fields_referenced(self, name:'_types.QualifiedNameType') -> List[int]: """ ``get_all_fields_referenced`` returns a list of offsets in the QualifiedName specified by name, which are referenced by code. @@ -3765,7 +3764,7 @@ class BinaryView: finally: core.BNFreeDataReferences(refs, count.value) - def get_all_sizes_referenced(self, name:SomeName) -> Mapping[int, List[int]]: + def get_all_sizes_referenced(self, name:'_types.QualifiedNameType') -> Mapping[int, List[int]]: """ ``get_all_sizes_referenced`` returns a map from field offset to a list of sizes of the accesses to it. @@ -3794,7 +3793,7 @@ class BinaryView: finally: core.BNFreeTypeFieldReferenceSizeInfo(refs, count.value) - def get_all_types_referenced(self, name:SomeName) -> Mapping[int, List['_types.Type']]: + def get_all_types_referenced(self, name:'_types.QualifiedNameType') -> Mapping[int, List['_types.Type']]: """ ``get_all_types_referenced`` returns a map from field offset to a related to the type field access. @@ -3827,7 +3826,7 @@ class BinaryView: finally: core.BNFreeTypeFieldReferenceTypeInfo(refs, count.value) - def get_sizes_referenced(self, name:SomeName, offset:int) -> List[int]: + def get_sizes_referenced(self, name:'_types.QualifiedNameType', offset:int) -> List[int]: """ ``get_sizes_referenced`` returns a list of sizes of the accesses to it. @@ -5642,7 +5641,7 @@ class BinaryView: raise ValueError(error_str) return variable.PossibleValueSet(self.arch, result) - def get_type_by_name(self, name:SomeName) -> Optional['_types.Type']: + def get_type_by_name(self, name:'_types.QualifiedNameType') -> Optional['_types.Type']: """ ``get_type_by_name`` returns the defined type whose name corresponds with the provided ``name`` @@ -5708,7 +5707,7 @@ class BinaryView: return None return result - def get_type_id(self, name:SomeName) -> str: + def get_type_id(self, name:'_types.QualifiedNameType') -> str: """ ``get_type_id`` returns the unique identifier of the defined type whose name corresponds with the provided ``name`` @@ -5754,7 +5753,7 @@ class BinaryView: return None return typelibrary.TypeLibrary(handle) - def is_type_auto_defined(self, name:SomeName) -> bool: + def is_type_auto_defined(self, name:'_types.QualifiedNameType') -> bool: """ ``is_type_auto_defined`` queries the user type list of name. If name is not in the *user* type list then the name is considered an *auto* type. @@ -5772,7 +5771,7 @@ class BinaryView: _name = _types.QualifiedName(name)._get_core_struct() return core.BNIsAnalysisTypeAutoDefined(self.handle, _name) - def define_type(self, type_id:str, default_name:SomeName, type_obj:'_types.Type') -> '_types.QualifiedName': + def define_type(self, type_id:str, default_name:'_types.QualifiedNameType', type_obj:'_types.Type') -> '_types.QualifiedName': """ ``define_type`` registers a :py:Class:`Type` ``type_obj`` of the given ``name`` in the global list of types for the current :py:Class:`BinaryView`. This method should only be used for automatically generated types. @@ -5795,7 +5794,7 @@ class BinaryView: core.BNFreeQualifiedName(reg_name) return result - def define_user_type(self, name:SomeName, type_obj:'_types.Type') -> None: + def define_user_type(self, name:'_types.QualifiedNameType', type_obj:'_types.Type') -> None: """ ``define_user_type`` registers a :py:Class:`Type` ``type_obj`` of the given ``name`` in the global list of user types for the current :py:Class:`BinaryView`. @@ -5810,9 +5809,8 @@ class BinaryView: >>> bv.get_type_by_name(name) <type: int32_t> """ - if isinstance(name, str): - name = _types.QualifiedName(name) - core.BNDefineUserAnalysisType(self.handle, name._get_core_struct(), type_obj.handle) + _name = _types.QualifiedName(name)._get_core_struct() + core.BNDefineUserAnalysisType(self.handle, _name, type_obj.handle) def undefine_type(self, type_id:str) -> None: """ @@ -5833,7 +5831,7 @@ class BinaryView: """ core.BNUndefineAnalysisType(self.handle, type_id) - def undefine_user_type(self, name:SomeName) -> None: + def undefine_user_type(self, name:'_types.QualifiedNameType') -> None: """ ``undefine_user_type`` removes a :py:Class:`Type` from the global list of user types for the current :py:Class:`BinaryView` @@ -5853,7 +5851,7 @@ class BinaryView: _name = _types.QualifiedName(name)._get_core_struct() core.BNUndefineUserAnalysisType(self.handle, _name) - def rename_type(self, old_name:SomeName, new_name:SomeName) -> None: + def rename_type(self, old_name:'_types.QualifiedNameType', new_name:'_types.QualifiedNameType') -> None: """ ``rename_type`` renames a type in the global list of types for the current :py:Class:`BinaryView` @@ -7398,73 +7396,50 @@ class BinaryWriter: core.BNSeekBinaryWriterRelative(self._handle, offset) +@dataclass class StructuredDataValue(object): - def __init__(self, type, address, value, endian): - """ - DEPRECATED use: TypedDataReader instead. - """ - self._type = type - self._address = address - self._value = value - self._endian = endian + """ + DEPRECATED use: TypedDataReader instead. + """ + type:'_types.Type' + address:int + value:bytes + endian:Endianness def __str__(self): - decode_str = "{}B".format(self._type.width) - return ' '.join(["{:02x}".format(x) for x in struct.unpack(decode_str, self._value)]) + decode_str = "{}B".format(self.type.width) + return ' '.join([f"{x:02x}" for x in struct.unpack(decode_str, self.value)]) def __repr__(self): - return "<StructuredDataValue type:{} value:{}>".format(str(self._type), str(self)) + return "<StructuredDataValue type:{} value:{}>".format(str(self.type), str(self)) def __int__(self): - if self._type.width == 1: - if self._endian == Endianness.LittleEndian: - code = "<B" - else: - code = ">B" - elif self._type.width == 2: - if self._endian == Endianness.LittleEndian: - code = "<H" - else: - code = ">H" - elif self._type.width == 4: - if self._endian == Endianness.LittleEndian: - code = "<I" - else: - code = ">I" - elif self._type.width == 8: - if self._endian == Endianness.LittleEndian: - code = "<Q" - else: - code = ">Q" + if self.type.width == 1: + code = "B" + elif self.type.width == 2: + code = "H" + elif self.type.width == 4: + code = "I" + elif self.type.width == 8: + code = "Q" else: - raise Exception("Could not convert to integer with width {}".format(self._type.width)) - - return struct.unpack(code, self._value)[0] - - @property - def type(self): - return self._type + raise Exception("Could not convert to integer with width {}".format(self.type.width)) - @property - def width(self): - return self._type.width + endian = "<" if self.endian == Endianness.LittleEndian else ">" + return struct.unpack(f"{endian}{code}", self.value)[0] @property - def address(self): - return self._address + def str(self) -> str: + return str(self) @property - def value(self): - return self._value + def width(self) -> int: + return len(self.type) @property - def int(self): + def int(self) -> int: return int(self) - @property - def str(self): - return str(self) - class StructuredDataView(object): """ @@ -7483,7 +7458,7 @@ class StructuredDataView(object): 003e >>> """ - def __init__(self, bv:'BinaryView', structure_name:SomeName, address:int): + def __init__(self, bv:'BinaryView', structure_name:'_types.QualifiedNameType', address:int): self._bv = bv self._structure_name = structure_name self._address = address diff --git a/python/callingconvention.py b/python/callingconvention.py index d17cc6e6..b0227b71 100644 --- a/python/callingconvention.py +++ b/python/callingconvention.py @@ -24,7 +24,6 @@ from typing import Optional # Binary Ninja components from . import _binaryninjacore as core -from .enums import VariableSourceType from . import log from . import variable from . import function @@ -401,45 +400,45 @@ class CallingConvention: result[0].index = in_var[0].index result[0].storage = in_var[0].storage - def perform_get_incoming_reg_value(self, reg:'architecture.RegisterName', func:'function.Function'): + def perform_get_incoming_reg_value(self, reg:'architecture.RegisterName', func:'function.Function') -> 'variable.RegisterValue': reg_stack = self.arch.get_reg_stack_for_reg(reg) if reg_stack is not None: if reg == self.arch.reg_stacks[reg_stack].stack_top_reg: return variable.ConstantRegisterValue(0) return variable.Undetermined() - def perform_get_incoming_flag_value(self, reg, func): + def perform_get_incoming_flag_value(self, reg:'architecture.RegisterName', func:'function.Function') -> 'variable.RegisterValue': return variable.Undetermined() def perform_get_incoming_var_for_parameter_var(self, in_var:'variable.CoreVariable', - func:Optional['function.Function']=None): + func:Optional['function.Function']=None) -> 'variable.CoreVariable': out_var = core.BNGetDefaultIncomingVariableForParameterVariable(self.handle, in_var.to_BNVariable()) return variable.CoreVariable.from_BNVariable(out_var) def perform_get_parameter_var_for_incoming_var(self, in_var:'variable.CoreVariable', - func:Optional['function.Function']=None): + func:Optional['function.Function']=None) -> 'variable.CoreVariable': out_var = core.BNGetDefaultParameterVariableForIncomingVariable(self.handle, in_var.to_BNVariable()) return variable.CoreVariable.from_BNVariable(out_var) - def with_confidence(self, confidence:int): + def with_confidence(self, confidence:int) -> 'CallingConvention': return CallingConvention(self.arch, handle = core.BNNewCallingConventionReference(self.handle), confidence = confidence) - def get_incoming_reg_value(self, reg:'architecture.RegisterType', func): + def get_incoming_reg_value(self, reg:'architecture.RegisterType', func:'function.Function') -> 'variable.RegisterValue': reg_num = self.arch.get_reg_index(reg) func_handle = None if func is not None: func_handle = func.handle return variable.RegisterValue.from_BNRegisterValue(core.BNGetIncomingRegisterValue(self.handle, reg_num, func_handle), self.arch) - def get_incoming_flag_value(self, flag, func): + def get_incoming_flag_value(self, flag:'architecture.FlagIndex', func:'function.Function') -> 'variable.RegisterValue': reg_num = self.arch.get_flag_index(flag) func_handle = None if func is not None: func_handle = func.handle return variable.RegisterValue.from_BNRegisterValue(core.BNGetIncomingFlagValue(self.handle, reg_num, func_handle), self.arch) - def get_incoming_var_for_parameter_var(self, in_var:'variable.CoreVariable', func:'function.Function'): + def get_incoming_var_for_parameter_var(self, in_var:'variable.CoreVariable', func:'function.Function') -> 'variable.Variable': in_buf = in_var.to_BNVariable() if func is None: func_obj = None @@ -448,7 +447,7 @@ class CallingConvention: out_var = core.BNGetIncomingVariableForParameterVariable(self.handle, in_buf, func_obj) return variable.Variable.from_BNVariable(func, out_var) - def get_parameter_var_for_incoming_var(self, in_var:'variable.CoreVariable', func:'function.Function'): + def get_parameter_var_for_incoming_var(self, in_var:'variable.CoreVariable', func:'function.Function') -> 'variable.Variable': in_buf = in_var.to_BNVariable() if func is None: func_obj = None @@ -458,9 +457,9 @@ class CallingConvention: return variable.Variable.from_BNVariable(func, out_var) @property - def arch(self): + def arch(self) -> 'architecture.Architecture': return self._arch @arch.setter - def arch(self, value): + def arch(self, value:'architecture.Architecture') -> None: self._arch = value diff --git a/python/databuffer.py b/python/databuffer.py index d99933a4..baf35b17 100644 --- a/python/databuffer.py +++ b/python/databuffer.py @@ -19,18 +19,22 @@ # IN THE SOFTWARE. import ctypes +from typing import Optional, Union # Binary Ninja components from . import _binaryninjacore as core +DataBufferInputType = Union[str, bytes, 'DataBuffer', int] class DataBuffer: def __init__(self, contents:bytes=b"", handle=None): if handle is not None: self.handle = core.handle_of_type(handle, core.BNDataBuffer) - elif isinstance(contents, int) or isinstance(contents, int): + elif isinstance(contents, int): self.handle = core.BNCreateDataBuffer(None, contents) elif isinstance(contents, DataBuffer): self.handle = core.BNDuplicateDataBuffer(contents.handle) + elif isinstance(contents, str): + self.handle = core.BNCreateDataBuffer(contents.encode("utf-8"), len(contents.encode("utf-8"))) else: self.handle = core.BNCreateDataBuffer(contents, len(contents)) @@ -125,34 +129,34 @@ class DataBuffer: ctypes.memmove(buf, data, len(self)) return buf.raw - def escape(self): + def escape(self) -> str: return core.BNDataBufferToEscapedString(self.handle) - def unescape(self): + def unescape(self) -> 'DataBuffer': return DataBuffer(handle=core.BNDecodeEscapedString(bytes(self))) - def base64_encode(self): + def base64_encode(self) -> str: return core.BNDataBufferToBase64(self.handle) - def base64_decode(self): + def base64_decode(self) -> 'DataBuffer': return DataBuffer(handle = core.BNDecodeBase64(bytes(self))) - def zlib_compress(self): + def zlib_compress(self) -> Optional['DataBuffer']: buf = core.BNZlibCompress(self.handle) if buf is None: return None return DataBuffer(handle = buf) - def zlib_decompress(self): + def zlib_decompress(self) -> Optional['DataBuffer']: buf = core.BNZlibDecompress(self.handle) if buf is None: return None return DataBuffer(handle = buf) -def escape_string(text): +def escape_string(text:bytes) -> str: return DataBuffer(text).escape() -def unescape_string(text): +def unescape_string(text:bytes) -> 'DataBuffer': return DataBuffer(text).unescape() diff --git a/python/function.py b/python/function.py index bc7901c6..5a620095 100644 --- a/python/function.py +++ b/python/function.py @@ -138,7 +138,7 @@ class ILReferenceSource: self._expr_id = expr_id @staticmethod - def get_il_name(il_type): + def get_il_name(il_type:FunctionGraphType) -> str: if il_type == FunctionGraphType.NormalFunctionGraph: return 'disassembly' if il_type == FunctionGraphType.LowLevelILFunctionGraph: @@ -1428,7 +1428,7 @@ class Function: core.BNRemoveUserTypeFieldReference(self.handle, from_arch.handle, from_addr, _name,\ offset, size) - def get_low_level_il_at(self, addr:int, arch:Optional['architecture.Architecture']=None): + def get_low_level_il_at(self, addr:int, arch:Optional['architecture.Architecture']=None) -> Optional['lowlevelil.LowLevelILInstruction']: """ ``get_low_level_il_at`` gets the LowLevelILInstruction corresponding to the given virtual address @@ -1542,7 +1542,7 @@ class Function: return result @property - def auto_address_tags(self): + def auto_address_tags(self) -> List['binaryview.Tag']: """ ``auto_address_tags`` gets a list of all auto-defined address Tags in the function. Tags are returned as a list of (arch, address, Tag) tuples. diff --git a/python/highlevelil.py b/python/highlevelil.py index 94b6dbfb..f19e6d77 100644 --- a/python/highlevelil.py +++ b/python/highlevelil.py @@ -90,25 +90,25 @@ class GotoLabel: return self.name @property - def label_id(self): + def label_id(self) -> int: return self.id @property - def name(self): + def name(self) -> str: assert self.function.source_function is not None, "Cant get name of function without source_function" return core.BNGetGotoLabelName(self.function.source_function.handle, self.id) @name.setter - def name(self, value): + def name(self, value:str) -> None: assert self.function.source_function is not None, "Cant set name of function without source_function" core.BNSetUserGotoLabelName(self.function.source_function.handle, self.id, value) @property - def definition(self) -> Optional['HighLevelILInstruction']: + def definition(self) -> Optional[HighLevelILInstruction]: return self.function.get_label(self.id) @property - def uses(self): + def uses(self) -> List['HighLevelILInstruction']: return self.function.get_label_uses(self.id) @@ -400,7 +400,7 @@ class HighLevelILInstruction: return self.core_instr.address @property - def source_operand(self): + def source_operand(self) -> int: return self.core_instr.source_operand @property @@ -1357,7 +1357,7 @@ class HighLevelILArray_index(HighLevelILInstruction): @property def vars_used_in_address(self) -> VariablesList: - return self.src.vars + return self.src @dataclass(frozen=True, repr=False) @@ -1381,7 +1381,7 @@ class HighLevelILArray_index_ssa(SSA, HighLevelILInstruction): @property def vars_used_in_address(self) -> VariablesList: - return self.src.vars + return self.src @property def operands(self) -> List[HighLevelILOperandType]: @@ -1412,7 +1412,7 @@ class HighLevelILSplit(HighLevelILInstruction): class HighLevelILDeref(HighLevelILUnaryBase): @property - def vars_used_in_address(self): + def vars_used_in_address(self) -> VariablesList: return self.vars @@ -1436,7 +1436,7 @@ class HighLevelILDeref_field(HighLevelILInstruction): return self.src.vars @property - def vars_used_in_address(self): + def vars_used_in_address(self) -> VariablesList: return self.vars @property @@ -1460,7 +1460,7 @@ class HighLevelILDeref_ssa(SSA, HighLevelILInstruction): return self.src.vars @property - def vars_used_in_address(self): + def vars_used_in_address(self) -> VariablesList: return self.vars @property @@ -1492,7 +1492,7 @@ class HighLevelILDeref_field_ssa(SSA, HighLevelILInstruction): return self.src.vars @property - def vars_used_in_address(self): + def vars_used_in_address(self) -> VariablesList: return self.vars @property diff --git a/python/mediumlevelil.py b/python/mediumlevelil.py index e12d8fe1..d10080f2 100644 --- a/python/mediumlevelil.py +++ b/python/mediumlevelil.py @@ -1811,7 +1811,7 @@ class MediumLevelILIntrinsic(MediumLevelILInstruction): @property def operands(self) -> List[MediumLevelILOperandType]: - return [self.output, self.intrinsic, self.params] + return [self.output, self.intrinsic, self.params] # TODO: Expand output and params before regeneration @dataclass(frozen=True, repr=False) diff --git a/python/metadata.py b/python/metadata.py index 1f72f7a4..598c35b2 100644 --- a/python/metadata.py +++ b/python/metadata.py @@ -19,13 +19,13 @@ # IN THE SOFTWARE. import ctypes -from typing import Union, Optional +from typing import Union, Optional, List, Tuple # Binary Ninja components from . import _binaryninjacore as core from .enums import MetadataType -MetadataValueType = Union[int, bool, str, bytes, float, list, tuple, dict] +MetadataValueType = Union[int, bool, str, bytes, float, List['MetadataValueType'], Tuple['MetadataValueType'], dict] class Metadata: def __init__(self, value:MetadataValueType=None, signed:Optional[bool]=None, diff --git a/python/scriptingprovider.py b/python/scriptingprovider.py index 335d9af1..94f76bcd 100644 --- a/python/scriptingprovider.py +++ b/python/scriptingprovider.py @@ -31,6 +31,7 @@ from pathlib import Path import re import os from typing import Generator, Optional, List, Tuple +from typing import Type as TypeHintType # Binary Ninja components import binaryninja @@ -798,7 +799,7 @@ from binaryninja import * class PythonScriptingProvider(ScriptingProvider): name = "Python" apiName = f"python{sys.version_info.major}" # Used for plugin compatibility testing - instance_class = PythonScriptingInstance + instance_class:TypeHintType[PythonScriptingInstance] = PythonScriptingInstance @property def _python_bin(self) -> Optional[str]: diff --git a/python/types.py b/python/types.py index dbdc601b..965d5f8d 100644 --- a/python/types.py +++ b/python/types.py @@ -20,9 +20,9 @@ import ctypes from typing import Generator, List, Union, Mapping, Tuple, Optional -from dataclasses import dataclass, field +from dataclasses import dataclass import uuid -from abc import ABC, abstractmethod +from abc import abstractmethod # Binary Ninja components from . import _binaryninjacore as core @@ -35,7 +35,6 @@ from . import architecture from . import types from . import binaryview from . import platform as _platform -from . import log from . import typelibrary QualifiedNameType = Union[List[str], str, 'QualifiedName', List[bytes]] @@ -522,7 +521,7 @@ class TypeBuilder: return NamedTypeReference.named_type_from_type_and_id(type_id, name, type) @staticmethod - def generate_named_type_reference(guid:str, name:QualifiedName): + def generate_named_type_reference(guid:str, name:QualifiedName) -> 'NamedTypeReferenceType': return NamedTypeReference.generate_named_type_reference(guid, name) @staticmethod |
