Как pylint помнит оценки из предыдущих прогонов?

В типичном прогоне пилинга мы получаем следующий результат:

Global evaluation
-----------------
Your code has been rated at 9.50/10 (previous run: 8.50/10)

Duplication
-----------

+-------------------------+------+---------+-----------+
|                         |now   |previous |difference |
+=========================+======+=========+===========+
|nb duplicated lines      |0     |0        |=          |
+-------------------------+------+---------+-----------+
|percent duplicated lines |0.000 |0.000    |=          |
+-------------------------+------+---------+-----------+

Интересно, как pylint помнит оценки из предыдущих запусков. В приведенном выше примере оценка от предыдущего прогона была 8.5.

Я хочу реализовать такую ​​функциональность в своем собственном модуле, и я подумал, что сначала должен узнать, как pylint реализует функциональность.

Я искал скрытые папки, где эти данные могли быть сохранены, но не найден.

Ответ 1

У меня есть файл .pylintrc в моем домашнем каталоге, который включает следующую строку:

#pickle collected data for later comparisons.
persistent=yes

Итак, кажется, что pylint использует pickle для сравнения

В lint.py из исходного кода:

def make_options():
        return (('ignore',
                 {'type' : 'csv', 'metavar' : '<file>[,<file>...]',
                  'dest' : 'black_list', 'default' : ('CVS',),
                  'help' : 'Add files or directories to the blacklist. '
                           'They should be base names, not paths.'}),
                ('persistent',
                 {'default': True, 'type' : 'yn', 'metavar' : '<y_or_n>',
                  'level': 1,
                  'help' : 'Pickle collected data for later comparisons.'})

Полный lint.py источник здесь

Самый интересный бит - это, вероятно, этот метод:

def close(self):
        """close the whole package /module, it time to make reports !

        if persistent run, pickle results for later comparison
        """
        if self.file_state.base_name is not None:
            # load previous results if any
            previous_stats = config.load_results(self.file_state.base_name)
            # XXX code below needs refactoring to be more reporter agnostic
            self.reporter.on_close(self.stats, previous_stats)
            if self.config.reports:
                sect = self.make_reports(self.stats, previous_stats)
                if self.config.files_output:
                    filename = 'pylint_global.' + self.reporter.extension
                    self.reporter.set_output(open(filename, 'w'))
            else:
                sect = Section()
            if self.config.reports or self.config.output_format == 'html':
                self.reporter.display_results(sect)
            # save results if persistent run
            if self.config.persistent:
                config.save_results(self.stats, self.file_state.base_name)
        else:
            self.reporter.on_close(self.stats, {})

Вы также захотите посмотреть источник config.py

def load_results(base):
    """try to unpickle and return data from file if it exists and is not
    corrupted

    return an empty dictionary if it doesn't exists
    """
    data_file = get_pdata_path(base, 1)
    try:
        with open(data_file, _PICK_LOAD) as stream:
            return pickle.load(stream)
    except:
        return {}