source: pycodebattler/trunk/pycodebattler/score.py @ 52

Revision 52, 4.7 KB checked in by atzm, 13 years ago (diff)

modify parameters

  • Property svn:keywords set to Id
Line 
1# -*- coding: utf-8 -*-
2# $Id$
3
4import os
5import sys
6import zlib
7import token
8import parser
9
10import cc
11import pep8
12
13
14def _compseq(seq, level):
15    c = zlib.compressobj(level)
16    return ''.join([c.compress(chunk) for chunk in seq] + [c.flush()])
17
18
19def _maxstrlen(seq, iferr=0):
20    try:
21        return max(len(l) for l in seq)
22    except:
23        return iferr
24
25
26class Scorer:
27    def __init__(self, lines):
28        self._code = ''.join(lines)
29        self._ccode = _compseq(lines, 9)
30        self._lines = lines
31        self._nlines = [l for l in lines
32                        if l.strip() and not l.strip().startswith('#')]
33
34        self._astpl = parser.suite(self.code()).totuple()
35        self._token_cache = {}
36
37        self.complexity()
38        self.style_errors()
39
40    def tupletree(self):
41        return self._astpl
42
43    def code(self):
44        return self._code
45
46    def lines(self):
47        return self._lines
48
49    def uncommented_lines(self):
50        return self._nlines
51
52    def bytes(self):
53        return len(self.code()) or 1
54
55    def uncommented_bytes(self):
56        return sum(len(l) for l in self.uncommented_lines()) or 1
57
58    def rows(self):
59        return len(self.lines()) or 1
60
61    def uncommented_rows(self):
62        return len(self.uncommented_lines()) or 1
63
64    def compressibility(self, level=6):
65        return float(len(self._ccode)) / self.bytes()
66
67    def token_bytes(self, types):
68        def _bytes(stp, bytes=0):
69            if not stp:
70                return bytes
71            if stp[0] in types:
72                bytes += len(stp[1])
73            else:
74                for p in stp[1:]:
75                    bytes = _bytes(p, bytes)
76            return bytes
77
78        types = tuple(types)
79
80        try:
81            ret = self._token_cache[types]
82        except KeyError:
83            ret = self._token_cache[types] = _bytes(self.tupletree())
84
85        return ret
86
87    def complexity(self, item='all', iferr=(256, 1)):
88        try:
89            stat = cc.measure_complexity(self._code, item)
90            ccpp = cc.PrettyPrinter(None, True)
91            cplx = zip(*ccpp.flatten_stats(stat))[-1]
92            self._ccsum = sum(cplx) or 1
93            self._cclen = len(cplx) or 1
94        except:
95            self._ccsum, self._cclen = iferr
96        return self._ccsum, self._cclen
97
98    def style_errors(self, name='', iferr=256):
99        pep8.process_options([name])
100        p8ck = pep8.Checker(None)
101        p8ck.lines = self._lines
102        p8ck.filename = name
103
104        try:
105            tmpfp = sys.stdout
106            sys.stdout = open(os.devnull, 'w')
107            self._estyle = p8ck.check_all() or 1
108        except:
109            self._estyle = iferr
110        finally:
111            sys.stdout = tmpfp
112        return self._estyle
113
114    def complex_score(self, coefficient=32):
115        maxlen = _maxstrlen(self.lines(), 256)
116        score = self._cclen * coefficient
117        score /= (maxlen / (coefficient * 2)) or 1
118        score /= (self._ccsum / ((coefficient / 3) or 1)) or 1
119        score *= self.compressibility()
120        return int(score) or 1
121
122    def style_score(self, coefficient=64):
123        data_bytes = self.token_bytes([token.NUMBER, token.STRING,
124                                       token.NAME, token.COLON])
125        score = self.uncommented_bytes() - data_bytes
126        score /= (self.uncommented_rows() / coefficient) or 1
127        score /= self._estyle
128        score *= (coefficient / 12) or 1
129        score *= self.compressibility()
130        return int(score) or 1
131
132    def lines_score(self, coefficient=4):
133        maxlen = _maxstrlen(self.lines(), 256)
134        data_bytes = self.token_bytes([token.NUMBER, token.STRING,
135                                       token.NAME, token.COLON])
136        score = self.uncommented_bytes() - data_bytes
137        score /= (maxlen / self.uncommented_rows()) or 1
138        score /= self.uncommented_rows()
139        score *= coefficient
140        score *= self.compressibility()
141        return int(score) or 1
142
143    def const_score(self, coefficient=2):
144        const_bytes = self.token_bytes([token.NUMBER, token.STRING]) or 1
145        score = self.uncommented_bytes() / const_bytes
146        score *= coefficient
147        score *= self.compressibility()
148        return int(score) or 1
149
150    def colon_score(self, coefficient=1):
151        colon_bytes = self.token_bytes([token.COLON]) or 1
152        score = self.uncommented_bytes()
153        score /= (score / colon_bytes) or 1
154        score *= coefficient
155        score *= self.compressibility()
156        return int(score) or 1
157
158    def name_score(self, coefficient=16):
159        name_bytes = self.token_bytes([token.NAME]) or 1
160        score = self.uncommented_bytes()
161        score /= (name_bytes / coefficient) or 1
162        score *= self.compressibility()
163        return int(score) or 1
Note: See TracBrowser for help on using the repository browser.