1from inspect import Parameter 
    2 
    3from jedi.cache import memoize_method 
    4from jedi import debug 
    5from jedi import parser_utils 
    6 
    7 
    8class _SignatureMixin: 
    9    def to_string(self): 
    10        def param_strings(): 
    11            is_positional = False 
    12            is_kw_only = False 
    13            for n in self.get_param_names(resolve_stars=True): 
    14                kind = n.get_kind() 
    15                is_positional |= kind == Parameter.POSITIONAL_ONLY 
    16                if is_positional and kind != Parameter.POSITIONAL_ONLY: 
    17                    yield '/' 
    18                    is_positional = False 
    19 
    20                if kind == Parameter.VAR_POSITIONAL: 
    21                    is_kw_only = True 
    22                elif kind == Parameter.KEYWORD_ONLY and not is_kw_only: 
    23                    yield '*' 
    24                    is_kw_only = True 
    25 
    26                yield n.to_string() 
    27 
    28            if is_positional: 
    29                yield '/' 
    30 
    31        s = self.name.string_name + '(' + ', '.join(param_strings()) + ')' 
    32        annotation = self.annotation_string 
    33        if annotation: 
    34            s += ' -> ' + annotation 
    35        return s 
    36 
    37 
    38class AbstractSignature(_SignatureMixin): 
    39    def __init__(self, value, is_bound=False): 
    40        self.value = value 
    41        self.is_bound = is_bound 
    42 
    43    @property 
    44    def name(self): 
    45        return self.value.name 
    46 
    47    @property 
    48    def annotation_string(self): 
    49        return '' 
    50 
    51    def get_param_names(self, resolve_stars=False): 
    52        param_names = self._function_value.get_param_names() 
    53        if self.is_bound: 
    54            return param_names[1:] 
    55        return param_names 
    56 
    57    def bind(self, value): 
    58        raise NotImplementedError 
    59 
    60    def matches_signature(self, arguments): 
    61        return True 
    62 
    63    def __repr__(self): 
    64        if self.value is self._function_value: 
    65            return '<%s: %s>' % (self.__class__.__name__, self.value) 
    66        return '<%s: %s, %s>' % (self.__class__.__name__, self.value, self._function_value) 
    67 
    68 
    69class TreeSignature(AbstractSignature): 
    70    def __init__(self, value, function_value=None, is_bound=False): 
    71        super().__init__(value, is_bound) 
    72        self._function_value = function_value or value 
    73 
    74    def bind(self, value): 
    75        return TreeSignature(value, self._function_value, is_bound=True) 
    76 
    77    @property 
    78    def _annotation(self): 
    79        # Classes don't need annotations, even if __init__ has one. They always 
    80        # return themselves. 
    81        if self.value.is_class(): 
    82            return None 
    83        return self._function_value.tree_node.annotation 
    84 
    85    @property 
    86    def annotation_string(self): 
    87        a = self._annotation 
    88        if a is None: 
    89            return '' 
    90        return a.get_code(include_prefix=False) 
    91 
    92    @memoize_method 
    93    def get_param_names(self, resolve_stars=False): 
    94        params = self._function_value.get_param_names() 
    95        if resolve_stars: 
    96            from jedi.inference.star_args import process_params 
    97            params = process_params(params) 
    98        if self.is_bound: 
    99            return params[1:] 
    100        return params 
    101 
    102    def matches_signature(self, arguments): 
    103        from jedi.inference.param import get_executed_param_names_and_issues 
    104        executed_param_names, issues = \ 
    105            get_executed_param_names_and_issues(self._function_value, arguments) 
    106        if issues: 
    107            return False 
    108 
    109        matches = all(executed_param_name.matches_signature() 
    110                      for executed_param_name in executed_param_names) 
    111        if debug.enable_notice: 
    112            tree_node = self._function_value.tree_node 
    113            signature = parser_utils.get_signature(tree_node) 
    114            if matches: 
    115                debug.dbg("Overloading match: %s@%s (%s)", 
    116                          signature, tree_node.start_pos[0], arguments, color='BLUE') 
    117            else: 
    118                debug.dbg("Overloading no match: %s@%s (%s)", 
    119                          signature, tree_node.start_pos[0], arguments, color='BLUE') 
    120        return matches 
    121 
    122 
    123class BuiltinSignature(AbstractSignature): 
    124    def __init__(self, value, return_string, function_value=None, is_bound=False): 
    125        super().__init__(value, is_bound) 
    126        self._return_string = return_string 
    127        self.__function_value = function_value 
    128 
    129    @property 
    130    def annotation_string(self): 
    131        return self._return_string 
    132 
    133    @property 
    134    def _function_value(self): 
    135        if self.__function_value is None: 
    136            return self.value 
    137        return self.__function_value 
    138 
    139    def bind(self, value): 
    140        return BuiltinSignature( 
    141            value, self._return_string, 
    142            function_value=self.value, 
    143            is_bound=True 
    144        ) 
    145 
    146 
    147class SignatureWrapper(_SignatureMixin): 
    148    def __init__(self, wrapped_signature): 
    149        self._wrapped_signature = wrapped_signature 
    150 
    151    def __getattr__(self, name): 
    152        return getattr(self._wrapped_signature, name)