예제 #1
0
    def field_to_swagger_object(self, field, swagger_object_type,
                                use_references, **kwargs):
        if not isinstance(field, serializers.SerializerMethodField):
            return NotHandled

        method = getattr(field.parent, field.method_name)
        if method is None:
            return NotHandled

        # attribute added by the swagger_serializer_method decorator
        serializer = getattr(method, "_swagger_serializer", None)

        if serializer:
            # in order of preference for description, use:
            # 1) field.help_text from SerializerMethodField(help_text)
            # 2) serializer.help_text from swagger_serializer_method(serializer)
            # 3) method's docstring
            description = field.help_text
            if description is None:
                description = getattr(serializer, 'help_text', None)
            if description is None:
                description = method.__doc__

            label = field.label
            if label is None:
                label = getattr(serializer, 'label', None)

            if inspect.isclass(serializer):
                serializer_kwargs = {
                    "help_text": description,
                    "label": label,
                    "read_only": True,
                }

                serializer = method._swagger_serializer(**serializer_kwargs)
            else:
                serializer.help_text = description
                serializer.label = label
                serializer.read_only = True

            return self.probe_field_inspectors(serializer,
                                               swagger_object_type,
                                               use_references,
                                               read_only=True)
        elif typing and inspect_signature:
            # look for Python 3.5+ style type hinting of the return value
            hint_class = inspect_signature(method).return_annotation

            if inspect.isclass(hint_class) and not issubclass(
                    hint_class, inspect._empty):
                type_info = get_basic_type_info_from_hint(hint_class)

                if type_info is not None:
                    SwaggerType, ChildSwaggerType = self._get_partial_types(
                        field, swagger_object_type, use_references, **kwargs)
                    return SwaggerType(**type_info)

        return NotHandled
