signature.py 4.7 KB

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