# -*- coding: utf-8 -*- # $Id$ import os import sys import token import parser import cc import pep8 class Scorer: def __init__(self, lines): self._lines = lines self._lnum = len(lines) self._code = ''.join(lines) self._bytes = len(self._code) self._nlines = [l for l in lines if not l.strip().startswith('#')] self._nlnum = len(self._nlines) self._nbytes = sum(len(l) for l in self._nlines) self._st = parser.suite(self._code) self._p8c = self._pep8count() self._cpsum, self._cplen = self._complexity() def _complexity(self, item='all'): try: stat = cc.measure_complexity(self._code, item) ccpp = cc.PrettyPrinter(None, True) cplx = zip(*ccpp.flatten_stats(stat))[-1] return sum(cplx) + 1, len(cplx) + 1 except: return 256, 1 def _pep8count(self, name=''): pep8.process_options([name]) p8ck = pep8.Checker(None) p8ck.lines = self._lines p8ck.filename = name try: tmpfp = sys.stdout sys.stdout = open(os.devnull, 'w') try: # nest for 2.4 or earlier return p8ck.check_all() + 1 except: return 256 finally: sys.stdout = tmpfp def _parsebytes(self, types): def litbytes(stp, bytes=0): if not stp: return bytes if stp[0] in types: bytes += len(stp[1]) else: for p in stp[1:]: bytes = litbytes(p, bytes) return bytes return litbytes(self._st.totuple()) @staticmethod def _strlen_max(seq, iferr=0): try: return max(len(l) for l in seq) except: return iferr def pep8_score(self): bytes = self._nbytes - self._parsebytes( [token.NUMBER, token.STRING, token.NAME, token.COLON]) return (bytes / ((self._nlnum / 256) + 1) / self._p8c) + 1 def complex_score(self): bmax = self._strlen_max(self._lines, 256) return (32 * self._cplen / ((bmax / 79) + 1) / \ ((self._cpsum / 12) + 1)) + 1 def lines_score(self): bmax = self._strlen_max(self._lines, 256) bytes = self._nbytes - self._parsebytes( [token.NUMBER, token.STRING, token.NAME, token.COLON]) return (bytes / ((bmax / (self._nlnum + 1)) + 1) / \ (self._nlnum + 1)) + 1 def const_score(self): cbytes = self._parsebytes([token.NUMBER, token.STRING]) + 1 return (self._nbytes + 1) // cbytes def colon_score(self): bytes = self._nbytes + 1 cbytes = self._parsebytes([token.COLON]) + 1 return (bytes // ((bytes // cbytes) + 1)) + 1 def name_score(self): bytes = self._nbytes + 1 nbytes = self._parsebytes([token.NAME]) + 1 return bytes // ((nbytes / 16) + 1)