예제 #2
0
    def code_obj_to_signature(code_obj: CodeType) -> str:
        """Get a function signature from a code object.

        See:
            https://stackoverflow.com/a/56761306/5094008

        """
        try:
            func = FunctionType(code_obj, {})
            arg_sequence = inspect_signature(func)
            return f'def {code_obj.co_name}{arg_sequence}:'
        except TypeError:
            # build our own signature
            return f"""\
예제 #3
0
   def __get_final_inner_function(self):
      """ Returns a string of an generated inner function with the code body from: func

      Tries to generate a new function with the 'code-body' from the `self.func`
      as well as the `self.args_list` and `self.kwargs_dict`

      :return: (str) generated inner function)
      :raise Err: example if an indentation is encountered which is not a multiple of the first found indentation
      """
      has_block_speedit = False
      _start_block_stripped_line = ''
      start_tag_block_speedit = 0
      end_tag_block_speedit = 0

      func_line, l_num = inspect_getsourcelines(self.func)
      sig = inspect_signature(self.func)
      indent_ = None
      func_def_indent = len(func_line[0]) - len(func_line[0].lstrip())
      func_body = func_line[1:]
      search_docstring = False

      # PREPARE: remove docstring and get final indentation
      first_none_docstring_idx = 0
      for idx, line_orig in enumerate(func_body):
         rstripped_line = line_orig.rstrip()
         if rstripped_line:
            stripped_codeline = rstripped_line.lstrip()
            if stripped_codeline[0] == '#':  # remove comment lines
               if not ('::SPEEDIT::' in stripped_codeline or '**SPEEDIT**' in stripped_codeline):
                  continue
            if search_docstring:
               if stripped_codeline[0:3] == '"""' or stripped_codeline[0:3] == "'''":
                  search_docstring = False
               continue
            else:
               codebody_indent = len(rstripped_line) - len(stripped_codeline)
               indent_ = codebody_indent - func_def_indent
               # Check if we have a docstring
               if stripped_codeline[0:3] == '"""' or stripped_codeline[0:3] == "'''":
                  search_docstring = True
                  continue
            first_none_docstring_idx = idx
            break

      # do the func code body
      adjusted_func_code_line = []
      for line_orig in func_body[first_none_docstring_idx:]:
         # remove empty
         if line_orig:
            # get indentation check it is a multiple of indent_
            rstrip_line = line_orig.rstrip()
            if rstrip_line:
               stripped_line = rstrip_line.lstrip()
               if stripped_line[0] == '#':  # remove comment lines: keep any with  ::SPEEDIT::
                  if '::SPEEDIT::' in stripped_line or '**SPEEDIT**' in stripped_line:
                     has_block_speedit = True
                  else:
                     continue
               line_indentation = len(rstrip_line) - len(stripped_line)
               if line_indentation % indent_ != 0:
                  raise Err('_TimeIT.get_final_inner_function', [
                     '<{}>: ERROR: indentation must be a multiple of the second function line: <{}>'.format(
                        self.orig_func_name,
                        indent_
                     ),
                     '  seems we encountered a wrong indented line: line_indentation: <{}>'.format(line_indentation),
                     '    {}'.format(line_orig)
                  ])
               line_indentation_level = int((line_indentation - func_def_indent) / indent_) + 1  # need one extra level

               if has_block_speedit:
                  if '::SPEEDIT::' in stripped_line:
                     if start_tag_block_speedit != end_tag_block_speedit:
                        # expected END Tag
                        raise Err('_TimeIT.get_final_inner_function', [
                           '<{}>: FUNCTION INNER TAG ERROR: has_block_speedit: <{}>'.format(
                              self.orig_func_name,
                              has_block_speedit
                           ),
                           '  Expected an END-TAG <**SPEEDIT**>: '
                           ' {}'.format(line_orig)
                        ])
                     adjusted_func_code_line.append(
                        ('   ' * line_indentation_level) + '_speedit_prefix__stmt_inner_start = _speedit_prefix__perf_counter()  # ::SPEEDIT::START internally added'
                     )
                     start_tag_block_speedit += 1
                     _start_block_stripped_line = stripped_line
                  elif '**SPEEDIT**' in stripped_line:
                     if end_tag_block_speedit != start_tag_block_speedit - 1:
                        # expected START TAG
                        raise Err('_TimeIT.get_final_inner_function', [
                           '<{}>: FUNCTION INNER TAG ERROR: has_block_speedit: <{}>'.format(
                              self.orig_func_name,
                              has_block_speedit),
                           '  Expected an START-TAG <::SPEEDIT::>:',
                           ' {}'.format(line_orig)
                        ])
                     # Do this inner result
                     adjusted_func_code_line.append((
                                                    '   ' * line_indentation_level) + '_speedit_prefix__result_time += _speedit_prefix__perf_counter() - _speedit_prefix__stmt_inner_start  # **SPEEDIT**END internally added')
                     if self.check_too_fast:
                        adjusted_func_code_line.append(
                           ('   ' * line_indentation_level) + 'if _speedit_prefix__result_time < _speedit_prefix__check_reference_time: raise Exception("in function: <{}>'.format(
                           self.orig_func_name) + ' code block: too fast to measure:\\n   code part: _speedit_prefix__result_time: <{:.11f}>  2 times _smallest_perf_counter_time: <{:.11f}>\\n  ' + '  _start_block_stripped_line: <{}>'.format(
                           _start_block_stripped_line) + '".format(_speedit_prefix__result_time, _speedit_prefix__check_reference_time))  # SPEEDIT: internally added')
                     end_tag_block_speedit += 1
                  else:
                     adjusted_func_code_line.append(('   ' * line_indentation_level) + stripped_line)
               else:
                  adjusted_func_code_line.append(('   ' * line_indentation_level) + stripped_line)

      # CHECK: LAST END TAG
      # e.g. if a function body ends with an END-TAG this is not returned by: inspect.getsourcelines(self.func)
      if has_block_speedit:
         if start_tag_block_speedit != end_tag_block_speedit:
            # Do the last inner result: ADDING an END-TAG
            adjusted_func_code_line.append(
               '      _speedit_prefix__result_time += _speedit_prefix__perf_counter() - _speedit_prefix__stmt_inner_start  # **SPEEDIT**END internally added')
            if self.check_too_fast:
               adjusted_func_code_line.append(
                  '      if _speedit_prefix__result_time < _speedit_prefix__check_reference_time: raise Exception("in function: <{}>'.format(
                     self.orig_func_name) + ' code block: too fast to measure:\\n   code part: _speedit_prefix__result_time: <{:.11f}>  2 times _smallest_perf_counter_time: <{:.11f}>\\n  ' + '  _start_block_stripped_line: <{}>'.format(
                     _start_block_stripped_line) + '".format(_speedit_prefix__result_time, _speedit_prefix__check_reference_time))  # SPEEDIT: internally added')

      # add the normal perf_counter time lines
      else:
         adjusted_func_code_line.insert(
            0,
            '      _speedit_prefix__stmt_inner_start = _speedit_prefix__perf_counter()  # ::SPEEDIT::START internally added'
         )
         adjusted_func_code_line.append(
            '      _speedit_prefix__result_time += _speedit_prefix__perf_counter() - _speedit_prefix__stmt_inner_start  # **SPEEDIT**END internally added')

         if self.check_too_fast:
            adjusted_func_code_line.append(
               '      if _speedit_prefix__result_time < _speedit_prefix__check_reference_time: raise Exception("in function: <{}>'.format(
                  self.orig_func_name) + ' code block: too fast to measure:\\n   code part: _speedit_prefix__result_time: <{:.11f}>  2 times _smallest_perf_counter_time: <{:.11f}>".format(_speedit_prefix__result_time, _speedit_prefix__check_reference_time))  # SPEEDIT: internally added')

      # Do the arguments
      final_param_line = []
      for param, value in sig.parameters.items():
         if value.kind == value.POSITIONAL_OR_KEYWORD:
            # check if we have a keyword
            if param in self.kwargs_dict:
               value_to_set = self.kwargs_dict.pop(param)
            else:  # use any positional
               if not self.args_list:
                  raise Err('_TimeIT.__get_final_inner_function', [
                     'orig_func_name: <{}>'.format(self.orig_func_name),
                     '  POSITIONAL_OR_KEYWORD ERROR: seems no such keyword nor enough positional arguments are supplied',
                     '   param: <{}>'.format(param),
                     '    list_of_positional_arguments: <{}>'.format(self.args_list),
                     '     dictionary_of_keyword_arguments: <{}>'.format(self.kwargs_dict),
                  ])
               value_to_set = self.args_list.pop(0)
            if isinstance(value_to_set, str):
               parameter_line = '{} = "{}"'.format(param, value_to_set)
            else:
               parameter_line = '{} = {}'.format(param, value_to_set)
            final_param_line.append(('   ' * 2) + parameter_line)
         elif value.kind == value.POSITIONAL_ONLY:
            value_to_set = self.args_list.pop(0)
            if isinstance(value_to_set, str):
               parameter_line = '{} = "{}"'.format(param, value_to_set)
            else:
               parameter_line = '{} = {}'.format(param, value_to_set)
            final_param_line.append(('   ' * 2) + parameter_line)
            # TODO: From docs: 3.4 Python has no explicit syntax for defining positional-only parameters, but many built-in and extension module functions (especially those that accept only one or two parameters) accept them.
            raise Err('_TimeIT.get_final_inner_function()', [
               'orig_func_name: <{}>'.format(self.orig_func_name),
               '  POSITIONAL_ONLY !! not sure what to do .. check in future if needed:',
               '   param: <{}> value.kind: <{}>'.format(param, value.kind)
            ])
         elif value.kind == value.VAR_POSITIONAL:  # do the remaining POSITIONAL arguments
            parameter_line = '{} = {}'.format(param, self.args_list)
            final_param_line.append(('   ' * 2) + parameter_line)
         elif value.kind == value.KEYWORD_ONLY:
            if param in self.kwargs_dict:
               value_to_set = self.kwargs_dict.pop(param)
            else:  # use the default
               value_to_set = value.default
            if isinstance(value_to_set, str):
               parameter_line = '{} = "{}"'.format(param, value_to_set)
            else:
               parameter_line = '{} = {}'.format(param, value_to_set)
            final_param_line.append(('   ' * 2) + parameter_line)
         elif value.kind == value.VAR_KEYWORD:  # do the remaining KEYWORD arguments
            parameter_line = '{} = {}'.format(param, self.kwargs_dict)
            final_param_line.append(('   ' * 2) + parameter_line)
         else:
            continue

      final_inner_function_lines = [
         'def inner():  # orig function name: {}'.format(self.orig_func_name),
         '   from time import perf_counter as _speedit_prefix__perf_counter',
         '',
         '   _speedit_prefix__run_sec = {}'.format(self.run_sec),
         '',
         '   # The smallest difference of calling _speedit_prefix__perf_counter() ',
         '   #   immediately after each other a couple of times',
         '   _speedit_prefix__check_reference_time = {}'.format(self.perf_counter_reference_time),
         '   _speedit_prefix__loops = 0',
         '   _speedit_prefix__all_loops_time_sec = 0.0',
         '   _speedit_prefix__avg_loop_sec = 0.0',
         '   _speedit_prefix__best_loop_sec = 99999999999.0',
         '   _speedit_prefix__second_best_loop_sec = 99999999999.0',
         '   _speedit_prefix__worst_loop_sec = 0.0',
         '   _speedit_prefix__second_worst_loop_sec = 0.0',
         '   if _speedit_prefix__run_sec == -1:',
         '      # only run it once',
         '      _speedit_prefix__run_once = True',
         '   else:',
         '      _speedit_prefix__run_once = False',
         '   _speedit_prefix__main_start_time = _speedit_prefix__perf_counter()',
         '   while True:',
         '      _speedit_prefix__loops += 1',
         '      _speedit_prefix__result_time = 0',
         '',
         '      # ==================== START CODE BLOCK ==================== #',
         '',
      ]

      final_inner_function_lines.extend(final_param_line)
      final_inner_function_lines.extend(adjusted_func_code_line)

      inner_function_lines_rest = [
         '',
         '      # ==================== END CODE BLOCK ==================== #',
         '',
         '      _speedit_prefix__all_loops_time_sec += _speedit_prefix__result_time',
         '      if _speedit_prefix__result_time <= _speedit_prefix__best_loop_sec:',
         '         _speedit_prefix__second_best_loop_sec = _speedit_prefix__best_loop_sec',
         '         _speedit_prefix__best_loop_sec = _speedit_prefix__result_time',
         '      if _speedit_prefix__result_time >= _speedit_prefix__worst_loop_sec:',
         '         _speedit_prefix__second_worst_loop_sec = _speedit_prefix__worst_loop_sec',
         '         _speedit_prefix__worst_loop_sec = _speedit_prefix__result_time',
         '      if _speedit_prefix__run_once:',
         '         break',
         '      # check if we have to get out',
         '      if _speedit_prefix__perf_counter() - _speedit_prefix__main_start_time >= _speedit_prefix__run_sec:',
         '         break',
         '   _speedit_prefix__avg_loop_sec = _speedit_prefix__all_loops_time_sec / _speedit_prefix__loops',
         '   if _speedit_prefix__second_best_loop_sec == 99999999999.0:',
         '      _speedit_prefix__second_best_loop_sec = -1.0',
         '   if _speedit_prefix__second_worst_loop_sec == 0.0:',
         '      _speedit_prefix__second_worst_loop_sec = -1.0',
         '   return {',
         '      "loops": _speedit_prefix__loops,',
         '      "all_loops_time_sec": _speedit_prefix__all_loops_time_sec,',
         '      "avg_loop_sec": _speedit_prefix__avg_loop_sec,',
         '      "best_loop_sec": _speedit_prefix__best_loop_sec,',
         '      "second_best_loop_sec": _speedit_prefix__second_best_loop_sec,',
         '      "worst_loop_sec": _speedit_prefix__worst_loop_sec,',
         '      "second_worst_loop_sec": _speedit_prefix__second_worst_loop_sec',
         '   }',
         ''
      ]
      final_inner_function_lines.extend(inner_function_lines_rest)

      return '\n'.join(final_inner_function_lines)
예제 #4
0
 def parameter_names(self):
     r""" Return the names of the parameters in this model. """
     return tuple(inspect_signature(self.expectation).parameters.keys())[1:]