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

Revision 79, 5.2 KB checked in by atzm, 13 years ago (diff)

fixed a bug, minus value

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