Changeset 40

Show
Ignore:
Timestamp:
06/07/06 17:27:35 (7 years ago)
Author:
mk
Message:

Refactored code for index computation (closes tickets #17 #18 #19 #20 #21 #22).

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • branches/mk/cheesecake/_util.py

    r11 r40  
    3232    output = p.communicate()[0] 
    3333    return p.returncode, output 
     34 
     35def command_successful(cmd): 
     36    """Returns True if command exited normally, False otherwise. 
     37    """ 
     38    rc, output = run_cmd(cmd) 
     39    if rc: 
     40        return False 
     41    return True 
    3442 
    3543class StdoutRedirector(object): 
  • branches/mk/cheesecake/cheesecake_index.py

    r38 r40  
    2626from math import ceil 
    2727 
    28 from _util import run_cmd, pad_with_dots, pad_left_spaces, pad_msg, pad_line 
     28from _util import run_cmd, pad_with_dots, pad_left_spaces, pad_msg, pad_line, command_successful 
    2929from _util import StdoutRedirector 
    3030import logger 
     
    3232from codeparser import CodeParser 
    3333 
    34 default_temp_directory = os.path.join(tempfile.gettempdir(), 'cheesecake_sandbox') 
    35  
     34__docformat__ = 'reStructuredText en' 
     35 
     36 
     37default_temp_directory = os.path.join(tempfile.gettempdir(), 
     38                                      'cheesecake_sandbox') 
     39 
     40################################################################################ 
     41## Helpers. 
     42################################################################################ 
     43 
     44def isiterable(obj): 
     45    return hasattr(obj, '__iter__') 
    3646 
    3747def has_extension(filename, ext): 
     
    4757    return os.path.splitext(filename)[1] == ext 
    4858 
     59def discover_file_type(filename): 
     60    """Discover type of a file according to its name and its parent directory. 
     61 
     62    Currently supported file types: 
     63        * pyc 
     64        * pyo 
     65        * module: .py files of an application 
     66        * demo: .py files for documentation/demonstration purposes 
     67        * test: .py files used for testing 
     68        * special: .py file for special purposes 
     69 
     70    :Note: This function only check file's name, and doesn't touch the 
     71           filesystem. If you have to, check if file exists by yourself. 
     72 
     73    >>> discover_file_type('module.py') 
     74    'module' 
     75    >>> discover_file_type('./setup.py') 
     76    'special' 
     77    >>> discover_file_type('some/directory/junk.pyc') 
     78    'pyc' 
     79    """ 
     80    dirs = filename.split(os.path.sep) 
     81    dirs, filename = dirs[:-1], dirs[-1] 
     82 
     83    if filename in ["setup.py", "ez_setup.py", "__pkginfo__.py"]: 
     84        return 'special' 
     85 
     86    if has_extension(filename, ".pyc"): 
     87        return 'pyc' 
     88    if has_extension(filename, ".pyo"): 
     89        return 'pyo' 
     90    if has_extension(filename, ".py"): 
     91        for dir in dirs: 
     92            if dir in ['test', 'tests']: 
     93                return 'test' 
     94            elif dir in ['docs', 'demo', 'example']: 
     95                return 'demo' 
     96        return 'module' 
     97 
     98def get_files_of_type(file_list, file_type): 
     99    """Return files from `file_list` that match given `file_type`. 
     100 
     101    >>> file_list = ['test/test_foo.py', 'setup.py', 'README', 'test/test_bar.py'] 
     102    >>> get_files_of_type(file_list, 'test') 
     103    ['test/test_foo.py', 'test/test_bar.py'] 
     104    """ 
     105    return filter(lambda x: discover_file_type(x) == file_type, file_list) 
     106 
     107def get_method_arguments(method): 
     108    """Return tuple of arguments for given method, excluding self. 
     109 
     110    >>> class Class: 
     111    ...     def method(s, arg1, arg2, other_arg): 
     112    ...         pass 
     113    >>> get_method_arguments(Class.method) 
     114    ('arg1', 'arg2', 'other_arg') 
     115    """ 
     116    return method.func_code.co_varnames[1:method.func_code.co_argcount] 
     117 
     118def get_attributes(obj, names): 
     119    """Return attributes dictionary with keys from `names`. 
     120 
     121    Object is queried for each attribute name, if it doesn't have this 
     122    attribute, default value None will be returned. 
     123 
     124    >>> class Class: 
     125    ...     pass 
     126    >>> obj = Class() 
     127    >>> obj.attr = True 
     128    >>> obj.value = 13 
     129    >>> obj.string = "Hello" 
     130 
     131    >>> d = get_attributes(obj, ['attr', 'string', 'other']) 
     132    >>> d == {'attr': True, 'string': "Hello", 'other': None} 
     133    True 
     134    """ 
     135    attrs = {} 
     136 
     137    for name in names: 
     138        attrs[name] = getattr(obj, name, None) 
     139 
     140    return attrs 
     141 
     142def camel2underscore(name): 
     143    """Convert name from CamelCase to underscore_name. 
     144 
     145    >>> camel2underscore('CamelCase') 
     146    'camel_case' 
     147    >>> camel2underscore('already_underscore_name') 
     148    'already_underscore_name' 
     149    >>> camel2underscore('BigHTMLClass') 
     150    'big_html_class' 
     151    >>> camel2underscore('') 
     152    '' 
     153    """ 
     154    if name and name[0].upper: 
     155        name = name[0].lower() + name[1:] 
     156 
     157    def capitalize(match): 
     158        string = match.group(1).lower().capitalize() 
     159        return string[:-1] + string[-1].upper() 
     160 
     161    def underscore(match): 
     162        return '_' + match.group(1).lower() 
     163 
     164    name = re.sub(r'([A-Z]+)', capitalize, name) 
     165    return re.sub(r'([A-Z])', underscore, name) 
     166 
     167def index_class_to_name(clsname): 
     168    """Covert index class name to index name. 
     169 
     170    >>> index_class_to_name("IndexDownload") 
     171    'download' 
     172    >>> index_class_to_name("IndexUnitTests") 
     173    'unit_tests' 
     174    >>> index_class_to_name("IndexPyPIDownload") 
     175    'py_pi_download' 
     176    """ 
     177    return camel2underscore(clsname.replace('Index', '', 1)) 
     178 
     179def is_empty(path): 
     180    """Returns True if file or directory pointed by `path` is empty. 
     181    """ 
     182    if os.path.isfile(path) and os.path.getsize(path) == 0: 
     183        return True 
     184    if os.path.isdir(path) and os.listdir(path) == []: 
     185        return True 
     186 
     187    return False 
     188 
     189def strip_dir_part(path, root): 
     190    """Strip `root` part from `path`. 
     191 
     192    >>> strip_dir_part('/home/ruby/file', '/home') 
     193    'ruby/file' 
     194    >>> strip_dir_part('/home/ruby/file', '/home/') 
     195    'ruby/file' 
     196    >>> strip_dir_part('/home/ruby/', '/home') 
     197    'ruby/' 
     198    >>> strip_dir_part('/home/ruby/', '/home/') 
     199    'ruby/' 
     200    """ 
     201    path = path.replace(root, '', 1) 
     202 
     203    if path.startswith(os.path.sep): 
     204        path = path[1:] 
     205 
     206    return path 
     207 
     208def get_files_dirs_list(root): 
     209    """Return list of all files and directories below `root`. 
     210 
     211    Root directory is excluded from files/directories paths. 
     212    """ 
     213    files = [] 
     214    directories = [] 
     215 
     216    for dirpath, dirnames, filenames in os.walk(root): 
     217        dirpath = strip_dir_part(dirpath, root) 
     218        files.extend(map(lambda x: os.path.join(dirpath, x), filenames)) 
     219        directories.extend(map(lambda x: os.path.join(dirpath, x), dirnames)) 
     220 
     221    return files, directories 
     222 
     223################################################################################ 
     224## Main index class. 
     225################################################################################ 
     226 
     227class NameSetter(type): 
     228    def __init__(cls, name, bases, dict): 
     229        if 'name' not in dict: 
     230            setattr(cls, 'name', index_class_to_name(name)) 
     231 
     232def make_indices_dict(indices): 
     233    indices_dict = {} 
     234    for index in indices: 
     235        indices_dict[index.name] = index 
     236    return indices_dict 
    49237 
    50238class Index(object): 
    51     """ 
    52     Encapsulates index attributes such as name, value, details 
    53     """ 
    54  
    55     def __init__(self, type, name="", value=0, details=""): 
    56         self.type = "index_" + type 
    57         self.name = self.type 
    58         if name: self.name += "_" + name 
    59         self.value = value 
    60         self.details = details 
    61          
     239    """Class describing one index. 
     240 
     241    Use it as a container index or subclass to create custom indices. 
     242 
     243    During class initialization, special attribute `name` is magically 
     244    set based on class name. See `index_class_to_name` and `NameSetter` 
     245    definitions for details. 
     246    """ 
     247    __metaclass__ = NameSetter 
     248 
     249    subindices = None 
     250 
     251    name = "unnamed" 
     252    value = -1 
     253    details = "" 
     254 
     255    def __init__(self, indices=[]): 
     256        if not self.subindices: 
     257            self.subindices = [] 
     258 
     259        # Create dictionary for fast reference. 
     260        self._indices_dict = make_indices_dict(self.subindices) 
     261 
     262        for index in indices: 
     263            self.add_subindex(index) 
     264 
     265        self._compute_arguments = get_method_arguments(self.compute) 
     266 
     267    def _iter_indices(self): 
     268        """Iterate over each subindex and yield their values. 
     269        """ 
     270        for index in self.subindices: 
     271            # Pass Cheesecake instance to other indices. 
     272            yield index.compute_with(self.cheesecake) 
     273            # Print index info after computing. 
     274            index.print_info() 
     275 
     276    def compute_with(self, cheesecake): 
     277        """Take given Cheesecake instance and compute index value. 
     278        """ 
     279        self.cheesecake = cheesecake 
     280        return self.compute(**get_attributes(cheesecake, self._compute_arguments)) 
     281 
     282    def compute(self): 
     283        """Compute index value and return it. 
     284 
     285        By default this method computes sum of all subindices. Override this 
     286        method when subclassing for different behaviour. 
     287 
     288        Parameters to this function are dynamically prepared with use of 
     289        `get_attributes` function. 
     290 
     291        :Warning: Don't use *args and **kwds arguments for this method. 
     292        """ 
     293        self.value = sum(self._iter_indices()) 
     294        return self.value 
     295 
     296    def _get_max_value(self): 
     297        if self.subindices: 
     298            return sum(map(lambda index: index.max_value, 
     299                           self.subindices)) 
     300        return 0 
     301 
     302    max_value = property(_get_max_value) 
     303 
     304    def add_subindex(self, index): 
     305        """Add subindex. 
     306 
     307        :Parameters: 
     308          `index` : Index instance 
     309              Index instance for inclusion. 
     310        """ 
     311        if not isinstance(index, Index): 
     312            raise ValueError("subindex have to be instance of Index") 
     313 
     314        self.subindices.append(index) 
     315        self._indices_dict[index.name] = index 
     316 
    62317    def print_info(self): 
    63         """ 
    64         Print index name padded with dots, followed by value and details 
    65         """ 
    66         msg = pad_with_dots(self.name) 
    67         msg += pad_left_spaces(self.value) 
    68         msg += " (" + self.details + ")" 
     318        """Print index name padded with dots, followed by value and details. 
     319        """ 
     320        print "%s%s (%s)" % (pad_with_dots(self.name), 
     321                             pad_left_spaces(self.value), 
     322                             self.details) 
     323 
     324    def __getitem__(self, name): 
     325        return self._indices_dict[name] 
     326 
     327class MegaIndex(Index): 
     328    """Index with special information schema, suitable for composite indices. 
     329    """ 
     330    def print_info(self): 
     331        max_value = self.max_value 
     332        if max_value == 0: 
     333            return 
     334 
     335        percentage = int(ceil(float(self.value) / float(max_value) * 100)) 
     336        print pad_line("-") 
     337 
     338        print pad_msg("%s INDEX (ABSOLUTE)" % self.name, self.value) 
     339        msg = pad_msg("%s INDEX (RELATIVE)" % self.name, percentage) 
     340        msg += " (%d out of a maximum of %d points is %d%%)" %\ 
     341             (self.value, max_value, percentage) 
     342 
    69343        print msg 
    70  
    71 class CompositeIndex(object): 
    72     """ 
    73     Collection of indexes of same type (e.g. files, dirs) 
    74     """ 
    75  
    76     def __init__(self, type): 
    77         """ 
    78         Indexes is a dict mapping names to Index objects 
    79         """ 
    80         self.type = type 
    81         self.indexes = {} 
    82  
    83     def set_index(self, name, value=0, details=""): 
    84         """ 
    85         Create new index or update existing index with specified attributes 
    86         """ 
    87         if self.indexes.has_key(name): 
    88             index = self.indexes[name] 
    89             index.value = value 
    90             index.details = details 
     344        print 
     345 
     346################################################################################ 
     347## Installability index. 
     348################################################################################ 
     349 
     350class IndexUrlDownload(Index): 
     351    max_value = 25 
     352 
     353    def compute(self, downloaded_from_url, package, url): 
     354        if downloaded_from_url: 
     355            self.details = "downloaded package %s from URL %s"  % (package, url) 
     356            self.value = self.max_value 
    91357        else: 
    92             self.indexes[name] = Index(self.type, name, value, details) 
    93          
    94     def print_info(self): 
    95         """ 
    96         Print index info for all indexes sorted alphanumerically by name 
    97         """ 
    98         names = self.indexes.keys() 
    99         names.sort() 
    100         for name in names: 
    101             index = self.indexes[name] 
    102             index.print_info() 
    103  
    104     def get_value(self): 
    105         """ 
    106         Return sum of individual index values 
    107         """ 
    108         value = 0 
    109         for key in self.indexes.keys(): 
    110             index = self.indexes[key] 
    111             value += index.value 
    112         return value 
    113  
    114     value = property(get_value) 
     358            self.value = 0 
     359 
     360        return self.value 
     361 
     362class IndexUnpack(Index): 
     363    max_value = 25 
     364 
     365    def compute(self, unpacked): 
     366        if unpacked: 
     367            self.details = "package unpacked successfully" 
     368            self.value = self.max_value 
     369        else: 
     370            self.value = 0 
     371 
     372        return self.value 
     373 
     374class IndexUnpackDir(Index): 
     375    max_value = 15 
     376 
     377    def compute(self, unpack_dir, original_package_name): 
     378        self.details = "unpack directory is " + unpack_dir 
     379 
     380        if original_package_name: 
     381            self.details += " instead of the expected " + original_package_name 
     382            self.value = 0 
     383        else: 
     384            self.details += " as expected" 
     385            self.value = self.max_value 
     386 
     387        return self.value 
     388 
     389class IndexInstall(Index): 
     390    max_value = 50 
     391 
     392    def compute(self, installed, sandbox_install_dir): 
     393        if installed: 
     394            self.details = "package installed in %s" % sandbox_install_dir 
     395            self.value = self.max_value 
     396        else: 
     397            self.details = "could not install package in %s" % sandbox_install_dir 
     398            self.value = 0 
     399 
     400        return self.value 
     401 
     402class IndexPyPIDownload(Index): 
     403    max_value = 50 
     404    distance_penalty = -5 
     405 
     406    def compute(self, package, found_on_cheeseshop, distance_from_pypi, download_url): 
     407        if download_url: 
     408            self.value = self.max_value 
     409 
     410            self.details = "downloaded package " + package 
     411 
     412            if not found_on_cheeseshop: 
     413                self.value += distance_from_pypi * self.distance_penalty 
     414 
     415                if distance_from_pypi: 
     416                    self.details += " following %d link" % distance_from_pypi 
     417                    if distance_from_pypi > 1: 
     418                        self.details += "s" 
     419                        self.details += " from PyPI" 
     420                    else: 
     421                        self.details += " from " + download_url 
     422            else: 
     423                self.details += " directly from the Cheese Shop" 
     424        else: 
     425            self.value = 0 
     426 
     427        return self.value 
     428 
     429class IndexGeneratedFiles(Index): 
     430    generated_files_penalty = -20 
     431 
     432    def compute(self, files_list): 
     433        self.value = 0 
     434 
     435        pyc_files = len(get_files_of_type(files_list, 'pyc')) 
     436        pyo_files = len(get_files_of_type(files_list, 'pyo')) 
     437 
     438        if pyc_files > 0 or pyo_files > 0: 
     439            self.value += self.generated_files_penalty 
     440 
     441        self.details = "%d .pyc and %d .pyo files found" % \ 
     442                                  (pyc_files, pyo_files) 
     443 
     444        return self.value 
     445 
     446class IndexInstallability(MegaIndex): 
     447    name = "INSTALLABILITY" 
     448 
     449    subindices = [ 
     450        IndexUnpack(), 
     451        IndexUnpackDir(), 
     452        IndexInstall(), 
     453        IndexGeneratedFiles(), 
     454    ] 
     455 
     456################################################################################ 
     457## Documentation index. 
     458################################################################################ 
     459 
     460def match_filename(name, rule): 
     461    """Check if `name` matches given `rule`. 
     462    """ 
     463    def equal(x, y): 
     464        x_root, x_ext = os.path.splitext(x) 
     465        y_root, y_ext = os.path.splitext(y.lower()) 
     466        if x_root in [y_root.lower(), y_root.upper(), y_root.capitalize()] \ 
     467               and x_ext in [y_ext.lower(), y_ext.upper()]: 
     468            return True 
     469        return False 
     470 
     471    if isinstance(rule, basestring): 
     472        if equal(name, rule): 
     473            return True 
     474    elif isinstance(rule, OneOf) and not rule.used: 
     475        for poss in rule.possibilities: 
     476            if match_filename(name, poss): 
     477                rule.used = True 
     478                return True 
     479 
     480    return False 
     481 
     482class OneOf(object): 
     483    def __init__(self, *possibilities): 
     484        self.possibilities = possibilities 
     485        self.used = False 
     486    def __str__(self): 
     487        return 'one of %s' % (self.possibilities,) 
     488 
     489def WithOptionalExt(name, extensions): 
     490    """Handy way of writing Cheese rules for files with extensions. 
     491 
     492    Instead of writing: 
     493        >>> one_of = OneOf('readme', 'readme.html', 'readme.txt') 
     494 
     495    Write this: 
     496        >>> opt_ext = WithOptionalExt('readme', ['html', 'txt']) 
     497 
     498    It means the same! (representation have a meaning) 
     499        >>> str(one_of) == str(opt_ext) 
     500        True 
     501    """ 
     502    possibilities = [name] 
     503    possibilities.extend(map(lambda x: name + '.' + x, extensions)) 
     504 
     505    return OneOf(*possibilities) 
     506 
     507def Doc(name): 
     508    return WithOptionalExt(name, ['html', 'txt']) 
     509 
     510class IndexRequiredFiles(Index): 
     511    cheese_files = { 
     512        'setup.py': 15, 
     513        Doc('readme'): 15, 
     514        OneOf(Doc('license'), Doc('copying')): 15, 
     515 
     516        Doc('authors'): 10, 
     517        Doc('announce'): 10, 
     518        Doc('changelog'): 10, 
     519        Doc('faq'): 10, 
     520        Doc('install'): 10, 
     521        Doc('news'): 10, 
     522        Doc('thanks'): 10, 
     523        Doc('todo'): 10, 
     524    } 
     525 
     526    cheese_dirs = { 
     527        'demo': 20, 
     528        'doc': 25, 
     529        'example': 20, 
     530        OneOf('test', 'tests'): 25, 
     531    } 
     532 
     533    max_value = sum(cheese_files.values() + cheese_dirs.values()) 
     534 
     535    def compute(self, files_list, dirs_list, package_dir): 
     536        self.value = 0 
     537        self.reset_rules(self.cheese_files.keys() + self.cheese_dirs.keys()) 
     538 
     539        files_count = 0 
     540        for filename in files_list: 
     541            if not is_empty(os.path.join(package_dir, filename)): 
     542                score = self.get_score(os.path.basename(filename), self.cheese_files) 
     543                if score != 0: 
     544                    self.value += score 
     545                    files_count += 1 
     546 
     547        directories_count = 0 
     548        for directory in dirs_list: 
     549            if not is_empty(os.path.join(package_dir, directory)): 
     550                score = self.get_score(os.path.basename(directory), self.cheese_dirs) 
     551                if score != 0: 
     552                    self.value += score 
     553                    directories_count += 1 
     554 
     555        self.details = "%d files and %d required directories found" % \ 
     556                       (files_count, directories_count) 
     557 
     558        return self.value 
     559 
     560    def get_score(self, name, specs): 
     561        for entry, value in specs.iteritems(): 
     562            if match_filename(name, entry): 
     563                self.cheesecake.log.debug("%d points entry found: %s (%s)" % \ 
     564                                          (value, name, entry)) 
     565                return value 
     566 
     567        return 0 
     568 
     569    def reset_rules(self, rules): 
     570        if isiterable(rules): 
     571            for rule in rules: 
     572                self.reset_rules(rule) 
     573        elif isinstance(rules, OneOf): 
     574            rules.used = False 
     575            self.reset_rules(rules.possibilities) 
     576 
     577class IndexDocstrings(Index): 
     578    max_value = 100 
     579 
     580    def compute(self, object_cnt, docstring_cnt): 
     581        percent = 0 
     582        if object_cnt > 0: 
     583            percent = float(docstring_cnt)/float(object_cnt) 
     584 
     585        # Scale the result. 
     586        self.value = int(ceil(percent * self.max_value)) 
     587 
     588        self.details = "found %d/%d=%.2f%% objects with docstrings" %\ 
     589                 (docstring_cnt, object_cnt, percent*100) 
     590 
     591        return self.value 
     592 
     593class IndexFormattedDocstrings(Index): 
     594    max_value = 50 
     595 
     596    def compute(self, object_cnt, docformat_cnt): 
     597        percent = 0 
     598        if object_cnt > 0: 
     599            percent = float(docformat_cnt)/float(object_cnt) 
     600 
     601        # Scale the result. 
     602        self.value = int(ceil(percent * self.max_value)) 
     603 
     604        self.details = "found %d/%d=%.2f%% objects with formatted docstrings" %\ 
     605                 (docformat_cnt, object_cnt, percent*100) 
     606 
     607        return self.value 
     608 
     609class IndexDocumentation(MegaIndex): 
     610    name = "DOCUMENTATION" 
     611 
     612    subindices = [ 
     613        IndexRequiredFiles(), 
     614        IndexDocstrings(), 
     615        IndexFormattedDocstrings(), 
     616    ] 
     617 
     618################################################################################ 
     619## Code "kwalitee" index. 
     620################################################################################ 
     621 
     622class IndexUnitTests(Index): 
     623    """Compute unittest index as percentage of methods/functions 
     624    that are exercised in unit tests. 
     625    """ 
     626    max_value = 50 
     627 
     628    def compute(self, files_list, functions, package_dir): 
     629        unittest_cnt = 0 
     630        self.functions_tested = {} 
     631 
     632        for testfile in get_files_of_type(files_list, 'test'): 
     633            fullpath = os.path.join(package_dir, testfile) 
     634            code = CodeParser(fullpath, self.cheesecake.log.debug) 
     635 
     636            func_called = code.functions_called() 
     637 
     638            for func in func_called: 
     639                self.functions_tested[func] = 1 
     640 
     641        for funcname in functions: 
     642            if self.is_unit_tested(funcname): 
     643                unittest_cnt += 1 
     644                self.log.cheesecake.debug("%s is unit tested" % funcname) 
     645 
     646        percent = 0 
     647        if len(functions) > 0: 
     648            percent = float(unittest_cnt)/float(len(functions)) 
     649 
     650        # Scale the result. 
     651        self.value = int(ceil(percent * self.max_value)) 
     652 
     653        self.details = "found %d/%d=%.2f%% unit tested methods/functions." %\ 
     654                 (unittest_cnt, len(functions), percent*100) 
     655 
     656        return self.value 
     657 
     658    def is_unit_tested(self, funcname): 
     659        elem = funcname.split(".") 
     660        n1 = elem[-1] 
     661        n2 = "" 
     662        if len(elem) > 1: 
     663            n2 = elem[-2] + "." + elem[-1] 
     664        for key in self.functions_tested.keys(): 
     665            if key.startswith(n1) or (n2 and key.startswith(n2)): 
     666                return True 
     667        return False 
     668 
     669class IndexPyLint(Index): 
     670    """Compute pylint index as average of positive pylint scores obtained for 
     671    the Python files identified in the package. 
     672    """ 
     673    name = "pylint" 
     674    max_value = 50 
     675 
     676    def compute(self, files_list, package_dir): 
     677        self.value = 0 
     678 
     679        # Try to run the pylint script 
     680        if not command_successful("pylint --version"): 
     681            self.details = "pylint not properly installed" 
     682            return self.value 
     683 
     684        pylint_value = 0 
     685        cnt = 0 
     686        for pyfile in get_files_of_type(files_list, 'module'): 
     687            fullpath = os.path.join(package_dir, pyfile) 
     688            path, filename = os.path.split(fullpath) 
     689            module, ext = os.path.splitext(filename) 
     690 
     691            self.cheesecake.log.debug("Running pylint on file " + fullpath) 
     692            rc, output = run_cmd("pylint " + fullpath) 
     693            if rc: 
     694                self.cheesecake.log.debug("encountered an error (%d)." % rc) 
     695                continue 
     696 
     697            score_line = output.split("\n")[-3] 
     698            s = re.search(r" (\d+\.\d+)/10", score_line) 
     699            # We only take positive scores into account 
     700            if s: 
     701                score = s.group(1) 
     702                if score == "0.00": 
     703                    self.cheesecake.log.debug("ignoring 0.00 score.") 
     704                    continue 
     705                else: 
     706                    self.cheesecake.log.debug("pylint score for module %s: %s" % (module, score)) 
     707                pylint_value += float(score) 
     708                cnt += 1 
     709 
     710        avg_score = 0 
     711        if cnt: 
     712            avg_score = float(pylint_value)/float(cnt) 
     713 
     714        self.value = int(ceil(avg_score/10.0 * self.max_value)) 
     715        self.details = "average pylint score is %.2f out of 10" % avg_score 
     716 
     717        return self.value 
     718 
     719class IndexCodeKwalitee(MegaIndex): 
     720    name = "CODE KWALITEE" 
     721 
     722    subindices = [ 
     723        IndexPyLint(), 
     724        # IndexUnitTests(), TODO 
     725    ] 
     726 
     727################################################################################ 
     728## Main Cheesecake class. 
     729################################################################################ 
    115730 
    116731class CheesecakeError(Exception): 
     
    119734    """ 
    120735    pass 
     736 
     737 
     738class CheesecakeIndex(Index): 
     739    name = "Cheesecake" 
     740    subindices = [ 
     741        IndexInstallability(), 
     742        IndexDocumentation(), 
     743        IndexCodeKwalitee(), 
     744    ] 
     745 
    121746 
    122747class Cheesecake(object): 
     
    135760        * average pylint score for all non-test and non-demo modules 
    136761    """ 
     762    index = CheesecakeIndex() 
    137763 
    138764    def __init__(self, name="", url="", path="", sandbox=None, config=None, 
    139765                logfile=None, verbose=False, quiet=False): 
    140         """ 
    141         Initialize critical variables, download and unpack package, walk package tree 
    142  
     766        """Initialize critical variables, download and unpack package, 
     767        walk package tree. 
    143768        """ 
    144769        self.name = name 
     
    162787        self.sandbox_install_dir = "" 
    163788 
     789        # Include indices revelant to current situation. 
     790        if self.name: 
     791            self.index["INSTALLABILITY"].add_subindex(IndexPyPIDownload()) 
     792        if self.url: 
     793            self.index["INSTALLABILITY"].add_subindex(IndexUrlDownload()) 
     794 
    164795        self.determine_pkg_name() 
    165796        self.configure_logging(logfile) 
    166         self.set_defaults() 
    167         self.get_config() 
    168         self.init_indexes() 
     797        #self.set_defaults() 
     798        #self.get_config() 
    169799        self.retrieve_pkg() 
    170800        self.unpack_pkg() 
    171801        self.walk_pkg() 
     802        self.install_pkg() 
    172803 
    173804    def raise_exception(self, msg): 
    174         """ 
    175         Cleanup, print error message and raise CheesecakeError 
    176  
    177         Don't use logging, since it can be called before logging has been setup 
     805        """Cleanup, print error message and raise CheesecakeError. 
     806 
     807        Don't use logging, since it can be called before logging has been setup. 
    178808        """ 
    179809        self.cleanup() 
     
    184814  
    185815    def cleanup(self): 
    186         """ 
    187         Delete temporary directories and files that were 
    188         created in the sandbox. At the end delete the sandbox itself. 
     816        """Delete temporary directories and files that were created 
     817        in the sandbox. At the end delete the sandbox itself. 
    189818        """ 
    190819        if os.path.isfile(self.sandbox_pkg_file): 
     
    198827                shutil.rmtree(dirname) 
    199828 
    200         for dir in [self.sandbox_pkg_dir, self.sandbox_install_dir, 
    201                     self.sandbox]: 
    202             delete_dir(dir) 
     829        delete_dir(self.sandbox) 
    203830 
    204831    def set_defaults(self): 
    205         """ 
    206         Set default values for variables that can also be defined 
    207         in the config file 
    208         """ 
    209         self.INDEX_PYPI_DOWNLOAD = 50 
    210         self.INDEX_PYPI_DISTANCE = 5 
    211         self.INDEX_URL_DOWNLOAD  = 25 
    212         self.INDEX_UNPACK        = 25 
    213         self.INDEX_UNPACK_DIR    = 15 
    214         self.INDEX_INSTALL       = 50 
    215         self.INDEX_FILE_CRITICAL = 15 
    216         self.INDEX_FILE          = 10 
    217         self.INDEX_REQUIRED_FILES = 100 
    218         self.INDEX_FILE_PYC      = -20 
    219         self.INDEX_FILE_PYO      = -20 
    220         self.INDEX_DIR_CRITICAL  = 25 
    221         self.INDEX_DIR           = 20 
    222         self.INDEX_DIR_EMPTY     = 5 
    223         self.MAX_INDEX_DOCSTRINGS = 100 # max. percentage of modules/classes/methods/functions with docstrings 
    224         self.MAX_INDEX_DOCFORMAT  = 100 # max. percentage of modules/classes/methods/functions with formatted docstrings 
    225         self.MAX_INDEX_UNITTESTS  = 100 # max. percentage of methods/functions that are unit tested 
    226         self.MAX_INDEX_PYLINT     = 100 # max. pylint score 
    227         self.cheese_files = ["readme", "install", "changelog", 
    228                             "news", "faq", 
    229                             "todo", "thanks", 
    230                             "license", "announce", 
    231                             "setup.py", 
    232                             ] 
    233         self.critical_cheese_files = ["readme", "license", "setup.py"] 
    234         self.cheese_dirs = ["doc", "test", "example", "demo"] 
    235         self.critical_cheese_dirs = ["doc", "test"] 
     832        """Set default values for variables that can also be defined 
     833        in the config file. 
     834        """ 
     835        pass 
    236836 
    237837    def get_config(self, config_dir=None): 
    238         """ 
    239         Retrieve values from configuration file 
    240         """ 
    241         self.config = get_pkg_config(self.short_pkg_name, config_dir) 
    242         for config_var in ["INDEX_PYPI_DOWNLOAD", "INDEX_PYPI_DISTANCE", 
    243             "INDEX_URL_DOWNLOAD", "INDEX_UNPACK", "INDEX_UNPACK_DIR", 
    244             "INDEX_INSTALL", "INDEX_FILE_CRITICAL", "INDEX_FILE", 
    245             "INDEX_REQUIRED_FILES", "INDEX_FILE_PYC", 
    246             "INDEX_FILE_PYO", 
    247             "INDEX_DIR_CRITICAL", "INDEX_DIR", "INDEX_DIR_EMPTY", 
    248             "MAX_INDEX_DOCSTRINGS", "MAX_INDEX_PYLINT", 
    249             "cheese_files", "critical_cheese_files",  
    250             "cheese_dirs", "critical_cheese_dirs", 
    251             ]: 
    252             value = self.config.get(config_var) 
    253             if value: setattr(self, config_var, value) 
     838        """Retrieve values from configuration file. 
     839        """ 
     840        pass 
    254841 
    255842    def determine_pkg_name(self): 
     
    263850 
    264851    def get_package_from_url(self): 
    265         """ 
    266         Use ``urlparse`` to obtain package path from URL 
     852        """Use ``urlparse`` to obtain package path from URL. 
    267853        """ 
    268854        (scheme,location,path,param,query,fragment_id) = urlparse(self.url) 
    269855        return self.get_package_from_path(path) 
    270856 
    271  
    272857    def get_package_from_path(self, path): 
    273         """ 
    274         Get package name as file portion of path 
     858        """Get package name as file portion of path. 
    275859        """ 
    276860        dir, file = os.path.split(path) 
     
    284868 
    285869    def configure_logging(self, logfile=None): 
    286         """ 
    287         Default settings for logging 
    288  
    289         if verbose, log goes to console, else it goes to logfile 
     870        """Default settings for logging. 
     871 
     872        If verbose, log goes to console, else it goes to logfile 
    290873        log.debug goes to logfile 
    291874        log.info goes to console 
     
    315898        self.log.debug("package = ", self.short_pkg_name) 
    316899 
    317     def init_indexes(self): 
    318         """ 
    319         Initialize variables used in index computation 
    320  
    321         * cheesecake_index: overall index for the package 
    322         * index: dict holding Index or CompositeIndex objects of various types 
    323         """ 
    324         self.cheesecake_index = 0 
    325         self.cheesecake_index_installability = 0 
    326         self.cheesecake_index_documentation = 0 
    327         self.cheesecake_index_codekwalitee = 0 
    328         self.max_cheesecake_index = self.INDEX_PYPI_DOWNLOAD + \ 
    329                                     self.INDEX_UNPACK + \ 
    330                                     self.INDEX_UNPACK_DIR + \ 
    331                                     self.INDEX_INSTALL + \ 
    332                                     self.MAX_INDEX_DOCSTRINGS + \ 
    333                                     self.MAX_INDEX_PYLINT  
    334 #                                    self.MAX_INDEX_UNITTESTS 
    335         self.max_cheesecake_index_installability = self.INDEX_PYPI_DOWNLOAD + \ 
    336                                             self.INDEX_UNPACK + \ 
    337                                             self.INDEX_UNPACK_DIR + \ 
    338                                             self.INDEX_INSTALL 
    339         self.max_cheesecake_index_documentation = self.INDEX_REQUIRED_FILES + \ 
    340                                         self.MAX_INDEX_DOCSTRINGS + \ 
    341                                         self.MAX_INDEX_DOCFORMAT 
    342         self.max_cheesecake_index_codekwalitee = self.MAX_INDEX_PYLINT  
    343 #                                        self.MAX_INDEX_UNITTESTS 
    344                                          
    345         self.index = {} 
    346         for index_type in ["file", "dir"]: 
    347             self.index[index_type] = CompositeIndex(index_type) 
    348         for index_type in ["pypi_download", "url_download",  
    349                            "unpack_dir", "unpack", "install", 
    350                            "docstrings", "doc_format", "unittests", "pylint"]: 
    351             self.index[index_type] = Index(index_type) 
    352  
    353         for cheese_file in self.cheese_files: 
    354             self.index["file"].set_index(name=cheese_file, details="file not found") 
    355             if cheese_file in self.critical_cheese_files: 
    356                 self.max_cheesecake_index += self.INDEX_FILE_CRITICAL 
    357                 self.max_cheesecake_index_documentation += self.INDEX_FILE_CRITICAL 
    358             else: 
    359                 self.max_cheesecake_index += self.INDEX_FILE 
    360                 self.max_cheesecake_index_documentation += self.INDEX_FILE 
    361         self.log.debug("cheese_files: " + ",".join(self.cheese_files)) 
    362         self.log.debug("critical_cheese_files: " + ",".join(self.critical_cheese_files)) 
    363  
    364         for cheese_dir in self.cheese_dirs: 
    365             self.index["dir"].set_index(name=cheese_dir, details="directory not found") 
    366             if cheese_dir in self.critical_cheese_dirs: 
    367                 self.max_cheesecake_index += self.INDEX_DIR_CRITICAL 
    368                 self.max_cheesecake_index_documentation += self.INDEX_DIR_CRITICAL 
    369             else: 
    370                 self.max_cheesecake_index += self.INDEX_DIR 
    371                 self.max_cheesecake_index_documentation += self.INDEX_DIR 
    372         self.log.debug("cheese_dirs: " + ",".join(self.cheese_dirs)) 
    373         self.log.debug("critical_cheese_dirs: " + ",".join(self.critical_cheese_dirs)) 
    374  
    375         self.pkg_files = {} 
    376         self.pkg_dirs = {} 
    377         self.file_types = ["py", "pyc", "pyo", "test"] 
    378         for type in self.file_types: 
    379             self.pkg_files[type] = [] 
    380  
    381         self.object_cnt = 0  # Number of modules/functions/classes/methods in .py files found 
    382         self.docstring_cnt = 0 
    383         self.docformat_cnt = 0 
    384         self.functions = [] # List of methods/functions found in .py files 
    385  
    386900    def retrieve_pkg(self): 
    387901        if self.name: 
     
    393907 
    394908    def get_package_from_url(self): 
    395         """ 
    396         Use ``urlparse`` to obtain package path from URL 
     909        """Use ``urlparse`` to obtain package path from URL. 
    397910        """ 
    398911        (scheme,location,path,param,query,fragment_id) = urlparse(self.url) 
    399         return self.get_package_from_path(path) 
    400          
     912        return self.get_package_from_path(path)         
    401913 
    402914    def get_package_from_path(self, path): 
    403         """ 
    404         Get package name as file portion of path 
     915        """Get package name as file portion of path. 
    405916        """ 
    406917        dir, file = os.path.split(path) 
     
    414925 
    415926    def get_pkg_from_pypi(self): 
    416         """ 
    417         Download package using setuptools utilities 
     927        """Download package using setuptools utilities. 
     928 
     929        :Ivariables: 
     930          download_url : str 
     931              URL that package was downloaded from. 
     932          distance_from_pypi : int 
     933              How many hops setuptools had to make to download package. 
     934          found_on_cheeseshop : bool 
     935              Whenever package has been found on CheeseShop. 
    418936        """ 
    419937        try: 
     
    422940            from pkg_resources import Requirement 
    423941            from distutils import log 
     942 
    424943            # Temporarily set the log verbosity to INFO so we can capture setuptools info messages 
    425944            old_threshold = log.set_threshold(log.INFO) 
     
    434953            sys.stdout = old_stdout 
    435954            log.set_threshold(old_threshold) 
     955 
    436956            if output is None: 
    437957                self.raise_exception("Error: Could not find distribution for " + self.name) 
    438             download_url = "" 
    439             distance_from_pypi = 0 
    440             #print captured_stdout 
     958 
     959            # Defaults. 
     960            self.download_url = "" 
     961            self.distance_from_pypi = 0 
     962            self.found_on_cheeseshop = False 
     963 
    441964            for line in captured_stdout.split('\n'): 
    442965                s = re.search(r"Reading http(.*)", line) 
     
    444967                    inspected_url = s.group(1) 
    445968                    if not re.search(r"www.python.org\/pypi", inspected_url): 
    446                         distance_from_pypi += 1 
     969                        self.distance_from_pypi += 1 
    447970                    continue 
    448971                s = re.search(r"Downloading (.*)", line) 
    449972                if s: 
    450                     download_url = s.group(1) 
     973                    self.download_url = s.group(1) 
    451974                    break 
     975 
    452976            self.sandbox_pkg_file = output 
    453977            self.package = self.get_package_from_path(output) 
    454             self.log.info("Downloaded package %s from %s" % (self.package, download_url)) 
    455             index_type = "pypi_download" 
    456             found_on_cheeseshop = False 
    457             if re.search(r"cheeseshop.python.org", download_url): 
    458                 value = self.INDEX_PYPI_DOWNLOAD 
    459                 found_on_cheeseshop = True 
    460             else: 
    461                 value = self.INDEX_PYPI_DOWNLOAD - distance_from_pypi * self.INDEX_PYPI_DISTANCE 
    462             self.index[index_type].value = value 
    463             details = "downloaded package " + self.package 
    464             if found_on_cheeseshop: 
    465                 details += " directly from the Cheese Shop" 
    466             elif distance_from_pypi: 
    467                 details += " following %d link" % distance_from_pypi 
    468                 if distance_from_pypi > 1: 
    469                     details += "s" 
    470                 details += " from PyPI" 
    471             else: 
    472                 details += "from " + download_url 
    473             self.index[index_type].details = details 
     978            self.log.info("Downloaded package %s from %s" % (self.package, self.download_url)) 
     979 
     980            if re.search(r"cheeseshop.python.org", self.download_url): 
     981                self.found_on_cheeseshop = True 
     982 
    474983        except ImportError, e: 
    475984            msg = "Error: setuptools is not installed and is required for downloading a package by name\n" 
     
    477986            msg += "Example: python cheesecake.py --url=http://www.mems-exchange.org/software/durus/Durus-3.1.tar.gz" 
    478987            self.raise_exception(msg) 
    479          
     988 
    480989    def download_pkg(self): 
    481         """ 
    482         Use ``urllib.urlretrieve`` to download package to file in sandbox dir 
     990        """Use ``urllib.urlretrieve`` to download package to file in sandbox dir. 
    483991        """ 
    484992        #self.log("Downloading package %s from URL %s" % (self.package, self.url)) 
     
    490998            self.raise_exception(str(e)) 
    491999        #self.log("Downloaded package %s to %s" % (self.package, downloaded_filename)) 
     1000 
    4921001        if re.search("Content-Type: details/html", str(headers)): 
    4931002            f = open(downloaded_filename) 
     
    4961005                self.raise_exception("Got '404 Not Found' error while trying to download package ... exiting") 
    4971006            f.close() 
    498         index_type = "url_download" 
    499         self.index[index_type].value = self.INDEX_URL_DOWNLOAD 
    500         self.index[index_type].details = "downloaded package %s from URL %s"  % (self.package, self.url) 
     1007 
     1008        self.downloaded_from_url = True 
    5011009         
    5021010    def copy_pkg(self): 
    503         """ 
    504         Copy package file to sandbox directory 
     1011        """Copy package file to sandbox directory. 
    5051012        """ 
    5061013        self.sandbox_pkg_file = os.path.join(self.sandbox, self.package) 
     
    5111018 
    5121019    def unpack_pkg(self): 
    513         """ 
    514         Unpack the package in the sandbox directory 
     1020        """Unpack the package in the sandbox directory. 
    5151021         
    5161022        Currently supported archive types: 
     
    5181024        * .tar.gz (handled with ``tarfile`` module) 
    5191025        * .zip (handled with ``zipfile`` module) 
     1026 
     1027        :Ivariables: 
     1028          original_package_name : str 
    5201029        """ 
    5211030        self.package_type = "" 
     1031 
    5221032        for type in self.package_types: 
    5231033            s = re.search(r"(.+)\.%s" % type, self.package) 
     
    5431053            self.unzip_pkg() 
    5441054 
    545         index_type = "unpack_dir" 
    546         details = "unpack directory is " + self.unpack_dir 
    5471055        if self.unpack_dir != self.package_name: 
    548             details += " instead of the expected " + self.package_name 
     1056            self.original_package_name = self.package_name 
    5491057            self.package_name = self.unpack_dir 
    550         else: 
    551             details += " as expected" 
    552             self.index[index_type].value = self.INDEX_UNPACK_DIR 
    553         self.index[index_type].details = details 
    5541058 
    5551059        if not self.quiet: 
     
    5571061 
    5581062    def untar_pkg(self): 
    559         """ 
    560         Untar the package in the sandbox directory 
    561  
    562         Uses tarfile module 
     1063        """Untar the package in the sandbox directory. 
     1064 
     1065        Uses tarfile module. 
    5631066        """ 
    5641067        try: 
     
    5731076        self.unpack_dir = tarinfo.name.split(os.sep)[0] 
    5741077 
    575         index_type = "unpack" 
    576         self.index[index_type].value = self.INDEX_UNPACK 
    577         self.index[index_type].details = "package untar-ed successfully" 
     1078        self.unpacked = True 
    5781079             
    5791080    def unzip_pkg(self): 
    580         """ 
    581         Unzip the package in the sandbox directory 
    582  
    583         Uses zipfile module 
     1081        """Unzip the package in the sandbox directory. 
     1082 
     1083        Uses zipfile module. 
    5841084        """ 
    5851085        try: 
     
    6061106        self.unpack_dir = unpack_dir.split(os.sep)[0] 
    6071107 
    608         index_type = "unpack" 
    609         self.index[index_type].value = self.INDEX_UNPACK 
    610         self.index[index_type].details = "package unzipped successfully" 
     1108        self.unpacked = True 
    6111109 
    6121110    def walk_pkg(self): 
    613         """ 
    614         Traverse the file system tree rooted at sandbox/package_name 
    615  
    616         * Compute indexes for special files and directories 
    617         * Identify Python files, test files, etc. 
    618         """ 
    619         cwd = os.getcwd() 
    620         os.chdir(self.sandbox) 
    621         for rootdir, dirs, files in os.walk(self.package_name): 
    622             head, tail = os.path.split(rootdir) 
    623  
    624             # Don't take package name into account when checking 
    625             # directories' names. 
    626             dirs_in_rootdir = rootdir.split(os.path.sep)[1:] 
    627  
    628             for cheese_dir in self.cheese_dirs: 
    629                 if re.search("^%s" % cheese_dir, tail): 
    630                     if files or dirs: 
    631                         if cheese_dir in self.critical_cheese_dirs: 
    632                             value = self.INDEX_DIR_CRITICAL 
    633                             details = "critical directory found" 
    634                             self.log.debug("critical_cheese_dir found: " + cheese_dir) 
    635                         else: 
    636                             value = self.INDEX_DIR 
    637                             details = "directory found" 
    638                             self.log.debug("cheese_dir found: " + cheese_dir) 
    639                     else: 
    640                         value = self.INDEX_DIR_EMPTY 
    641                         details = "empty directory found" 
    642                         self.log.debug("empty cheese_dir found: " + cheese_dir) 
    643                     self.index["dir"].set_index(cheese_dir, value, details) 
    644             for file in files: 
    645                 fullpath = os.path.join(rootdir, file) 
    646  
    647                 cheese_file = self.which_cheese_file(file) 
    648                 if cheese_file and os.path.getsize(fullpath) != 0: 
    649                     if cheese_file in self.critical_cheese_files: 
    650                         value = self.INDEX_FILE_CRITICAL 
    651                         details = "critical file found" 
    652                         self.log.debug("critical_cheese_file found: " + cheese_file) 
    653                     else: 
    654                         value = self.INDEX_FILE 
    655                         details = "file found" 
    656                         self.log.debug("cheese_file found: " + cheese_file) 
    657                     self.index["file"].set_index(cheese_file, value, details) 
    658  
    659                 if self.is_py_file(file, dirs_in_rootdir): 
    660                     self.pkg_files["py"].append(fullpath) 
    661                     self.log.debug("py file found: " + fullpath) 
    662                     pyfile = os.path.join(self.sandbox, fullpath) 
    663                     # Parse the file and count objects (modules/classes/functions) 
    664                     # and their associated docstrings 
    665                     code = CodeParser(pyfile, self.log.debug) 
    666                     self.object_cnt += code.object_count() 
    667                     self.docstring_cnt += code.docstring_count() 
    668                     self.docformat_cnt += code.formatted_docstrings_count 
    669                     self.functions += code.functions 
    670                 elif self.is_test_file(file, dirs_in_rootdir): 
    671                     self.pkg_files["test"].append(fullpath) 
    672                     self.log.debug("test file found: " + fullpath) 
    673                 elif self.is_pyc_file(file, dirs_in_rootdir): 
    674                     self.pkg_files["pyc"].append(fullpath) 
    675                     self.log.debug("pyc file found: " + fullpath) 
    676                 elif self.is_pyo_file(file, dirs_in_rootdir): 
    677                     self.pkg_files["pyo"].append(fullpath) 
    678                     self.log.debug("pyo file found: " + fullpath) 
    679  
    680         len_pyc_list = len(self.pkg_files["pyc"]) 
    681         if len_pyc_list: 
    682             self.index["file"].set_index("pyc", value=self.INDEX_FILE_PYC, 
    683                 details="%d .pyc files found" % len_pyc_list) 
    684  
    685         len_pyo_list = len(self.pkg_files["pyo"]) 
    686         if len_pyo_list: 
    687             self.index["file"].set_index("pyo", value=self.INDEX_FILE_PYO, 
    688                 details="%d .pyo files found" % len_pyo_list) 
    689  
    690         self.log.debug("Found %d py files" % len(self.pkg_files["py"])) 
    691         self.log.debug("Found %d pyc files" % len_pyc_list) 
    692         self.log.debug("Found %d pyo files" % len_pyo_list) 
    693         self.log.debug("Found %d test files" % len(self.pkg_files["test"])) 
    694  
    695         os.chdir(cwd) 
    696  
    697     def which_cheese_file(self, filename): 
    698         """Find out which Cheese file coresponds to given filename (if any). 
    699  
    700         Return False if filename is not a Cheese file. 
    701         """ 
    702         text_cheese_files = filter(lambda x: not has_extension(x, ".py"), 
    703                                    self.cheese_files) 
    704         py_cheese_files = filter(lambda x: has_extension(x, ".py"), 
    705                                  self.cheese_files) 
    706  
    707         name, extension = os.path.splitext(filename) 
    708  
    709         if extension in ['', '.txt', '.TXT']: 
    710             for cheese_file in text_cheese_files: 
    711                 if name in [cheese_file, cheese_file.capitalize(), 
    712                             cheese_file.upper()]: 
    713                     return cheese_file 
    714         elif extension in ['.py', '.PY']: 
    715             for cheese_file in py_cheese_files: 
    716                 if filename in [cheese_file, cheese_file.capitalize(), 
    717                             cheese_file.upper()]: 
    718                     return cheese_file 
    719  
    720         return False 
    721  
    722     def is_pyc_file(self, filename, dirs): 
    723         return has_extension(filename, ".pyc") 
    724  
    725     def is_pyo_file(self, filename, dirs): 
    726         return has_extension(filename, ".pyo") 
    727  
    728     def is_py_file(self, filename, dirs): 
    729         """ 
    730         Return True if file ends with .py and it is not a special file and it is not 
    731         in special directory 
    732         """ 
    733         if not has_extension(filename, ".py"): 
    734             return False 
    735         if file in ["setup.py", "ez_setup.py", "__init__.py", "__pkginfo__.py"]: 
    736             return False 
    737         for dir in dirs: 
    738             if dir.startswith("test") or \ 
    739                 dir.startswith("docs") or \ 
    740                 dir.startswith("demo") or \ 
    741                 dir.startswith("example"): 
    742                 return False 
    743         return True 
    744  
    745     def is_test_file(self, filename, dirs): 
    746         """ 
    747         Return True is file is in directory rooted at "test" or "tests" 
    748         """ 
    749         if not has_extension(filename, ".py"): 
    750             return False 
    751         if file in ["__init__.py"]: 
    752             return False 
    753         for dir in dirs: 
    754             if dir.startswith("test"): 
    755                 return True 
    756         return False 
    757  
    758     def index_file(self): 
    759         """ 
    760         Return CompositeIndex object of type "file" 
    761         """ 
    762         return self.index["file"] 
    763  
    764     def index_dir(self): 
    765         """ 
    766         Return CompositeIndex object of type "dir" 
    767         """ 
    768         return self.index["dir"] 
    769  
    770     def index_pypi_download(self): 
    771         """ 
    772         Verify that package can be downloaded from PyPI 
    773  
    774         Return Index object of type "pypi_download" 
    775         """ 
    776         index_type = "pypi_download" 
    777         if self.url: 
    778             # Package was downloaded directly from URL 
    779             self.index[index_type].value = 0 
    780             self.index[index_type].details = "package was downloaded directly from URL" 
    781  
    782         if self.package_path: 
    783             # Package was processed from file system path 
    784             self.index[index_type].value = 0 
    785             self.index[index_type].details = "package was processed from file system path" 
    786              
    787         # Otherwise, index["pypi_download"] was already set in get_pkg_from_pypi() 
    788         return self.index["pypi_download"] 
    789  
    790     def index_url_download(self): 
    791         """ 
    792         Verify that package can be downloaded from an URL 
    793  
    794         Return Index object of type "download" 
    795         """ 
    796         # index["download"] is already set in download_pkg() 
    797         return self.index["url_download"] 
    798  
    799     def index_unpack(self): 
    800         """ 
    801         Verify that package can be unpacked 
    802  
    803         Return Index object of type "unpack" 
    804         """ 
    805         # index["unpack"] is already set in unpack_pkg() 
    806         return self.index["unpack"] 
    807  
    808     def index_unpack_dir(self): 
    809         """ 
    810         Verify that unpack directory has same name as package 
    811  
    812         Return Index object of type "unpack_dir" 
    813         """ 
    814         # index["unpack_dir"] is already set in unpack_pkg() 
    815         return self.index["unpack_dir"] 
    816  
    817     def index_install(self): 
    818         """ 
    819         Verify that package can be installed in alternate directory 
    820  
    821         Return Index object of type "install" 
    822         """ 
    823         index_type = "install" 
     1111        """Get package files and directories. 
     1112 
     1113        :Ivariables: 
     1114          dirs_list : list 
     1115              List of directories package contains. 
     1116          docstring_cnt : int 
     1117              Number of docstrings found in all package objects. 
     1118          docformat_cnt : int 
     1119              Number of formatted docstrings found in all package objects. 
     1120          files_list : list 
     1121              List of files package contains. 
     1122          functions : list 
     1123              List of all functions defined in package sources. 
     1124          object_cnt : int 
     1125              Number of documentable objects found in all package modules. 
     1126          package_dir : str 
     1127              Path to project directory. 
     1128        """ 
     1129        self.package_dir = os.path.join(self.sandbox, self.package_name) 
     1130 
     1131        self.files_list, self.dirs_list = get_files_dirs_list(self.package_dir) 
     1132 
     1133        self.object_cnt = 0 
     1134        self.docstring_cnt = 0 
     1135        self.docformat_cnt = 0 
     1136        self.functions = [] 
     1137 
     1138        # Parse all application files and count objects 
     1139        # (modules/classes/functions) and their associated docstrings. 
     1140        for py_file in get_files_of_type(self.files_list, 'module'): 
     1141            pyfile = os.path.join(self.package_dir, py_file) 
     1142            code = CodeParser(pyfile, self.log.debug) 
     1143 
     1144            self.object_cnt += code.object_count() 
     1145            self.docstring_cnt += code.docstring_count() 
     1146            self.docformat_cnt += code.formatted_docstrings_count 
     1147            self.functions += code.functions 
     1148 
     1149        # Log a bit of debugging info. 
     1150        self.log.debug("Found %d files: %s." % (len(self.files_list), 
     1151                                                ', '.join(self.files_list))) 
     1152        self.log.debug("Found %d directories: %s." % (len(self.dirs_list), 
     1153                                                      ', '.join(self.dirs_list))) 
     1154 
     1155    def install_pkg(self): 
     1156        """Verify that package can be installed in alternate directory. 
     1157 
     1158        :Ivariables: 
     1159          installed : bool 
     1160              Describes whenever package has been succefully installed. 
     1161        """ 
    8241162        self.sandbox_install_dir = os.path.join(self.sandbox, "tmp_install_%s" % self.package_name) 
     1163 
    8251164        cwd = os.getcwd() 
    8261165        os.chdir(os.path.join(self.sandbox, self.package_name)) 
     1166 
    8271167        rc, output = run_cmd("python setup.py install --root=" + self.sandbox_install_dir) 
     1168 
     1169        # Install succeeded 
    8281170        if not rc: 
    829             # Install succeeded 
    830             self.index[index_type].value = self.INDEX_INSTALL 
    831             self.index[index_type].details = details="package installed in %s" % self.sandbox_install_dir 
    832         else: 
    833             # Install failed 
    834             self.index[index_type].details = "could not install package in %s" % self.sandbox_install_dir 
     1171            self.installed = True 
     1172 
    8351173        os.chdir(cwd) 
    836         return self.index[index_type] 
    837  
    838     def index_docstrings(self): 
    839         """ 
    840         Compute docstring index as percentage of modules/classes/methods/functions 
    841         that have docstrings associated with them 
    842  
    843         Return Index object of type "docstrings" 
    844         """ 
    845         index_type = "docstrings" 
    846         if self.object_cnt: 
    847             percent = float(self.docstring_cnt)/float(self.object_cnt) 
    848         else: 
    849             percent = 0 
    850         index_value = int(ceil(percent*100)) 
    851         details = "found %d/%d=%.2f%% modules/classes/methods/functions with docstrings" %\ 
    852                  (self.docstring_cnt, self.object_cnt, percent*100) 
    853         self.index[index_type].value = index_value 
    854         self.index[index_type].details = details 
    855         return self.index[index_type] 
    856  
    857     def index_doc_format(self): 
    858         percent = float(self.docformat_cnt)/float(self.object_cnt) 
    859         index_value = int(ceil(percent*100)) 
    860         details = "found %d/%d=%.2f%% modules/classes/methods/functions with formatted docstrings" %\ 
    861                  (self.docformat_cnt, self.object_cnt, percent*100) 
    862         self.index["doc_format"].value = index_value 
    863         self.index["doc_format"].details = details 
    864         return self.index["doc_format"] 
    865  
    866     def index_unittests(self): 
    867         """ 
    868         Compute unittest index as percentage of methods/functions 
    869         that are exercised in unit tests 
    870  
    871         Return Index object of type "unittests" 
    872         """ 
    873         unittest_cnt = 0 
    874         index_type = "unittests" 
    875         self.functions_tested = {} 
    876         for testfile in self.pkg_files["test"]: 
    877             fullpath = os.path.join(self.sandbox, testfile) 
    878             code = CodeParser(fullpath, self.log.debug) 
    879             func_called = code.functions_called() 
    880             self.log.debug("Functions called in unit test:") 
    881             self.log.debug(func_called) 
    882             for func in func_called: 
    883                 self.functions_tested[func] = 1 
    884         self.log.debug("FUNCTIONS TO BE CHECKED WHETHER THEY ARE UNIT TESTED:") 
    885         self.log.debug(self.functions) 
    886         self.log.debug("FUNCTIONS THAT ARE UNIT TESTED:") 
    887         self.log.debug(self.functions_tested.keys()) 
    888         for funcname in self.functions: 
    889             if self.is_unit_tested(funcname): 
    890                 unittest_cnt += 1 
    891                 self.log.debug("%s is unit tested" % funcname) 
    892         cnt = len(self.functions) 
    893         if cnt: 
    894             percent = float(unittest_cnt)/float(cnt) 
    895         else: 
    896             percent = 0 
    897         index_value = int(ceil(percent*100)) 
    898         details = "found %d/%d=%.2f%% unit tested methods/functions" % (unittest_cnt, cnt, percent*100) 
    899         self.index[index_type].value = index_value 
    900         self.index[index_type].details = details 
    901         return self.index[index_type] 
    902  
    903     def is_unit_tested(self, funcname): 
    904         elem = funcname.split(".") 
    905         n1 = elem[-1] 
    906         n2 = "" 
    907         if len(elem) > 1: 
    908             n2 = elem[-2] + "." + elem[-1] 
    909         for key in self.functions_tested.keys(): 
    910             if key.startswith(n1) or (n2 and key.startswith(n2)): 
    911                 return True 
    912         return False 
    913  
    914     def index_pylint(self): 
    915         """ 
    916         Compute pylint index as average of positive pylint scores obtained for 
    917         the Python files identified in the package 
    918  
    919         Return Index object of type "pylint" 
    920         """ 
    921         index_type = "pylint" 
    922             # Try to run the pylint script 
    923         rc, output = run_cmd("pylint --version") 
    924         if rc: 
    925             # We encountered an error 
    926             self.index[index_type].details = "pylint not properly installed" 
    927             return self.index[index_type] 
    928         index_pylint = 0 
    929         cnt = 0 
    930         for pyfile in self.pkg_files["py"]: 
    931             (path, filename) = os.path.split(pyfile) 
    932             (module, ext) = os.path.splitext(filename) 
    933             if module == "setup" or module == "ez_setup" or module.startswith("__"): 
    934                 continue 
    935             fullpath = os.path.join(self.sandbox, pyfile) 
    936             self.log.debug("Running pylint on file " + fullpath) 
    937             rc, output = run_cmd("pylint " + fullpath) 
    938             if rc: 
    939                 # We encountered an error 
    940                 continue 
    941             score_line = output.split("\n")[-3] 
    942             s = re.search(r" (\d+\.\d+)/10", score_line) 
    943             # We only take positive scores into account 
    944             if s: 
    945                 score = s.group(1) 
    946                 self.log.debug("pylint score for module %s: %s" % (module, score)) 
    947                 if score == "0.00": 
    948                     self.log.debug("Ignoring scores of 0.00") 
    949                     continue 
    950                 index_pylint += float(score) 
    951                 cnt += 1 
    952         if cnt: 
    953             avg_value = float(index_pylint)/float(cnt) 
    954         else: 
    955             avg_value = 0 
    956         index_value = int(ceil(avg_value*10)) 
    957         self.index[index_type].value = index_value 
    958         self.index[index_type].details = "average score is %.2f out of 10" % avg_value 
    959         return self.index[index_type] 
    9601174 
    9611175    def compute_cheesecake_index(self): 
    962         """ 
    963         Compute overall Cheesecake index for the package by adding up  
    964         specific indexes 
    965         """ 
    966         self.log.info("A given package can currently reach a MAXIMUM number of %d points" % self.max_cheesecake_index) 
     1176        """Compute overall Cheesecake index for the package by adding up 
     1177        specific indexes. 
     1178        """ 
     1179        # Recursively compute all indices. 
     1180        max_cheesecake_index = self.index.max_value 
     1181 
     1182        # Pass Cheesecake instance to the main Index object. 
     1183        cheesecake_index = self.index.compute_with(self) 
     1184        percentage = (cheesecake_index * 100) / max_cheesecake_index 
     1185 
     1186        self.log.info("A given package can currently reach a MAXIMUM number of %d points" % max_cheesecake_index) 
    9671187        self.log.info("Starting computation of Cheesecake index for package '%s'" % (self.package)) 
    9681188 
    969         index_types = [] 
    970         #if self.name: 
    971         #    index_types.append("pypi_download") 
    972         index_types.append("pypi_download") 
    973         if self.url: 
    974             index_types.append("url_download") 
    975         index_types += ["unpack", "unpack_dir", "install"] 
    976         self.cheesecake_index_installability = self.process_partial_index("INSTALLABILITY",\ 
    977                                          index_types, self.max_cheesecake_index_installability) 
    978  
    979         index_types = ["file", "dir", "doc_format", "docstrings"] 
    980         self.cheesecake_index_documentation = self.process_partial_index("DOCUMENTATION",\ 
    981                                          index_types, self.max_cheesecake_index_documentation) 
    982  
    983         index_types = [  
    984                         #"unittests", 
    985                         "pylint", 
    986                         ] 
    987         self.cheesecake_index_codekwalitee = self.process_partial_index("CODE KWALITEE",\ 
    988                                          index_types, self.max_cheesecake_index_codekwalitee) 
    989  
     1189        # Print summary. 
    9901190        print 
    991         self.print_separator_line("=") 
    992         print pad_msg("OVERALL CHEESECAKE INDEX (ABSOLUTE)", self.cheesecake_index) 
    993         percentage = (self.cheesecake_index * 100) / self.max_cheesecake_index 
    994         msg = pad_msg("OVERALL CHEESECAKE INDEX (RELATIVE)", percentage) 
    995         msg += " (%d out of a maximum of %d points is %d%%)" %\ 
    996              (self.cheesecake_index, self.max_cheesecake_index, percentage) 
    997         print msg 
    998         self.cleanup() 
    999  
    1000         return self.cheesecake_index 
    1001  
    1002     def process_partial_index(self, partial_index_name, index_types, max_value): 
    1003         print 
    1004         self.log.info("Starting computation of %s index (max. points = %d)" % \ 
    1005                             (partial_index_name, max_value)) 
    1006         partial_index_value = 0 
    1007         for index_type in index_types: 
    1008             partial_index_value += self.process_index(index_type) 
    1009  
    1010         self.print_separator_line() 
    1011         print pad_msg("%s INDEX (ABSOLUTE)" % partial_index_name, partial_index_value) 
    1012         percentage = (partial_index_value * 100) / max_value 
    1013         msg = pad_msg("%s INDEX (RELATIVE)" % partial_index_name, percentage) 
    1014         msg += " (%d out of a maximum of %d points is %d%%)" %\ 
    1015              (partial_index_value, max_value, percentage) 
    1016         print msg 
    1017         return partial_index_value 
    1018  
    1019     def process_index(self, index_type): 
    1020         """ 
    1021         Compute and print index of specified type 
    1022         """ 
    1023         index = self.index[index_type] 
    1024         index_method = "index_" + index_type 
    1025         getattr(self, index_method)() 
    1026         if not self.quiet: 
    1027             index.print_info() 
    1028         self.cheesecake_index += index.value 
    1029         return index.value 
    1030  
    1031     def print_separator_line(self, char="-"): 
    1032         """ 
    1033         Print line of text, unless quiet flag was given 
    1034         """ 
    1035         if self.quiet: 
    1036             return 
    1037         print pad_line(char) 
     1191        print pad_line("=") 
     1192        print pad_msg("OVERALL CHEESECAKE INDEX (ABSOLUTE)", cheesecake_index) 
     1193        print "%s (%d out of a maximum of %d points is %d%%)" % \ 
     1194              (pad_msg("OVERALL CHEESECAKE INDEX (RELATIVE)", percentage), 
     1195               cheesecake_index, 
     1196               max_cheesecake_index, 
     1197               percentage) 
     1198 
     1199        return cheesecake_index 
    10381200 
    10391201 
     
    10901252                       quiet=quiet) 
    10911253        c.compute_cheesecake_index() 
     1254        c.cleanup() 
    10921255    except CheesecakeError, e: 
    10931256        print str(e) 
  • branches/mk/cheesecake/model.py

    r31 r40  
    431431        else: 
    432432            fn = '<None>' 
    433         print fn, type, detail 
     433        #print fn, type, detail 
    434434        self.warnings.setdefault(type, []).append((fn, detail)) 
    435435 
  • branches/mk/tests/_mockup_cheesecake.py

    r29 r40  
    2020            self.quiet = True 
    2121 
     22            self.unpack_dir = sandbox 
     23 
    2224            self.determine_pkg_name() 
    2325            self.configure_logging(logfile) 
    2426            self.set_defaults() 
    25             self.init_indexes() 
    2627 
    2728    def setUp(self): 
  • branches/mk/tests/test_cheese_files.py

    r29 r40  
    1010 
    1111 
    12 def critical_in_log(filename, loglines): 
    13     return "[cheesecake:logfile] critical_cheese_file found: %s\n" % filename in loglines 
    14  
    1512def cheesefile_in_log(filename, loglines): 
    16     return "[cheesecake:logfile] cheese_file found: %s\n" % filename in loglines 
     13    return "entry found: %s" % filename in loglines 
    1714 
    1815 
    19 class TestBogusCheeseFiles(MockupCheesecakeTest): 
     16class CheeseFilesTest(MockupCheesecakeTest): 
     17    def _do_it(self, files, create_files, inside_log): 
     18        create_files(self.prefix_with_package_name(files)) 
     19        self.cheesecake.walk_pkg() 
     20        self.cheesecake.compute_cheesecake_index() 
     21 
     22        loglines = ''.join(readlines_from_file(self._mock_logfile)) 
     23 
     24        for filename in files: 
     25            print "Checking if %s was counted..." % filename 
     26            assert cheesefile_in_log(filename, loglines) is inside_log 
     27 
     28class TestBogusCheeseFiles(CheeseFilesTest): 
    2029    def test_bogus_filenames(self): 
    21         bogus_filenames = self.prefix_with_package_name(['ReAdMe', 
    22                                                          'install.txt.txt', 
    23                                                          'setupXpy', 
    24                                                          'newsXtxt', 
    25                                                          'todoGARBAGE', 
    26                                                          'setup.py.txt']) 
    27         self.create_files(bogus_filenames) 
    28         self.cheesecake.walk_pkg() 
     30        bogus_filenames = ['ReAdMe', 
     31                           'install.txt.txt', 
     32                           'setupXpy', 
     33                           'newsXtxt', 
     34                           'todoGARBAGE', 
     35                           'setup.py.txt'] 
     36        self._do_it(bogus_filenames, self.create_files, False) 
    2937 
    30         loglines = readlines_from_file(self._mock_logfile) 
     38class TestGoodCheeseFiles(CheeseFilesTest): 
     39    def test_good_filenames(self): 
     40        good_filenames = ['Readme', 'INSTALL.txt', 'setup.py', 'news.TXT'] 
     41        self._do_it(good_filenames, self.create_files, True) 
    3142 
    32         assert not critical_in_log('readme', loglines) 
    33         assert not cheesefile_in_log('install', loglines) 
    34         assert not critical_in_log('setup.py', loglines) 
    35         assert not cheesefile_in_log('news', loglines) 
    36         assert not cheesefile_in_log('todo', loglines) 
    37  
    38  
    39 class TestGoodCheeseFiles(MockupCheesecakeTest): 
    40     def test_good_filenames(self): 
    41         bogus_filenames = self.prefix_with_package_name(['Readme', 
    42                                                          'INSTALL.txt', 
    43                                                          'setup.py', 
    44                                                          'news.TXT']) 
    45         self.create_files(bogus_filenames) 
    46         self.cheesecake.walk_pkg() 
    47  
    48         loglines = readlines_from_file(self._mock_logfile) 
    49  
    50         assert critical_in_log('readme', loglines) 
    51         assert cheesefile_in_log('install', loglines) 
    52         assert critical_in_log('setup.py', loglines) 
    53         assert cheesefile_in_log('news', loglines) 
    54  
    55  
    56 class TestEmptyCheeseFiles(MockupCheesecakeTest): 
     43class TestEmptyCheeseFiles(CheeseFilesTest): 
    5744    def test_empty_filenames(self): 
    58         empty_filenames = self.prefix_with_package_name(['Readme', 
    59                                                          'INSTALL', 
    60                                                          'setup.py']) 
    61         self.create_empty_files(empty_filenames) 
    62         self.cheesecake.walk_pkg() 
    63  
    64         loglines = readlines_from_file(self._mock_logfile) 
    65  
    66         assert not critical_in_log('readme', loglines) 
    67         assert not cheesefile_in_log('install', loglines) 
    68         assert not critical_in_log('setup.py', loglines) 
     45        empty_filenames = ['Readme', 'INSTALL', 'setup.py'] 
     46        self._do_it(empty_filenames, self.create_empty_files, False) 
  • branches/mk/tests/test_count_files.py

    r33 r40  
     1 
     2import _path_cheesecake 
     3from cheesecake.cheesecake_index import get_files_of_type 
    14 
    25from _mockup_cheesecake import MockupCheesecakeTest 
     
    69class TestNoTestFiles(MockupCheesecakeTest): 
    710    def test_discover_no_test_files(self): 
    8         py_files = self.prefix_with_package_name(['main.py', 'module.py']) 
    9         self.create_files(py_files
     11        py_files = ['main.py', 'module.py'] 
     12        self.create_files(self.prefix_with_package_name(py_files)
    1013        self.cheesecake.walk_pkg() 
     14        self.cheesecake.compute_cheesecake_index() 
    1115 
    12         assert set(self.cheesecake.pkg_files['py']) == set(py_files) 
    13         assert self.cheesecake.pkg_files['pyc'] == [] 
    14         assert self.cheesecake.pkg_files['pyo'] == [] 
    15         assert self.cheesecake.pkg_files['test'] == [] 
     16        def get_list(type): 
     17            return get_files_of_type(self.cheesecake.files_list, type) 
     18 
     19        assert set(get_list('module')) == set(py_files) 
     20        assert get_list('pyc') == [] 
     21        assert get_list('pyo') == [] 
     22        assert get_list('test') == [] 
    1623 
    1724 
    1825class TestPycPyoFiles(MockupCheesecakeTest): 
    1926    def test_some_pyc_and_pyo_files(self): 
    20         py_files = self.prefix_with_package_name(['main.py']) 
    21         pyc_files = self.prefix_with_package_name(['main.pyc', 'missing.pyc']) 
    22         pyo_files = self.prefix_with_package_name(['main.pyo', 'optimised.pyo']) 
     27        py_files = ['main.py'] 
     28        pyc_files = ['main.pyc', 'missing.pyc'] 
     29        pyo_files = ['main.pyo', 'optimised.pyo'] 
    2330 
    24         self.create_files(py_files + pyc_files + pyo_files
     31        self.create_files(self.prefix_with_package_name(py_files + pyc_files + pyo_files)
    2532        self.cheesecake.walk_pkg() 
     33        self.cheesecake.compute_cheesecake_index() 
    2634 
    27         assert set(self.cheesecake.pkg_files['py']) == set(py_files) 
    28         assert set(self.cheesecake.pkg_files['pyc']) == set(pyc_files) 
    29         assert set(self.cheesecake.pkg_files['pyo']) == set(pyo_files) 
    30         assert self.cheesecake.pkg_files['test'] == [] 
     35        def get_list(type): 
     36            return get_files_of_type(self.cheesecake.files_list, type) 
     37 
     38        assert set(get_list('module')) == set(py_files) 
     39        assert set(get_list('pyc')) == set(pyc_files) 
     40        assert set(get_list('pyo')) == set(pyo_files) 
     41        assert get_list('test') == [] 
  • branches/mk/tests/test_index_docstrings.py

    r39 r40  
    2626 
    2727    def test_index_docstrings(self): 
    28         index = self.cheesecake.index_docstrings() 
     28        index = self.cheesecake.index["DOCUMENTATION"]["docstrings"] 
     29        index.compute_with(self.cheesecake) 
    2930 
    30         assert index.name == "index_docstrings" 
     31        assert index.name == "docstrings" 
    3132        assert index.value == self.index_int 
    32         assert index.details == "found %d/%d=%.2f%% modules/classes/methods/functions with docstrings" %\ 
     33        assert index.details == "found %d/%d=%.2f%% objects with docstrings" %\ 
    3334                            (self.docstring_count, self.documentable_objects, self.index_float*100) 
  • branches/mk/tests/test_index_install.py

    r8 r40  
     1import os 
     2 
    13import _path_cheesecake 
    24from cheesecake.cheesecake_index import Cheesecake 
    3 import os 
     5 
    46datadir = os.path.abspath(os.path.join(os.path.dirname(__file__), "data")) 
    57 
    6 class TestIndexInstall: 
    7  
     8class TestIndexInstall(object): 
    89    def setUp(self): 
    910        self.cheesecake = None 
     
    1718    def test_index_install_correct_package(self): 
    1819        self.cheesecake = Cheesecake(path=os.path.join(datadir, "nose-0.8.3.tar.gz")) 
    19         index = self.cheesecake.index_install() 
    20         assert index.name == "index_install" 
    21         assert index.value == self.cheesecake.INDEX_INSTALL 
     20 
     21        index = self.cheesecake.index["INSTALLABILITY"]["install"] 
     22        index.compute_with(self.cheesecake) 
     23 
     24        assert index.name == "install" 
     25        assert index.value == index.max_value 
    2226        assert index.details == "package installed in " + self.cheesecake.sandbox_install_dir 
    2327 
    2428    def test_index_install_incorrect_package(self): 
    2529        self.cheesecake = Cheesecake(path=os.path.join(datadir, "package1.tar.gz")) 
    26         index = self.cheesecake.index_install() 
    27         assert index.name == "index_install" 
     30 
     31        index = self.cheesecake.index["INSTALLABILITY"]["install"] 
     32        index.compute_with(self.cheesecake) 
     33 
     34        assert index.name == "install" 
    2835        assert index.value == 0 
    2936        assert index.details == "could not install package in " + self.cheesecake.sandbox_install_dir 
  • branches/mk/tests/test_index_installability.py

    r8 r40  
     1import os 
     2 
    13import _path_cheesecake 
    24from cheesecake.cheesecake_index import Cheesecake 
    3 import os 
     5from cheesecake.cheesecake_index import IndexPyPIDownload 
     6from cheesecake.cheesecake_index import IndexUnpack 
     7from cheesecake.cheesecake_index import IndexUnpackDir 
     8from cheesecake.cheesecake_index import IndexInstall 
     9from cheesecake.cheesecake_index import IndexUrlDownload 
     10 
    411datadir = os.path.abspath(os.path.join(os.path.dirname(__file__), "data")) 
    512 
    6 class TestIndexInstallability: 
    7  
     13class TestIndexInstallability(object): 
    814    def setUp(self): 
    915        self.cheesecake = None 
     
    1723    def test_index_installability_local_path(self): 
    1824        self.cheesecake = Cheesecake(path=os.path.join(datadir, "nose-0.8.3.tar.gz")) 
    19         assert self.cheesecake.max_cheesecake_index_installability == \ 
    20             self.cheesecake.INDEX_PYPI_DOWNLOAD + self.cheesecake.INDEX_UNPACK + \ 
    21             self.cheesecake.INDEX_UNPACK_DIR + self.cheesecake.INDEX_INSTALL 
    22                                      
    23         index_types = ["pypi_download", "unpack", "unpack_dir", "install"] 
    24         cheesecake_index_installability = self.cheesecake.process_partial_index("INSTALLABILITY",\ 
    25                                          index_types, self.cheesecake.max_cheesecake_index_installability) 
    26         assert cheesecake_index_installability == self.cheesecake.INDEX_UNPACK + \ 
    27                 self.cheesecake.INDEX_UNPACK_DIR + self.cheesecake.INDEX_INSTALL 
     25 
     26        index = self.cheesecake.index["INSTALLABILITY"] 
     27        parts = [IndexUnpack, IndexUnpackDir, IndexInstall] 
     28 
     29        assert index.max_value == sum(map(lambda x: x.max_value, parts)) 
     30 
     31        index.compute_with(self.cheesecake) 
     32        assert index.value == sum(map(lambda x: x.max_value, parts)) 
    2833 
    2934    def test_index_installability_url_download(self): 
    3035        self.cheesecake = Cheesecake(url="http://www.agilistas.org/cheesecake/nose-0.8.3.tar.gz") 
    31         assert self.cheesecake.max_cheesecake_index_installability == \ 
    32             self.cheesecake.INDEX_PYPI_DOWNLOAD + self.cheesecake.INDEX_UNPACK + \ 
    33             self.cheesecake.INDEX_UNPACK_DIR + self.cheesecake.INDEX_INSTALL 
    34         index_types = ["pypi_download", "url_download", "unpack", "unpack_dir", "install"] 
    35         cheesecake_index_installability = self.cheesecake.process_partial_index("INSTALLABILITY",\ 
    36                                          index_types, self.cheesecake.max_cheesecake_index_installability) 
    37         assert cheesecake_index_installability == \ 
    38             self.cheesecake.INDEX_URL_DOWNLOAD + self.cheesecake.INDEX_UNPACK + \ 
    39             self.cheesecake.INDEX_UNPACK_DIR + self.cheesecake.INDEX_INSTALL 
     36 
     37        index = self.cheesecake.index["INSTALLABILITY"] 
     38        parts = [IndexUnpack, IndexUnpackDir, IndexInstall, IndexUrlDownload] 
     39 
     40        assert index.max_value == sum(map(lambda x: x.max_value, parts)) 
     41 
     42        index.compute_with(self.cheesecake) 
     43        assert index.value == sum(map(lambda x: x.max_value, parts)) 
  • branches/mk/tests/test_index_unpack.py

    r22 r40  
     1import os 
     2import tempfile 
     3 
    14import _path_cheesecake 
    25from cheesecake.cheesecake_index import Cheesecake, CheesecakeError, pad_msg 
    3  
    4 import os 
    5 import tempfile 
    66 
    77default_temp_directory = os.path.join(tempfile.gettempdir(), 'cheesecake_sandbox') 
     
    99 
    1010class TestIndexUnpack(object): 
    11  
    1211    def setUp(self): 
    1312        self.cheesecake = None 
     
    1918        os.unlink(self.cheesecake.logfile) 
    2019 
    21     def _run_valid(self, package_file, message): 
     20    def _run_valid(self, package_file): 
    2221        self.cheesecake = Cheesecake(path=os.path.join(datadir, package_file)) 
    23         index = self.cheesecake.index_unpack() 
    24         assert index.name == "index_unpack" 
    25         assert index.value == self.cheesecake.INDEX_UNPACK 
    26         assert index.details == message 
     22 
     23        index = self.cheesecake.index["INSTALLABILITY"]["unpack"] 
     24        index.compute_with(self.cheesecake) 
     25 
     26        assert index.name == "unpack" 
     27        assert index.value == index.max_value 
     28        assert index.details == "package unpacked successfully" 
    2729 
    2830    def test_index_unpack_valid_tar_gz(self): 
    29         self._run_valid("package1.tar.gz", "package untar-ed successfully"
     31        self._run_valid("package1.tar.gz"
    3032 
    3133    def test_index_unpack_valid_tgz(self): 
    32         self._run_valid("package1.tgz", "package untar-ed successfully"
     34        self._run_valid("package1.tgz"
    3335 
    3436    def test_index_unpack_valid_zip(self): 
    35         self._run_valid("package1.zip", "package unzipped successfully"
     37        self._run_valid("package1.zip"
    3638 
    3739    def _run_invalid(self, package_file, message): 
  • branches/mk/tests/test_index_unpack_dir.py

    r8 r40  
     1import os 
     2 
    13import _path_cheesecake 
    2 from cheesecake.cheesecake_index import Cheesecake 
    3 import os 
     4from cheesecake.cheesecake_index import Cheesecake, IndexUnpackDir 
     5 
    46datadir = os.path.abspath(os.path.join(os.path.dirname(__file__), "data")) 
    57 
    6 class TestIndexUnpackDir: 
    7  
     8class IndexUnpackDirTest(object): 
    89    def setUp(self): 
    910        self.cheesecake = None 
     
    1516        os.unlink(self.cheesecake.logfile) 
    1617 
     18class TestIndexUnpackDirCorrectPackage(IndexUnpackDirTest): 
    1719    def test_index_unpack_dir_correct_package(self): 
    1820        self.cheesecake = Cheesecake(path=os.path.join(datadir, "package1.tar.gz")) 
    19         index = self.cheesecake.index_unpack_dir() 
    20         assert index.name == "index_unpack_dir" 
    21         assert index.value == self.cheesecake.INDEX_UNPACK_DIR 
     21        index = self.cheesecake.index["INSTALLABILITY"]["unpack_dir"] 
     22 
     23        index.compute_with(self.cheesecake) 
     24 
     25        assert index.name == "unpack_dir" 
     26        assert index.value == IndexUnpackDir.max_value 
    2227        assert index.details == "unpack directory is " + self.cheesecake.package_name + " as expected" 
    2328 
     29class TestIndexUnpackDirCorrectPackage(IndexUnpackDirTest): 
    2430    def test_index_unpack_dir_incorrect_package(self): 
    2531        self.cheesecake = Cheesecake(path=os.path.join(datadir, "package_renamed.tar.gz")) 
    26         index = self.cheesecake.index_unpack_dir() 
    27         assert index.name == "index_unpack_dir" 
     32        index = self.cheesecake.index["INSTALLABILITY"]["unpack_dir"] 
     33 
     34        index.compute_with(self.cheesecake) 
     35 
     36        assert index.name == "unpack_dir" 
     37        print index.value, index.max_value 
    2838        assert index.value == 0 
    2939        assert index.details == "unpack directory is package1 instead of the expected package_renamed" 
  • branches/mk/tests/test_index_url_download.py

    r22 r40  
    1 import _path_cheesecake 
    2 from cheesecake.cheesecake_index import Cheesecake, CheesecakeError, pad_msg 
    3          
    41import os 
    52import tempfile 
    63 
     4import _path_cheesecake 
     5from cheesecake.cheesecake_index import Cheesecake, CheesecakeError, pad_msg, IndexUrlDownload 
     6         
    77default_temp_directory = os.path.join(tempfile.gettempdir(), 'cheesecake_sandbox') 
    88 
    99 
    1010class TestIndexInstallability(object): 
    11  
    1211    def setUp(self): 
    1312        self.cheesecake = None 
     
    3332                try: 
    3433                    self.cheesecake = Cheesecake(url=url) 
    35                     index = self.cheesecake.index_url_download() 
    36                     assert index.name == "index_url_download" 
    37                     assert index.value == self.cheesecake.INDEX_URL_DOWNLOAD 
     34 
     35                    index = self.cheesecake.index["INSTALLABILITY"]["url_download"] 
     36                    index.compute_with(self.cheesecake) 
     37 
     38                    assert index.name == "url_download" 
     39                    assert index.value == IndexUrlDownload.max_value 
    3840                    assert index.details == "downloaded package " + \ 
    3941                           self.cheesecake.package + " from URL " + \ 
  • branches/mk/tests/test_init_cleanup.py

    r18 r40  
    4444    def test_cleanup_after_install(self): 
    4545        self.cheesecake = Cheesecake(path=os.path.join(datadir, "package1.tar.gz")) 
    46         self.cheesecake.index_install() 
    4746        self.cheesecake.cleanup() 
    4847        assert not os.path.exists(self.cheesecake.sandbox_pkg_dir)