[45] | 1 | # -*- coding: utf-8 -*- |
---|
[47] | 2 | # $Id$ |
---|
[45] | 3 | |
---|
| 4 | import os |
---|
| 5 | import sys |
---|
| 6 | import token |
---|
| 7 | import parser |
---|
| 8 | |
---|
| 9 | import cc |
---|
| 10 | import pep8 |
---|
| 11 | |
---|
| 12 | |
---|
| 13 | class Scorer: |
---|
| 14 | def __init__(self, lines): |
---|
| 15 | self._lines = lines |
---|
| 16 | self._lnum = len(lines) |
---|
| 17 | self._code = ''.join(lines) |
---|
| 18 | self._bytes = len(self._code) |
---|
| 19 | |
---|
| 20 | self._nlines = [l for l in lines if not l.strip().startswith('#')] |
---|
| 21 | self._nlnum = len(self._nlines) |
---|
| 22 | self._nbytes = sum(len(l) for l in self._nlines) |
---|
| 23 | |
---|
| 24 | self._st = parser.suite(self._code) |
---|
| 25 | self._p8c = self._pep8count() |
---|
| 26 | self._cpsum, self._cplen = self._complexity() |
---|
| 27 | |
---|
| 28 | def _complexity(self, item='all'): |
---|
| 29 | try: |
---|
| 30 | stat = cc.measure_complexity(self._code, item) |
---|
| 31 | ccpp = cc.PrettyPrinter(None, True) |
---|
| 32 | cplx = zip(*ccpp.flatten_stats(stat))[-1] |
---|
| 33 | return sum(cplx) + 1, len(cplx) + 1 |
---|
| 34 | except: |
---|
| 35 | return 256, 1 |
---|
| 36 | |
---|
| 37 | def _pep8count(self, name=''): |
---|
| 38 | pep8.process_options([name]) |
---|
| 39 | p8ck = pep8.Checker(None) |
---|
| 40 | p8ck.lines = self._lines |
---|
| 41 | p8ck.filename = name |
---|
| 42 | |
---|
| 43 | try: |
---|
| 44 | tmpfp = sys.stdout |
---|
| 45 | sys.stdout = open(os.devnull, 'w') |
---|
| 46 | |
---|
| 47 | try: # nest for 2.4 or earlier |
---|
| 48 | return p8ck.check_all() + 1 |
---|
| 49 | except: |
---|
| 50 | return 256 |
---|
| 51 | finally: |
---|
| 52 | sys.stdout = tmpfp |
---|
| 53 | |
---|
| 54 | def _parsebytes(self, types): |
---|
| 55 | def litbytes(stp, bytes=0): |
---|
| 56 | if not stp: |
---|
| 57 | return bytes |
---|
| 58 | if stp[0] in types: |
---|
| 59 | bytes += len(stp[1]) |
---|
| 60 | else: |
---|
| 61 | for p in stp[1:]: |
---|
| 62 | bytes = litbytes(p, bytes) |
---|
| 63 | return bytes |
---|
| 64 | return litbytes(self._st.totuple()) |
---|
| 65 | |
---|
| 66 | @staticmethod |
---|
| 67 | def _strlen_max(seq, iferr=0): |
---|
| 68 | try: |
---|
| 69 | return max(len(l) for l in seq) |
---|
| 70 | except: |
---|
| 71 | return iferr |
---|
| 72 | |
---|
| 73 | def pep8_score(self): |
---|
| 74 | bytes = self._nbytes - self._parsebytes( |
---|
| 75 | [token.NUMBER, token.STRING, token.NAME, token.COLON]) |
---|
| 76 | return (bytes / ((self._nlnum / 256) + 1) / self._p8c) + 1 |
---|
| 77 | |
---|
| 78 | def complex_score(self): |
---|
| 79 | bmax = self._strlen_max(self._lines, 256) |
---|
| 80 | return (32 * self._cplen / ((bmax / 79) + 1) / \ |
---|
| 81 | ((self._cpsum / 12) + 1)) + 1 |
---|
| 82 | |
---|
| 83 | def lines_score(self): |
---|
| 84 | bmax = self._strlen_max(self._lines, 256) |
---|
| 85 | bytes = self._nbytes - self._parsebytes( |
---|
| 86 | [token.NUMBER, token.STRING, token.NAME, token.COLON]) |
---|
| 87 | return (bytes / ((bmax / (self._nlnum + 1)) + 1) / \ |
---|
| 88 | (self._nlnum + 1)) + 1 |
---|
| 89 | |
---|
| 90 | def const_score(self): |
---|
| 91 | cbytes = self._parsebytes([token.NUMBER, token.STRING]) + 1 |
---|
| 92 | return (self._nbytes + 1) // cbytes |
---|
| 93 | |
---|
| 94 | def colon_score(self): |
---|
| 95 | bytes = self._nbytes + 1 |
---|
| 96 | cbytes = self._parsebytes([token.COLON]) + 1 |
---|
| 97 | return (bytes // ((bytes // cbytes) + 1)) + 1 |
---|
| 98 | |
---|
| 99 | def name_score(self): |
---|
| 100 | bytes = self._nbytes + 1 |
---|
| 101 | nbytes = self._parsebytes([token.NAME]) + 1 |
---|
| 102 | return bytes // ((nbytes / 16) + 1) |
---|