PKãI6Áa=¦  cheesecake/cheesecake_index.py#!/usr/bin/env python """Cheesecake: How tasty is your code? The idea of the Cheesecake project is to rank Python packages based on various empirical "kwalitee" factors, such as: * whether the package can be downloaded from PyPI given its name * whether the package can be unpacked * whether the package can be installed into an alternate directory * existence of certain files such as README, INSTALL, LICENSE, setup.py etc. * percentage of modules/functions/classes/methods with docstrings * ... and many others """ import os import re import shutil import sys import tempfile from optparse import OptionParser from urllib import urlretrieve from urlparse import urlparse from math import ceil import logger from util import pad_with_dots, pad_left_spaces, pad_right_spaces, pad_msg, pad_line from util import run_cmd, command_successful from util import unzip_package, untar_package, unegg_package from util import mkdirs from util import StdoutRedirector from util import time_function from codeparser import CodeParser from __init__ import __version__ as VERSION import pep8 __docformat__ = 'reStructuredText en' __revision__ = '$Revision: 176 $'[11:-1].strip() ################################################################################ ## Helpers. ################################################################################ if 'sorted' not in dir(__builtins__): def sorted(L): new_list = L[:] new_list.sort() return new_list if 'set' not in dir(__builtins__): from sets import Set as set def isiterable(obj): """Check whether object is iterable. >>> isiterable([1,2,3]) True >>> isiterable("string") True >>> isiterable(object) False """ return hasattr(obj, '__iter__') or isinstance(obj, basestring) def has_extension(filename, ext): """Check if filename has given extension. >>> has_extension("foobar.py", ".py") True >>> has_extension("foo.bar.py", ".py") True >>> has_extension("foobar.pyc", ".py") False This function is case insensitive. >>> has_extension("FOOBAR.PY", ".py") True """ return os.path.splitext(filename.lower())[1] == ext.lower() def discover_file_type(filename): """Discover type of a file according to its name and its parent directory. Currently supported file types: * pyc * pyo * module: .py files of an application * demo: .py files for documentation/demonstration purposes * test: .py files used for testing * special: .py file for special purposes :Note: This function only checks file's name, and doesn't touch the filesystem. If you have to, check if file exists by yourself. >>> discover_file_type('module.py') 'module' >>> discover_file_type('./setup.py') 'special' >>> discover_file_type('some/directory/junk.pyc') 'pyc' >>> discover_file_type('examples/readme.txt') >>> discover_file_type('examples/runthis.py') 'demo' >>> discover_file_type('optimized.pyo') 'pyo' >>> test_files = ['ut/test_this_and_that.py', ... 'another_test.py', ... 'TEST_MY_MODULE.PY'] >>> for filename in test_files: ... assert discover_file_type(filename) == 'test', filename >>> discover_file_type('this_is_not_a_test_really.py') 'module' """ dirs = filename.split(os.path.sep) dirs, filename = dirs[:-1], dirs[-1] if filename in ["setup.py", "ez_setup.py", "__pkginfo__.py"]: return 'special' if has_extension(filename, ".pyc"): return 'pyc' if has_extension(filename, ".pyo"): return 'pyo' if has_extension(filename, ".py"): for dir in dirs: if dir in ['test', 'tests']: return 'test' elif dir in ['doc', 'docs', 'demo', 'example', 'examples']: return 'demo' # Most test frameworks look for files starting with "test_". # py.test also looks at files with trailing "_test". if filename.lower().startswith('test_') or \ os.path.splitext(filename)[0].lower().endswith('_test'): return 'test' return 'module' def get_files_of_type(file_list, file_type): """Return files from `file_list` that match given `file_type`. >>> file_list = ['test/test_foo.py', 'setup.py', 'README', 'test/test_bar.py'] >>> get_files_of_type(file_list, 'test') ['test/test_foo.py', 'test/test_bar.py'] """ return filter(lambda x: discover_file_type(x) == file_type, file_list) def get_package_name_from_path(path): """Get package name as file portion of path. >>> get_package_name_from_path('/some/random/path/package.tar.gz') 'package.tar.gz' >>> get_package_name_from_path('/path/underscored_name.zip') 'underscored_name.zip' >>> get_package_name_from_path('/path/unknown.extension.txt') 'unknown.extension.txt' """ dir, filename = os.path.split(path) return filename def get_package_name_from_url(url): """Use ``urlparse`` to obtain package name from URL. >>> get_package_name_from_url('http://www.example.com/file.tar.bz2') 'file.tar.bz2' >>> get_package_name_from_url('https://www.example.com/some/dir/file.txt') 'file.txt' """ (scheme,location,path,param,query,fragment_id) = urlparse(url) return get_package_name_from_path(path) def get_package_name_and_type(package, known_extensions): """Return package name and type. Package type must exists in known_extensions list. Otherwise None is returned. >>> extensions = ['tar.gz', 'zip'] >>> get_package_name_and_type('underscored_name.zip', extensions) ('underscored_name', 'zip') >>> get_package_name_and_type('unknown.extension.txt', extensions) """ for package_type in known_extensions: if package.endswith('.'+package_type): # Package name is name of package without file extension (ex. twill-7.3). return package[:package.rfind('.'+package_type)], package_type def get_method_arguments(method): """Return tuple of arguments for given method, excluding self. >>> class Class: ... def method(s, arg1, arg2, other_arg): ... pass >>> get_method_arguments(Class.method) ('arg1', 'arg2', 'other_arg') """ return method.func_code.co_varnames[1:method.func_code.co_argcount] def get_attributes(obj, names): """Return attributes dictionary with keys from `names`. Object is queried for each attribute name, if it doesn't have this attribute, default value None will be returned. >>> class Class: ... pass >>> obj = Class() >>> obj.attr = True >>> obj.value = 13 >>> obj.string = "Hello" >>> d = get_attributes(obj, ['attr', 'string', 'other']) >>> d == {'attr': True, 'string': "Hello", 'other': None} True """ attrs = {} for name in names: attrs[name] = getattr(obj, name, None) return attrs def camel2underscore(name): """Convert name from CamelCase to underscore_name. >>> camel2underscore('CamelCase') 'camel_case' >>> camel2underscore('already_underscore_name') 'already_underscore_name' >>> camel2underscore('BigHTMLClass') 'big_html_class' >>> camel2underscore('') '' """ if name and name[0].upper: name = name[0].lower() + name[1:] def capitalize(match): string = match.group(1).lower().capitalize() return string[:-1] + string[-1].upper() def underscore(match): return '_' + match.group(1).lower() name = re.sub(r'([A-Z]+)', capitalize, name) return re.sub(r'([A-Z])', underscore, name) def index_class_to_name(clsname): """Covert index class name to index name. >>> index_class_to_name("IndexDownload") 'download' >>> index_class_to_name("IndexUnitTests") 'unit_tests' >>> index_class_to_name("IndexPyPIDownload") 'py_pi_download' """ return camel2underscore(clsname.replace('Index', '', 1)) def is_empty(path): """Returns True if file or directory pointed by `path` is empty. """ if os.path.isfile(path) and os.path.getsize(path) == 0: return True if os.path.isdir(path) and os.listdir(path) == []: return True return False def strip_dir_part(path, root): """Strip `root` part from `path`. >>> strip_dir_part('/home/ruby/file', '/home') 'ruby/file' >>> strip_dir_part('/home/ruby/file', '/home/') 'ruby/file' >>> strip_dir_part('/home/ruby/', '/home') 'ruby/' >>> strip_dir_part('/home/ruby/', '/home/') 'ruby/' """ path = path.replace(root, '', 1) if path.startswith(os.path.sep): path = path[1:] return path def get_files_dirs_list(root): """Return list of all files and directories below `root`. Root directory is excluded from files/directories paths. """ files = [] directories = [] for dirpath, dirnames, filenames in os.walk(root): dirpath = strip_dir_part(dirpath, root) files.extend(map(lambda x: os.path.join(dirpath, x), filenames)) directories.extend(map(lambda x: os.path.join(dirpath, x), dirnames)) return files, directories def length(L): """Overall length of all strings in list. >>> length(['a', 'bc', 'd', '', 'efg']) 7 """ return sum(map(lambda x: len(x), L)) def generate_arguments(arguments, max_length): """Pass list of strings in chunks of size not greater than max_length. >>> for x in generate_arguments(['abc', 'def'], 4): ... print x ['abc'] ['def'] >>> for x in generate_arguments(['a', 'bc', 'd', 'e', 'f'], 2): ... print x ['a'] ['bc'] ['d', 'e'] ['f'] If a single argument is larger than max_length, ValueError is raised. >>> L = [] >>> for x in generate_arguments(['abc', 'de', 'fghijk', 'l'], 4): ... L.append(x) Traceback (most recent call last): ... ValueError: Argument 'fghijk' larger than 4. >>> L [['abc'], ['de']] """ L = [] i = 0 # We have to look ahead, so C-style loop here. while arguments: if L == [] and len(arguments[i]) > max_length: raise ValueError("Argument '%s' larger than %d." % (arguments[i], max_length)) L.append(arguments[i]) # End of arguments: yield then terminate. if i == len(arguments) - 1: yield L break # Adding next argument would exceed max_length, so yield now. if length(L) + len(arguments[i+1]) > max_length: yield L L = [] i += 1 ################################################################################ ## Main index class. ################################################################################ class NameSetter(type): def __init__(cls, name, bases, dict): if 'name' not in dict: setattr(cls, 'name', name) if 'compute_with' in dict: orig_compute_with = cls.compute_with def _timed_compute_with(self, cheesecake): (ret, self.time_taken) = time_function(lambda: orig_compute_with(self, cheesecake)) self.cheesecake.log.debug("Index %s computed in %.2f seconds." % (self.name, self.time_taken)) return ret setattr(cls, 'compute_with', _timed_compute_with) def __repr__(cls): return '' % cls.name def make_indices_dict(indices): indices_dict = {} for index in indices: indices_dict[index.name] = index return indices_dict class Index(object): """Class describing one index. Use it as a container index or subclass to create custom indices. During class initialization, special attribute `name` is magically set based on class name. See `NameSetter` definitions for details. """ __metaclass__ = NameSetter subindices = None name = "unnamed" value = -1 details = "" info = "" def __init__(self, *indices): # When indices are given explicitly they override the default. if indices: self.subindices = [] self._indices_dict = {} for index in indices: self.add_subindex(index) else: if self.subindices: new_subindices = [] for index in self.subindices: # index must be a class subclassing from Index. assert isinstance(index, type) assert issubclass(index, Index) new_subindices.append(index()) self.subindices = new_subindices else: self.subindices = [] # Create dictionary for fast reference. self._indices_dict = make_indices_dict(self.subindices) self._compute_arguments = get_method_arguments(self.compute) def _iter_indices(self): """Iterate over each subindex and yield their values. """ for index in self.subindices[:]: try: # Pass Cheesecake instance to a subindex. yield index.compute_with(self.cheesecake) # Print index info after computing. if not self.cheesecake.quiet: index.print_info() except: # When exception is thrown, silence it # and remove this subindex from the list. self.subindices.remove(index) def compute_with(self, cheesecake): """Take given Cheesecake instance and compute index value. """ self.cheesecake = cheesecake return self.compute(**get_attributes(cheesecake, self._compute_arguments)) def compute(self): """Compute index value and return it. By default this method computes sum of all subindices. Override this method when subclassing for different behaviour. Parameters to this function are dynamically prepared with use of `get_attributes` function. :Warning: Don't use \*args and \*\*kwds arguments for this method. """ self.value = sum(self._iter_indices()) return self.value def decide(self, cheesecake, when): """Decide if this index should be computed. If index has children, it will automatically remove all for which decide() return false. """ if self.subindices: # Iterate over copy, as we may remove some elements. for index in self.subindices[:]: if not getattr(index, 'decide_' + when)(cheesecake): self.remove_subindex(index.name) return self.subindices return True def decide_before_download(self, cheesecake): return self.decide(cheesecake, 'before_download') def decide_after_download(self, cheesecake): return self.decide(cheesecake, 'after_download') def add_info(self, info_line): """Add information about index computation process, which will be visible with --verbose flag. """ self.info += "[%s] %s\n" % (index_class_to_name(self.name), info_line) def _get_max_value(self): if self.subindices: return sum(map(lambda index: index.max_value, self.subindices)) return 0 max_value = property(_get_max_value) def _get_requirements(self): if self.subindices: return list(self._compute_arguments) + \ reduce(lambda x,y: x + y.requirements, self.subindices, []) return list(self._compute_arguments) requirements = property(_get_requirements) def add_subindex(self, index): """Add subindex. :Parameters: `index` : Index instance Index instance for inclusion. """ if not isinstance(index, Index): raise ValueError("subindex has to be instance of Index") self.subindices.append(index) self._indices_dict[index.name] = index def remove_subindex(self, index_name): """Remove subindex (refered by name). :Parameters: `index` : Index name Index name to be removed. """ index = self._indices_dict[index_name] self.subindices.remove(index) del self._indices_dict[index_name] def _print_info_one(self): if self.cheesecake.verbose: sys.stdout.write(self.get_info()) print "%s (%s)" % (pad_msg(index_class_to_name(self.name), self.value), self.details) def _print_info_many(self): max_value = self.max_value if max_value == 0: return percentage = int(ceil(float(self.value) / float(max_value) * 100)) print pad_line("-") print pad_msg("%s INDEX (ABSOLUTE)" % self.name, self.value) msg = pad_msg("%s INDEX (RELATIVE)" % self.name, percentage) msg += " (%d out of a maximum of %d points is %d%%)" %\ (self.value, max_value, percentage) print msg print def print_info(self): """Print index name padded with dots, followed by value and details. """ if self.subindices: self._print_info_many() else: self._print_info_one() def __getitem__(self, name): return self._indices_dict[name] def get_info(self): if self.subindices: return ''.join(map(lambda index: index.get_info(), self.subindices)) return self.info ################################################################################ ## Index that computes scores based on files and directories. ################################################################################ class OneOf(object): def __init__(self, *possibilities): self.possibilities = possibilities def __str__(self): return '/'.join(map(lambda x: str(x), self.possibilities)) def WithOptionalExt(name, extensions): """Handy way of writing Cheese rules for files with extensions. Instead of writing: >>> one_of = OneOf('readme', 'readme.html', 'readme.txt') Write this: >>> opt_ext = WithOptionalExt('readme', ['html', 'txt']) It means the same! (representation has a meaning) >>> str(one_of) == str(opt_ext) True """ possibilities = [name] possibilities.extend(map(lambda x: name + '.' + x, extensions)) return OneOf(*possibilities) def Doc(name): return WithOptionalExt(name, ['html', 'txt']) class FilesIndex(Index): _used_rules = [] def _compute_from_rules(self, files_list, package_dir, files_rules): self._used_rules = [] files_count = 0 value = 0 for filename in files_list: if not is_empty(os.path.join(package_dir, filename)): score = self.get_score(os.path.basename(filename), files_rules) if score != 0: value += score files_count += 1 return files_count, value def get_score(self, name, specs): for entry, value in specs.iteritems(): if self.match_filename(name, entry): self.cheesecake.log.debug("%d points entry found: %s (%s)" % \ (value, name, entry)) return value return 0 def get_not_used(self, files_rules): """Get only these of files_rules that didn't match during computation. >>> rules = { ... Doc('readme'): 30, ... OneOf(Doc('license'), Doc('copying')): 30, ... 'demo': 10, ... } >>> index = FilesIndex() >>> index._used_rules.append('demo') >>> map(lambda x: str(x), index.get_not_used(rules.keys())) ['license/license.html/license.txt/copying/copying.html/copying.txt', 'readme/readme.html/readme.txt'] """ return filter(lambda rule: rule not in self._used_rules, files_rules) def match_filename(self, name, rule): """Check if `name` matches given `rule`. """ def equal(x, y): x_root, x_ext = os.path.splitext(x) y_root, y_ext = os.path.splitext(y.lower()) if x_root in [y_root.lower(), y_root.upper(), y_root.capitalize()] \ and x_ext in [y_ext.lower(), y_ext.upper()]: return True return False if rule in self._used_rules: return False if isinstance(rule, basestring): if equal(name, rule): self._used_rules.append(rule) return True elif isinstance(rule, OneOf): for poss in rule.possibilities: if self.match_filename(name, poss): self._used_rules.append(rule) return True return False ################################################################################ ## Installability index. ################################################################################ class IndexUrlDownload(Index): """Give points for successful downloading of a package. """ max_value = 25 def compute(self, downloaded_from_url, package, url): if downloaded_from_url: self.details = "downloaded package %s from URL %s" % (package, url) self.value = self.max_value else: self.value = 0 return self.value def decide_before_download(self, cheesecake): return cheesecake.url class IndexUnpack(Index): """Give points for successful unpacking of a package archive. """ max_value = 25 def compute(self, unpacked): if unpacked: self.details = "package unpacked successfully" self.value = self.max_value else: self.details = "package couldn't be unpacked" self.value = 0 return self.value class IndexUnpackDir(Index): """Check if package unpack directory resembles package archive name. """ max_value = 15 def compute(self, unpack_dir, original_package_name): self.details = "unpack directory is " + unpack_dir if original_package_name: self.details += " instead of the expected " + original_package_name self.value = 0 else: self.details += " as expected" self.value = self.max_value return self.value def decide_after_download(self, cheesecake): return cheesecake.package_type != 'egg' class IndexSetupPy(FilesIndex): """Reward packages that have setup.py file. """ name = "setup.py" max_value = 25 files_rules = { 'setup.py': 25, } def compute(self, files_list, package_dir): setup_py_found, self.value = self._compute_from_rules(files_list, package_dir, self.files_rules) if setup_py_found: self.details = "setup.py found" else: self.details = "setup.py not found" return self.value def decide_after_download(self, cheesecake): return cheesecake.package_type != 'egg' class IndexInstall(Index): """Check if package can be installed via "python setup.py" command. """ max_value = 50 def compute(self, installed, sandbox_install_dir): if installed: self.details = "package installed in %s" % sandbox_install_dir self.value = self.max_value else: self.details = "could not install package in %s" % sandbox_install_dir self.value = 0 return self.value def decide_before_download(self, cheesecake): return not cheesecake.static_only class IndexPyPIDownload(Index): """Check if package was successfully downloaded from PyPI and how far from it actual package was. Distance is number of links user has to follow to download a given software package. """ max_value = 50 distance_penalty = -5 def compute(self, package, found_on_cheeseshop, found_locally, distance_from_pypi, download_url): if download_url: self.value = self.max_value self.details = "downloaded package " + package if not found_on_cheeseshop: if distance_from_pypi > 0: self.value += (distance_from_pypi - 1) * self.distance_penalty self.details += " following %d link" % distance_from_pypi if distance_from_pypi > 1: self.details += "s" self.details += " from PyPI" else: self.details += " from " + download_url else: self.details += " directly from the Cheese Shop" else: if found_locally: self.details = "found on local filesystem" self.value = 0 return self.value def decide_before_download(self, cheesecake): return cheesecake.name class IndexGeneratedFiles(Index): """Lower score for automatically generated files that should not be present in a package. """ generated_files_penalty = -20 max_value = 0 def compute(self, files_list): self.value = 0 pyc_files = len(get_files_of_type(files_list, 'pyc')) pyo_files = len(get_files_of_type(files_list, 'pyo')) if pyc_files > 0 or pyo_files > 0: self.value += self.generated_files_penalty self.details = "%d .pyc and %d .pyo files found" % \ (pyc_files, pyo_files) return self.value def decide_after_download(self, cheesecake): return cheesecake.package_type != 'egg' class IndexInstallability(Index): name = "INSTALLABILITY" subindices = [ IndexPyPIDownload, IndexUrlDownload, IndexUnpack, IndexUnpackDir, IndexSetupPy, IndexInstall, IndexGeneratedFiles, ] ################################################################################ ## Documentation index. ################################################################################ class IndexRequiredFiles(FilesIndex): """Check for existence of important files, like README or INSTALL. """ cheese_files = { Doc('readme'): 30, OneOf(Doc('license'), Doc('copying')): 30, OneOf(Doc('announce'), Doc('changelog'), Doc('changes')): 20, Doc('install'): 20, Doc('authors'): 10, Doc('faq'): 10, Doc('news'): 10, Doc('thanks'): 10, Doc('todo'): 10, } cheese_dirs = { OneOf('doc', 'docs'): 30, OneOf('test', 'tests'): 30, OneOf('demo', 'example', 'examples'): 10, } max_value = sum(cheese_files.values() + cheese_dirs.values()) def compute(self, files_list, dirs_list, package_dir): # Inform user of files and directories the package is missing. def make_info(dictionary, what): missing = self.get_not_used(dictionary.keys()) importance = {30: ' critical', 20: ' important'} positive_msg = "Package has%s %s: %s." negative_msg = "Package doesn't have%s %s: %s." for key in dictionary.keys(): msg = positive_msg if key in missing: msg = negative_msg self.add_info(msg % (importance.get(dictionary[key], ''), what, str(key))) # Compute required files. files_count, files_value = self._compute_from_rules(files_list, package_dir, self.cheese_files) make_info(self.cheese_files, 'file') # Compute required directories. dirs_count, dirs_value = self._compute_from_rules(dirs_list, package_dir, self.cheese_dirs) make_info(self.cheese_dirs, 'directory') self.value = files_value + dirs_value self.details = "%d files and %d required directories found" % \ (files_count, dirs_count) return self.value class IndexDocstrings(Index): """Compute how many objects have relevant docstrings. """ max_value = 100 def compute(self, object_cnt, docstring_cnt): percent = 0 if object_cnt > 0: percent = float(docstring_cnt)/float(object_cnt) # Scale the result. self.value = int(ceil(percent * self.max_value)) self.details = "found %d/%d=%.2f%% objects with docstrings" %\ (docstring_cnt, object_cnt, percent*100) return self.value class IndexFormattedDocstrings(Index): """Compute how many of existing docstrings include any formatting, like epytext or reST. """ max_value = 30 def compute(self, object_cnt, docformat_cnt): percent = 0 if object_cnt > 0: percent = float(docformat_cnt)/float(object_cnt) # Scale the result. # We give 10p for 25% of formatted docstrings, 20p for 50% and 30p for 75%. self.value = 0 if percent > 0.75: self.add_info("%.2f%% formatted docstrings found, which is > 75%% and is worth 30p." % (percent*100)) self.value = 30 elif percent > 0.50: self.add_info("%.2f%% formatted docstrings found, which is > 50%% and is worth 20p." % (percent*100)) self.value = 20 elif percent > 0.25: self.add_info("%.2f%% formatted docstrings found, which is > 25%% and is worth 10p." % (percent*100)) self.value = 10 else: self.add_info("%.2f%% formatted docstrings found, which is < 25%%, no points given." % (percent*100)) self.details = "found %d/%d=%.2f%% objects with formatted docstrings" %\ (docformat_cnt, object_cnt, percent*100) return self.value class IndexDocumentation(Index): name = "DOCUMENTATION" subindices = [ IndexRequiredFiles, IndexDocstrings, IndexFormattedDocstrings, ] ################################################################################ ## Code "kwalitee" index. ################################################################################ class IndexUnitTests(Index): """Compute unittest index as percentage of methods/functions that are exercised in unit tests. """ max_value = 50 def compute(self, files_list, functions, classes, package_dir): unittest_cnt = 0 functions_tested = set() # Gather all function names called from test files. for testfile in get_files_of_type(files_list, 'test'): fullpath = os.path.join(package_dir, testfile) code = CodeParser(fullpath, self.cheesecake.log.debug) functions_tested = functions_tested.union(code.functions_called) for name in functions + classes: if name in functions_tested: unittest_cnt += 1 self.cheesecake.log.debug("%s is unit tested" % name) functions_classes_cnt = len(functions) + len(classes) percent = 0 if functions_classes_cnt > 0: percent = float(unittest_cnt)/float(functions_classes_cnt) # Scale the result. self.value = int(ceil(percent * self.max_value)) self.details = "found %d/%d=%.2f%% unit tested classes/methods/functions." %\ (unittest_cnt, functions_classes_cnt, percent*100) return self.value class IndexUnitTested(Index): """Check if the package has unit tests which can be easily found by any of known test frameworks. """ max_value = 30 def compute(self, doctests_count, unittests_count, files_list, classes, methods): unit_tested = False if doctests_count > 0: self.add_info("Package includes doctest tests.") unit_tested = True if unittests_count > 0: self.add_info("Package has tests that inherit from unittest.TestCase.") unit_tested = True if get_files_of_type(files_list, 'test'): self.add_info("Package has filenames which probably contain tests (in format test_* or *_test)") unit_tested = True for method in methods: if self._is_test_method(method): self.add_info("Some classes have setUp/tearDown methods which are commonly used in unit tests.") unit_tested = True break if unit_tested: self.value = self.max_value self.details = "has unit tests" else: self.value = 0 self.details = "doesn't have unit tests" return self.value def _is_test_method(self, method): nose_methods = ['setup', 'setup_package', 'setup_module', 'setUp', 'setUpPackage', 'setUpModule', 'teardown', 'teardown_package', 'teardown_module', 'tearDown', 'tearDownModule', 'tearDownPackage'] for test_method in nose_methods: if method.endswith(test_method): return True return False class IndexPyLint(Index): """Compute pylint index of the whole package. """ name = "pylint" max_value = 50 disabled_messages = [ 'W0403', # relative import 'W0406', # importing of self ] pylint_args = ' '.join(map(lambda x: '--disable-msg=%s' % x, disabled_messages)) def compute(self, files_list, package_dir, pylint_max_execution_time): # See if pylint script location is set via environment variable pylint_location = os.environ.get("PYLINT", "pylint") # Maximum length of arguments (not very precise). max_arguments_length = 65536 # Exclude __init__.py files from score as they cause pylint # to fail with ImportError "Unable to find module for %s in %s". files_to_lint = filter(lambda name: not name.endswith('__init__.py'), get_files_of_type(files_list, 'module')) # Switching cwd so that pylint works correctly regarding # running it on individual modules. original_cwd = os.getcwd() # Note: package_dir may be a file if the archive contains a single file. # If this is the case, change dir to the parent dir of that file. if os.path.isfile(package_dir): package_dir = os.path.dirname(package_dir) os.chdir(package_dir) pylint_score = 0 count = 0 error_count = 0 for filenames in generate_arguments(files_to_lint, max_arguments_length - len(self.pylint_args)): filenames = ' '.join(filenames) self.cheesecake.log.debug("Running pylint on files: %s." % filenames) # Run pylint, but don't allow it to work longer than one minute. rc, output = run_cmd("%s %s --persistent=n %s" % (pylint_location, filenames, self.pylint_args), max_timeout=pylint_max_execution_time) if rc: if output == 'Time exceeded': # Raise and exception what will cause PyLint to be removed from list of indices # and thus won't affect the score. self.cheesecake.log.debug("pylint exceeded maximum execution time of %d seconds and was terminated." % \ pylint_max_execution_time) raise OSError self.cheesecake.log.debug("encountered an error (%d):\n***\n%s\n***\n" % (rc, output)) error_count += 1 else: # Extract score from pylint output. score_line = output.split("\n")[-3] s = re.search(r" (-?\d+\.\d+)/10", score_line) if s: pylint_score += float(s.group(1)) count += 1 # Switching back to the original cwd. os.chdir(original_cwd) if count: pylint_score = float(pylint_score)/float(count) self.details = "pylint score was %.2f out of 10" % pylint_score elif error_count: self.details = "encountered an error during pylint execution" else: self.details = "no files to check found" # Assume scores below zero as zero for means of index value computation. if pylint_score < 0: pylint_score = 0 self.value = int(ceil(pylint_score/10.0 * self.max_value)) self.add_info("Score is %.2f/10, which is %d%% of maximum %d points = %d." % (pylint_score, int(pylint_score*10), self.max_value, self.value)) return self.value def decide_before_download(self, cheesecake): # Try to run the pylint script if not command_successful("pylint --version"): cheesecake.log.debug("pylint not properly installed, omitting pylint index.") return False return not cheesecake.lite class IndexPEP8(Index): """Compute PEP8 index for the modules in the package. """ name = "pep8" # # Max value is a number of possible pep8 errors times 2, # plus number of possible pep8 warnings. # # Currently pep8 module support 15 errors: # E101, # E111, E112, E113, # E201, E202, E203, # E211, # E221, E222, # E301, E302, E303, # E401, # E501 # and 4 warnings: # W191, # W291, # W601, # W602 # max_value = 34 error_score = -2 warning_score = -1 def compute(self, files_list, package_dir): files_to_score = get_files_of_type(files_list, 'module') if len(files_to_score) == 0: self.value = 0 self.details = "no modules found" return self.value full_paths = [os.path.join(package_dir, file) for file in files_to_score] arglist = ["-qq"] + full_paths pep8.process_options(arglist) for file in files_to_score: fullpath = os.path.join(package_dir, file) pep8.input_file(fullpath) error_stats = pep8.get_error_statistics() warning_stats = pep8.get_warning_statistics() errors = len(error_stats) warnings = len(warning_stats) total_error_score = self.error_score * errors total_warning_score = self.warning_score * warnings score = total_error_score + total_warning_score self.value = self.max_value + score self.add_info("Errors:") self.add_info("Count Details") for stat in error_stats: self.add_info(stat) self.add_info("pep8.py found %d error types; we're scoring %d per error type" % (errors, self.error_score)) self.add_info("Error score: %d" % total_error_score) self.add_info("Warnings:") self.add_info("Count Details") for stat in warning_stats: self.add_info(stat) self.add_info("pep8.py found %d warning types; we're scoring %d per warning type" % (warnings, self.warning_score)) self.add_info("Warning score: %d" % total_warning_score) self.add_info("Total pep8 score: %d - %d = %d" % (self.max_value, abs(score), self.value)) self.details = "pep8.py check: %d error types, %d warning types" % (errors, warnings) return self.value def decide_before_download(self, cheesecake): return cheesecake.with_pep8 class IndexCodeKwalitee(Index): name = "CODE KWALITEE" subindices = [ #IndexUnitTests, IndexUnitTested, IndexPyLint, IndexPEP8, ] ################################################################################ ## Main Cheesecake class. ################################################################################ class CheesecakeError(Exception): """Custom exception class for Cheesecake-specific errors. """ pass class CheesecakeIndex(Index): name = "Cheesecake" subindices = [ IndexInstallability, IndexDocumentation, IndexCodeKwalitee, ] class Step(object): """Single step during computation of package score. """ def __init__(self, provides): self.provides = provides def decide(self, cheesecake): """Decide if step should be run. It checks if there's at least one index from current profile that need variables provided by this step. Override this method for other behaviour. """ for provide in self.provides: if provide in cheesecake.index.requirements: return True return False class StepByVariable(Step): """Step which is always run if given Cheesecake instance variable is true. """ def __init__(self, variable_name, provides): self.variable_name = variable_name Step.__init__(self, provides) def decide(self, cheesecake): if getattr(cheesecake, self.variable_name, None): return True # Fallback to the default. return Step.decide(self, cheesecake) class Cheesecake(object): """Computes 'goodness' of Python packages. Generates "cheesecake index" that takes into account things like: * whether the package can be downloaded * whether the package can be unpacked * whether the package can be installed into an alternate directory * existence of certain files such as README, INSTALL, LICENSE, setup.py etc. * existence of certain directories such as doc, test, demo, examples * percentage of modules/functions/classes/methods with docstrings * percentage of functions/methods that are unit tested * average pylint score for all non-test and non-demo modules """ steps = {} package_types = { "tar.gz": untar_package, "tgz": untar_package, "zip": unzip_package, "egg": unegg_package, } def __init__(self, keep_log = False, lite = False, logfile = None, name = "", path = "", pylint_max_execution_time = None, quiet = False, sandbox = None, static_only = False, url = "", verbose = False, with_pep8 = False): """Initialize critical variables, download and unpack package, walk package tree. """ self.name = name self.url = url self.package_path = path if self.name: self.package = self.name elif self.url: self.package = get_package_name_from_url(self.url) elif self.package_path: self.package = get_package_name_from_path(self.package_path) else: self.raise_exception("No package name, URL or path specified... exiting") # Setup a sandbox. self.sandbox = sandbox or tempfile.mkdtemp(prefix='cheesecake') if not os.path.isdir(self.sandbox): os.mkdir(self.sandbox) self.verbose = verbose self.quiet = quiet self.static_only = static_only self.lite = lite self.keep_log = keep_log self.with_pep8 = with_pep8 self.pylint_max_execution_time = pylint_max_execution_time self.sandbox_pkg_file = "" self.sandbox_pkg_dir = "" self.sandbox_install_dir = "" # Configure logging as soon as possible. self.configure_logging(logfile) # Setup Cheesecake index. self.index = CheesecakeIndex() self.index.decide_before_download(self) self.log.debug("Profile requirements: %s." % ', '.join(sorted(self.index.requirements))) # Get the package. self.run_step('get_pkg_from_pypi') self.run_step('download_pkg') self.run_step('copy_pkg') # Get package name and type. name_and_type = get_package_name_and_type(self.package, self.package_types.keys()) if not name_and_type: msg = "Could not determine package type for package '%s'" % self.package msg += "\nCurrently recognized types: " + ", ".join(self.package_types.keys()) self.raise_exception(msg) self.package_name, self.package_type = name_and_type self.log.debug("Package name: " + self.package_name) self.log.debug("Package type: " + self.package_type) # Make last indices decisions. self.index.decide_after_download(self) # Unpack package and list its files. self.run_step('unpack_pkg') self.run_step('walk_pkg') # Install package. self.run_step('install_pkg') def raise_exception(self, msg): """Cleanup, print error message and raise CheesecakeError. Don't use logging, since it can be called before logging has been setup. """ self.cleanup(remove_log_file=False) msg += "\nDetailed info available in log file %s" % self.logfile raise CheesecakeError("Error: " + msg) def cleanup(self, remove_log_file=True): """Delete temporary directories and files that were created in the sandbox. At the end delete the sandbox itself. """ if os.path.isfile(self.sandbox_pkg_file): self.log("Removing file %s" % self.sandbox_pkg_file) os.unlink(self.sandbox_pkg_file) def delete_dir(dirname): "Delete directory recursively and generate log message." if os.path.isdir(dirname): self.log("Removing directory %s" % dirname) shutil.rmtree(dirname) delete_dir(self.sandbox) if remove_log_file and not self.keep_log: log_path = os.path.join(self.sandbox, self.logfile) if os.path.exists(log_path): os.unlink(log_path) def configure_logging(self, logfile=None): """Default settings for logging. If verbose, log goes to console, else it goes to logfile. log.debug and log.info goes to logfile. log.warn and log.error go to both logfile and stdout. """ if logfile: self.logfile = logfile else: self.logfile = os.path.join(tempfile.gettempdir(), self.package + ".log") logger.setconsumer('logfile', open(str(self.logfile), 'w', buffering=1)) logger.setconsumer('console', logger.STDOUT) logger.setconsumer('null', None) self.log = logger.MultipleProducer('cheesecake logfile') self.log.info = logger.MultipleProducer('cheesecake logfile') self.log.debug = logger.MultipleProducer('cheesecake logfile') self.log.warn = logger.MultipleProducer('cheesecake console') self.log.error = logger.MultipleProducer('cheesecake console') def run_step(self, step_name): """Run step if its decide() method returns True. """ step = self.steps[step_name] if step.decide(self): step_method = getattr(self, step_name) step_method() steps['get_pkg_from_pypi'] = StepByVariable('name', ['download_url', 'distance_from_pypi', 'found_on_cheeseshop', 'found_locally', 'sandbox_pkg_file']) def get_pkg_from_pypi(self): """Download package using setuptools utilities. New attributes: download_url : str URL that package was downloaded from. distance_from_pypi : int How many hops setuptools had to make to download package. found_on_cheeseshop : bool Whenever package has been found on CheeseShop. found_locally : bool Whenever package has been already installed. """ self.log.info("Trying to download package %s from PyPI using setuptools utilities" % self.name) try: from setuptools.package_index import PackageIndex from pkg_resources import Requirement from distutils import log from distutils.errors import DistutilsError except ImportError, e: msg = "setuptools is not installed and is required for downloading a package by name\n" msg += "You can download and process a package by its full URL via the -u or --url option\n" msg += "Example: python cheesecake.py --url=http://www.mems-exchange.org/software/durus/Durus-3.1.tar.gz" self.raise_exception(msg) def drop_setuptools_info(stdout, error=None): """Drop all setuptools output as INFO. """ self.log.info("*** Begin setuptools output") map(self.log.info, stdout.splitlines()) if error: self.log.info(str(error)) self.log.info("*** End setuptools output") def fetch_package(mode): """Fetch package from PyPI. Mode can be one of: * 'pypi_source': get source package from PyPI * 'pypi_any': get source/egg package from PyPI * 'any': get package from PyPI or local filesystem Returns tuple (status, output), where `status` is True if fetch was successful and False if it failed. `output` is PackageIndex.fetch() return value. """ if 'pypi' in mode: pkgindex = PackageIndex(search_path=[]) else: pkgindex = PackageIndex() if mode == 'pypi_source': source = True else: source = False try: output = pkgindex.fetch(Requirement.parse(self.name), self.sandbox, force_scan=True, source=source) return True, output except DistutilsError, e: return False, e # Temporarily set the log verbosity to INFO so we can capture setuptools # info messages. old_threshold = log.set_threshold(log.INFO) old_stdout = sys.stdout sys.stdout = StdoutRedirector() # Try to get source package from PyPI first, then egg from PyPI, and if # that fails search in locally installed packages. for mode, info in [('pypi_source', "source package on PyPI"), ('pypi_any', "egg on PyPI"), ('any', "locally installed package")]: msg = "Looking for %s... " % info status, output = fetch_package(mode) if status and output: self.log.info(msg + "found!") break self.log.info(msg + "failed.") # Bring back old stdout. captured_stdout = sys.stdout.read_buffer() sys.stdout = old_stdout log.set_threshold(old_threshold) # If all runs failed, we must raise an error. if not status: drop_setuptools_info(captured_stdout, output) self.raise_exception("setuptools returned an error: %s\n" % str(output).splitlines()[0]) # If fetch returned nothing, package wasn't found. if output is None: drop_setuptools_info(captured_stdout) self.raise_exception("Could not find distribution for " + self.name) # Defaults. self.download_url = "" self.distance_from_pypi = 0 self.found_on_cheeseshop = False self.found_locally = False for line in captured_stdout.splitlines(): s = re.search(r"Reading http(.*)", line) if s: inspected_url = s.group(1) if "python.org/pypi" not in inspected_url: self.distance_from_pypi += 1 continue s = re.search(r"Downloading (.*)", line) if s: self.download_url = s.group(1) break self.sandbox_pkg_file = output self.package = get_package_name_from_path(output) self.log.info("Downloaded package %s from %s" % (self.package, self.download_url)) if os.path.isdir(self.sandbox_pkg_file): self.found_locally = True if "cheeseshop.python.org" in self.download_url: self.found_on_cheeseshop = True steps['download_pkg'] = StepByVariable('url', ['sandbox_pkg_file', 'downloaded_from_url']) def download_pkg(self): """Use ``urllib.urlretrieve`` to download package to file in sandbox dir. """ #self.log("Downloading package %s from URL %s" % (self.package, self.url)) self.sandbox_pkg_file = os.path.join(self.sandbox, self.package) try: downloaded_filename, headers = urlretrieve(self.url, self.sandbox_pkg_file) except IOError, e: self.log.error("Error downloading package %s from URL %s" % (self.package, self.url)) self.raise_exception(str(e)) #self.log("Downloaded package %s to %s" % (self.package, downloaded_filename)) if headers.gettype() in ["text/html"]: f = open(downloaded_filename) if re.search("404 Not Found", "".join(f.readlines())): f.close() self.raise_exception("Got '404 Not Found' error while trying to download package ... exiting") f.close() self.downloaded_from_url = True steps['copy_pkg'] = StepByVariable('package_path', ['sandbox_pkg_file']) def copy_pkg(self): """Copy package file to sandbox directory. """ self.sandbox_pkg_file = os.path.join(self.sandbox, self.package) if not os.path.isfile(self.package_path): self.raise_exception("%s is not a valid file ... exiting" % self.package_path) self.log("Copying file %s to %s" % (self.package_path, self.sandbox_pkg_file)) shutil.copyfile(self.package_path, self.sandbox_pkg_file) steps['unpack_pkg'] = Step(['original_package_name', 'sandbox_pkg_dir', 'unpacked', 'unpack_dir']) def unpack_pkg(self): """Unpack the package in the sandbox directory. Check `package_types` attribute for list of currently supported archive types. New attributes: original_package_name : str Package name guessed from the package name. Will be set only if package name is different than unpacked directory name. """ self.sandbox_pkg_dir = os.path.join(self.sandbox, self.package_name) if os.path.isdir(self.sandbox_pkg_dir): shutil.rmtree(self.sandbox_pkg_dir) # Call appropriate function to unpack the package. unpack = self.package_types[self.package_type] self.unpack_dir = unpack(self.sandbox_pkg_file, self.sandbox) if self.unpack_dir is None: self.raise_exception("Could not unpack package %s ... exiting" % \ self.sandbox_pkg_file) self.unpacked = True if self.unpack_dir != self.package_name: self.original_package_name = self.package_name self.package_name = self.unpack_dir steps['walk_pkg'] = Step(['dirs_list', 'docstring_cnt', 'docformat_cnt', 'doctests_count', 'unittests_count', 'files_list', 'functions', 'classes', 'methods', 'object_cnt', 'package_dir']) def walk_pkg(self): """Get package files and directories. New attributes: dirs_list : list List of directories package contains. docstring_cnt : int Number of docstrings found in all package objects. docformat_cnt : int Number of formatted docstrings found in all package objects. doctests_count : int Number of docstrings that include doctests. unittests_count : int Number of classes which inherit from unittest.TestCase. files_list : list List of files package contains. functions : list List of all functions defined in package sources. classes : list List of all classes defined in package sources. methods : list List of all methods defined in package sources. object_cnt : int Number of documentable objects found in all package modules. package_dir : str Path to project directory. """ self.package_dir = os.path.join(self.sandbox, self.package_name) self.files_list, self.dirs_list = get_files_dirs_list(self.package_dir) self.object_cnt = 0 self.docstring_cnt = 0 self.docformat_cnt = 0 self.doctests_count = 0 self.functions = [] self.classes = [] self.methods = [] self.unittests_count = 0 # Parse all application files and count objects # (modules/classes/functions) and their associated docstrings. for py_file in get_files_of_type(self.files_list, 'module'): pyfile = os.path.join(self.package_dir, py_file) code = CodeParser(pyfile, self.log.debug) self.object_cnt += code.object_count() self.docstring_cnt += code.docstring_count() self.docformat_cnt += code.formatted_docstrings_count self.functions += code.functions self.classes += code.classes self.methods += code.methods self.doctests_count += code.doctests_count self.unittests_count += code.unittests_count # Log a bit of debugging info. self.log.debug("Found %d files: %s." % (len(self.files_list), ', '.join(self.files_list))) self.log.debug("Found %d directories: %s." % (len(self.dirs_list), ', '.join(self.dirs_list))) steps['install_pkg'] = Step(['installed']) def install_pkg(self): """Verify that package can be installed in alternate directory. New attributes: installed : bool Describes whenever package has been succefully installed. """ self.sandbox_install_dir = os.path.join(self.sandbox, "tmp_install_%s" % self.package_name) if self.package_type == 'egg': # Create dummy Python directories. mkdirs('%s/lib/python2.3/site-packages/' % self.sandbox_install_dir) mkdirs('%s/lib/python2.4/site-packages/' % self.sandbox_install_dir) environment = {'PYTHONPATH': '%(sandbox)s/lib/python2.3/site-packages/:'\ '%(sandbox)s/lib/python2.4/site-packages/' % \ {'sandbox': self.sandbox_install_dir}, # Pass PATH to child process. 'PATH': os.getenv('PATH')} rc, output = run_cmd("easy_install --no-deps --prefix %s %s" % \ (self.sandbox_install_dir, self.sandbox_pkg_file), environment) else: package_dir = os.path.join(self.sandbox, self.package_name) if not os.path.isdir(package_dir): package_dir = self.sandbox cwd = os.getcwd() os.chdir(package_dir) rc, output = run_cmd("python setup.py install --root=%s" % \ self.sandbox_install_dir) os.chdir(cwd) if rc: self.log('*** Installation failed. Captured output:') # Stringify output as it may be an exception. for output_line in str(output).splitlines(): self.log(output_line) self.log('*** End of captured output.') else: self.log('Installation into %s successful.' % \ self.sandbox_install_dir) self.installed = True def compute_cheesecake_index(self): """Compute overall Cheesecake index for the package by adding up specific indexes. """ # Pass Cheesecake instance to the main Index object. cheesecake_index = self.index.compute_with(self) # Get max value *after* computing indices, because computing # process can remove some indices from the list. max_cheesecake_index = self.index.max_value percentage = (cheesecake_index * 100) / max_cheesecake_index self.log.info("A given package can currently reach a MAXIMUM number of %d points" % max_cheesecake_index) self.log.info("Starting computation of Cheesecake index for package '%s'" % (self.package)) # Print summary. if self.quiet: print "Cheesecake index: %d (%d / %d)" % (percentage, cheesecake_index, max_cheesecake_index) else: print print pad_line("=") print pad_msg("OVERALL CHEESECAKE INDEX (ABSOLUTE)", cheesecake_index) print "%s (%d out of a maximum of %d points is %d%%)" % \ (pad_msg("OVERALL CHEESECAKE INDEX (RELATIVE)", percentage), cheesecake_index, max_cheesecake_index, percentage) return cheesecake_index ################################################################################ ## Command line. ################################################################################ def process_cmdline_args(): """Parse command-line options. """ parser = OptionParser() # Options for package retrieval. parser.add_option("-n", "--name", dest="name", default="", help="package name (will be retrieved via setuptools utilities, if present)") parser.add_option("-p", "--path", dest="path", default="", help="path of tar.gz/zip package on local file system") parser.add_option("-u", "--url", dest="url", default="", help="package URL") # Output formatting options. parser.add_option("-q", "--quiet", action="store_true", dest="quiet", default=False, help="only print Cheesecake index value (default=False)") parser.add_option("-v", "--verbose", action="store_true", dest="verbose", default=False, help="verbose output (default=False)") # Index choice options. parser.add_option("--lite", action="store_true", dest="lite", default=False, help="don't run time-consuming tests (default=False)") parser.add_option("-t", "--static", action="store_true", dest="static", default=False, help="don't run any code from the package being tested (default=False)") parser.add_option("--with-pep8", action="store_true", dest="with_pep8", default=False, help="check pep8 conformance") # Other options. parser.add_option("-l", "--logfile", dest="logfile", default=None, help="file to log all cheesecake messages") parser.add_option("-s", "--sandbox", dest="sandbox", default=None, help="directory where package will be unpacked "\ "(default is to use random directory inside %s)" % tempfile.gettempdir()) parser.add_option("--keep-log", action="store_true", dest="keep_log", default=False, help="don't remove log file even if run was successful") parser.add_option("--pylint-max-execution-time", action="store", dest="pylint_max_execution_time", default=120, help="maximum time (in seconds) you allow pylint process to run (default=120)") parser.add_option("-V", "--version", action="store_true", dest="version", default=False, help="Output cheesecake version and exit") (options, args) = parser.parse_args() return options def main(): """Display Cheesecake index for package specified via command-line options. """ options = process_cmdline_args() keep_log = options.keep_log lite = options.lite logfile = options.logfile name = options.name path = options.path quiet = options.quiet sandbox = options.sandbox static_only = options.static url = options.url verbose = options.verbose version = options.version with_pep8 = options.with_pep8 pylint_max_execution_time = int(options.pylint_max_execution_time) if version: print "Cheesecake version %s (rev. %s)" % (VERSION, __revision__) sys.exit(0) if not name and not url and not path: print "Error: No package name, URL or path specified (see --help)" sys.exit(1) try: c = Cheesecake(keep_log = keep_log, lite = lite, logfile = logfile, name = name, path = path, pylint_max_execution_time = pylint_max_execution_time, quiet = quiet, sandbox = sandbox, static_only = static_only, url = url, verbose = verbose, with_pep8 = with_pep8) c.compute_cheesecake_index() c.cleanup() except CheesecakeError, e: print str(e) if __name__ == "__main__": main() PKãI6ÇvTÁŠŸŠŸcheesecake/subprocess.py# subprocess - Subprocesses with accessible I/O streams # # For more information about this module, see PEP 324. # # Copyright (c) 2003-2004 by Peter Astrand # # By obtaining, using, and/or copying this software and/or its # associated documentation, you agree that you have read, understood, # and will comply with the following terms and conditions: # # Permission to use, copy, modify, and distribute this software and # its associated documentation for any purpose and without fee is # hereby granted, provided that the above copyright notice appears in # all copies, and that both that copyright notice and this permission # notice appear in supporting documentation, and that the name of the # author not be used in advertising or publicity pertaining to # distribution of the software without specific, written prior # permission. # # THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, # INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. # IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR # CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS # OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION # WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. r"""subprocess - Subprocesses with accessible I/O streams This module allows you to spawn processes, connect to their input/output/error pipes, and obtain their return codes. This module intends to replace several other, older modules and functions, like: os.system os.spawn* os.popen* popen2.* commands.* Information about how the subprocess module can be used to replace these modules and functions can be found below. Using the subprocess module =========================== This module defines one class called Popen: class Popen(args, bufsize=0, executable=None, stdin=None, stdout=None, stderr=None, preexec_fn=None, close_fds=False, shell=False, cwd=None, env=None, universal_newlines=False, startupinfo=None, creationflags=0): Arguments are: args should be a string, or a sequence of program arguments. The program to execute is normally the first item in the args sequence or string, but can be explicitly set by using the executable argument. On UNIX, with shell=False (default): In this case, the Popen class uses os.execvp() to execute the child program. args should normally be a sequence. A string will be treated as a sequence with the string as the only item (the program to execute). On UNIX, with shell=True: If args is a string, it specifies the command string to execute through the shell. If args is a sequence, the first item specifies the command string, and any additional items will be treated as additional shell arguments. On Windows: the Popen class uses CreateProcess() to execute the child program, which operates on strings. If args is a sequence, it will be converted to a string using the list2cmdline method. Please note that not all MS Windows applications interpret the command line the same way: The list2cmdline is designed for applications using the same rules as the MS C runtime. bufsize, if given, has the same meaning as the corresponding argument to the built-in open() function: 0 means unbuffered, 1 means line buffered, any other positive value means use a buffer of (approximately) that size. A negative bufsize means to use the system default, which usually means fully buffered. The default value for bufsize is 0 (unbuffered). stdin, stdout and stderr specify the executed programs' standard input, standard output and standard error file handles, respectively. Valid values are PIPE, an existing file descriptor (a positive integer), an existing file object, and None. PIPE indicates that a new pipe to the child should be created. With None, no redirection will occur; the child's file handles will be inherited from the parent. Additionally, stderr can be STDOUT, which indicates that the stderr data from the applications should be captured into the same file handle as for stdout. If preexec_fn is set to a callable object, this object will be called in the child process just before the child is executed. If close_fds is true, all file descriptors except 0, 1 and 2 will be closed before the child process is executed. if shell is true, the specified command will be executed through the shell. If cwd is not None, the current directory will be changed to cwd before the child is executed. If env is not None, it defines the environment variables for the new process. If universal_newlines is true, the file objects stdout and stderr are opened as a text files, but lines may be terminated by any of '\n', the Unix end-of-line convention, '\r', the Macintosh convention or '\r\n', the Windows convention. All of these external representations are seen as '\n' by the Python program. Note: This feature is only available if Python is built with universal newline support (the default). Also, the newlines attribute of the file objects stdout, stdin and stderr are not updated by the communicate() method. The startupinfo and creationflags, if given, will be passed to the underlying CreateProcess() function. They can specify things such as appearance of the main window and priority for the new process. (Windows only) This module also defines two shortcut functions: call(*args, **kwargs): Run command with arguments. Wait for command to complete, then return the returncode attribute. The arguments are the same as for the Popen constructor. Example: retcode = call(["ls", "-l"]) Exceptions ---------- Exceptions raised in the child process, before the new program has started to execute, will be re-raised in the parent. Additionally, the exception object will have one extra attribute called 'child_traceback', which is a string containing traceback information from the childs point of view. The most common exception raised is OSError. This occurs, for example, when trying to execute a non-existent file. Applications should prepare for OSErrors. A ValueError will be raised if Popen is called with invalid arguments. Security -------- Unlike some other popen functions, this implementation will never call /bin/sh implicitly. This means that all characters, including shell metacharacters, can safely be passed to child processes. Popen objects ============= Instances of the Popen class have the following methods: poll() Check if child process has terminated. Returns returncode attribute. wait() Wait for child process to terminate. Returns returncode attribute. communicate(input=None) Interact with process: Send data to stdin. Read data from stdout and stderr, until end-of-file is reached. Wait for process to terminate. The optional stdin argument should be a string to be sent to the child process, or None, if no data should be sent to the child. communicate() returns a tuple (stdout, stderr). Note: The data read is buffered in memory, so do not use this method if the data size is large or unlimited. The following attributes are also available: stdin If the stdin argument is PIPE, this attribute is a file object that provides input to the child process. Otherwise, it is None. stdout If the stdout argument is PIPE, this attribute is a file object that provides output from the child process. Otherwise, it is None. stderr If the stderr argument is PIPE, this attribute is file object that provides error output from the child process. Otherwise, it is None. pid The process ID of the child process. returncode The child return code. A None value indicates that the process hasn't terminated yet. A negative value -N indicates that the child was terminated by signal N (UNIX only). Replacing older functions with the subprocess module ==================================================== In this section, "a ==> b" means that b can be used as a replacement for a. Note: All functions in this section fail (more or less) silently if the executed program cannot be found; this module raises an OSError exception. In the following examples, we assume that the subprocess module is imported with "from subprocess import *". Replacing /bin/sh shell backquote --------------------------------- output=`mycmd myarg` ==> output = Popen(["mycmd", "myarg"], stdout=PIPE).communicate()[0] Replacing shell pipe line ------------------------- output=`dmesg | grep hda` ==> p1 = Popen(["dmesg"], stdout=PIPE) p2 = Popen(["grep", "hda"], stdin=p1.stdout) output = p2.communicate()[0] Replacing os.system() --------------------- sts = os.system("mycmd" + " myarg") ==> p = Popen("mycmd" + " myarg", shell=True) sts = os.waitpid(p.pid, 0) Note: * Calling the program through the shell is usually not required. * It's easier to look at the returncode attribute than the exitstatus. A more real-world example would look like this: try: retcode = call("mycmd" + " myarg", shell=True) if retcode < 0: print >>sys.stderr, "Child was terminated by signal", -retcode else: print >>sys.stderr, "Child returned", retcode except OSError, e: print >>sys.stderr, "Execution failed:", e Replacing os.spawn* ------------------- P_NOWAIT example: pid = os.spawnlp(os.P_NOWAIT, "/bin/mycmd", "mycmd", "myarg") ==> pid = Popen(["/bin/mycmd", "myarg"]).pid P_WAIT example: retcode = os.spawnlp(os.P_WAIT, "/bin/mycmd", "mycmd", "myarg") ==> retcode = call(["/bin/mycmd", "myarg"]) Vector example: os.spawnvp(os.P_NOWAIT, path, args) ==> Popen([path] + args[1:]) Environment example: os.spawnlpe(os.P_NOWAIT, "/bin/mycmd", "mycmd", "myarg", env) ==> Popen(["/bin/mycmd", "myarg"], env={"PATH": "/usr/bin"}) Replacing os.popen* ------------------- pipe = os.popen(cmd, mode='r', bufsize) ==> pipe = Popen(cmd, shell=True, bufsize=bufsize, stdout=PIPE).stdout pipe = os.popen(cmd, mode='w', bufsize) ==> pipe = Popen(cmd, shell=True, bufsize=bufsize, stdin=PIPE).stdin (child_stdin, child_stdout) = os.popen2(cmd, mode, bufsize) ==> p = Popen(cmd, shell=True, bufsize=bufsize, stdin=PIPE, stdout=PIPE, close_fds=True) (child_stdin, child_stdout) = (p.stdin, p.stdout) (child_stdin, child_stdout, child_stderr) = os.popen3(cmd, mode, bufsize) ==> p = Popen(cmd, shell=True, bufsize=bufsize, stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=True) (child_stdin, child_stdout, child_stderr) = (p.stdin, p.stdout, p.stderr) (child_stdin, child_stdout_and_stderr) = os.popen4(cmd, mode, bufsize) ==> p = Popen(cmd, shell=True, bufsize=bufsize, stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True) (child_stdin, child_stdout_and_stderr) = (p.stdin, p.stdout) Replacing popen2.* ------------------ Note: If the cmd argument to popen2 functions is a string, the command is executed through /bin/sh. If it is a list, the command is directly executed. (child_stdout, child_stdin) = popen2.popen2("somestring", bufsize, mode) ==> p = Popen(["somestring"], shell=True, bufsize=bufsize stdin=PIPE, stdout=PIPE, close_fds=True) (child_stdout, child_stdin) = (p.stdout, p.stdin) (child_stdout, child_stdin) = popen2.popen2(["mycmd", "myarg"], bufsize, mode) ==> p = Popen(["mycmd", "myarg"], bufsize=bufsize, stdin=PIPE, stdout=PIPE, close_fds=True) (child_stdout, child_stdin) = (p.stdout, p.stdin) The popen2.Popen3 and popen3.Popen4 basically works as subprocess.Popen, except that: * subprocess.Popen raises an exception if the execution fails * the capturestderr argument is replaced with the stderr argument. * stdin=PIPE and stdout=PIPE must be specified. * popen2 closes all filedescriptors by default, but you have to specify close_fds=True with subprocess.Popen. """ import sys mswindows = (sys.platform == "win32") import os import types import traceback if mswindows: import threading import msvcrt if 0: # <-- change this to use pywin32 instead of the _subprocess driver import pywintypes from win32api import GetStdHandle, STD_INPUT_HANDLE, \ STD_OUTPUT_HANDLE, STD_ERROR_HANDLE from win32api import GetCurrentProcess, DuplicateHandle, \ GetModuleFileName, GetVersion from win32con import DUPLICATE_SAME_ACCESS, SW_HIDE from win32pipe import CreatePipe from win32process import CreateProcess, STARTUPINFO, \ GetExitCodeProcess, STARTF_USESTDHANDLES, \ STARTF_USESHOWWINDOW, CREATE_NEW_CONSOLE from win32event import WaitForSingleObject, INFINITE, WAIT_OBJECT_0 else: from _subprocess import * class STARTUPINFO: dwFlags = 0 hStdInput = None hStdOutput = None hStdError = None class pywintypes: error = IOError else: import select import errno import fcntl import pickle __all__ = ["Popen", "PIPE", "STDOUT", "call", "ProcessError"] try: MAXFD = os.sysconf("SC_OPEN_MAX") except: MAXFD = 256 # True/False does not exist on 2.2.0 try: False except NameError: False = 0 True = 1 _active = [] def _cleanup(): for inst in _active[:]: inst.poll() PIPE = -1 STDOUT = -2 def call(*args, **kwargs): """Run command with arguments. Wait for command to complete, then return the returncode attribute. The arguments are the same as for the Popen constructor. Example: retcode = call(["ls", "-l"]) """ return Popen(*args, **kwargs).wait() def list2cmdline(seq): """ Translate a sequence of arguments into a command line string, using the same rules as the MS C runtime: 1) Arguments are delimited by white space, which is either a space or a tab. 2) A string surrounded by double quotation marks is interpreted as a single argument, regardless of white space contained within. A quoted string can be embedded in an argument. 3) A double quotation mark preceded by a backslash is interpreted as a literal double quotation mark. 4) Backslashes are interpreted literally, unless they immediately precede a double quotation mark. 5) If backslashes immediately precede a double quotation mark, every pair of backslashes is interpreted as a literal backslash. If the number of backslashes is odd, the last backslash escapes the next double quotation mark as described in rule 3. """ # See # http://msdn.microsoft.com/library/en-us/vccelng/htm/progs_12.asp result = [] needquote = False for arg in seq: bs_buf = [] # Add a space to separate this argument from the others if result: result.append(' ') needquote = (" " in arg) or ("\t" in arg) if needquote: result.append('"') for c in arg: if c == '\\': # Don't know if we need to double yet. bs_buf.append(c) elif c == '"': # Double backspaces. result.append('\\' * len(bs_buf)*2) bs_buf = [] result.append('\\"') else: # Normal char if bs_buf: result.extend(bs_buf) bs_buf = [] result.append(c) # Add remaining backspaces, if any. if bs_buf: result.extend(bs_buf) if needquote: result.append('"') return ''.join(result) class ProcessError(Exception): """This exception is raised when there is an error calling a subprocess.""" pass class Popen(object): def __init__(self, args, bufsize=0, executable=None, stdin=None, stdout=None, stderr=None, preexec_fn=None, close_fds=False, shell=False, cwd=None, env=None, universal_newlines=False, startupinfo=None, creationflags=0): """Create new Popen instance.""" _cleanup() if mswindows: if preexec_fn is not None: raise ValueError("preexec_fn is not supported on Windows " "platforms") if close_fds: raise ValueError("close_fds is not supported on Windows " "platforms") else: # POSIX if startupinfo is not None: raise ValueError("startupinfo is only supported on Windows " "platforms") if creationflags != 0: raise ValueError("creationflags is only supported on Windows " "platforms") self.stdin = None self.stdout = None self.stderr = None self.pid = None self.returncode = None self.universal_newlines = universal_newlines # Input and output objects. The general principle is like # this: # # Parent Child # ------ ----- # p2cwrite ---stdin---> p2cread # c2pread <--stdout--- c2pwrite # errread <--stderr--- errwrite # # On POSIX, the child objects are file descriptors. On # Windows, these are Windows file handles. The parent objects # are file descriptors on both platforms. The parent objects # are None when not using PIPEs. The child objects are None # when not redirecting. (p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite) = self._get_handles(stdin, stdout, stderr) self._execute_child(args, executable, preexec_fn, close_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite) if p2cwrite: self.stdin = os.fdopen(p2cwrite, 'wb', bufsize) if c2pread: if universal_newlines: self.stdout = os.fdopen(c2pread, 'rU', bufsize) else: self.stdout = os.fdopen(c2pread, 'rb', bufsize) if errread: if universal_newlines: self.stderr = os.fdopen(errread, 'rU', bufsize) else: self.stderr = os.fdopen(errread, 'rb', bufsize) _active.append(self) def _translate_newlines(self, data): data = data.replace("\r\n", "\n") data = data.replace("\r", "\n") return data if mswindows: # # Windows methods # def _get_handles(self, stdin, stdout, stderr): """Construct and return tupel with IO objects: p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite """ if stdin == None and stdout == None and stderr == None: return (None, None, None, None, None, None) p2cread, p2cwrite = None, None c2pread, c2pwrite = None, None errread, errwrite = None, None if stdin == None: p2cread = GetStdHandle(STD_INPUT_HANDLE) elif stdin == PIPE: p2cread, p2cwrite = CreatePipe(None, 0) # Detach and turn into fd p2cwrite = p2cwrite.Detach() p2cwrite = msvcrt.open_osfhandle(p2cwrite, 0) elif type(stdin) == types.IntType: p2cread = msvcrt.get_osfhandle(stdin) else: # Assuming file-like object p2cread = msvcrt.get_osfhandle(stdin.fileno()) p2cread = self._make_inheritable(p2cread) if stdout == None: c2pwrite = GetStdHandle(STD_OUTPUT_HANDLE) elif stdout == PIPE: c2pread, c2pwrite = CreatePipe(None, 0) # Detach and turn into fd c2pread = c2pread.Detach() c2pread = msvcrt.open_osfhandle(c2pread, 0) elif type(stdout) == types.IntType: c2pwrite = msvcrt.get_osfhandle(stdout) else: # Assuming file-like object c2pwrite = msvcrt.get_osfhandle(stdout.fileno()) c2pwrite = self._make_inheritable(c2pwrite) if stderr == None: errwrite = GetStdHandle(STD_ERROR_HANDLE) elif stderr == PIPE: errread, errwrite = CreatePipe(None, 0) # Detach and turn into fd errread = errread.Detach() errread = msvcrt.open_osfhandle(errread, 0) elif stderr == STDOUT: errwrite = c2pwrite elif type(stderr) == types.IntType: errwrite = msvcrt.get_osfhandle(stderr) else: # Assuming file-like object errwrite = msvcrt.get_osfhandle(stderr.fileno()) errwrite = self._make_inheritable(errwrite) return (p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite) def _make_inheritable(self, handle): """Return a duplicate of handle, which is inheritable""" return DuplicateHandle(GetCurrentProcess(), handle, GetCurrentProcess(), 0, 1, DUPLICATE_SAME_ACCESS) def _find_w9xpopen(self): """Find and return absolut path to w9xpopen.exe""" w9xpopen = os.path.join(os.path.dirname(GetModuleFileName(0)), "w9xpopen.exe") if not os.path.exists(w9xpopen): # Eeek - file-not-found - possibly an embedding # situation - see if we can locate it in sys.exec_prefix w9xpopen = os.path.join(os.path.dirname(sys.exec_prefix), "w9xpopen.exe") if not os.path.exists(w9xpopen): raise RuntimeError("Cannot locate w9xpopen.exe, which is " "needed for Popen to work with your " "shell or platform.") return w9xpopen def _execute_child(self, args, executable, preexec_fn, close_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite): """Execute program (MS Windows version)""" if not isinstance(args, types.StringTypes): args = list2cmdline(args) # Process startup details default_startupinfo = STARTUPINFO() if startupinfo == None: startupinfo = default_startupinfo if not None in (p2cread, c2pwrite, errwrite): startupinfo.dwFlags |= STARTF_USESTDHANDLES startupinfo.hStdInput = p2cread startupinfo.hStdOutput = c2pwrite startupinfo.hStdError = errwrite if shell: default_startupinfo.dwFlags |= STARTF_USESHOWWINDOW default_startupinfo.wShowWindow = SW_HIDE comspec = os.environ.get("COMSPEC", "cmd.exe") args = comspec + " /c " + args if (GetVersion() >= 0x80000000L or os.path.basename(comspec).lower() == "command.com"): # Win9x, or using command.com on NT. We need to # use the w9xpopen intermediate program. For more # information, see KB Q150956 # (http://web.archive.org/web/20011105084002/http://support.microsoft.com/support/kb/articles/Q150/9/56.asp) w9xpopen = self._find_w9xpopen() args = '"%s" %s' % (w9xpopen, args) # Not passing CREATE_NEW_CONSOLE has been known to # cause random failures on win9x. Specifically a # dialog: "Your program accessed mem currently in # use at xxx" and a hopeful warning about the # stability of your system. Cost is Ctrl+C wont # kill children. creationflags |= CREATE_NEW_CONSOLE # Start the process try: hp, ht, pid, tid = CreateProcess(executable, args, # no special security None, None, # must inherit handles to pass std # handles 1, creationflags, env, cwd, startupinfo) except pywintypes.error, e: # Translate pywintypes.error to WindowsError, which is # a subclass of OSError. FIXME: We should really # translate errno using _sys_errlist (or simliar), but # how can this be done from Python? raise WindowsError(*e.args) # Retain the process handle, but close the thread handle self._handle = hp self.pid = pid ht.Close() # Child is launched. Close the parent's copy of those pipe # handles that only the child should have open. You need # to make sure that no handles to the write end of the # output pipe are maintained in this process or else the # pipe will not close when the child process exits and the # ReadFile will hang. if p2cread != None: p2cread.Close() if c2pwrite != None: c2pwrite.Close() if errwrite != None: errwrite.Close() def poll(self): """Check if child process has terminated. Returns returncode attribute.""" if self.returncode == None: if WaitForSingleObject(self._handle, 0) == WAIT_OBJECT_0: self.returncode = GetExitCodeProcess(self._handle) _active.remove(self) return self.returncode def wait(self): """Wait for child process to terminate. Returns returncode attribute.""" if self.returncode == None: obj = WaitForSingleObject(self._handle, INFINITE) self.returncode = GetExitCodeProcess(self._handle) _active.remove(self) return self.returncode def _readerthread(self, fh, buffer): buffer.append(fh.read()) def communicate(self, input=None): """Interact with process: Send data to stdin. Read data from stdout and stderr, until end-of-file is reached. Wait for process to terminate. The optional input argument should be a string to be sent to the child process, or None, if no data should be sent to the child. communicate() returns a tuple (stdout, stderr).""" stdout = None # Return stderr = None # Return if self.stdout: stdout = [] stdout_thread = threading.Thread(target=self._readerthread, args=(self.stdout, stdout)) stdout_thread.setDaemon(True) stdout_thread.start() if self.stderr: stderr = [] stderr_thread = threading.Thread(target=self._readerthread, args=(self.stderr, stderr)) stderr_thread.setDaemon(True) stderr_thread.start() if self.stdin: if input != None: self.stdin.write(input) self.stdin.close() if self.stdout: stdout_thread.join() if self.stderr: stderr_thread.join() # All data exchanged. Translate lists into strings. if stdout != None: stdout = stdout[0] if stderr != None: stderr = stderr[0] # Translate newlines, if requested. We cannot let the file # object do the translation: It is based on stdio, which is # impossible to combine with select (unless forcing no # buffering). if self.universal_newlines and hasattr(open, 'newlines'): if stdout: stdout = self._translate_newlines(stdout) if stderr: stderr = self._translate_newlines(stderr) self.wait() return (stdout, stderr) else: # # POSIX methods # def _get_handles(self, stdin, stdout, stderr): """Construct and return tupel with IO objects: p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite """ p2cread, p2cwrite = None, None c2pread, c2pwrite = None, None errread, errwrite = None, None if stdin == None: pass elif stdin == PIPE: p2cread, p2cwrite = os.pipe() elif type(stdin) == types.IntType: p2cread = stdin else: # Assuming file-like object p2cread = stdin.fileno() if stdout == None: pass elif stdout == PIPE: c2pread, c2pwrite = os.pipe() elif type(stdout) == types.IntType: c2pwrite = stdout else: # Assuming file-like object c2pwrite = stdout.fileno() if stderr == None: pass elif stderr == PIPE: errread, errwrite = os.pipe() elif stderr == STDOUT: errwrite = c2pwrite elif type(stderr) == types.IntType: errwrite = stderr else: # Assuming file-like object errwrite = stderr.fileno() return (p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite) def _set_cloexec_flag(self, fd): try: cloexec_flag = fcntl.FD_CLOEXEC except AttributeError: cloexec_flag = 1 old = fcntl.fcntl(fd, fcntl.F_GETFD) fcntl.fcntl(fd, fcntl.F_SETFD, old | cloexec_flag) def _close_fds(self, but): for i in range(3, MAXFD): if i == but: continue try: os.close(i) except: pass def _execute_child(self, args, executable, preexec_fn, close_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite): """Execute program (POSIX version)""" if isinstance(args, types.StringTypes): args = [args] if shell: args = ["/bin/sh", "-c"] + args if executable == None: executable = args[0] # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = os.pipe() self._set_cloexec_flag(errpipe_write) self.pid = os.fork() if self.pid == 0: # Child try: # Close parent's pipe ends if p2cwrite: os.close(p2cwrite) if c2pread: os.close(c2pread) if errread: os.close(errread) os.close(errpipe_read) # Dup fds for child if p2cread: os.dup2(p2cread, 0) if c2pwrite: os.dup2(c2pwrite, 1) if errwrite: os.dup2(errwrite, 2) # Close pipe fds. Make sure we doesn't close the same # fd more than once. if p2cread: os.close(p2cread) if c2pwrite and c2pwrite not in (p2cread,): os.close(c2pwrite) if errwrite and errwrite not in (p2cread, c2pwrite): os.close(errwrite) # Close all other fds, if asked for if close_fds: self._close_fds(but=errpipe_write) if cwd != None: os.chdir(cwd) if preexec_fn: apply(preexec_fn) if env == None: os.execvp(executable, args) else: os.execvpe(executable, args, env) except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) # This exitcode won't be reported to applications, so it # really doesn't matter what we return. os._exit(255) # Parent os.close(errpipe_write) if p2cread and p2cwrite: os.close(p2cread) if c2pwrite and c2pread: os.close(c2pwrite) if errwrite and errread: os.close(errwrite) # Wait for exec to fail or succeed; possibly raising exception data = os.read(errpipe_read, 1048576) # Exceptions limited to 1 MB os.close(errpipe_read) if data != "": child_exception = pickle.loads(data) raise ProcessError, child_exception def _handle_exitstatus(self, sts): if os.WIFSIGNALED(sts): self.returncode = -os.WTERMSIG(sts) elif os.WIFEXITED(sts): self.returncode = os.WEXITSTATUS(sts) else: # Should never happen raise RuntimeError("Unknown child exit status!") _active.remove(self) def poll(self): """Check if child process has terminated. Returns returncode attribute.""" if self.returncode == None: try: pid, sts = os.waitpid(self.pid, os.WNOHANG) if pid == self.pid: self._handle_exitstatus(sts) except os.error: pass return self.returncode def wait(self): """Wait for child process to terminate. Returns returncode attribute.""" if self.returncode == None: pid, sts = os.waitpid(self.pid, 0) self._handle_exitstatus(sts) return self.returncode def communicate(self, input=None): """Interact with process: Send data to stdin. Read data from stdout and stderr, until end-of-file is reached. Wait for process to terminate. The optional input argument should be a string to be sent to the child process, or None, if no data should be sent to the child. communicate() returns a tuple (stdout, stderr).""" read_set = [] write_set = [] stdout = None # Return stderr = None # Return if self.stdin: # Flush stdio buffer. This might block, if the user has # been writing to .stdin in an uncontrolled fashion. self.stdin.flush() if input: write_set.append(self.stdin) else: self.stdin.close() if self.stdout: read_set.append(self.stdout) stdout = [] if self.stderr: read_set.append(self.stderr) stderr = [] while read_set or write_set: rlist, wlist, xlist = select.select(read_set, write_set, []) if self.stdin in wlist: # When select has indicated that the file is writable, # we can write up to PIPE_BUF bytes without risk # blocking. POSIX defines PIPE_BUF >= 512 bytes_written = os.write(self.stdin.fileno(), input[:512]) input = input[bytes_written:] if not input: self.stdin.close() write_set.remove(self.stdin) if self.stdout in rlist: data = os.read(self.stdout.fileno(), 1024) if data == "": self.stdout.close() read_set.remove(self.stdout) stdout.append(data) if self.stderr in rlist: data = os.read(self.stderr.fileno(), 1024) if data == "": self.stderr.close() read_set.remove(self.stderr) stderr.append(data) # All data exchanged. Translate lists into strings. if stdout != None: stdout = ''.join(stdout) if stderr != None: stderr = ''.join(stderr) # Translate newlines, if requested. We cannot let the file # object do the translation: It is based on stdio, which is # impossible to combine with select (unless forcing no # buffering). if self.universal_newlines and hasattr(open, 'newlines'): if stdout: stdout = self._translate_newlines(stdout) if stderr: stderr = self._translate_newlines(stderr) self.wait() return (stdout, stderr) def _demo_posix(): # # Example 1: Simple redirection: Get process list # plist = Popen(["ps"], stdout=PIPE).communicate()[0] print "Process list:" print plist # # Example 2: Change uid before executing child # if os.getuid() == 0: p = Popen(["id"], preexec_fn=lambda: os.setuid(100)) p.wait() # # Example 3: Connecting several subprocesses # print "Looking for 'hda'..." p1 = Popen(["dmesg"], stdout=PIPE) p2 = Popen(["grep", "hda"], stdin=p1.stdout, stdout=PIPE) print repr(p2.communicate()[0]) # # Example 4: Catch execution error # print print "Trying a weird file..." try: print Popen(["/this/path/does/not/exist"]).communicate() except OSError, e: if e.errno == errno.ENOENT: print "The file didn't exist. I thought so..." print "Child traceback:" print e.child_traceback else: print "Error", e.errno else: print >>sys.stderr, "Gosh. No error." def _demo_windows(): # # Example 1: Connecting several subprocesses # print "Looking for 'PROMPT' in set output..." p1 = Popen("set", stdout=PIPE, shell=True) p2 = Popen('find "PROMPT"', stdin=p1.stdout, stdout=PIPE) print repr(p2.communicate()[0]) # # Example 2: Simple execution of program # print "Executing calc..." p = Popen("calc") p.wait() if __name__ == "__main__": if mswindows: _demo_windows() else: _demo_posix() PKãI6º&ŽÚ$$cheesecake/util.py"""Utility functions for Cheesecake project. """ import os import shutil import signal import sys import tarfile import time import zipfile from subprocess import call, ProcessError, Popen, PIPE, STDOUT PAD_TEXT = 40 PAD_VALUE = 4 def run_cmd(cmd, env=None, max_timeout=None): """Run command and return its return code and its output. >>> run_cmd('/bin/true') (0, '') >>> run_cmd('/bin/cat', max_timeout=0.2) (1, 'Time exceeded') """ arglist = cmd.split() output = os.tmpfile() try: p = Popen(arglist, stdout=output, stderr=STDOUT, env=env) except Exception, e: return 1, e # Wait only max_timeout seconds. if max_timeout: start = time.time() while p.poll() is None: time.sleep(0.1) if time.time() - start > max_timeout: os.kill(p.pid, signal.SIGINT) p.wait() return 1, "Time exceeded" p.wait() output.seek(0) return p.returncode, output.read() def command_successful(cmd): """Returns True if command exited normally, False otherwise. >>> command_successful('/bin/true') True >>> command_successful('this-command-doesnt-exist') False """ rc, output = run_cmd(cmd) return rc == 0 class StdoutRedirector(object): """Redirect stdout to a temporary file. """ def __init__(self, filename=None): if filename: self.fh = open(filename, 'w') else: self.fh = os.tmpfile() def write(self, buf): self.fh.write(buf) def flush(self): self.fh.flush() def read_buffer(self): """Return contents of the temporary file. """ self.fh.seek(0) return self.fh.read() def pad_with_dots(msg, length=PAD_TEXT): """Pad text with dots up to given length. >>> pad_with_dots("Hello world", 20) 'Hello world ........' >>> pad_with_dots("Exceeding length", 10) 'Exceeding length' """ msg_length = len(msg) if msg_length >= length: return msg msg = msg + " " for i in range(msg_length+1, length): msg += "." return msg def pad_left_spaces(value, length=PAD_VALUE): """Pad value with spaces at left up to given length. >>> pad_left_spaces(15, 4) ' 15' >>> pad_left_spaces(123456, 2) '123456' >>> len(pad_left_spaces("")) == PAD_VALUE True """ if not isinstance(value, basestring): value = str(value) diff = length - len(value) return " " * diff + value def pad_right_spaces(value, length=PAD_VALUE): """Pad value with spaces at left up to given length. >>> pad_right_spaces(123, 5) '123 ' >>> pad_right_spaces(12.1, 5) '12.1 ' """ if not isinstance(value, basestring): value = str(value) diff = length - len(value) return value + " " * diff def pad_msg(msg, value, msg_length=PAD_TEXT, value_length=PAD_VALUE): """Pad message with dots and pad value with spaces. >>> pad_msg("123456", 77, msg_length=10, value_length=4) '123456 ... 77' >>> pad_msg("123", u"45", msg_length=5, value_length=3) u'123 . 45' """ return msg + " " +"." * (msg_length-len(msg)-1) + pad_left_spaces(value, value_length) def pad_line(char="=", length=(PAD_TEXT+PAD_VALUE+1)): """Return line consisting of 'char' characters. >>> pad_line('*', 3) '***' >>> pad_line(length=10) '==========' """ return char * length def unzip_package(package, destination): """Unzip given `package` to the `destination` directory. Return name of unpacked directory or None on error. """ try: z = zipfile.ZipFile(package) except zipfile.error: return None # Get directory structure from zip and create it in destination directory. for name in z.namelist(): (dir, file) = os.path.split(name) unpack_dir = dir target_dir = os.path.join(destination, dir) if not os.path.exists(target_dir): os.makedirs(target_dir) # Extract files to directory structure for i, name in enumerate(z.namelist()): if not name.endswith('/'): outfile = open(os.path.join(destination, name), 'wb') outfile.write(z.read(name)) outfile.flush() outfile.close() return unpack_dir.split(os.sep)[0] def untar_package(package, destination): """Untar given `package` to the `destination` directory. Return name of unpacked directory or None on error. """ try: t = tarfile.open(package) except tarfile.ReadError, e: return None for member in t.getmembers(): t.extract(member, destination) tarinfo = t.members[0] return tarinfo.name.split(os.sep)[0] def unegg_package(package, destination): """Unpack given egg to the `destination` directory. Return name of unpacked directory or None on error. """ if os.path.isdir(package): package_name = os.path.basename(package) destination = os.path.join(destination, package_name) shutil.copytree(package, destination, symlinks=True) return package_name else: return unzip_package(package, destination) def mkdirs(dir): """Make directory with parent directories as needed. Don't throw an exception if directory exists. """ parts = dir.split(os.path.sep) for length in xrange(1, len(parts)+1): path = os.path.sep.join([''] + parts[:length]) if not os.path.exists(path): os.mkdir(path) def time_function(function): """Measure function execution time. Return (return value, time taken) tuple. >>> def fun(x): ... return x*2 >>> ret, time_taken = time_function(lambda: fun(5)) >>> ret 10 """ start = time.time() ret = function() end = time.time() return ret, end-start PKãI6¥¼“Zcheesecake/__init__.py__version__ = '0.6.1' PKãI6† ä¼¼cheesecake/logger.pyimport sys, re ######################################################## ############### PRODUCERS ############################## ######################################################## class Message(object): def __init__(self, keywords, args): self.keywords = keywords self.args = args def content(self): return " ".join(map(str, self.args)) def prefix(self): return "[%s] " % (":".join(self.keywords)) def __str__(self): return self.prefix() + self.content() class Producer(object): """ Log producer API which sends messages to be logged to a 'consumer' object, which then prints them to stdout, stderr, files, etc. """ Message = Message # to allow later customization keywords2consumer = {} def __init__(self, keywords): if isinstance(keywords, str): keywords = tuple(keywords.split()) self.keywords = keywords def __repr__(self): return "" % ":".join(self.keywords) def __getattr__(self, name): if name[0] == '_': raise AttributeError, name producer = self.__class__(self.keywords + (name,)) setattr(self, name, producer) return producer def __call__(self, *args): func = self._getconsumer(self.keywords) if func is not None: func(self.Message(self.keywords, args)) def _getconsumer(self, keywords): for i in range(len(self.keywords), 0, -1): try: return self.keywords2consumer[self.keywords[:i]] except KeyError: continue return self.keywords2consumer.get('default', default_consumer) default = Producer('default') def default_consumer(msg): print str(msg) Producer.keywords2consumer['default'] = default_consumer class MultipleProducer(Producer): def __call__(self, *args, **kwargs): for func in self._getconsumer(self.keywords): if func is not None: return func(self.Message(self.keywords, args), **kwargs) def _getconsumer(self, keywords): found_consumer = False for keyword in keywords: consumer = self.keywords2consumer.get((keyword,)) found_consumer = True yield consumer if not found_consumer: yield self.keywords2consumer.get('default', default_consumer) ######################################################## ############### CONSUMERS ############################## ######################################################## class File(object): def __init__(self, f): assert hasattr(f, 'write') assert isinstance(f, file) or not hasattr(f, 'open') self._file = f def __call__(self, msg): print >>self._file, str(msg) class Path(File): def __init__(self, filename, append=False): mode = append and 'a' or 'w' f = open(str(filename), mode, buffering=1) super(Path, self).__init__(f) def STDOUT(msg): print >>sys.stdout, str(msg) def STDERR(msg): print >>sys.stderr, str(msg) def setconsumer(keywords, consumer): # normalize to tuples if isinstance(keywords, str): keywords = tuple(map(None, keywords.split())) elif not isinstance(keywords, tuple): raise TypeError("key %r is not a string or tuple" % (keywords,)) if consumer is not None and not callable(consumer): if not hasattr(consumer, 'write'): raise TypeError("%r should be None, callable or file-like" % (consumer,)) consumer = File(consumer) #print "setting consumer for " + str(keywords) + "to " + str(consumer) Producer.keywords2consumer[keywords] = consumer PKãI66&n°X°Xcheesecake/model.py""" Code borrowed from Michael Hudson's docextractor package with the author's permission. The original code is available at http://codespeak.net/svn/user/mwh/docextractor/. Changes: * do not print warnings to stdout (in System.warning) * collect all function calls """ from compiler import ast import sys import os import cPickle as pickle import __builtin__ import sets from compiler.transformer import parse, parseFile from compiler.visitor import walk import ast_pp def get_call_name(node): assert isinstance(node, ast.CallFunc) def get_name(node): if isinstance(node, ast.CallFunc): return None elif isinstance(node, ast.Name): return node.name elif isinstance(node, str): return node elif isinstance(node, tuple): if len(node) == 1: return node[0] else: return "%s.%s" % (get_name(node[:-1][0]), node[-1]) elif isinstance(node, ast.Getattr): return get_name(node.asList()) else: return None return get_name(node.node) def get_function_calls(node, fc): if not isinstance(node, ast.Node): return for child in node.getChildren(): if isinstance(child, ast.CallFunc): func_called = get_call_name(child) if func_called: fc[func_called] = 1 get_function_calls(child, fc) class Documentable(object): def __init__(self, system, prefix, name, docstring, parent=None): self.system = system self.prefix = prefix self.name = name self.docstring = docstring self.parent = parent self.setup() def setup(self): self.contents = {} self.orderedcontents = [] self._name2fullname = {} def fullName(self): return self.prefix + self.name def shortdocstring(self): docstring = self.docstring if docstring: docstring = docstring.rstrip() if len(docstring) > 20: docstring = docstring[:8] + '...' + docstring[-8:] return docstring def __repr__(self): return "%s %r"%(self.__class__.__name__, self.fullName()) def name2fullname(self, name): if name in self._name2fullname: return self._name2fullname[name] else: return self.parent.name2fullname(name) def resolveDottedName(self, dottedname, verbose=False): parts = dottedname.split('.') obj = self system = self.system while parts[0] not in obj._name2fullname: obj = obj.parent if obj is None: if parts[0] in system.allobjects: obj = system.allobjects[parts[0]] break for othersys in system.moresystems: if parts[0] in othersys.allobjects: obj = othersys.allobjects[parts[0]] break else: if verbose: print "1 didn't find %r from %r"%(dottedname, self.fullName()) return None break else: fn = obj._name2fullname[parts[0]] if fn in system.allobjects: obj = system.allobjects[fn] else: if verbose: print "1.5 didn't find %r from %r"%(dottedname, self.fullName()) return None for p in parts[1:]: if p not in obj.contents: if verbose: print "2 didn't find %r from %r"%(dottedname, self.fullName()) return None obj = obj.contents[p] if verbose: print dottedname, '->', obj.fullName(), 'in', self.fullName() return obj def dottedNameToFullName(self, dottedname): if '.' not in dottedname: start, rest = dottedname, '' else: start, rest = dottedname.split('.', 1) rest = '.' + rest obj = self while start not in obj._name2fullname: obj = obj.parent if obj is None: return dottedname return obj._name2fullname[start] + rest def __getstate__(self): # this is so very, very evil. # see doc/extreme-pickling-pain.txt for more. r = {} for k, v in self.__dict__.iteritems(): if isinstance(v, Documentable): r['$'+k] = v.fullName() elif isinstance(v, list) and v: for vv in v: if vv is not None and not isinstance(vv, Documentable): r[k] = v break else: rr = [] for vv in v: if vv is None: rr.append(vv) else: rr.append(vv.fullName()) r['@'+k] = rr elif isinstance(v, dict) and v: for vv in v.itervalues(): if not isinstance(vv, Documentable): r[k] = v break else: rr = {} for kk, vv in v.iteritems(): rr[kk] = vv.fullName() r['!'+k] = rr else: r[k] = v return r class Package(Documentable): kind = "Package" def name2fullname(self, name): raise NameError class Module(Documentable): kind = "Module" def name2fullname(self, name): if name in self._name2fullname: return self._name2fullname[name] elif name in __builtin__.__dict__: return name else: self.system.warning("optimistic name resolution", name) return name class Class(Documentable): kind = "Class" def setup(self): super(Class, self).setup() self.bases = [] self.rawbases = [] self.baseobjects = [] self.subclasses = [] class Function(Documentable): kind = "Function" class ModuleVistor(object): def __init__(self, system, modname): self.system = system self.modname = modname self.morenodes = [] def default(self, node): for child in node.getChildNodes(): self.visit(child) def postpone(self, docable, node): self.morenodes.append((docable, node)) def visitModule(self, node): if self.system.current and self.modname in self.system.current.contents: m = self.system.current.contents[self.modname] assert m.docstring is None m.docstring = node.doc self.system.push(m, node) self.default(node) self.system.pop(m) else: if not self.system.current: roots = [x for x in self.system.rootobjects if x.name == self.modname] if roots: mod, = roots self.system.push(mod, node) self.default(node) self.system.pop(mod) return self.system.pushModule(self.modname, node.doc) self.default(node) self.system.popModule() def visitClass(self, node): cls = self.system.pushClass(node.name, node.doc) if node.lineno is not None: cls.linenumber = node.lineno for n in node.bases: str_base = ast_pp.pp(n) cls.rawbases.append(str_base) base = cls.dottedNameToFullName(str_base) cls.bases.append(base) self.default(node) self.system.popClass() def visitFrom(self, node): modname = expandModname(self.system, node.modname) name2fullname = self.system.current._name2fullname for fromname, asname in node.names: if fromname == '*': self.system.warning("import *", modname) if modname not in self.system.allobjects: return mod = self.system.allobjects[modname] # this might fail if you have an import-* cycle, or if # you're just not running the import star finder to # save time (not that this is possibly without # commenting stuff out yet, but...) if isinstance(mod, Package): self.system.warning("import * from a package", modname) return if mod.processed: for n in mod.contents: name2fullname[n] = modname + '.' + n else: self.system.warning("unresolvable import *", modname) return if asname is None: asname = fromname name2fullname[asname] = modname + '.' + fromname def visitImport(self, node): name2fullname = self.system.current._name2fullname for fromname, asname in node.names: fullname = expandModname(self.system, fromname) if asname is None: asname = fromname.split('.', 1)[0] # aaaaargh! python sucks. parts = fullname.split('.') for i, part in enumerate(fullname.split('.')[::-1]): if part == asname: fullname = '.'.join(parts[:len(parts)-i]) name2fullname[asname] = fullname break else: name2fullname[asname] = '.'.join(parts) else: name2fullname[asname] = fullname def visitFunction(self, node): fc = {} get_function_calls(node, fc) func = self.system.pushFunction(node.name, node.doc, fc) if node.lineno is not None: func.linenumber = node.lineno # ast.Function has a pretty lame representation of # arguments. Let's convert it to a nice concise format # somewhat like what inspect.getargspec returns argnames = node.argnames[:] kwname = starargname = None if node.kwargs: kwname = argnames.pop(-1) if node.varargs: starargname = argnames.pop(-1) defaults = [] for default in node.defaults: try: defaults.append(ast_pp.pp(default)) except (KeyboardInterrupt, SystemExit): raise except Exception, e: self.system.warning("unparseable default", "%s: %s %r"%(e.__class__.__name__, e, default)) defaults.append('???') # argh, convert unpacked-arguments from tuples to lists, # because that's what getargspec uses and the unit test # compares it argnames2 = [] for argname in argnames: if isinstance(argname, tuple): argname = list(argname) argnames2.append(argname) func.argspec = (argnames2, starargname, kwname, tuple(defaults)) self.postpone(func, node.code) self.system.popFunction() states = [ 'blank', 'preparse', 'importstarred', 'parsed', 'finalized', ] class System(object): Class = Class Module = Module Package = Package Function = Function ModuleVistor = ModuleVistor def __init__(self): self.current = None self._stack = [] self.allobjects = {} self.orderedallobjects = [] self.rootobjects = [] self.warnings = {} # importstargraph contains edges {importer:[imported]} but only # for import * statements self.importstargraph = {} self.func_called = {} self.state = 'blank' self.packages = [] self.moresystems = [] self.urlprefix = '' def _push(self, cls, name, docstring): if self.current: prefix = self.current.fullName() + '.' parent = self.current else: prefix = '' parent = None obj = cls(self, prefix, name, docstring, parent) if parent: parent.orderedcontents.append(obj) parent.contents[name] = obj parent._name2fullname[name] = obj.fullName() else: self.rootobjects.append(obj) self.current = obj self.orderedallobjects.append(obj) fullName = obj.fullName() #print 'push', cls.__name__, fullName if fullName in self.allobjects: obj = self.handleDuplicate(obj) else: self.allobjects[obj.fullName()] = obj return obj def handleDuplicate(self, obj): '''This is called when we see two objects with the same .fullName(), for example: class C: if something: def meth(self): implementation 1 else: def meth(self): implementation 2 The default is that the second definition "wins". ''' i = 0 fn = obj.fullName() while (fn + ' ' + str(i)) in self.allobjects: i += 1 prev = self.allobjects[obj.fullName()] prev.name = obj.name + ' ' + str(i) self.allobjects[prev.fullName()] = prev self.warning("duplicate", self.allobjects[obj.fullName()]) self.allobjects[obj.fullName()] = obj return obj def _pop(self, cls): assert isinstance(self.current, cls) ## if self.current.parent: ## print 'pop', self.current.fullName(), '->', self.current.parent.fullName() ## else: ## print 'pop', self.current.fullName(), '->', self.current.parent self.current = self.current.parent def push(self, obj, node=None): self._stack.append(self.current) self.current = obj def pop(self, obj): assert self.current is obj, "%r is not %r"%(self.current, obj) self.current = self._stack.pop() def pushClass(self, name, docstring): return self._push(self.Class, name, docstring) def popClass(self): self._pop(self.Class) def pushModule(self, name, docstring): return self._push(self.Module, name, docstring) def popModule(self): self._pop(self.Module) def pushFunction(self, name, docstring, func_called): self.func_called.update(func_called) return self._push(self.Function, name, docstring) def popFunction(self): self._pop(self.Function) def pushPackage(self, name, docstring): return self._push(self.Package, name, docstring) def popPackage(self): self._pop(self.Package) def report(self): for o in self.rootobjects: self._report(o, '') def _report(self, o, indent): print indent, o for o2 in o.orderedcontents: self._report(o2, indent+' ') def resolveAlias(self, n): if '.' not in n: return n mod, clsname = n.split('.') if not mod or mod not in self.allobjects: return n m = self.allobjects[mod] if not isinstance(m, Module): return n if clsname in m._name2fullname: newname = m.name2fullname(clsname) if newname not in self.allobjects: return self.resolveAlias(newname) else: return newname def resolveAliases(self): for ob in self.orderedallobjects: if not isinstance(ob, Class): continue for i, b in enumerate(ob.bases): if b not in self.allobjects: ob.bases[i] = self.resolveAlias(b) def warning(self, type, detail): if self.current is not None: fn = self.current.fullName() else: fn = '' self.warnings.setdefault(type, []).append((fn, detail)) def objectsOfType(self, cls): for o in self.orderedallobjects: if isinstance(o, cls): yield o def finalStateComputations(self): self.recordBasesAndSubclasses() def recordBasesAndSubclasses(self): for cls in self.objectsOfType(Class): for n in cls.bases: o = cls.parent.resolveDottedName(n) cls.baseobjects.append(o) if o: o.subclasses.append(cls) def __getstate__(self): state = self.__dict__.copy() del state['moresystems'] return state def __setstate__(self, state): self.moresystems = [] # this is so very, very evil. # see doc/extreme-pickling-pain.txt for more. self.__dict__.update(state) for obj in self.orderedallobjects: for k, v in obj.__dict__.copy().iteritems(): if k.startswith('$'): del obj.__dict__[k] obj.__dict__[k[1:]] = self.allobjects[v] elif k.startswith('@'): n = [] for vv in v: if vv is None: n.append(None) else: n.append(self.allobjects[vv]) del obj.__dict__[k] obj.__dict__[k[1:]] = n elif k.startswith('!'): n = {} for kk, vv in v.iteritems(): n[kk] = self.allobjects[vv] del obj.__dict__[k] obj.__dict__[k[1:]] = n def expandModname(system, modname, givewarning=True): c = system.current if '.' in modname: prefix, suffix = modname.split('.', 1) suffix = '.' + suffix else: prefix, suffix = modname, '' while c is not None and not isinstance(c, Package): c = c.parent while c is not None: if prefix in c.contents: break c = c.parent if c is not None: if givewarning: system.warning("local import", modname) return c.contents[prefix].fullName() + suffix else: return prefix + suffix class ImportStarFinder(object): def __init__(self, system, modfullname): self.system = system self.modfullname = modfullname def visitFrom(self, node): if node.names[0][0] == '*': modname = expandModname(self.system, node.modname, False) self.system.importstargraph.setdefault( self.modfullname, []).append(modname) def processModuleAst(ast, name, system): mv = system.ModuleVistor(system, name) walk(ast, mv) while mv.morenodes: obj, node = mv.morenodes.pop(0) system.push(obj, node) mv.visit(node) system.pop(obj) def fromText(src, modname='', system=None): if system is None: _system = System() else: _system = system processModuleAst(parse(src), modname, _system) if system is None: _system.finalStateComputations() return _system.rootobjects[0] def preprocessDirectory(system, dirpath): assert system.state in ['blank', 'preparse'] if os.path.basename(dirpath): package = system.pushPackage(os.path.basename(dirpath), None) else: package = None for fname in os.listdir(dirpath): fullname = os.path.join(dirpath, fname) if os.path.isdir(fullname) and os.path.exists(os.path.join(fullname, '__init__.py')) and fname != 'test': preprocessDirectory(system, fullname) elif fname.endswith('.py'): modname = os.path.splitext(fname)[0] mod = system.pushModule(modname, None) mod.filepath = fullname mod.processed = False system.popModule() if package: system.popPackage() system.state = 'preparse' def findImportStars(system): assert system.state in ['preparse'] modlist = list(system.objectsOfType(Module)) for mod in modlist: system.push(mod.parent) isf = ImportStarFinder(system, mod.fullName()) try: ast = parseFile(mod.filepath) except (SyntaxError, ValueError): system.warning("cannot parse", mod.filepath) walk(ast, isf) system.pop(mod.parent) system.state = 'importstarred' def extractDocstrings(system): assert system.state in ['preparse', 'importstarred'] # and so much more... modlist = list(system.objectsOfType(Module)) newlist = toposort([m.fullName() for m in modlist], system.importstargraph) for mod in newlist: mod = system.allobjects[mod] system.push(mod.parent) try: ast = parseFile(mod.filepath) except (SyntaxError, ValueError): system.warning("cannot parse", mod.filepath) processModuleAst(ast, mod.name, system) mod.processed = True system.pop(mod.parent) system.state = 'parsed' def finalStateComputations(system): assert system.state in ['parsed'] system.finalStateComputations() system.state = 'finalized' def processDirectory(system, dirpath): preprocessDirectory(system, dirpath) findImportStars(system) extractDocstrings(system) finalStateComputations(system) def toposort(input, edges): # this doesn't detect cycles in any clever way. output = [] input = dict.fromkeys(input) def p(i): for j in edges.get(i, []): if j in input: del input[j] p(j) output.append(i) while input: p(input.popitem()[0]) return output def main(systemcls, argv): if '-r' in argv: argv.remove('-r') assert len(argv) == 1 system = systemcls() processDirectory(system, argv[0]) pickle.dump(system, open('da.out', 'wb'), pickle.HIGHEST_PROTOCOL) print print 'warning summary:' for k, v in system.warnings.iteritems(): print k, len(v) else: system = systemcls() for fname in argv: modname = os.path.splitext(os.path.basename(fname))[0] # XXX! processModuleAst(parseFile(fname), modname, system) system.report() if __name__ == '__main__': main(System, sys.argv[1:]) PKãI6¾U$!FFcheesecake/ast_pp.py# this is stolen from exarkun's sandbox import sys from StringIO import StringIO from pprint import pprint from compiler import parse, walk class SourceWriter(object): _i = 0 def __init__(self): self.s = StringIO() def w(self, s): self.s.write(s) def nl(self): self.s.write('\n') self.s.write(' ' * 4 * self._i) def indent(self): self._i += 1 self.nl() def dedent(self): self._i -= 1 self.nl() def visitModule(self, node): if node.doc is not None: self.wl(repr(node.doc)) walk(node.node, self) def visitStmt(self, node): for n in node.getChildren(): walk(n, self) def visitFunction(self, node): fmt = 'def %s(%s):' if node.defaults: nargs = len(node.argnames) ndefs = len(node.defaults) noDefaults = node.argnames[:nargs-ndefs] s = ', '.join(node.argnames[:noDefaults]) if ndefs < nargs: argdefs = zip(node.argnames[noDefaults:], node.defaults) s = s + ', ' + ', '.join(['='.join(x) for x in argdefs]) else: s = ', '.join(node.argnames) self.w(fmt % (node.name, s)) self.indent() try: walk(node.code, self) finally: self.dedent() def visitAssign(self, node): walk(node.nodes[0], self) self.w(' = ') walk(node.expr, self) self.nl() def visitAssName(self, node): self.w(node.name) def visitCallFunc(self, node): walk(node.node, self) self.w('(') for a in node.args[:-1]: walk(a, self) self.w(', ') for a in node.args[-1:]: walk(a, self) self.w(')') def visitListComp(self, node): self.w('[') walk(node.expr, self) for q in node.quals: walk(q, self) self.w(']') def visitListCompFor(self, node): self.w(' for ') walk(node.assign, self) self.w(' in ') walk(node.list, self) for expr in node.ifs: self.w(' if ') walk(expr, self) def visitName(self, node): self.w(node.name) def visitDiscard(self, node): walk(node.expr, self) self.nl() def visitPrintnl(self, node): self.w('print ') if node.dest: self.w('>>') walk(node.dest, self) self.w(', ') for e in node.nodes: walk(e, self) self.nl() def visitGetattr(self, node): walk(node.expr, self) self.w('.') self.w(node.attrname) def visitImport(self, node): self.w('import ') for (mod, as_word) in node.names: self.w(mod) if as_word is not None: self.w(' as ') self.w(as_word) self.w(', ') self.nl() def visitFrom(self, node): self.w('from ') self.w(node.modname) self.w(' import ') for (mod, as_word) in node.names: self.w(mod) if as_word is not None: self.w(' as ') self.w(as_word) self.w(', ') self.nl() def visitConst(self, node): self.w(repr(node.value)) def visitReturn(self, node): self.w('return ') walk(node.value, self) self.nl() def visitClass(self, node): self.w('class ') self.w(node.name) if node.bases: self.w('(') for b in node.bases: walk(b, self) self.w(', ') self.w('):') self.indent() try: if node.doc is not None: self.w(repr(node.doc)) walk(node.code, self) finally: self.dedent() def visitAssAttr(self, node): walk(node.expr, self) self.w('.') self.w(node.attrname) def visitMul(self, node): walk(node.left, self) self.w(' * ') walk(node.right, self) def visitSub(self, node): walk(node.left, self) self.w(' - ') walk(node.right, self) def visitAdd(self, node): walk(node.left, self) self.w(' + ') walk(node.right, self) def visitMod(self, node): walk(node.left, self) self.w(' % ') walk(node.right, self) def visitAugAssign(self, node): walk(node.node, self) self.w(' ') self.w(node.op) self.w(' ') walk(node.expr, self) self.nl() def visitIf(self, node): keyword = 'if' for (cond, body) in node.tests: self.w(keyword) self.w(' ') walk(cond, self) self.w(':') self.indent() try: walk(body, self) finally: self.dedent() keyword = 'elif' if node.else_: self.w('else:') self.indent() try: walk(node.else_, self) finally: self.dedent() def visitCompare(self, node): walk(node.expr, self) for (op, arg) in node.ops: self.w(' ') self.w(op) self.w(' ') walk(arg, self) def visitFor(self, node): self.w('for ') walk(node.assign, self) self.w(' in ') walk(node.list, self) self.w(':') self.indent() try: walk(node.body, self) finally: self.dedent() if node.else_: self.w('else:') self.indent() try: walk(node.else_, self) finally: self.dedent() def visitSlice(self, node): walk(node.expr, self) self.w('[') if node.lower: walk(node.lower, self) self.w(':') if node.upper: walk(node.upper, self) self.w(']') def visitTuple(self, node): self.w('(') if len(node.nodes) == 0: pass elif len(node.nodes) == 1: walk(node.nodes[0], self) self.w(',') else: for expr in node.nodes[:-1]: walk(expr, self) self.w(', ') walk(node.nodes[-1], self) self.w(')') def visitTryFinally(self, node): self.w('try:') self.indent() try: walk(node.body, self) finally: self.dedent() self.w('finally:') self.indent() try: walk(node.final, self) finally: self.dedent() def visitSubscript(self, node): walk(node.expr, self) self.w('[') walk(node.subs[0], self) self.w(']') def visitUnarySub(self, node): self.w('-') walk(node.expr, self) def visitAssTuple(self, node): self.w('(') for expr in node.nodes: walk(expr, self) self.w(', ') self.w(')') def visitRaise(self, node): self.w('raise ') walk(node.expr1, self) if node.expr2: self.w(', ') walk(node.expr2, self) if node.expr3: self.w(', ') walk(node.expr3, self) self.nl() def visitDict(self, node): self.w('{') for (k, v) in node.items: walk(k, self) self.w(':') walk(v, self) self.w(',') self.w('}') def __str__(self): return self.s.getvalue() def pp(ast): sw = SourceWriter() walk(ast, sw) return sw.s.getvalue() def magic(s): ast = parse(s) sw = SourceWriter() walk(ast, sw) return ast, sw if __name__ == '__main__': f = file(__file__, 'r').read() ast, sw = magic(f) print sw print ast PKãI6†^L°´´cheesecake/codeparser.pyimport doctest import os import re import logger from model import System, Module, Class, Function, parseFile, processModuleAst # Python 2.3/2.4 compatibilty hacks. if getattr(doctest, 'DocTestParser', False): # Python 2.4 have DocTestParser class. get_doctests = doctest.DocTestParser().get_examples else: # Python 2.3 have _extract_examples function. get_doctests = doctest._extract_examples def compile_regex(pattern, user_map=None): """Compile a regex pattern using default or user mapping. """ # Handy regular expressions. mapping = {'ALPHA': r'[-.,?!\w]', 'WORD': r'[-.,?!\s\w]', 'START': r'(^|\s)', 'END': r'([.,?!\s]|$)'} if user_map: mapping = mapping.copy() mapping.update(user_map) def sub(text, mapping): for From, To in mapping.iteritems(): text = text.replace(From, To) return text pattern = sub(pattern, mapping) return re.compile(pattern, re.LOCALE | re.VERBOSE) def inline_markup(start, end=None, mapping=None): if end is None: end = start return compile_regex(r'''(START %(start)s ALPHA %(end)s END) | (START %(start)s ALPHA WORD* ALPHA %(end)s END)'''\ % {'start': start, 'end': end}, mapping) def line_markup(start, end=None): return inline_markup(start, end, mapping={'ALPHA': r'[-.,?!\s\w]', 'START': r'(\n|^)[\ \t]*', 'END': r''}) supported_formats = { # reST refrence: http://docutils.sourceforge.net/docs/ref/rst/restructuredtext.html 'reST': [ inline_markup(r'\*'), # emphasis inline_markup(r'\*\*'), # strong inline_markup(r'``'), # inline inline_markup(r'\(', r'_\)', # hyperlink {'ALPHA': r'\w', 'WORD': r'[-.\w]'}), inline_markup(r'\(`', r'`_\)'), # long hyperlink line_markup(r':'), # field line_markup(r'[*+-]', r''), # unordered list line_markup(r'((\d+) | ([a-zA-Z]+) [.\)])', r''), # ordered list line_markup(r'\( ((\d+) | ([a-zA-Z]+)) \)', r''), # ordered list ], # epytext reference: http://epydoc.sourceforge.net/epytext.html 'epytext': [ re.compile(r'[BCEGILMSUX]\{.*\}'), # inline elements line_markup(r'@[a-z]+([\ \t][a-zA-Z]+)?:', r''), # fields line_markup(r'-', r''), # unordered list line_markup(r'\d+(\.\d+)*', r''), # ordered list ], # javadoc reference: http://java.sun.com/j2se/1.4.2/docs/tooldocs/solaris/javadoc.html 'javadoc': [ re.compile(r'<[a-zA-z]+[^>]*>'), # HTML elements line_markup(r'@[a-z][a-zA-Z]*\s', r''), # normal tags re.compile(r'{@ ((docRoot) | (inheritDoc) | (link) | (linkplain) |'\ ' (value)) [^}]* }', re.VERBOSE), # special tags ], } def use_format(text, format): """Return True if text includes given documentation format and False otherwise. See supported_formats for list of known formats. """ for pattern in supported_formats[format]: if re.search(pattern, text): return True return False class CodeParser(object): """Information about the structure of a Python module. * Collects modules, classes, methods, functions and associated docstrings * Based on mwh's docextractor.model module """ def __init__(self, pyfile, log=None): """Initialize Code Parser object. :Parameters: `pyfile` : str Path to a Python module to parse. `log` : logger.Producer instance Logger to use during code parsing. """ if log: self.log = log.codeparser else: self.log = logger.default.codeparser self.modules = [] self.classes = [] self.methods = [] self.method_func = [] self.functions = [] self.docstrings = [] # objects that have docstrings self.docstrings_by_format = {} self.formatted_docstrings_count = 0 self.doctests_count = 0 self.unittests_count = 0 # Initialize lists of format docstrings. for format in supported_formats: self.docstrings_by_format[format] = [] (path, filename) = os.path.split(pyfile) (module, ext) = os.path.splitext(filename) self.log("Inspecting file: " + pyfile) self.system = System() try: processModuleAst(parseFile(pyfile), module, self.system) except Exception, e: self.log("Code parsing error occured:\n***\n%s\n***" % str(e)) return for obj in self.system.orderedallobjects: fullname = obj.fullName() if isinstance(obj, Module): self.modules.append(fullname) if isinstance(obj, Class): if 'unittest.TestCase' in obj.bases or 'TestCase' in obj.bases: self.unittests_count += 1 self.classes.append(fullname) if isinstance(obj, Function): self.method_func.append(fullname) if isinstance(obj.docstring, str) and obj.docstring.strip(): self.docstrings.append(fullname) # Check docstring for known documenation formats. formatted = False for format in supported_formats: if use_format(obj.docstring, format): self.docstrings_by_format[format].append(fullname) formatted = True if formatted: self.formatted_docstrings_count += 1 # Check if docstring include any doctests. if get_doctests(obj.docstring): self.doctests_count += 1 for method_or_func in self.method_func: method_found = 0 for cls in self.classes: if method_or_func.startswith(cls): self.methods.append(method_or_func) method_found = 1 break if not method_found: self.functions.append(method_or_func) self.log("modules: " + ",".join(self.modules)) self.log("classes: " + ",".join(self.classes)) self.log("methods: " + ",".join(self.methods)) self.log("functions: " + ",".join(self.functions)) self.log("docstrings: %s" % self.docstrings_by_format) self.log("number of doctests: %d" % self.doctests_count) def object_count(self): """Return number of objects found in this module. Objects include: * module * classes * methods * functions """ module_count = len(self.modules) cls_count = len(self.classes) method_count = len(self.methods) func_count = len(self.functions) return module_count + cls_count + method_count + func_count def docstring_count(self): """Return number of docstrings found in this module. """ return len(self.docstrings) def docstring_count_by_type(self, type): """Return number of docstrings of given type found in this module. """ return len(self.docstrings_by_format[type]) def _functions_called(self): """Return list of functions called by functions/methods defined in this module. """ return self.system.func_called.keys() functions_called = property(_functions_called) PKãI6TKWûdûdcheesecake/pep8.py#!/usr/bin/python # pep8.py - Check Python source code formatting, according to PEP 8 # Copyright (C) 2006 Johann C. Rocholl # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation files # (the "Software"), to deal in the Software without restriction, # including without limitation the rights to use, copy, modify, merge, # publish, distribute, sublicense, and/or sell copies of the Software, # and to permit persons to whom the Software is furnished to do so, # subject to the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS # BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. """ Check Python source code formatting, according to PEP 8: http://www.python.org/dev/peps/pep-0008/ For usage and a list of options, try this: $ python pep8.py -h This program and its regression test suite live here: http://svn.browsershots.org/trunk/devtools/pep8/ http://trac.browsershots.org/browser/trunk/devtools/pep8/ Groups of errors and warnings: E errors W warnings 100 indentation 200 whitespace 300 blank lines 400 imports 500 line length 600 deprecation You can add checks to this program by writing plugins. Each plugin is a simple function that is called for each line of source code, either physical or logical. Physical line: - Raw line of text from the input file. Logical line: - Multi-line statements converted to a single line. - Stripped left and right. - Contents of strings replaced with 'xxx' of same length. - Comments removed. The check function requests physical or logical lines by the name of the first argument: def maximum_line_length(physical_line) def extraneous_whitespace(logical_line) def indentation(logical_line, indent_level, state) The last example above demonstrates how check plugins can request additional information with extra arguments. All attributes of the Checker object are available. Some examples: lines: a list of the raw lines from the input file tokens: the tokens that contribute to this logical line state: dictionary for passing information across lines indent_level: indentation (with tabs expanded to multiples of 8) The docstring of each check function shall be the relevant part of text from PEP 8. It is printed if the user enables --show-pep8. """ import os import sys import re import time import inspect import tokenize from optparse import OptionParser from keyword import iskeyword from fnmatch import fnmatch __version__ = '0.2.0' __revision__ = '$Rev: 930 $' default_exclude = '.svn,CVS,*.pyc,*.pyo' indent_match = re.compile(r'([ \t]*)').match raise_comma_match = re.compile(r'raise\s+\w+\s*(,)').match operators = """ + - * / % ^ & | = < > >> << += -= *= /= %= ^= &= |= == <= >= >>= <<= != <> : in is or not and """.split() options = None args = None ############################################################################## # Plugins (check functions) for physical lines ############################################################################## def tabs_or_spaces(physical_line, state): """ Never mix tabs and spaces. The most popular way of indenting Python is with spaces only. The second-most popular way is with tabs only. Code indented with a mixture of tabs and spaces should be converted to using spaces exclusively. When invoking the Python command line interpreter with the -t option, it issues warnings about code that illegally mixes tabs and spaces. When using -tt these warnings become errors. These options are highly recommended! """ indent = indent_match(physical_line).group(1) if not indent: return if 'indent_char' in state: indent_char = state['indent_char'] else: indent_char = indent[0] state['indent_char'] = indent_char for offset, char in enumerate(indent): if char != indent_char: return offset, "E101 indentation contains mixed spaces and tabs" def tabs_obsolete(physical_line): """ For new projects, spaces-only are strongly recommended over tabs. Most editors have features that make this easy to do. """ indent = indent_match(physical_line).group(1) if indent.count('\t'): return indent.index('\t'), "W191 indentation contains tabs" def trailing_whitespace(physical_line): """ JCR: Trailing whitespace is superfluous. """ physical_line = physical_line.rstrip('\n') # chr(10), newline physical_line = physical_line.rstrip('\r') # chr(13), carriage return physical_line = physical_line.rstrip('\x0c') # chr(12), form feed, ^L stripped = physical_line.rstrip() if physical_line != stripped: return len(stripped), "W291 trailing whitespace" def maximum_line_length(physical_line): """ Limit all lines to a maximum of 79 characters. There are still many devices around that are limited to 80 character lines; plus, limiting windows to 80 characters makes it possible to have several windows side-by-side. The default wrapping on such devices looks ugly. Therefore, please limit all lines to a maximum of 79 characters. For flowing long blocks of text (docstrings or comments), limiting the length to 72 characters is recommended. """ length = len(physical_line.rstrip()) if length > 79: return 79, "E501 line too long (%d characters)" % length ############################################################################## # Plugins (check functions) for logical lines ############################################################################## def blank_lines(logical_line, state, indent_level): """ Separate top-level function and class definitions with two blank lines. Method definitions inside a class are separated by a single blank line. Extra blank lines may be used (sparingly) to separate groups of related functions. Blank lines may be omitted between a bunch of related one-liners (e.g. a set of dummy implementations). Use blank lines in functions, sparingly, to indicate logical sections. """ line = logical_line blank_lines = state.get('blank_lines', 0) if line.startswith('def '): if indent_level > 0 and blank_lines != 1: return 0, "E301 expected 1 blank line, found %d" % blank_lines if indent_level == 0 and blank_lines != 2: return 0, "E302 expected 2 blank lines, found %d" % blank_lines if blank_lines > 2: return 0, "E303 too many blank lines (%d)" % blank_lines def extraneous_whitespace(logical_line): """ Avoid extraneous whitespace in the following situations: - Immediately inside parentheses, brackets or braces. - Immediately before a comma, semicolon, or colon. """ line = logical_line for char in '([{': found = line.find(char + ' ') if found > -1: return found + 1, "E201 whitespace after '%s'" % char for char in '}])': found = line.find(' ' + char) if found > -1 and line[found - 1] != ',': return found, "E202 whitespace before '%s'" % char for char in ',;:': found = line.find(' ' + char) if found > -1: return found, "E203 whitespace before '%s'" % char def indentation(logical_line, indent_level, state): """ Use 4 spaces per indentation level. For really old code that you don't want to mess up, you can continue to use 8-space tabs. """ line = logical_line previous_level = state.get('indent_level', 0) indent_expect = state.get('indent_expect', False) state['indent_expect'] = line.rstrip('#').rstrip().endswith(':') indent_char = state.get('indent_char', ' ') state['indent_level'] = indent_level if indent_char == ' ' and indent_level % 4: return 0, "E111 indentation is not a multiple of four" if indent_expect and indent_level <= previous_level: return 0, "E112 expected an indented block" if not indent_expect and indent_level > previous_level: return 0, "E113 unexpected indentation" def whitespace_before_parameters(logical_line, tokens): """ Avoid extraneous whitespace in the following situations: - Immediately before the open parenthesis that starts the argument list of a function call. - Immediately before the open parenthesis that starts an indexing or slicing. """ prev_type = tokens[0][0] prev_text = tokens[0][1] prev_end = tokens[0][3] for index in range(1, len(tokens)): token_type, text, start, end, line = tokens[index] if (token_type == tokenize.OP and text in '([' and start != prev_end and prev_type == tokenize.NAME and (index < 2 or tokens[index - 2][1] != 'class') and (not iskeyword(prev_text))): return prev_end, "E211 whitespace before '%s'" % text prev_type = token_type prev_text = text prev_end = end def whitespace_around_operator(logical_line): """ Avoid extraneous whitespace in the following situations: - More than one space around an assignment (or other) operator to align it with another. """ line = logical_line for operator in operators: found = line.find(' ' + operator) if found > -1: return found, "E221 multiple spaces before operator" found = line.find('\t' + operator) if found > -1: return found, "E222 tab before operator" def imports_on_separate_lines(logical_line): """ Imports should usually be on separate lines. """ line = logical_line if line.startswith('import '): found = line.find(',') if found > -1: return found, "E401 multiple imports on one line" def python_3000_has_key(logical_line): """ The {}.has_key() method will be removed in the future version of Python. Use the 'in' operation instead, like: d = {"a": 1, "b": 2} if "b" in d: print d["b"] """ pos = logical_line.find('.has_key(') if pos > -1: return pos, "W601 .has_key() is deprecated, use 'in'" def python_3000_raise_comma(logical_line): """ When raising an exception, use "raise ValueError('message')" instead of the older form "raise ValueError, 'message'". The paren-using form is preferred because when the exception arguments are long or include string formatting, you don't need to use line continuation characters thanks to the containing parentheses. The older form will be removed in Python 3000. """ match = raise_comma_match(logical_line) if match: return match.start(1), "W602 deprecated form of raising exception" ############################################################################## # Helper functions ############################################################################## def expand_indent(line): """ Return the amount of indentation. Tabs are expanded to the next multiple of 8. >>> expand_indent(' ') 4 >>> expand_indent('\\t') 8 >>> expand_indent(' \\t') 8 >>> expand_indent(' \\t') 8 >>> expand_indent(' \\t') 16 """ result = 0 for char in line: if char == '\t': result = result / 8 * 8 + 8 elif char == ' ': result += 1 else: break return result ############################################################################## # Framework to run all checks ############################################################################## def message(text): """Print a message.""" # print >> sys.stderr, options.prog + ': ' + text # print >> sys.stderr, text print text def find_checks(argument_name): """ Find all globally visible functions where the first argument name starts with argument_name. """ checks = [] function_type = type(find_checks) for name, function in globals().iteritems(): if type(function) is function_type: args = inspect.getargspec(function)[0] if len(args) >= 1 and args[0].startswith(argument_name): checks.append((name, function, args)) checks.sort() return checks def mute_string(text): """ Replace contents with 'xxx' to prevent syntax matching. >>> mute_string('"abc"') '"xxx"' >>> mute_string("'''abc'''") "'''xxx'''" >>> mute_string("r'abc'") "r'xxx'" """ start = 1 end = len(text) - 1 # String modifiers (e.g. u or r) if text.endswith('"'): start += text.index('"') elif text.endswith("'"): start += text.index("'") # Triple quotes if text.endswith('"""') or text.endswith("'''"): start += 2 end -= 2 return text[:start] + 'x' * (end - start) + text[end:] class Checker: """ Load a Python source file, tokenize it, check coding style. """ def __init__(self, filename): self.filename = filename self.lines = file(filename).readlines() self.physical_checks = find_checks('physical_line') self.logical_checks = find_checks('logical_line') options.counters['physical lines'] = \ options.counters.get('physical lines', 0) + len(self.lines) def readline(self): """ Get the next line from the input buffer. """ self.line_number += 1 if self.line_number > len(self.lines): return '' return self.lines[self.line_number - 1] def readline_check_physical(self): """ Check and return the next physical line. This method can be used to feed tokenize.generate_tokens. """ line = self.readline() self.check_physical(line) return line def run_check(self, check, argument_names): """ Run a check plugin. """ arguments = [] for name in argument_names: arguments.append(getattr(self, name)) return check(*arguments) def check_physical(self, line): """ Run all physical checks on a raw input line. """ self.physical_line = line for name, check, argument_names in self.physical_checks: result = self.run_check(check, argument_names) if result is not None: offset, text = result self.report_error(self.line_number, offset, text, check) def build_tokens_line(self): """ Build a logical line from tokens. """ self.mapping = [] logical = [] length = 0 previous = None for token in self.tokens: token_type, text = token[0:2] if token_type in (tokenize.COMMENT, tokenize.NL, tokenize.INDENT, tokenize.DEDENT, tokenize.NEWLINE): continue if token_type == tokenize.STRING: text = mute_string(text) if previous: end_line, end = previous[3] start_line, start = token[2] if end_line != start_line: # different row if self.lines[end_line - 1][end - 1] not in '{[(': logical.append(' ') length += 1 elif end != start: # different column fill = self.lines[end_line - 1][end:start] logical.append(fill) length += len(fill) self.mapping.append((length, token)) logical.append(text) length += len(text) previous = token self.logical_line = ''.join(logical) def check_logical(self): """ Build a line from tokens and run all logical checks on it. """ options.counters['logical lines'] = \ options.counters.get('logical lines', 0) + 1 self.build_tokens_line() first_line = self.lines[self.mapping[0][1][2][0] - 1] indent = first_line[:self.mapping[0][1][2][1]] self.indent_level = expand_indent(indent) if options.verbose >= 2: print self.logical_line[:80].rstrip() for name, check, argument_names in self.logical_checks: if options.verbose >= 3: print ' ', name result = self.run_check(check, argument_names) if result is not None: offset, text = result if type(offset) is tuple: original_number, original_offset = offset else: for token_offset, token in self.mapping: if offset >= token_offset: original_number = token[2][0] original_offset = (token[2][1] + offset - token_offset) self.report_error(original_number, original_offset, text, check) def check_all(self): """ Run all checks on the input file. """ self.file_errors = 0 self.line_number = 0 self.state = {'blank_lines': 0} self.tokens = [] parens = 0 for token in tokenize.generate_tokens(self.readline_check_physical): # print tokenize.tok_name[token[0]], repr(token) self.tokens.append(token) token_type, text = token[0:2] if token_type == tokenize.OP and text in '([{': parens += 1 if token_type == tokenize.OP and text in '}])': parens -= 1 if token_type == tokenize.NEWLINE and not parens: self.check_logical() self.state['blank_lines'] = 0 self.tokens = [] if token_type == tokenize.NL and len(self.tokens) == 1: self.state['blank_lines'] += 1 self.tokens = [] return self.file_errors def report_error(self, line_number, offset, text, check): """ Report an error, according to options. """ if options.quiet == 1 and not self.file_errors: message(self.filename) self.file_errors += 1 code = text[:4] options.counters[code] = options.counters.get(code, 0) + 1 options.messages[code] = text[5:] if options.quiet: return if options.testsuite: base = os.path.basename(self.filename)[:4] if base == code: return if base[0] == 'E' and code[0] == 'W': return if ignore_code(code): return if options.counters[code] == 1 or options.repeat: message("%s:%s:%d: %s" % (self.filename, line_number, offset + 1, text)) if options.show_source: line = self.lines[line_number - 1] message(line.rstrip()) message(' ' * offset + '^') if options.show_pep8: message(check.__doc__.lstrip('\n').rstrip()) def input_file(filename): """ Run all checks on a Python source file. """ if excluded(filename) or not filename_match(filename): return {} if options.verbose: message('checking ' + filename) options.counters['files'] = options.counters.get('files', 0) + 1 errors = Checker(filename).check_all() if options.testsuite and not errors: message("%s: %s" % (filename, "no errors found")) def input_dir(dirname): """ Check all Python source files in this directory and all subdirectories. """ dirname = dirname.rstrip('/') if excluded(dirname): return for root, dirs, files in os.walk(dirname): if options.verbose: message('directory ' + root) options.counters['directories'] = \ options.counters.get('directories', 0) + 1 dirs.sort() for subdir in dirs: if excluded(subdir): dirs.remove(subdir) files.sort() for filename in files: input_file(os.path.join(root, filename)) def excluded(filename): """ Check if options.exclude contains a pattern that matches filename. """ for pattern in options.exclude: if fnmatch(filename, pattern): return True def filename_match(filename): """ Check if options.filename contains a pattern that matches filename. If options.filename is unspecified, this always returns True. """ if not options.filename: return True for pattern in options.filename: if fnmatch(filename, pattern): return True def ignore_code(code): """ Check if options.ignore contains a prefix of the error code. """ for ignore in options.ignore: if code.startswith(ignore): return True def get_error_statistics(): """Get error statistics.""" return get_statistics("E") def get_warning_statistics(): """Get warning statistics.""" return get_statistics("W") def get_statistics(prefix=''): """ Get statistics for message codes that start with the prefix. prefix='' matches all errors and warnings prefix='E' matches all errors prefix='W' matches all warnings prefix='E4' matches all errors that have to do with imports """ stats = [] keys = options.messages.keys() keys.sort() for key in keys: if key.startswith(prefix): stats.append('%-7s %s %s' % (options.counters[key], key, options.messages[key])) return stats def print_statistics(prefix=''): """Print overall statistics (number of errors and warnings).""" for line in get_statistics(prefix): print line def print_benchmark(elapsed): """ Print benchmark numbers. """ print '%-7.2f %s' % (elapsed, 'seconds elapsed') keys = ['directories', 'files', 'logical lines', 'physical lines'] for key in keys: if key in options.counters: print '%-7d %s per second (%d total)' % ( options.counters[key] / elapsed, key, options.counters[key]) def process_options(arglist=None): """ Process options passed either via arglist or via command line args. """ global options, args usage = "%prog [options] input ..." parser = OptionParser(usage) parser.add_option('-v', '--verbose', default=0, action='count', help="print status messages, or debug with -vv") parser.add_option('-q', '--quiet', default=0, action='count', help="report only file names, or nothing with -qq") parser.add_option('--exclude', metavar='patterns', default=default_exclude, help="skip matches (default %s)" % default_exclude) parser.add_option('--filename', metavar='patterns', help="only check matching files (e.g. *.py)") parser.add_option('--ignore', metavar='errors', default='', help="skip errors and warnings (e.g. E4,W)") parser.add_option('--repeat', action='store_true', help="show all occurrences of the same error") parser.add_option('--show-source', action='store_true', help="show source code for each error") parser.add_option('--show-pep8', action='store_true', help="show text of PEP 8 for each error") parser.add_option('--statistics', action='store_true', help="count errors and warnings") parser.add_option('--benchmark', action='store_true', help="measure processing speed") parser.add_option('--testsuite', metavar='dir', help="run regression tests from dir") parser.add_option('--doctest', action='store_true', help="run doctest on myself") options, args = parser.parse_args(arglist) if options.testsuite: args.append(options.testsuite) if len(args) == 0: parser.error('input not specified') options.prog = os.path.basename(sys.argv[0]) options.exclude = options.exclude.split(',') for index in range(len(options.exclude)): options.exclude[index] = options.exclude[index].rstrip('/') if options.filename: options.filename = options.filename.split(',') if options.ignore: options.ignore = options.ignore.split(',') else: options.ignore = [] options.counters = {} options.messages = {} return options, args def _main(): """ Parse options and run checks on Python source. """ options, args = process_options() if options.doctest: import doctest return doctest.testmod() start_time = time.time() for path in args: if os.path.isdir(path): input_dir(path) else: input_file(path) elapsed = time.time() - start_time if options.statistics: print_statistics() if options.benchmark: print_benchmark(elapsed) if __name__ == '__main__': _main() PKçI6‚¢ú„>„>cheesecake/cheesecake_index.pyc;ò ËËEc@s}dZdkZdkZdkZdkZdkZdklZdkl Z dk l Z dk l Z dk Z dklZlZlZlZlZdklZlZdklZlZlZd klZd klZd klZd klZd klZ dk!Z!dZ"ddd!i#ƒZ$de%e&ƒjo d„Z'nde%e&ƒjodk(l)Z*nd„Z+d„Z,d„Z-d„Z.d„Z/d„Z0d„Z1d„Z2d„Z3d„Z4d „Z5d!„Z6d"„Z7d#„Z8d$„Z9d%„Z:d&e;fd'„ƒYZ<d(„Z=d)e>fd*„ƒYZ?d+e>fd,„ƒYZ@d-„ZAd.„ZBd/e?fd0„ƒYZCd1e?fd2„ƒYZDd3e?fd4„ƒYZEd5e?fd6„ƒYZFd7eCfd8„ƒYZGd9e?fd:„ƒYZHd;e?fd<„ƒYZId=e?fd>„ƒYZJd?e?fd@„ƒYZKdAeCfdB„ƒYZLdCe?fdD„ƒYZMdEe?fdF„ƒYZNdGe?fdH„ƒYZOdIe?fdJ„ƒYZPdKe?fdL„ƒYZQdMe?fdN„ƒYZRdOe?fdP„ƒYZSdQe?fdR„ƒYZTdSeUfdT„ƒYZVdUe?fdV„ƒYZWdWe>fdX„ƒYZXdYeXfdZ„ƒYZYd[e>fd\„ƒYZZd]„Z[d^„Z\e]d_jo e\ƒndS(`sòCheesecake: How tasty is your code? The idea of the Cheesecake project is to rank Python packages based on various empirical "kwalitee" factors, such as: * whether the package can be downloaded from PyPI given its name * whether the package can be unpacked * whether the package can be installed into an alternate directory * existence of certain files such as README, INSTALL, LICENSE, setup.py etc. * percentage of modules/functions/classes/methods with docstrings * ... and many others N(s OptionParser(s urlretrieve(surlparse(sceil(s pad_with_dotsspad_left_spacesspad_right_spacesspad_msgspad_line(srun_cmdscommand_successful(s unzip_packages untar_packages unegg_package(smkdirs(sStdoutRedirector(s time_function(s CodeParser(s __version__sreStructuredText ens$Revision: 176 $i iÿÿÿÿssortedcCs|}|iƒ|SdS(N(sLsnew_listssort(sLsnew_list((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pyssorted/s sset(sSetcCs!t|dƒp t|tƒSdS(s—Check whether object is iterable. >>> isiterable([1,2,3]) True >>> isiterable("string") True >>> isiterable(object) False s__iter__N(shasattrsobjs isinstances basestring(sobj((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pys isiterable7s cCs*tii|iƒƒd|iƒjSdS(s+Check if filename has given extension. >>> has_extension("foobar.py", ".py") True >>> has_extension("foo.bar.py", ".py") True >>> has_extension("foobar.pyc", ".py") False This function is case insensitive. >>> has_extension("FOOBAR.PY", ".py") True iN(sosspathssplitextsfilenameslowersext(sfilenamesext((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pys has_extensionCs cCs-|itiiƒ}|d |df\}}|dddgjodSnt|dƒodSnt|dƒod Snt|d ƒoœxM|D]E}|d d gjod Sq”|d ddddgjodSq”q”W|iƒi dƒp#tii |ƒdiƒi dƒod SndSndS(svDiscover type of a file according to its name and its parent directory. Currently supported file types: * pyc * pyo * module: .py files of an application * demo: .py files for documentation/demonstration purposes * test: .py files used for testing * special: .py file for special purposes :Note: This function only checks file's name, and doesn't touch the filesystem. If you have to, check if file exists by yourself. >>> discover_file_type('module.py') 'module' >>> discover_file_type('./setup.py') 'special' >>> discover_file_type('some/directory/junk.pyc') 'pyc' >>> discover_file_type('examples/readme.txt') >>> discover_file_type('examples/runthis.py') 'demo' >>> discover_file_type('optimized.pyo') 'pyo' >>> test_files = ['ut/test_this_and_that.py', ... 'another_test.py', ... 'TEST_MY_MODULE.PY'] >>> for filename in test_files: ... assert discover_file_type(filename) == 'test', filename >>> discover_file_type('this_is_not_a_test_really.py') 'module' iÿÿÿÿssetup.pys ez_setup.pys__pkginfo__.pysspecials.pycspycs.pyospyos.pysteststestssdocsdocssdemosexamplesexamplesstest_is_testsmoduleN( sfilenamessplitsosspathssepsdirss has_extensionsdirslowers startswithssplitextsendswith(sfilenamesdirssdir((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pysdiscover_file_typeSs&" <cst‡d†|ƒSdS(sîReturn files from `file_list` that match given `file_type`. >>> file_list = ['test/test_foo.py', 'setup.py', 'README', 'test/test_bar.py'] >>> get_files_of_type(file_list, 'test') ['test/test_foo.py', 'test/test_bar.py'] cst|ƒˆjS(N(sdiscover_file_typesxs file_type(sx(s file_type(s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pys–sN(sfilters file_list(s file_lists file_type((s file_types9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pysget_files_of_typescCs tii|ƒ\}}|SdS(sEGet package name as file portion of path. >>> get_package_name_from_path('/some/random/path/package.tar.gz') 'package.tar.gz' >>> get_package_name_from_path('/path/underscored_name.zip') 'underscored_name.zip' >>> get_package_name_from_path('/path/unknown.extension.txt') 'unknown.extension.txt' N(sosspathssplitsdirsfilename(spathsdirsfilename((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pysget_package_name_from_path˜s cCs,t|ƒ\}}}}}}t|ƒSdS(sñUse ``urlparse`` to obtain package name from URL. >>> get_package_name_from_url('http://www.example.com/file.tar.bz2') 'file.tar.bz2' >>> get_package_name_from_url('https://www.example.com/some/dir/file.txt') 'file.txt' N( surlparsesurlsschemeslocationspathsparamsquerys fragment_idsget_package_name_from_path(surlsparams fragment_idslocationsqueryspathsscheme((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pysget_package_name_from_url¥scCsHxA|D]9}|id|ƒo||id|ƒ |fSqqWdS(sOReturn package name and type. Package type must exists in known_extensions list. Otherwise None is returned. >>> extensions = ['tar.gz', 'zip'] >>> get_package_name_and_type('underscored_name.zip', extensions) ('underscored_name', 'zip') >>> get_package_name_and_type('unknown.extension.txt', extensions) s.N(sknown_extensionss package_typespackagesendswithsrfind(spackagesknown_extensionss package_type((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pysget_package_name_and_type°s cCs|iid|ii!SdS(sêReturn tuple of arguments for given method, excluding self. >>> class Class: ... def method(s, arg1, arg2, other_arg): ... pass >>> get_method_arguments(Class.method) ('arg1', 'arg2', 'other_arg') iN(smethods func_codes co_varnamess co_argcount(smethod((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pysget_method_argumentsÀscCs5h}x$|D]}t||tƒ||>> class Class: ... pass >>> obj = Class() >>> obj.attr = True >>> obj.value = 13 >>> obj.string = "Hello" >>> d = get_attributes(obj, ['attr', 'string', 'other']) >>> d == {'attr': True, 'string': "Hello", 'other': None} True N(sattrssnamessnamesgetattrsobjsNone(sobjsnamessnamesattrs((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pysget_attributesËs cCso|o |dio|diƒ|d}nd„}d„}tid||ƒ}tid||ƒSdS(s Convert name from CamelCase to underscore_name. >>> camel2underscore('CamelCase') 'camel_case' >>> camel2underscore('already_underscore_name') 'already_underscore_name' >>> camel2underscore('BigHTMLClass') 'big_html_class' >>> camel2underscore('') '' iicCs5|idƒiƒiƒ}|d |diƒSdS(Niiÿÿÿÿ(smatchsgroupslowers capitalizesstringsupper(smatchsstring((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pys capitalizeòscCsd|idƒiƒSdS(Ns_i(smatchsgroupslower(smatch((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pys underscoreöss([A-Z]+)s([A-Z])N(snamesupperslowers capitalizes underscoresressub(snames capitalizes underscore((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pyscamel2underscoreãs   cCst|idddƒƒSdS(síCovert index class name to index name. >>> index_class_to_name("IndexDownload") 'download' >>> index_class_to_name("IndexUnitTests") 'unit_tests' >>> index_class_to_name("IndexPyPIDownload") 'py_pi_download' sIndexsiN(scamel2underscoresclsnamesreplace(sclsname((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pysindex_class_to_nameüs cCsmtii|ƒotii|ƒdjotSntii|ƒoti|ƒgjotSntSdS(sBReturns True if file or directory pointed by `path` is empty. iN(sosspathsisfilesgetsizesTruesisdirslistdirsFalse(spath((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pysis_emptys ,)cCsA|i|ddƒ}|itiiƒo|d}n|SdS(s"Strip `root` part from `path`. >>> strip_dir_part('/home/ruby/file', '/home') 'ruby/file' >>> strip_dir_part('/home/ruby/file', '/home/') 'ruby/file' >>> strip_dir_part('/home/ruby/', '/home') 'ruby/' >>> strip_dir_part('/home/ruby/', '/home/') 'ruby/' siN(spathsreplacesroots startswithsosssep(spathsroot((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pysstrip_dir_parts cs„g}g}xgti|ƒD]V\‰}}tˆ|ƒ‰|i t ‡d†|ƒƒ|i t ‡d†|ƒƒqW||fSdS(syReturn list of all files and directories below `root`. Root directory is excluded from files/directories paths. cstiiˆ|ƒS(N(sosspathsjoinsdirpathsx(sx(sdirpath(s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pys/sN( sfiless directoriessosswalksrootsdirpathsdirnamess filenamessstrip_dir_partsextendsmap(srootsfiless directoriessdirnamessdirpaths filenames((sdirpaths9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pysget_files_dirs_list%s cCsttd„|ƒƒSdS(s^Overall length of all strings in list. >>> length(['a', 'bc', 'd', '', 'efg']) 7 cCs t|ƒS(N(slensx(sx((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pys:sN(ssumsmapsL(sL((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pyslength4sccsÏg}d}x¼|o´|gjot||ƒ|jotd|||fƒ‚n|i||ƒ|t|ƒdjo |VPnt|ƒt||dƒ|jo|Vg}n|d7}qWdS(sŽPass list of strings in chunks of size not greater than max_length. >>> for x in generate_arguments(['abc', 'def'], 4): ... print x ['abc'] ['def'] >>> for x in generate_arguments(['a', 'bc', 'd', 'e', 'f'], 2): ... print x ['a'] ['bc'] ['d', 'e'] ['f'] If a single argument is larger than max_length, ValueError is raised. >>> L = [] >>> for x in generate_arguments(['abc', 'de', 'fghijk', 'l'], 4): ... L.append(x) Traceback (most recent call last): ... ValueError: Argument 'fghijk' larger than 4. >>> L [['abc'], ['de']] isArgument '%s' larger than %d.iN(sLsis argumentsslens max_lengths ValueErrorsappendslength(s argumentss max_lengthsisL((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pysgenerate_arguments<s$% s NameSettercBstZd„Zd„ZRS(Ncs[d|jot|d|ƒnd|jo)|i‰‡d†}t|d|ƒndS(Nsnames compute_withcsLt‡‡‡d†ƒ\}ˆ_ˆiiidˆiˆifƒ|SdS(Ncs ˆˆˆƒS(N(sorig_compute_withsselfs cheesecake((sorig_compute_withsselfs cheesecake(s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pysxss"Index %s computed in %.2f seconds.(s time_functionsretsselfs time_takens cheesecakeslogsdebugsname(sselfs cheesecakesret(sorig_compute_with(sselfs cheesecakes9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pys_timed_compute_withws!#(sdictssetattrsclssnames compute_withsorig_compute_withs_timed_compute_with(sclssnamesbasessdicts_timed_compute_withsorig_compute_with((sorig_compute_withs9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pys__init__ps     cCsd|iSdS(Ns(sclssname(scls((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pys__repr__~s(s__name__s __module__s__init__s__repr__(((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pys NameSetteros cCs,h}x|D]}|||iîsi(sselfs subindicesssumsmap(sself((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pys_get_max_valueìs  cCsB|io't|iƒtd„|igƒSnt|iƒSdS(NcCs ||iS(N(sxsys requirements(sxsy((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pys÷s(sselfs subindicesslists_compute_argumentssreduce(sself((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pys_get_requirementsôs 'cCsEt|tƒ otdƒ‚n|ii|ƒ||i|i6s(sselfs subindicessjoinsmapsinfo(sself((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pysget_info4s  (s__name__s __module__s__doc__s NameSetters __metaclass__sNones subindicessnamesvaluesdetailssinfos__init__s _iter_indicess compute_withscomputesdecidesdecide_before_downloadsdecide_after_downloadsadd_infos_get_max_valuespropertys max_values_get_requirementss requirementss add_subindexsremove_subindexs_print_info_ones_print_info_manys print_infos __getitem__sget_info(((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pysIndex‡s4                 sOneOfcBstZd„Zd„ZRS(NcGs ||_dS(N(s possibilitiessself(sselfs possibilities((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pys__init__>scCs ditd„|iƒƒSdS(Ns/cCs t|ƒS(N(sstrsx(sx((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pysAs(sjoinsmapsselfs possibilities(sself((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pys__str__@s(s__name__s __module__s__init__s__str__(((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pysOneOf=s cs3ˆg}|it‡d†|ƒƒt|ŒSdS(sZHandy way of writing Cheese rules for files with extensions. Instead of writing: >>> one_of = OneOf('readme', 'readme.html', 'readme.txt') Write this: >>> opt_ext = WithOptionalExt('readme', ['html', 'txt']) It means the same! (representation has a meaning) >>> str(one_of) == str(opt_ext) True cs ˆd|S(Ns.(snamesx(sx(sname(s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pysQsN(snames possibilitiessextendsmaps extensionssOneOf(snames extensionss possibilities((snames9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pysWithOptionalExtCs  cCst|ddgƒSdS(Nshtmlstxt(sWithOptionalExtsname(sname((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pysDocUss FilesIndexcBs2tZgZd„Zd„Zd„Zd„ZRS(NcCs˜g|_d}d}xr|D]j}ttii ||ƒƒ oG|i tii |ƒ|ƒ}|djo||7}|d7}q†qqW||fSdS(Nii(sselfs _used_ruless files_countsvalues files_listsfilenamesis_emptysosspathsjoins package_dirs get_scoresbasenames files_rulessscore(sselfs files_lists package_dirs files_rulessvaluesfilenamesscores files_count((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pys_compute_from_rules[s   cCs`xU|iƒD]G\}}|i||ƒo(|iii d|||fƒ|Sq q WdSdS(Ns%d points entry found: %s (%s)i( sspecss iteritemssentrysvaluesselfsmatch_filenamesnames cheesecakeslogsdebug(sselfsnamesspecssentrysvalue((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pys get_scoreis    cst‡d†|ƒSdS(sìGet only these of files_rules that didn't match during computation. >>> rules = { ... Doc('readme'): 30, ... OneOf(Doc('license'), Doc('copying')): 30, ... 'demo': 10, ... } >>> index = FilesIndex() >>> index._used_rules.append('demo') >>> map(lambda x: str(x), index.get_not_used(rules.keys())) ['license/license.html/license.txt/copying/copying.html/copying.txt', 'readme/readme.html/readme.txt'] cs |ˆijS(N(srulesselfs _used_rules(srule(sself(s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pyssN(sfilters files_rules(sselfs files_rules((sselfs9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pys get_not_usedrs  cCs¸d„}||ijotSnt|tƒo,|||ƒo|ii|ƒt Sq°nTt|t ƒoCx@|i D]1}|i ||ƒo|ii|ƒt SqwqwWntSdS(s.Check if `name` matches given `rule`. cCstii|ƒ\}}tii|iƒƒ\}}||iƒ|i ƒ|i ƒgjo||iƒ|i ƒgjot Snt SdS(N(sosspathssplitextsxsx_rootsx_extsyslowersy_rootsy_extsuppers capitalizesTruesFalse(sxsysx_rootsy_extsy_rootsx_ext((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pysequal…s GN(sequalsrulesselfs _used_rulessFalses isinstances basestringsnamesappendsTruesOneOfs possibilitiessposssmatch_filename(sselfsnamesrulesequalsposs((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pysmatch_filename‚s   (s__name__s __module__s _used_ruless_compute_from_ruless get_scores get_not_usedsmatch_filename(((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pys FilesIndexXs   sIndexUrlDownloadcBs&tZdZdZd„Zd„ZRS(s9Give points for successful downloading of a package. icCs>|o#d||f|_|i|_n d|_|iSdS(Ns!downloaded package %s from URL %si(sdownloaded_from_urlspackagesurlsselfsdetailss max_valuesvalue(sselfsdownloaded_from_urlspackagesurl((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pyscompute¥s  cCs |iSdS(N(s cheesecakesurl(sselfs cheesecake((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pysdecide_before_download®s(s__name__s __module__s__doc__s max_valuescomputesdecide_before_download(((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pysIndexUrlDownload s  s IndexUnpackcBstZdZdZd„ZRS(s?Give points for successful unpacking of a package archive. icCs=|od|_|i|_nd|_d|_|iSdS(Nspackage unpacked successfullyspackage couldn't be unpackedi(sunpackedsselfsdetailss max_valuesvalue(sselfsunpacked((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pyscompute¶s    (s__name__s __module__s__doc__s max_valuescompute(((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pys IndexUnpack±s sIndexUnpackDircBs&tZdZdZd„Zd„ZRS(sFCheck if package unpack directory resembles package archive name. icCsZd||_|o |id|7_d|_n|id7_|i|_|iSdS(Nsunpack directory is s instead of the expected is as expected(s unpack_dirsselfsdetailssoriginal_package_namesvalues max_value(sselfs unpack_dirsoriginal_package_name((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pyscomputeÅs   cCs|idjSdS(Nsegg(s cheesecakes package_type(sselfs cheesecake((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pysdecide_after_downloadÑs(s__name__s __module__s__doc__s max_valuescomputesdecide_after_download(((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pysIndexUnpackDirÀs  s IndexSetupPycBs;tZdZdZdZhdd 75%% and is worth 30p.idif0.5sD%.2f%% formatted docstrings found, which is > 50%% and is worth 20p.if0.25sD%.2f%% formatted docstrings found, which is > 25%% and is worth 10p.i sD%.2f%% formatted docstrings found, which is < 25%%, no points given.s4found %d/%d=%.2f%% objects with formatted docstrings(spercents object_cntsfloats docformat_cntsselfsvaluesadd_infosdetails(sselfs object_cnts docformat_cntspercent((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pyscomputeœs         (s__name__s __module__s__doc__s max_valuescompute(((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pysIndexFormattedDocstrings–s sIndexDocumentationcBstZdZeeegZRS(Ns DOCUMENTATION(s__name__s __module__snamesIndexRequiredFilessIndexDocstringssIndexFormattedDocstringss subindices(((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pysIndexDocumentationµssIndexUnitTestscBstZdZdZd„ZRS(sdCompute unittest index as percentage of methods/functions that are exercised in unit tests. i2c Cs3d} tƒ} xVt|dƒD]E} tii|| ƒ} t | |i iiƒ}| i|iƒ} qWxD||D]8}|| jo%| d7} |i iid|ƒqsqsWt|ƒt|ƒ}d}|djot| ƒt|ƒ}ntt||iƒƒ|_d| ||df|_|iSdS(Nistestis%s is unit testeds9found %d/%d=%.2f%% unit tested classes/methods/functions.id(s unittest_cntssetsfunctions_testedsget_files_of_types files_liststestfilesosspathsjoins package_dirsfullpaths CodeParsersselfs cheesecakeslogsdebugscodesunionsfunctions_calleds functionssclassessnameslensfunctions_classes_cntspercentsfloatsintsceils max_valuesvaluesdetails( sselfs files_lists functionssclassess package_dirscodesnamespercentsfunctions_classes_cntsfunctions_testeds unittest_cntsfullpathstestfile((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pyscomputeÈs&     (s__name__s __module__s__doc__s max_valuescompute(((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pysIndexUnitTestsÂs sIndexUnitTestedcBs&tZdZdZd„Zd„ZRS(sgCheck if the package has unit tests which can be easily found by any of known test frameworks. icCsët}|djo|idƒt}n|djo|idƒt}nt|dƒo|idƒt}nx6|D].}|i |ƒo|idƒt}Pq|q|W|o|i |_ d|_nd|_ d|_|i SdS( NisPackage includes doctest tests.s6Package has tests that inherit from unittest.TestCase.stestsOPackage has filenames which probably contain tests (in format test_* or *_test)sOSome classes have setUp/tearDown methods which are commonly used in unit tests.shas unit testssdoesn't have unit tests(sFalses unit_testedsdoctests_countsselfsadd_infosTruesunittests_countsget_files_of_types files_listsmethodssmethods_is_test_methods max_valuesvaluesdetails(sselfsdoctests_countsunittests_counts files_listsclassessmethodssmethods unit_tested((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pyscomputeës,              c Cs[ddddddddd d d d g }x&|D]}|i|ƒotSq1q1WtSdS( Nssetups setup_packages setup_modulessetUps setUpPackages setUpModulesteardownsteardown_packagesteardown_modulestearDownstearDownModulestearDownPackage(s nose_methodss test_methodsmethodsendswithsTruesFalse(sselfsmethods nose_methodss test_method((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pys_is_test_method s * (s__name__s __module__s__doc__s max_valuescomputes_is_test_method(((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pysIndexUnitTestedås  s IndexPyLintcBsStZdZdZdZddgZdied„eƒƒZd„Z d„Z RS( s/Compute pylint index of the whole package. spylinti2sW0403sW0406s cCsd|S(Ns--disable-msg=%s(sx(sx((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pysscCsytiiddƒ}d} td„t|dƒƒ} ti ƒ}ti i |ƒoti i|ƒ}nti|ƒd} d} d}x%t| | t|iƒƒD]} di| ƒ} |iiid| ƒtd || |ifd |ƒ\}}|oY|d jo!|iiid |ƒt ‚n|iiid ||fƒ|d7}q§|i!dƒd}t#i$d|ƒ}|o'| t&|i'dƒƒ7} | d7} q§q§Wti|ƒ| o't&| ƒt&| ƒ} d| |_(n|o d|_(n d|_(| djo d} nt)t*| d|i+ƒƒ|_,|i-d| t)| dƒ|i+|i,fƒ|i,SdS(NsPYLINTspylinticCs|idƒ S(Ns __init__.py(snamesendswith(sname((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pys)ssmoduleis sRunning pylint on files: %s.s%s %s --persistent=n %ss max_timeouts Time exceededsHpylint exceeded maximum execution time of %d seconds and was terminated.s&encountered an error (%d): *** %s *** is iýÿÿÿs (-?\d+\.\d+)/10spylint score was %.2f out of 10s,encountered an error during pylint executionsno files to check foundf10.0s:Score is %.2f/10, which is %d%% of maximum %d points = %d.i (.sossenvironsgetspylint_locationsmax_arguments_lengthsfiltersget_files_of_types files_lists files_to_lintsgetcwds original_cwdspathsisfiles package_dirsdirnameschdirs pylint_scorescounts error_countsgenerate_argumentsslensselfs pylint_argss filenamessjoins cheesecakeslogsdebugsrun_cmdspylint_max_execution_timesrcsoutputsOSErrorssplits score_linesressearchsssfloatsgroupsdetailssintsceils max_valuesvaluesadd_info(sselfs files_lists package_dirspylint_max_execution_times error_countspylint_locationsrcs score_linesss files_to_lints filenamess pylint_scorescountsmax_arguments_lengthsoutputs original_cwd((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pyscompute sP           -cCs2tdƒ o|iidƒtSn|i SdS(Nspylint --versions5pylint not properly installed, omitting pylint index.(scommand_successfuls cheesecakeslogsdebugsFalseslite(sselfs cheesecake((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pysdecide_before_downloadhs( s__name__s __module__s__doc__snames max_valuesdisabled_messagessjoinsmaps pylint_argsscomputesdecide_before_download(((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pys IndexPyLints   Hs IndexPEP8cBs8tZdZdZdZdZdZd„Zd„ZRS(s7Compute PEP8 index for the modules in the package. spep8i"iþÿÿÿiÿÿÿÿcCs0t|dƒ} t| ƒdjod|_d|_|iSngi}| D]}|t i i ||ƒƒqM~} dg| }ti|ƒx0| D](}t i i ||ƒ}ti|ƒq–Wtiƒ} tiƒ}t| ƒ}t|ƒ} |i|} |i| }| |}|i||_|i dƒ|i dƒx| D]}|i |ƒqGW|i d||ifƒ|i d| ƒ|i d ƒ|i dƒx|D]}|i |ƒqªW|i d | |ifƒ|i d |ƒ|i d |it"|ƒ|ifƒd || f|_|iSdS(Nsmoduleisno modules founds-qqsErrors:sCount Detailss=pep8.py found %d error types; we're scoring %d per error typesError score: %ds Warnings:sApep8.py found %d warning types; we're scoring %d per warning typesWarning score: %dsTotal pep8 score: %d - %d = %ds/pep8.py check: %d error types, %d warning types(#sget_files_of_types files_listsfiles_to_scoreslensselfsvaluesdetailssappends_[1]sfilesosspathsjoins package_dirs full_pathssarglistspep8sprocess_optionssfullpaths input_filesget_error_statisticss error_statssget_warning_statisticss warning_statsserrorsswarningss error_scorestotal_error_scores warning_scorestotal_warning_scoresscores max_valuesadd_infosstatsabs(sselfs files_lists package_dirsfilesarglistserrorssscores warning_statssstatswarningss error_statss full_pathssfiles_to_scorestotal_error_scores_[1]sfullpathstotal_warning_score((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pyscomputesJ   6             &cCs |iSdS(N(s cheesecakes with_pep8(sselfs cheesecake((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pysdecide_before_download·s( s__name__s __module__s__doc__snames max_values error_scores warning_scorescomputesdecide_before_download(((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pys IndexPEP8ps  *sIndexCodeKwaliteecBstZdZeeegZRS(Ns CODE KWALITEE(s__name__s __module__snamesIndexUnitTesteds IndexPyLints IndexPEP8s subindices(((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pysIndexCodeKwaliteeºssCheesecakeErrorcBstZdZRS(s;Custom exception class for Cheesecake-specific errors. (s__name__s __module__s__doc__(((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pysCheesecakeErrorÈs sCheesecakeIndexcBstZdZeeegZRS(Ns Cheesecake(s__name__s __module__snamesIndexInstallabilitysIndexDocumentationsIndexCodeKwalitees subindices(((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pysCheesecakeIndexÎssStepcBs tZdZd„Zd„ZRS(s5Single step during computation of package score. cCs ||_dS(N(sprovidessself(sselfsprovides((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pys__init__ÚscCs7x,|iD]!}||iijotSq q WtSdS(sÉDecide if step should be run. It checks if there's at least one index from current profile that need variables provided by this step. Override this method for other behaviour. N(sselfsprovidessprovides cheesecakesindexs requirementssTruesFalse(sselfs cheesecakesprovide((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pysdecideÝs   (s__name__s __module__s__doc__s__init__sdecide(((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pysStep×s  sStepByVariablecBs tZdZd„Zd„ZRS(sLStep which is always run if given Cheesecake instance variable is true. cCs||_ti||ƒdS(N(s variable_namesselfsSteps__init__sprovides(sselfs variable_namesprovides((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pys__init__ës cCs2t||itƒotSnti||ƒSdS(N(sgetattrs cheesecakesselfs variable_namesNonesTruesStepsdecide(sselfs cheesecake((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pysdecideïs(s__name__s __module__s__doc__s__init__sdecide(((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pysStepByVariableès  s Cheesecakec Bs…tZdZhZhde<de<de<ded |i}|d di |i%i&ƒƒ7}|i|ƒn| \|_)|_*|iid |i)ƒ|iid |i*ƒ|ii+|ƒ|i#dƒ|i#dƒ|i#dƒdS(s_Initialize critical variables, download and unpack package, walk package tree. s1No package name, URL or path specified... exitingsprefixs cheesecakessProfile requirements: %s.s, sget_pkg_from_pypis download_pkgscopy_pkgs1Could not determine package type for package '%s's Currently recognized types: sPackage name: sPackage type: s unpack_pkgswalk_pkgs install_pkgN(,snamesselfsurlspaths package_pathspackagesget_package_name_from_urlsget_package_name_from_pathsraise_exceptionssandboxstempfilesmkdtempsossisdirsmkdirsverbosesquiets static_onlysliteskeep_logs with_pep8spylint_max_execution_timessandbox_pkg_filessandbox_pkg_dirssandbox_install_dirsconfigure_loggingslogfilesCheesecakeIndexsindexsdecide_before_downloadslogsdebugsjoinssorteds requirementssrun_stepsget_package_name_and_types package_typesskeyss name_and_typesmsgs package_names package_typesdecide_after_download(sselfskeep_logsliteslogfilesnamespathspylint_max_execution_timesquietssandboxs static_onlysurlsverboses with_pep8s name_and_typesmsg((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pys__init__sV                   )       cCs5|idtƒ|d|i7}td|ƒ‚dS(s’Cleanup, print error message and raise CheesecakeError. Don't use logging, since it can be called before logging has been setup. sremove_log_files' Detailed info available in log file %ssError: N(sselfscleanupsFalsesmsgslogfilesCheesecakeError(sselfsmsg((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pysraise_exception`scs°tiiˆiƒo(ˆidˆiƒtiˆiƒn‡d†}|ˆiƒ|oˆi oCtii ˆiˆi ƒ}tii|ƒoti|ƒq¬ndS(sDelete temporary directories and files that were created in the sandbox. At the end delete the sandbox itself. sRemoving file %scs9tii|ƒo"ˆid|ƒti|ƒndS(s6Delete directory recursively and generate log message.sRemoving directory %sN(sosspathsisdirsdirnamesselfslogsshutilsrmtree(sdirname(sself(s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pys delete_dirssN(sosspathsisfilesselfssandbox_pkg_fileslogsunlinks delete_dirssandboxsremove_log_fileskeep_logsjoinslogfileslog_pathsexists(sselfsremove_log_fileslog_paths delete_dir((sselfs9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pyscleanupks  cCsî|o ||_n&tiitiƒ|idƒ|_ti dt t |iƒdddƒƒti dti ƒti dt ƒtidƒ|_tidƒ|i_tidƒ|i_tid ƒ|i_tid ƒ|i_d S( s×Default settings for logging. If verbose, log goes to console, else it goes to logfile. log.debug and log.info goes to logfile. log.warn and log.error go to both logfile and stdout. s.logslogfilesws bufferingisconsolesnullscheesecake logfilescheesecake consoleN(slogfilesselfsosspathsjoinstempfiles gettempdirspackagesloggers setconsumersopensstrsSTDOUTsNonesMultipleProducerslogsinfosdebugswarnserror(sselfslogfile((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pysconfigure_logging€s %(cCs;|i|}|i|ƒot||ƒ}|ƒndS(s6Run step if its decide() method returns True. N(sselfsstepss step_namesstepsdecidesgetattrs step_method(sselfs step_namessteps step_method((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pysrun_step–s  snames download_urlsdistance_from_pypisfound_on_cheeseshops found_locallyssandbox_pkg_filesget_pkg_from_pypic s&ˆiidˆiƒy8dkl‰dkl‰dkl}dk l ‰Wn<t j o0}d}|d7}|d7}ˆi|ƒnXt‡d †}‡‡‡‡d †} |i|iƒ}ti}tƒt_x†d d fd dfddfgD]c\}} d| }| |ƒ\}}|o|oˆii|dƒPnˆii|dƒqûWtiiƒ}|t_|i|ƒ| o2|||ƒˆidt|ƒiƒdƒn|tjo"||ƒˆidˆiƒndˆ_ dˆ_!t"ˆ_#t"ˆ_$x“|iƒD]…} t&i'd| ƒ}|o6|i)dƒ}d|joˆi!d7_!q!q!nt&i'd| ƒ}|o|i)dƒˆ_ Pq!q!W|ˆ_+t,|ƒˆ_-ˆiidˆi-ˆi fƒt.i/i0ˆi+ƒo t1ˆ_$ndˆi jo t1ˆ_#ndS(sÆDownload package using setuptools utilities. New attributes: download_url : str URL that package was downloaded from. distance_from_pypi : int How many hops setuptools had to make to download package. found_on_cheeseshop : bool Whenever package has been found on CheeseShop. found_locally : bool Whenever package has been already installed. sBTrying to download package %s from PyPI using setuptools utilities(s PackageIndex(s Requirement(slog(sDistutilsErrorsNsetuptools is not installed and is required for downloading a package by name sRYou can download and process a package by its full URL via the -u or --url option s`Example: python cheesecake.py --url=http://www.mems-exchange.org/software/durus/Durus-3.1.tar.gzcs^ˆiidƒtˆii|iƒƒ|oˆiit|ƒƒnˆiidƒdS(s0Drop all setuptools output as INFO. s*** Begin setuptools outputs*** End setuptools outputN(sselfslogsinfosmapsstdouts splitlinesserrorsstr(sstdoutserror(sself(s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pysdrop_setuptools_info¾s cs§d|joˆdgƒ}n ˆƒ}|djo t}nt}y;|iˆiˆi ƒˆi dtd|ƒ}t|fSWnˆj o}t|fSnXdS(s»Fetch package from PyPI. Mode can be one of: * 'pypi_source': get source package from PyPI * 'pypi_any': get source/egg package from PyPI * 'any': get package from PyPI or local filesystem Returns tuple (status, output), where `status` is True if fetch was successful and False if it failed. `output` is PackageIndex.fetch() return value. spypis search_paths pypi_sources force_scanssourceN(smodes PackageIndexspkgindexsTruessourcesFalsesfetchs RequirementsparsesselfsnamessandboxsoutputsDistutilsErrorse(smodespkgindexssourcesoutputse(s Requirements PackageIndexsDistutilsErrorsself(s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pys fetch_packageÇs      s pypi_sourcessource package on PyPIspypi_anys egg on PyPIsanyslocally installed packagesLooking for %s... sfound!sfailed.s!setuptools returned an error: %s is Could not find distribution for ssReading http(.*)ispython.org/pypisDownloading (.*)sDownloaded package %s from %sscheeseshop.python.orgN(2sselfslogsinfosnamessetuptools.package_indexs PackageIndexs pkg_resourcess Requirements distutilssdistutils.errorssDistutilsErrors ImportErrorsesmsgsraise_exceptionsNonesdrop_setuptools_infos fetch_packages set_thresholdsINFOs old_thresholdssyssstdouts old_stdoutsStdoutRedirectorsmodesstatussoutputs read_bufferscaptured_stdoutsstrs splitliness download_urlsdistance_from_pypisFalsesfound_on_cheeseshops found_locallyslinesressearchsssgroups inspected_urlssandbox_pkg_filesget_package_name_from_pathspackagesosspathsisdirsTrue(sselfslogsdrop_setuptools_infos old_thresholdsmsgsstatuss PackageIndexs old_stdouts inspected_urls fetch_packageslinesDistutilsErrorsinfos Requirementsescaptured_stdoutsssmodesoutput((sselfs PackageIndexs RequirementsDistutilsErrors9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pysget_pkg_from_pypi¤sr       !  "     %            surlsdownloaded_from_urls download_pkgcCstii|i|iƒ|_yt|i|iƒ\}}WnHt j o<}|i id|i|ifƒ|it|ƒƒnX|iƒdgjoWt|ƒ}tiddi|iƒƒƒo|iƒ|idƒn|iƒnt|_dS(sOUse ``urllib.urlretrieve`` to download package to file in sandbox dir. s(Error downloading package %s from URL %ss text/htmls 404 Not FoundssFGot '404 Not Found' error while trying to download package ... exitingN(sosspathsjoinsselfssandboxspackagessandbox_pkg_files urlretrievesurlsdownloaded_filenamesheaderssIOErrorseslogserrorsraise_exceptionsstrsgettypesopensfsressearchs readlinessclosesTruesdownloaded_from_url(sselfsesfsheaderssdownloaded_filename((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pys download_pkg&s  " s package_pathscopy_pkgcCs„tii|i|iƒ|_tii|iƒ o|i d|iƒn|i d|i|ifƒt i |i|iƒdS(s0Copy package file to sandbox directory. s"%s is not a valid file ... exitingsCopying file %s to %sN( sosspathsjoinsselfssandboxspackagessandbox_pkg_filesisfiles package_pathsraise_exceptionslogsshutilscopyfile(sself((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pyscopy_pkg=s soriginal_package_namessandbox_pkg_dirsunpackeds unpack_dirs unpack_pkgcCsÔtii|i|iƒ|_tii|iƒoti |iƒn|i |i }||i |iƒ|_|itjo|id|i ƒnt|_|i|ijo|i|_|i|_ndS(shUnpack the package in the sandbox directory. Check `package_types` attribute for list of currently supported archive types. New attributes: original_package_name : str Package name guessed from the package name. Will be set only if package name is different than unpacked directory name. s'Could not unpack package %s ... exitingN(sosspathsjoinsselfssandboxs package_namessandbox_pkg_dirsisdirsshutilsrmtrees package_typess package_typesunpackssandbox_pkg_files unpack_dirsNonesraise_exceptionsTruesunpackedsoriginal_package_name(sselfsunpack((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pys unpack_pkgJs   s dirs_lists docstring_cnts docformat_cntsdoctests_countsunittests_counts files_lists functionssclassessmethodss object_cnts package_dirswalk_pkgcCsÃtii|i|iƒ|_t|iƒ\|_|_ d|_ d|_ d|_ d|_ g|_g|_g|_d|_xÝt|idƒD]É}tii|i|ƒ}t||iiƒ}|i |iƒ7_ |i |iƒ7_ |i |i7_ |i|i7_|i|i7_|i|i7_|i |i 7_ |i|i7_q”W|iidt|iƒdi|iƒfƒ|iidt|i ƒdi|i ƒfƒdS(sGet package files and directories. New attributes: dirs_list : list List of directories package contains. docstring_cnt : int Number of docstrings found in all package objects. docformat_cnt : int Number of formatted docstrings found in all package objects. doctests_count : int Number of docstrings that include doctests. unittests_count : int Number of classes which inherit from unittest.TestCase. files_list : list List of files package contains. functions : list List of all functions defined in package sources. classes : list List of all classes defined in package sources. methods : list List of all methods defined in package sources. object_cnt : int Number of documentable objects found in all package modules. package_dir : str Path to project directory. ismodulesFound %d files: %s.s, sFound %d directories: %s.N(sosspathsjoinsselfssandboxs package_names package_dirsget_files_dirs_lists files_lists dirs_lists object_cnts docstring_cnts docformat_cntsdoctests_counts functionssclassessmethodssunittests_countsget_files_of_typespy_filespyfiles CodeParserslogsdebugscodes object_countsdocstring_countsformatted_docstrings_countslen(sselfspyfilescodespy_file((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pyswalk_pkgrs2        /s installeds install_pkgcCs™tii|id|iƒ|_|idjo|td|iƒtd|iƒhddhd|i<<dti dƒ<}t d |i|i f|ƒ\}}n|tii|i|iƒ}tii|ƒ o |i}ntiƒ}ti|ƒt d |iƒ\}}ti|ƒ|oH|id ƒx't|ƒiƒD]}|i|ƒqPW|id ƒn|id |iƒt|_dS(sÁVerify that package can be installed in alternate directory. New attributes: installed : bool Describes whenever package has been succefully installed. stmp_install_%sseggs%s/lib/python2.3/site-packages/s%s/lib/python2.4/site-packages/s PYTHONPATHsQ%(sandbox)s/lib/python2.3/site-packages/:%(sandbox)s/lib/python2.4/site-packages/ssandboxsPATHs%easy_install --no-deps --prefix %s %ss!python setup.py install --root=%ss)*** Installation failed. Captured output:s*** End of captured output.s Installation into %s successful.N(sosspathsjoinsselfssandboxs package_namessandbox_install_dirs package_typesmkdirssgetenvs environmentsrun_cmdssandbox_pkg_filesrcsoutputs package_dirsisdirsgetcwdscwdschdirslogsstrs splitliness output_linesTrues installed(sselfs output_lines environmentsrcsoutputscwds package_dir((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pys install_pkg°s."1     cCs·|ii|ƒ}|ii}|d|}|iid|ƒ|iid|i ƒ|i od|||fGHn9Ht dƒGHt d|ƒGHdt d|ƒ|||fGH|Sd S( s`Compute overall Cheesecake index for the package by adding up specific indexes. idsAA given package can currently reach a MAXIMUM number of %d pointss9Starting computation of Cheesecake index for package '%s'sCheesecake index: %d (%d / %d)s=s#OVERALL CHEESECAKE INDEX (ABSOLUTE)s.%s (%d out of a maximum of %d points is %d%%)s#OVERALL CHEESECAKE INDEX (RELATIVE)N( sselfsindexs compute_withscheesecake_indexs max_valuesmax_cheesecake_indexs percentageslogsinfospackagesquietspad_linespad_msg(sselfscheesecake_indexsmax_cheesecake_indexs percentage((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pyscompute_cheesecake_indexÝs   (s__name__s __module__s__doc__sstepss untar_packages unzip_packages unegg_packages package_typessFalsesNones__init__sraise_exceptionsTruescleanupsconfigure_loggingsrun_stepsStepByVariablesget_pkg_from_pypis download_pkgscopy_pkgsSteps unpack_pkgswalk_pkgs install_pkgscompute_cheesecake_index(((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pys Cheesecakeös0 *-R       1 = -c Cs tƒ}|iddddddddƒ|id d dd dddd ƒ|id dddddddƒ|idddddddtddƒ|idddddddtddƒ|iddddddtddƒ|idddddd dtdd!ƒ|id"dddd#dtdd$ƒ|id%d&dd'dtdd(ƒ|id)d*dd+dtdd,tiƒƒ|id-dddd.dtdd/ƒ|id0dd1dd2dd3dd4ƒ|id5d6dddd7dtdd8ƒ|iƒ\}}|Sd9S(:s Parse command-line options. s-ns--namesdestsnamesdefaultsshelpsEpackage name (will be retrieved via setuptools utilities, if present)s-ps--pathspaths/path of tar.gz/zip package on local file systems-us--urlsurls package URLs-qs--quietsactions store_truesquiets1only print Cheesecake index value (default=False)s-vs --verbosesverbosesverbose output (default=False)s--liteslites.don't run time-consuming tests (default=False)s-ts--staticsstatics@don't run any code from the package being tested (default=False)s --with-pep8s with_pep8scheck pep8 conformances-ls --logfileslogfiles#file to log all cheesecake messagess-ss --sandboxssandboxsWdirectory where package will be unpacked (default is to use random directory inside %s)s --keep-logskeep_logs0don't remove log file even if run was successfuls--pylint-max-execution-timesstorespylint_max_execution_timeixsGmaximum time (in seconds) you allow pylint process to run (default=120)s-Vs --versionsversions"Output cheesecake version and exitN( s OptionParsersparsers add_optionsFalsesNonestempfiles gettempdirs parse_argssoptionssargs(sargssparsersoptions((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pysprocess_cmdline_argss@  cCsitƒ}|i}|i}|i}|i} |i}|i} |i}|i }|i } |i }|i }|i}t|iƒ}|o dttfGHtidƒn| o | o| odGHtidƒnyitd|d|d|d| d |d |d | d |d |d| d|d|ƒ } | iƒ| iƒWn tj o} t| ƒGHnXdS(sMDisplay Cheesecake index for package specified via command-line options. sCheesecake version %s (rev. %s)is:Error: No package name, URL or path specified (see --help)iskeep_logsliteslogfilesnamespathspylint_max_execution_timesquietssandboxs static_onlysurlsverboses with_pep8N(sprocess_cmdline_argssoptionsskeep_logsliteslogfilesnamespathsquietssandboxsstatics static_onlysurlsverbosesversions with_pep8sintspylint_max_execution_timesVERSIONs __revision__ssyssexits Cheesecakescscompute_cheesecake_indexscleanupsCheesecakeErrorsesstr(sverbosespylint_max_execution_times with_pep8skeep_logsversionslites static_onlyspathslogfilescsesnamesurlsquietssandboxsoptions((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pysmain0sL                s__main__(^s__doc__sossresshutilssysstempfilesoptparses OptionParsersurllibs urlretrievesurlparsesmathsceilsloggersutils pad_with_dotsspad_left_spacesspad_right_spacesspad_msgspad_linesrun_cmdscommand_successfuls unzip_packages untar_packages unegg_packagesmkdirssStdoutRedirectors time_functions codeparsers CodeParsers__init__s __version__sVERSIONspep8s __docformat__sstrips __revision__sdirs __builtins__ssortedssetssSetssets isiterables has_extensionsdiscover_file_typesget_files_of_typesget_package_name_from_pathsget_package_name_from_urlsget_package_name_and_typesget_method_argumentssget_attributesscamel2underscoresindex_class_to_namesis_emptysstrip_dir_partsget_files_dirs_listslengthsgenerate_argumentsstypes NameSettersmake_indices_dictsobjectsIndexsOneOfsWithOptionalExtsDocs FilesIndexsIndexUrlDownloads IndexUnpacksIndexUnpackDirs IndexSetupPys IndexInstallsIndexPyPIDownloadsIndexGeneratedFilessIndexInstallabilitysIndexRequiredFilessIndexDocstringssIndexFormattedDocstringssIndexDocumentationsIndexUnitTestssIndexUnitTesteds IndexPyLints IndexPEP8sIndexCodeKwalitees ExceptionsCheesecakeErrorsCheesecakeIndexsStepsStepByVariables Cheesecakesprocess_cmdline_argssmains__name__(MsIndexsOneOfssets CheesecakesIndexFormattedDocstringssget_package_name_and_types IndexPyLintspad_msgsget_package_name_from_urlsIndexDocumentationsmake_indices_dictspad_linescommand_successfulsshutils __docformat__sIndexGeneratedFilesscamel2underscorespad_right_spacess __revision__s IndexUnpacks has_extensionstempfiles FilesIndexs untar_packagesprocess_cmdline_argssrun_cmds CodeParsersresStepsIndexUrlDownloadsIndexUnpackDirs NameSettersDocsstrip_dir_partsloggersmainsget_method_argumentss OptionParsersIndexPyPIDownloadsStepByVariables pad_with_dotss IndexInstallsdiscover_file_typesIndexInstallabilitys isiterablespad_left_spacessceilssyss unzip_packagesVERSIONs unegg_packagesmkdirssgenerate_argumentssIndexDocstringss IndexPEP8ssortedsCheesecakeIndexsWithOptionalExtsIndexUnitTestedsCheesecakeErrorsIndexRequiredFilessIndexCodeKwaliteesStdoutRedirectorsget_package_name_from_pathsis_emptys IndexSetupPysget_files_of_typesurlparsespep8slengthsindex_class_to_namesget_attributessget_files_dirs_lists urlretrievesIndexUnitTestssoss time_function((s9build/bdist.linux-i686/egg/cheesecake/cheesecake_index.pys? s˜          %         <       3 ¶  H&8 #/\J ÿÿ . , PKçI6^zsãü€ü€cheesecake/subprocess.pyc;ò ËËEc@s¢dZdkZeidjZdkZdkZdkZeoCdkZdkZdk Tdfd„ƒYZ dfd„ƒYZ n%dk Z dk Z dkZdkZdd d d d gZyeid ƒZWn dZnXyeWnej odZdZnXgZd„ZdZdZd„Zd„Zd efd„ƒYZdefd„ƒYZd„Z d„Z!e"djoeo e!ƒqže ƒndS(sH)subprocess - Subprocesses with accessible I/O streams This module allows you to spawn processes, connect to their input/output/error pipes, and obtain their return codes. This module intends to replace several other, older modules and functions, like: os.system os.spawn* os.popen* popen2.* commands.* Information about how the subprocess module can be used to replace these modules and functions can be found below. Using the subprocess module =========================== This module defines one class called Popen: class Popen(args, bufsize=0, executable=None, stdin=None, stdout=None, stderr=None, preexec_fn=None, close_fds=False, shell=False, cwd=None, env=None, universal_newlines=False, startupinfo=None, creationflags=0): Arguments are: args should be a string, or a sequence of program arguments. The program to execute is normally the first item in the args sequence or string, but can be explicitly set by using the executable argument. On UNIX, with shell=False (default): In this case, the Popen class uses os.execvp() to execute the child program. args should normally be a sequence. A string will be treated as a sequence with the string as the only item (the program to execute). On UNIX, with shell=True: If args is a string, it specifies the command string to execute through the shell. If args is a sequence, the first item specifies the command string, and any additional items will be treated as additional shell arguments. On Windows: the Popen class uses CreateProcess() to execute the child program, which operates on strings. If args is a sequence, it will be converted to a string using the list2cmdline method. Please note that not all MS Windows applications interpret the command line the same way: The list2cmdline is designed for applications using the same rules as the MS C runtime. bufsize, if given, has the same meaning as the corresponding argument to the built-in open() function: 0 means unbuffered, 1 means line buffered, any other positive value means use a buffer of (approximately) that size. A negative bufsize means to use the system default, which usually means fully buffered. The default value for bufsize is 0 (unbuffered). stdin, stdout and stderr specify the executed programs' standard input, standard output and standard error file handles, respectively. Valid values are PIPE, an existing file descriptor (a positive integer), an existing file object, and None. PIPE indicates that a new pipe to the child should be created. With None, no redirection will occur; the child's file handles will be inherited from the parent. Additionally, stderr can be STDOUT, which indicates that the stderr data from the applications should be captured into the same file handle as for stdout. If preexec_fn is set to a callable object, this object will be called in the child process just before the child is executed. If close_fds is true, all file descriptors except 0, 1 and 2 will be closed before the child process is executed. if shell is true, the specified command will be executed through the shell. If cwd is not None, the current directory will be changed to cwd before the child is executed. If env is not None, it defines the environment variables for the new process. If universal_newlines is true, the file objects stdout and stderr are opened as a text files, but lines may be terminated by any of '\n', the Unix end-of-line convention, '\r', the Macintosh convention or '\r\n', the Windows convention. All of these external representations are seen as '\n' by the Python program. Note: This feature is only available if Python is built with universal newline support (the default). Also, the newlines attribute of the file objects stdout, stdin and stderr are not updated by the communicate() method. The startupinfo and creationflags, if given, will be passed to the underlying CreateProcess() function. They can specify things such as appearance of the main window and priority for the new process. (Windows only) This module also defines two shortcut functions: call(*args, **kwargs): Run command with arguments. Wait for command to complete, then return the returncode attribute. The arguments are the same as for the Popen constructor. Example: retcode = call(["ls", "-l"]) Exceptions ---------- Exceptions raised in the child process, before the new program has started to execute, will be re-raised in the parent. Additionally, the exception object will have one extra attribute called 'child_traceback', which is a string containing traceback information from the childs point of view. The most common exception raised is OSError. This occurs, for example, when trying to execute a non-existent file. Applications should prepare for OSErrors. A ValueError will be raised if Popen is called with invalid arguments. Security -------- Unlike some other popen functions, this implementation will never call /bin/sh implicitly. This means that all characters, including shell metacharacters, can safely be passed to child processes. Popen objects ============= Instances of the Popen class have the following methods: poll() Check if child process has terminated. Returns returncode attribute. wait() Wait for child process to terminate. Returns returncode attribute. communicate(input=None) Interact with process: Send data to stdin. Read data from stdout and stderr, until end-of-file is reached. Wait for process to terminate. The optional stdin argument should be a string to be sent to the child process, or None, if no data should be sent to the child. communicate() returns a tuple (stdout, stderr). Note: The data read is buffered in memory, so do not use this method if the data size is large or unlimited. The following attributes are also available: stdin If the stdin argument is PIPE, this attribute is a file object that provides input to the child process. Otherwise, it is None. stdout If the stdout argument is PIPE, this attribute is a file object that provides output from the child process. Otherwise, it is None. stderr If the stderr argument is PIPE, this attribute is file object that provides error output from the child process. Otherwise, it is None. pid The process ID of the child process. returncode The child return code. A None value indicates that the process hasn't terminated yet. A negative value -N indicates that the child was terminated by signal N (UNIX only). Replacing older functions with the subprocess module ==================================================== In this section, "a ==> b" means that b can be used as a replacement for a. Note: All functions in this section fail (more or less) silently if the executed program cannot be found; this module raises an OSError exception. In the following examples, we assume that the subprocess module is imported with "from subprocess import *". Replacing /bin/sh shell backquote --------------------------------- output=`mycmd myarg` ==> output = Popen(["mycmd", "myarg"], stdout=PIPE).communicate()[0] Replacing shell pipe line ------------------------- output=`dmesg | grep hda` ==> p1 = Popen(["dmesg"], stdout=PIPE) p2 = Popen(["grep", "hda"], stdin=p1.stdout) output = p2.communicate()[0] Replacing os.system() --------------------- sts = os.system("mycmd" + " myarg") ==> p = Popen("mycmd" + " myarg", shell=True) sts = os.waitpid(p.pid, 0) Note: * Calling the program through the shell is usually not required. * It's easier to look at the returncode attribute than the exitstatus. A more real-world example would look like this: try: retcode = call("mycmd" + " myarg", shell=True) if retcode < 0: print >>sys.stderr, "Child was terminated by signal", -retcode else: print >>sys.stderr, "Child returned", retcode except OSError, e: print >>sys.stderr, "Execution failed:", e Replacing os.spawn* ------------------- P_NOWAIT example: pid = os.spawnlp(os.P_NOWAIT, "/bin/mycmd", "mycmd", "myarg") ==> pid = Popen(["/bin/mycmd", "myarg"]).pid P_WAIT example: retcode = os.spawnlp(os.P_WAIT, "/bin/mycmd", "mycmd", "myarg") ==> retcode = call(["/bin/mycmd", "myarg"]) Vector example: os.spawnvp(os.P_NOWAIT, path, args) ==> Popen([path] + args[1:]) Environment example: os.spawnlpe(os.P_NOWAIT, "/bin/mycmd", "mycmd", "myarg", env) ==> Popen(["/bin/mycmd", "myarg"], env={"PATH": "/usr/bin"}) Replacing os.popen* ------------------- pipe = os.popen(cmd, mode='r', bufsize) ==> pipe = Popen(cmd, shell=True, bufsize=bufsize, stdout=PIPE).stdout pipe = os.popen(cmd, mode='w', bufsize) ==> pipe = Popen(cmd, shell=True, bufsize=bufsize, stdin=PIPE).stdin (child_stdin, child_stdout) = os.popen2(cmd, mode, bufsize) ==> p = Popen(cmd, shell=True, bufsize=bufsize, stdin=PIPE, stdout=PIPE, close_fds=True) (child_stdin, child_stdout) = (p.stdin, p.stdout) (child_stdin, child_stdout, child_stderr) = os.popen3(cmd, mode, bufsize) ==> p = Popen(cmd, shell=True, bufsize=bufsize, stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=True) (child_stdin, child_stdout, child_stderr) = (p.stdin, p.stdout, p.stderr) (child_stdin, child_stdout_and_stderr) = os.popen4(cmd, mode, bufsize) ==> p = Popen(cmd, shell=True, bufsize=bufsize, stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True) (child_stdin, child_stdout_and_stderr) = (p.stdin, p.stdout) Replacing popen2.* ------------------ Note: If the cmd argument to popen2 functions is a string, the command is executed through /bin/sh. If it is a list, the command is directly executed. (child_stdout, child_stdin) = popen2.popen2("somestring", bufsize, mode) ==> p = Popen(["somestring"], shell=True, bufsize=bufsize stdin=PIPE, stdout=PIPE, close_fds=True) (child_stdout, child_stdin) = (p.stdout, p.stdin) (child_stdout, child_stdin) = popen2.popen2(["mycmd", "myarg"], bufsize, mode) ==> p = Popen(["mycmd", "myarg"], bufsize=bufsize, stdin=PIPE, stdout=PIPE, close_fds=True) (child_stdout, child_stdin) = (p.stdout, p.stdin) The popen2.Popen3 and popen3.Popen4 basically works as subprocess.Popen, except that: * subprocess.Popen raises an exception if the execution fails * the capturestderr argument is replaced with the stderr argument. * stdin=PIPE and stdout=PIPE must be specified. * popen2 closes all filedescriptors by default, but you have to specify close_fds=True with subprocess.Popen. Nswin32(s*s STARTUPINFOcBs tZdZeZeZeZRS(Ni(s__name__s __module__sdwFlagssNones hStdInputs hStdOutputs hStdError(((s3build/bdist.linux-i686/egg/cheesecake/subprocess.pys STARTUPINFOss pywintypescBstZeZRS(N(s__name__s __module__sIOErrorserror(((s3build/bdist.linux-i686/egg/cheesecake/subprocess.pys pywintypes„ssPopensPIPEsSTDOUTscalls ProcessErrors SC_OPEN_MAXiiicCs xtD]}|iƒqWdS(N(s_activesinstspoll(sinst((s3build/bdist.linux-i686/egg/cheesecake/subprocess.pys_cleanupœsiÿÿÿÿiþÿÿÿcOst||ŽiƒSdS(sÓRun command with arguments. Wait for command to complete, then return the returncode attribute. The arguments are the same as for the Popen constructor. Example: retcode = call(["ls", "-l"]) N(sPopensargsskwargsswait(sargsskwargs((s3build/bdist.linux-i686/egg/cheesecake/subprocess.pyscall¤scCsFg}t}x&|D]}g}|o|idƒnd|jp d|j}|o|idƒnx–|D]Ž}|djo|i|ƒqo|djo2|idt|ƒdƒg}|idƒqo|o|i |ƒg}n|i|ƒqoW|o|i |ƒn|o|idƒqqWdi |ƒSdS( s• Translate a sequence of arguments into a command line string, using the same rules as the MS C runtime: 1) Arguments are delimited by white space, which is either a space or a tab. 2) A string surrounded by double quotation marks is interpreted as a single argument, regardless of white space contained within. A quoted string can be embedded in an argument. 3) A double quotation mark preceded by a backslash is interpreted as a literal double quotation mark. 4) Backslashes are interpreted literally, unless they immediately precede a double quotation mark. 5) If backslashes immediately precede a double quotation mark, every pair of backslashes is interpreted as a literal backslash. If the number of backslashes is odd, the last backslash escapes the next double quotation mark as described in rule 3. s s s"s\is\"sN( sresultsFalses needquotesseqsargsbs_bufsappendscslensextendsjoin(sseqscs needquotesresultsargsbs_buf((s3build/bdist.linux-i686/egg/cheesecake/subprocess.pys list2cmdline¯s8    cBstZdZRS(sIThis exception is raised when there is an error calling a subprocess.(s__name__s __module__s__doc__(((s3build/bdist.linux-i686/egg/cheesecake/subprocess.pys ProcessErrorñs cBsâtZdeeeeeeeeeeedd„ Zd„ZeoOd„Zd„Zd„Z d„Z d„Z d „Z d „Z ed „ZnLd „Zd „Zd„Zd„Z d„Zd„Z d„Z ed„ZRS(NicCs×tƒto8|tj otdƒ‚n|otdƒ‚q€n;| tj otdƒ‚n|djotdƒ‚nt|_ t|_ t|_ t|_ t|_ | |_|i|||ƒ\}}}}}}|i||||| | | | || ||||||ƒ|oti|d|ƒ|_ n|o?| oti|d|ƒ|_ q€ti|d|ƒ|_ n|o?| oti|d|ƒ|_ qÆti|d|ƒ|_ nti |ƒd S( sCreate new Popen instance.s0preexec_fn is not supported on Windows platformss/close_fds is not supported on Windows platformss2startupinfo is only supported on Windows platformsis4creationflags is only supported on Windows platformsswbsrUsrbN(!s_cleanups mswindowss preexec_fnsNones ValueErrors close_fdss startupinfos creationflagssselfsstdinsstdoutsstderrspids returncodesuniversal_newliness _get_handlessp2creadsp2cwritesc2preadsc2pwriteserrreadserrwrites_execute_childsargss executablescwdsenvsshellsossfdopensbufsizes_activesappend(sselfsargssbufsizes executablesstdinsstdoutsstderrs preexec_fns close_fdssshellscwdsenvsuniversal_newliness startupinfos creationflagsserrreadsc2preadserrwritesc2pwritesp2creadsp2cwrite((s3build/bdist.linux-i686/egg/cheesecake/subprocess.pys__init__÷sF         '   cCs,|iddƒ}|iddƒ}|SdS(Ns s s (sdatasreplace(sselfsdata((s3build/bdist.linux-i686/egg/cheesecake/subprocess.pys_translate_newlines@sc Cs²|tjo|tjo |tjottttttfSnttf\}}ttf\} }ttf\}}|tjot t ƒ}nƒ|t jo7t tdƒ\}}|iƒ}ti|dƒ}n?t|ƒtijoti|ƒ}nti|iƒƒ}|i|ƒ}|tjot tƒ}nƒ|t jo7t tdƒ\} }| iƒ} ti| dƒ} n?t|ƒtijoti|ƒ}nti|iƒƒ}|i|ƒ}|tjot tƒ}nš|t jo7t tdƒ\}}|iƒ}ti|dƒ}nV|tjo |}n?t|ƒtijoti|ƒ}nti|iƒƒ}|i|ƒ}||| |||fSdS(s|Construct and return tupel with IO objects: p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite iN(sstdinsNonesstdoutsstderrsp2creadsp2cwritesc2preadsc2pwriteserrreadserrwrites GetStdHandlesSTD_INPUT_HANDLEsPIPEs CreatePipesDetachsmsvcrtsopen_osfhandlestypestypessIntTypes get_osfhandlesfilenosselfs_make_inheritablesSTD_OUTPUT_HANDLEsSTD_ERROR_HANDLEsSTDOUT( sselfsstdinsstdoutsstderrserrreadsp2creadsp2cwriteserrwritesc2pwritesc2pread((s3build/bdist.linux-i686/egg/cheesecake/subprocess.pys _get_handlesJsN'           cCs#ttƒ|tƒddtƒSdS(s2Return a duplicate of handle, which is inheritableiiN(sDuplicateHandlesGetCurrentProcessshandlesDUPLICATE_SAME_ACCESS(sselfshandle((s3build/bdist.linux-i686/egg/cheesecake/subprocess.pys_make_inheritable†s  cCstiitiitdƒƒdƒ}tii|ƒ oLtiitiitiƒdƒ}tii|ƒ ot dƒ‚q‡n|SdS(s,Find and return absolut path to w9xpopen.exeis w9xpopen.exesZCannot locate w9xpopen.exe, which is needed for Popen to work with your shell or platform.N( sosspathsjoinsdirnamesGetModuleFileNamesw9xpopensexistsssyss exec_prefixs RuntimeError(sselfsw9xpopen((s3build/bdist.linux-i686/egg/cheesecake/subprocess.pys_find_w9xpopens  c Cs÷t|tiƒ ot|ƒ}ntƒ}|tjo |}nt| ||fj o.|i t O_ | |_||_||_n| o˜|i tO_ t|_tiiddƒ}|d|}tƒdjptii|ƒiƒdjo*|iƒ}d||f}| t!O} q(ny4t"||ttd| |||ƒ \}}}}Wn't*i+j o}t-|iŒ‚nX||_.||_(|i/ƒ| tjo| i/ƒn|tjo|i/ƒn|tjo|i/ƒndS( s$Execute program (MS Windows version)sCOMSPECscmd.exes /c ls command.coms"%s" %siN(0s isinstancesargsstypess StringTypess list2cmdlines STARTUPINFOsdefault_startupinfos startupinfosNonesp2creadsc2pwriteserrwritesdwFlagssSTARTF_USESTDHANDLESs hStdInputs hStdOutputs hStdErrorsshellsSTARTF_USESHOWWINDOWsSW_HIDEs wShowWindowsossenvironsgetscomspecs GetVersionspathsbasenameslowersselfs_find_w9xpopensw9xpopens creationflagssCREATE_NEW_CONSOLEs CreateProcesss executablesenvscwdshpshtspidstids pywintypesserrorses WindowsErrors_handlesClose(sselfsargss executables preexec_fns close_fdsscwdsenvsuniversal_newliness startupinfos creationflagssshellsp2creadsp2cwritesc2preadsc2pwriteserrreadserrwritespidscomspecstidsdefault_startupinfoshpshtsesw9xpopen((s3build/bdist.linux-i686/egg/cheesecake/subprocess.pys_execute_childsN       /        cCs[|itjo@t|idƒtjo#t|iƒ|_ti|ƒqPn|iSdS(sQCheck if child process has terminated. Returns returncode attribute.iN( sselfs returncodesNonesWaitForSingleObjects_handles WAIT_OBJECT_0sGetExitCodeProcesss_activesremove(sself((s3build/bdist.linux-i686/egg/cheesecake/subprocess.pyspollís cCsP|itjo5t|itƒ}t|iƒ|_ti |ƒn|iSdS(sOWait for child process to terminate. Returns returncode attribute.N( sselfs returncodesNonesWaitForSingleObjects_handlesINFINITEsobjsGetExitCodeProcesss_activesremove(sselfsobj((s3build/bdist.linux-i686/egg/cheesecake/subprocess.pyswait÷s cCs|i|iƒƒdS(N(sbuffersappendsfhsread(sselfsfhsbuffer((s3build/bdist.linux-i686/egg/cheesecake/subprocess.pys _readerthreadscCs¶t}t}|ioEg}tid|id|i|fƒ}|it ƒ|i ƒn|ioEg}tid|id|i|fƒ}|it ƒ|i ƒn|i o2|tjo|i i|ƒn|i iƒn|io|iƒn|io|iƒn|tjo|d}n|tjo|d}n|io ttdƒo8|o|i|ƒ}n|o|i|ƒ}qžn|iƒ||fSdS(szInteract with process: Send data to stdin. Read data from stdout and stderr, until end-of-file is reached. Wait for process to terminate. The optional input argument should be a string to be sent to the child process, or None, if no data should be sent to the child. communicate() returns a tuple (stdout, stderr).stargetsargsisnewlinesN(sNonesstdoutsstderrsselfs threadingsThreads _readerthreads stdout_threads setDaemonsTruesstarts stderr_threadsstdinsinputswritesclosesjoinsuniversal_newlinesshasattrsopens_translate_newlinesswait(sselfsinputsstdoutsstderrs stdout_threads stderr_thread((s3build/bdist.linux-i686/egg/cheesecake/subprocess.pys communicatesD           c Cs‡ttf\}}ttf\} }ttf\}}|tjonP|tjot i ƒ\}}n-t |ƒt i jo |}n |iƒ}|tjonP|tjot i ƒ\} }n-t |ƒt i jo |}n |iƒ}|tjong|tjot i ƒ\}}nD|tjo |}n-t |ƒt i jo |}n |iƒ}||| |||fSdS(s|Construct and return tupel with IO objects: p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite N(sNonesp2creadsp2cwritesc2preadsc2pwriteserrreadserrwritesstdinsPIPEsosspipestypestypessIntTypesfilenosstdoutsstderrsSTDOUT( sselfsstdinsstdoutsstderrserrreadsp2creadsp2cwriteserrwritesc2pwritesc2pread((s3build/bdist.linux-i686/egg/cheesecake/subprocess.pys _get_handles>s8              cCs\y ti}Wntj o d}nXti|tiƒ}ti|ti||BƒdS(Ni(sfcntls FD_CLOEXECs cloexec_flagsAttributeErrorsfdsF_GETFDsoldsF_SETFD(sselfsfdsolds cloexec_flag((s3build/bdist.linux-i686/egg/cheesecake/subprocess.pys_set_cloexec_flagks   cCsMxFtdtƒD]5}||joqnyti|ƒWqqXqWdS(Ni(srangesMAXFDsisbutsossclose(sselfsbutsi((s3build/bdist.linux-i686/egg/cheesecake/subprocess.pys _close_fdsus cCsQt|tiƒo |g}n| oddg|}n|tjo|d}ntiƒ\}}|i |ƒti ƒ|_|idjoy—| oti| ƒn| oti| ƒn|oti|ƒnti|ƒ| oti| dƒn|oti|dƒn|oti|dƒn| oti| ƒn|o || fjoti|ƒn|o|| |fjoti|ƒn|o|id|ƒn|tjoti|ƒn|ot|ƒn|tjoti||ƒnti|||ƒWn\t i!ƒ\}}}t%i&|||ƒ}di(|ƒ|_)ti*|t+i,|ƒƒnXti-dƒnti|ƒ| o| oti| ƒn|o| oti|ƒn|o|oti|ƒnti.|d ƒ}ti|ƒ|djot+i0|ƒ}t2|‚nd S( sExecute program (POSIX version)s/bin/shs-ciiisbutsiÿiN(3s isinstancesargsstypess StringTypessshells executablesNonesosspipes errpipe_reads errpipe_writesselfs_set_cloexec_flagsforkspidsp2cwritesclosesc2preadserrreadsp2creadsdup2sc2pwriteserrwrites close_fdss _close_fdsscwdschdirs preexec_fnsapplysenvsexecvpsexecvpessyssexc_infosexc_types exc_valuestbs tracebacksformat_exceptions exc_linessjoinschild_tracebackswritespicklesdumpss_exitsreadsdatasloadsschild_exceptions ProcessError(sselfsargss executables preexec_fns close_fdsscwdsenvsuniversal_newliness startupinfos creationflagssshellsp2creadsp2cwritesc2preadsc2pwriteserrreadserrwrites exc_linesschild_exceptions errpipe_writesexc_typestbsdatas errpipe_reads exc_value((s3build/bdist.linux-i686/egg/cheesecake/subprocess.pys_execute_childsx           cCsjti|ƒoti|ƒ |_n3ti|ƒoti|ƒ|_n tdƒ‚t i |ƒdS(NsUnknown child exit status!( soss WIFSIGNALEDsstssWTERMSIGsselfs returncodes WIFEXITEDs WEXITSTATUSs RuntimeErrors_activesremove(sselfssts((s3build/bdist.linux-i686/egg/cheesecake/subprocess.pys_handle_exitstatusás  cCs{|itjo`yCti|itiƒ\}}||ijo|i|ƒnWqpti j oqpXn|iSdS(sQCheck if child process has terminated. Returns returncode attribute.N( sselfs returncodesNonesosswaitpidspidsWNOHANGsstss_handle_exitstatusserror(sselfspidssts((s3build/bdist.linux-i686/egg/cheesecake/subprocess.pyspollís cCsG|itjo,ti|idƒ\}}|i|ƒn|iSdS(sOWait for child process to terminate. Returns returncode attribute.iN(sselfs returncodesNonesosswaitpidspidsstss_handle_exitstatus(sselfspidssts((s3build/bdist.linux-i686/egg/cheesecake/subprocess.pyswaitús c Cs»g}g}t}t} |io9|iiƒ|o|i |iƒq[|ii ƒn|io|i |iƒg}n|io|i |iƒg} nxk|p|o\t i ||gƒ\}} }|i| joVti|iiƒ|d ƒ}||}| o!|ii ƒ|i|iƒq8n|i|joZti|iiƒdƒ}|djo!|ii ƒ|i|iƒn|i |ƒn|i|joZti|iiƒdƒ}|djo!|ii ƒ|i|iƒn| i |ƒq¦q¦W|tjodi|ƒ}n| tjodi| ƒ} n|io ttdƒo8|o|i|ƒ}n| o|i| ƒ} q£n|iƒ|| fSdS(szInteract with process: Send data to stdin. Read data from stdout and stderr, until end-of-file is reached. Wait for process to terminate. The optional input argument should be a string to be sent to the child process, or None, if no data should be sent to the child. communicate() returns a tuple (stdout, stderr).iissnewlinesN(sread_sets write_setsNonesstdoutsstderrsselfsstdinsflushsinputsappendsclosesselectsrlistswlistsxlistsosswritesfilenos bytes_writtensremovesreadsdatasjoinsuniversal_newlinesshasattrsopens_translate_newlinesswait( sselfsinputsrlistsxlistsstdouts write_setsdatas bytes_writtensread_setsstderrswlist((s3build/bdist.linux-i686/egg/cheesecake/subprocess.pys communicates`               (s__name__s __module__sNonesFalses__init__s_translate_newliness mswindowss _get_handless_make_inheritables_find_w9xpopens_execute_childspollswaits _readerthreads communicates_set_cloexec_flags _close_fdss_handle_exitstatus(((s3build/bdist.linux-i686/egg/cheesecake/subprocess.pysPopenös&0I  <   P 9 - b cCs.tdgdtƒiƒd}dGH|GHtiƒdjo&tdgdd„ƒ}|iƒndGHtd gdtƒ}td d gd |i dtƒ}t |iƒdƒGHHd GHytdgƒiƒGHWnJt j o>}|itijodGHdGH|iGHq*dG|iGHnXtidIJdS(Nspssstdoutis Process list:sids preexec_fncCs tidƒS(Nid(sosssetuid(((s3build/bdist.linux-i686/egg/cheesecake/subprocess.pysZssLooking for 'hda'...sdmesgsgrepshdasstdinsTrying a weird file...s/this/path/does/not/exists'The file didn't exist. I thought so...sChild traceback:sErrorsGosh. No error.(sPopensPIPEs communicatesplistsossgetuidspswaitsp1sstdoutsp2sreprsOSErrorseserrnosENOENTschild_tracebackssyssstderr(sp2sp1sespsplist((s3build/bdist.linux-i686/egg/cheesecake/subprocess.pys _demo_posixNs*! cCsldGHtddtdtƒ}tdd|idtƒ}t|iƒdƒGHdGHtd ƒ}|i ƒdS( Ns%Looking for 'PROMPT' in set output...ssetsstdoutsshells find "PROMPT"sstdinisExecuting calc...scalc( sPopensPIPEsTruesp1sstdoutsp2sreprs communicatespswait(sp2sp1sp((s3build/bdist.linux-i686/egg/cheesecake/subprocess.pys _demo_windowsws s__main__(#s__doc__ssyssplatforms mswindowssosstypess tracebacks threadingsmsvcrts _subprocesss STARTUPINFOs pywintypessselectserrnosfcntlspickles__all__ssysconfsMAXFDsFalses NameErrorsTrues_actives_cleanupsPIPEsSTDOUTscalls list2cmdlines Exceptions ProcessErrorsobjectsPopens _demo_posixs _demo_windowss__name__(sSTDOUTs mswindowssselectsPIPEs__all__serrnos _demo_posixsmsvcrts_cleanupscallsTruesfcntls STARTUPINFOsPopenssyss pywintypesstypess ProcessErrorsFalsesoss_actives tracebacks list2cmdlines threadings _demo_windowssMAXFDspickle((s3build/bdist.linux-i686/egg/cheesecake/subprocess.pys?esT               BÿÿZ )   PKçI65@uàÀ%À%cheesecake/util.pyc;ò ËËEc@sdZdkZdkZdkZdkZdkZdkZdkZdkl Z l Z l Z l Z l Z dZdZeed„Zd„Zdefd„ƒYZed „Zed „Zed „Zeed „Zd eedd„Zd„Zd„Zd„Zd„Zd„ZdS(s*Utility functions for Cheesecake project. N(scalls ProcessErrorsPopensPIPEsSTDOUTi(icCs|iƒ}tiƒ}y"t|d|dtd|ƒ}Wnt j o}d|fSnX|o}t i ƒ}xn|iƒtjoVt idƒt i ƒ||jo.ti|itiƒ|iƒddfSqrqrWn|iƒ|idƒ|i|iƒfSdS( s¬Run command and return its return code and its output. >>> run_cmd('/bin/true') (0, '') >>> run_cmd('/bin/cat', max_timeout=0.2) (1, 'Time exceeded') sstdoutsstderrsenvif0.10000000000000001s Time exceedediN(scmdssplitsarglistsosstmpfilesoutputsPopensSTDOUTsenvsps Exceptionses max_timeoutstimesstartspollsNonessleepskillspidssignalsSIGINTswaitsseeks returncodesread(scmdsenvs max_timeoutsespsoutputsarglistsstart((s-build/bdist.linux-i686/egg/cheesecake/util.pysrun_cmds&  "     cCs t|ƒ\}}|djSdS(s²Returns True if command exited normally, False otherwise. >>> command_successful('/bin/true') True >>> command_successful('this-command-doesnt-exist') False iN(srun_cmdscmdsrcsoutput(scmdsoutputsrc((s-build/bdist.linux-i686/egg/cheesecake/util.pyscommand_successful0ssStdoutRedirectorcBs5tZdZed„Zd„Zd„Zd„ZRS(s)Redirect stdout to a temporary file. cCs0|ot|dƒ|_ntiƒ|_dS(Nsw(sfilenamesopensselfsfhsosstmpfile(sselfsfilename((s-build/bdist.linux-i686/egg/cheesecake/util.pys__init__>scCs|ii|ƒdS(N(sselfsfhswritesbuf(sselfsbuf((s-build/bdist.linux-i686/egg/cheesecake/util.pyswriteDscCs|iiƒdS(N(sselfsfhsflush(sself((s-build/bdist.linux-i686/egg/cheesecake/util.pysflushGscCs!|iidƒ|iiƒSdS(s/Return contents of the temporary file. iN(sselfsfhsseeksread(sself((s-build/bdist.linux-i686/egg/cheesecake/util.pys read_bufferJs(s__name__s __module__s__doc__sNones__init__swritesflushs read_buffer(((s-build/bdist.linux-i686/egg/cheesecake/util.pysStdoutRedirector;s    cCs[t|ƒ}||jo|Sn|d}x%t|d|ƒD]}|d7}q?W|SdS(sµPad text with dots up to given length. >>> pad_with_dots("Hello world", 20) 'Hello world ........' >>> pad_with_dots("Exceeding length", 10) 'Exceeding length' s is.N(slensmsgs msg_lengthslengthsrangesi(smsgslengthsis msg_length((s-build/bdist.linux-i686/egg/cheesecake/util.pys pad_with_dotsPs   cCsAt|tƒ ot|ƒ}n|t|ƒ}d||SdS(sÈPad value with spaces at left up to given length. >>> pad_left_spaces(15, 4) ' 15' >>> pad_left_spaces(123456, 2) '123456' >>> len(pad_left_spaces("")) == PAD_VALUE True s N(s isinstancesvalues basestringsstrslengthslensdiff(svalueslengthsdiff((s-build/bdist.linux-i686/egg/cheesecake/util.pyspad_left_spacesbs cCsAt|tƒ ot|ƒ}n|t|ƒ}|d|SdS(s’Pad value with spaces at left up to given length. >>> pad_right_spaces(123, 5) '123 ' >>> pad_right_spaces(12.1, 5) '12.1 ' s N(s isinstancesvalues basestringsstrslengthslensdiff(svalueslengthsdiff((s-build/bdist.linux-i686/egg/cheesecake/util.pyspad_right_spacesqs cCs/|dd|t|ƒdt||ƒSdS(sÔPad message with dots and pad value with spaces. >>> pad_msg("123456", 77, msg_length=10, value_length=4) '123456 ... 77' >>> pad_msg("123", u"45", msg_length=5, value_length=3) u'123 . 45' s s.iN(smsgs msg_lengthslenspad_left_spacessvalues value_length(smsgsvalues msg_lengths value_length((s-build/bdist.linux-i686/egg/cheesecake/util.pyspad_msg~ss=icCs ||SdS(s‚Return line consisting of 'char' characters. >>> pad_line('*', 3) '***' >>> pad_line(length=10) '==========' N(scharslength(scharslength((s-build/bdist.linux-i686/egg/cheesecake/util.pyspad_lineˆsc Cs7yti|ƒ}Wntij o tSnXxl|iƒD]^}ti i |ƒ\} }| }ti i|| ƒ}ti i|ƒ oti|ƒq=q=Wx}t|iƒƒD]i\}}|idƒ oLtti i||ƒdƒ}|i|i|ƒƒ|iƒ|iƒq²q²W|i tiƒdSdS(ssUnzip given `package` to the `destination` directory. Return name of unpacked directory or None on error. s/swbiN(szipfilesZipFilespackageszserrorsNonesnamelistsnamesosspathssplitsdirsfiles unpack_dirsjoins destinations target_dirsexistssmakedirss enumeratesisendswithsopensoutfileswritesreadsflushsclosessep( spackages destinationsnamesis unpack_dirsoutfilesfiles target_dirszsdir((s-build/bdist.linux-i686/egg/cheesecake/util.pys unzip_package’s(    cCsyti|ƒ}Wntij o }tSnXx$|iƒD]}|i ||ƒq?W|i d}|i itiƒdSdS(ssUntar given `package` to the `destination` directory. Return name of unpacked directory or None on error. iN(starfilesopenspackagests ReadErrorsesNones getmemberssmembersextracts destinationsmembersstarinfosnamessplitsosssep(spackages destinationsesmemberststarinfo((s-build/bdist.linux-i686/egg/cheesecake/util.pys untar_package®s   cCsitii|ƒoEtii|ƒ}tii||ƒ}ti ||dt ƒ|Snt ||ƒSdS(snUnpack given egg to the `destination` directory. Return name of unpacked directory or None on error. ssymlinksN( sosspathsisdirspackagesbasenames package_namesjoins destinationsshutilscopytreesTrues unzip_package(spackages destinations package_name((s-build/bdist.linux-i686/egg/cheesecake/util.pys unegg_package¾scCs‚|itiiƒ}xftdt|ƒdƒD]K}tiii dg|| ƒ}tii |ƒ oti |ƒq/q/WdS(siMake directory with parent directories as needed. Don't throw an exception if directory exists. isN( sdirssplitsosspathssepspartssxrangeslenslengthsjoinsexistssmkdir(sdirslengthspartsspath((s-build/bdist.linux-i686/egg/cheesecake/util.pysmkdirsËs cCs3tiƒ}|ƒ}tiƒ}|||fSdS(sÊMeasure function execution time. Return (return value, time taken) tuple. >>> def fun(x): ... return x*2 >>> ret, time_taken = time_function(lambda: fun(5)) >>> ret 10 N(stimesstartsfunctionsretsend(sfunctionsstartsendsret((s-build/bdist.linux-i686/egg/cheesecake/util.pys time_functionÖs    (s__doc__sossshutilssignalssysstarfilestimeszipfiles subprocessscalls ProcessErrorsPopensPIPEsSTDOUTsPAD_TEXTs PAD_VALUEsNonesrun_cmdscommand_successfulsobjectsStdoutRedirectors pad_with_dotsspad_left_spacesspad_right_spacesspad_msgspad_lines unzip_packages untar_packages unegg_packagesmkdirss time_function(sSTDOUTspad_msgspad_linescommand_successfulsshutilspad_right_spacess untar_packagestarfilesrun_cmdsPIPEscallstimes pad_with_dotsszipfilesPopenspad_left_spacesssyss unzip_packages unegg_packagesmkdirss ProcessErrorsStdoutRedirectorsosssignalsPAD_TEXTs PAD_VALUEs time_function((s-build/bdist.linux-i686/egg/cheesecake/util.pys?s.       %        PKçI6˜`n­±±cheesecake/__init__.pyc;ò ËËEc@s dZdS(s0.6.1N(s __version__(s __version__((s1build/bdist.linux-i686/egg/cheesecake/__init__.pys?sPKçI6ÌÃ&ç{{cheesecake/logger.pyc;ò ËËEc@sÁdkZdkZdefd„ƒYZdefd„ƒYZedƒZd„Zeeids:(sjoinsselfskeywords(sself((s/build/bdist.linux-i686/egg/cheesecake/logger.pys__repr__#scCsO|ddjo t|‚n|i|i|fƒ}t|||ƒ|SdS(Nis_(snamesAttributeErrorsselfs __class__skeywordssproducerssetattr(sselfsnamesproducer((s/build/bdist.linux-i686/egg/cheesecake/logger.pys __getattr__&s  cGs@|i|iƒ}|tj o||i|i|ƒƒndS(N(sselfs _getconsumerskeywordssfuncsNonesMessagesargs(sselfsargssfunc((s/build/bdist.linux-i686/egg/cheesecake/logger.pys__call__-s cCslxRtt|iƒddƒD]5}y|i|i| SWqtj o qqXqW|iidtƒSdS(Niiÿÿÿÿsdefault( srangeslensselfskeywordssiskeywords2consumersKeyErrorsgetsdefault_consumer(sselfskeywordssi((s/build/bdist.linux-i686/egg/cheesecake/logger.pys _getconsumer2s ( s__name__s __module__s__doc__sMessageskeywords2consumers__init__s__repr__s __getattr__s__call__s _getconsumer(((s/build/bdist.linux-i686/egg/cheesecake/logger.pysProducers     sdefaultcCst|ƒGHdS(N(sstrsmsg(smsg((s/build/bdist.linux-i686/egg/cheesecake/logger.pysdefault_consumer<ssMultipleProducercBstZd„Zd„ZRS(NcOsNxG|i|iƒD]3}|tj o ||i|i|ƒ|SqqWdS(N(sselfs _getconsumerskeywordssfuncsNonesMessagesargsskwargs(sselfsargsskwargssfunc((s/build/bdist.linux-i686/egg/cheesecake/logger.pys__call__Cs ccsYt}x-|D]%}|ii|fƒ}t}|Vq W| o|iidt ƒVndS(Nsdefault( sFalsesfound_consumerskeywordsskeywordsselfskeywords2consumersgetsconsumersTruesdefault_consumer(sselfskeywordssfound_consumerskeywordsconsumer((s/build/bdist.linux-i686/egg/cheesecake/logger.pys _getconsumerHs(s__name__s __module__s__call__s _getconsumer(((s/build/bdist.linux-i686/egg/cheesecake/logger.pysMultipleProducerAs sFilecBstZd„Zd„ZRS(NcCsLt|dƒpt‚t|tƒpt|dƒ pt‚||_dS(Nswritesopen(shasattrsfsAssertionErrors isinstancesfilesselfs_file(sselfsf((s/build/bdist.linux-i686/egg/cheesecake/logger.pys__init__Vs(cCs|it|ƒIJdS(N(sselfs_filesstrsmsg(sselfsmsg((s/build/bdist.linux-i686/egg/cheesecake/logger.pys__call__[s(s__name__s __module__s__init__s__call__(((s/build/bdist.linux-i686/egg/cheesecake/logger.pysFileUs sPathcBstZed„ZRS(NcCsI|odpd}tt|ƒ|ddƒ}tt|ƒi |ƒdS(Nsasws bufferingi( sappendsmodesopensstrsfilenamesfssupersPathsselfs__init__(sselfsfilenamesappendsfsmode((s/build/bdist.linux-i686/egg/cheesecake/logger.pys__init___s(s__name__s __module__sFalses__init__(((s/build/bdist.linux-i686/egg/cheesecake/logger.pysPath^scCstit|ƒIJdS(N(ssyssstdoutsstrsmsg(smsg((s/build/bdist.linux-i686/egg/cheesecake/logger.pysSTDOUTdscCstit|ƒIJdS(N(ssyssstderrsstrsmsg(smsg((s/build/bdist.linux-i686/egg/cheesecake/logger.pysSTDERRgscCs»t|tƒottt|iƒƒƒ}n)t|tƒ otd|fƒ‚n|tj o t |ƒ o8t |dƒ otd|fƒ‚nt |ƒ}n|t i |s      cCsh|_g|_h|_dS(N(sselfscontentssorderedcontentss_name2fullname(sself((s.build/bdist.linux-i686/egg/cheesecake/model.pyssetupEs  cCs|i|iSdS(N(sselfsprefixsname(sself((s.build/bdist.linux-i686/egg/cheesecake/model.pysfullNameIscCsU|i}|o=|iƒ}t|ƒdjo|d d|d}qMn|SdS(Niis...iøÿÿÿ(sselfs docstringsrstripslen(sselfs docstring((s.build/bdist.linux-i686/egg/cheesecake/model.pysshortdocstringKs   cCsd|ii|iƒfSdS(Ns%s %r(sselfs __class__s__name__sfullName(sself((s.build/bdist.linux-i686/egg/cheesecake/model.pys__repr__RscCs3||ijo|i|Sn|ii|ƒSdS(N(snamesselfs_name2fullnamesparents name2fullname(sselfsname((s.build/bdist.linux-i686/egg/cheesecake/model.pys name2fullnameTsc CsÅ|idƒ}|}|i}x|d|ijo«|i}|tjo‘|d|i jo|i |d}Pnx_|i D]0}|d|i jo|i |d}PqqW|od||i ƒfGHntSPq!q!W|i|d}||i jo|i |}n%|od||i ƒfGHntSxW|dD]K}||ijo(|od||i ƒfGHntSn|i|}qBW|o%|GdG|i ƒGdG|i ƒGHn|SdS( Ns.is1 didn't find %r from %rs1.5 didn't find %r from %ris2 didn't find %r from %rs->sin(s dottednamessplitspartssselfsobjssystems_name2fullnamesparentsNones allobjectss moresystemssothersyssverbosesfullNamesfnspscontents( sselfs dottednamesverbosesobjssystemspspartssfnsothersys((s.build/bdist.linux-i686/egg/cheesecake/model.pysresolveDottedNameZsF       %cCs”d|jo|df\}}n#|iddƒ\}}d|}|}x3||ijo"|i}|tjo|SqNqNW|i||SdS(Ns.si( s dottednamesstartsrestssplitsselfsobjs_name2fullnamesparentsNone(sselfs dottednamesobjsrestsstart((s.build/bdist.linux-i686/egg/cheesecake/model.pysdottedNameToFullName‚s     cCs¢h}x‘|iiƒD]€\}}t|tƒo|iƒ|d|        ( s__name__s __module__sNones__init__ssetupsfullNamesshortdocstrings__repr__s name2fullnamesFalsesresolveDottedNamesdottedNameToFullNames __getstate__(((s.build/bdist.linux-i686/egg/cheesecake/model.pys Documentable=s       ( sPackagecBstZdZd„ZRS(NsPackagecCs t‚dS(N(s NameError(sselfsname((s.build/bdist.linux-i686/egg/cheesecake/model.pys name2fullname³s(s__name__s __module__skinds name2fullname(((s.build/bdist.linux-i686/egg/cheesecake/model.pysPackage±ssModulecBstZdZd„ZRS(NsModulecCsR||ijo|i|Sn0|tijo|Sn|iid|ƒ|SdS(Nsoptimistic name resolution(snamesselfs_name2fullnames __builtin__s__dict__ssystemswarning(sselfsname((s.build/bdist.linux-i686/egg/cheesecake/model.pys name2fullname¹s (s__name__s __module__skinds name2fullname(((s.build/bdist.linux-i686/egg/cheesecake/model.pysModule·ssClasscBstZdZd„ZRS(NsClasscCs;tt|ƒiƒg|_g|_g|_g|_dS(N(ssupersClasssselfssetupsbasessrawbasess baseobjectss subclasses(sself((s.build/bdist.linux-i686/egg/cheesecake/model.pyssetupÅs    (s__name__s __module__skindssetup(((s.build/bdist.linux-i686/egg/cheesecake/model.pysClassÃssFunctioncBstZdZRS(NsFunction(s__name__s __module__skind(((s.build/bdist.linux-i686/egg/cheesecake/model.pysFunctionÍss ModuleVistorcBsPtZd„Zd„Zd„Zd„Zd„Zd„Zd„Zd„Z RS( NcCs||_||_g|_dS(N(ssystemsselfsmodnames morenodes(sselfssystemsmodname((s.build/bdist.linux-i686/egg/cheesecake/model.pys__init__Òs  cCs(x!|iƒD]}|i|ƒq WdS(N(snodes getChildNodesschildsselfsvisit(sselfsnodeschild((s.build/bdist.linux-i686/egg/cheesecake/model.pysdefault×s cCs|ii||fƒdS(N(sselfs morenodessappendsdocablesnode(sselfsdocablesnode((s.build/bdist.linux-i686/egg/cheesecake/model.pyspostponeÛscCsh|iio|i|iiijom|iii|i}|itjpt‚|i |_|ii ||ƒ|i |ƒ|ii |ƒnÒ|ii ogi}|iiD]'}|i|ijo||ƒqµqµ~}|oA|\}|ii ||ƒ|i |ƒ|ii |ƒdSq1n|ii|i|i ƒ|i |ƒ|iiƒdS(N(sselfssystemscurrentsmodnamescontentssms docstringsNonesAssertionErrorsnodesdocspushsdefaultspopsappends_[1]s rootobjectssxsnamesrootssmods pushModules popModule(sselfsnodesms_[1]sxsrootssmod((s.build/bdist.linux-i686/egg/cheesecake/model.pys visitModuleÞs$&  D    cCs«|ii|i|iƒ}|itj o|i|_ nxO|i D]D}t i |ƒ}|ii|ƒ|i|ƒ}|i i|ƒqEW|i|ƒ|iiƒdS(N(sselfssystems pushClasssnodesnamesdocsclsslinenosNones linenumbersbasessnsast_ppsppsstr_basesrawbasessappendsdottedNameToFullNamesbasesdefaultspopClass(sselfsnodesnsbasesclssstr_base((s.build/bdist.linux-i686/egg/cheesecake/model.pys visitClassós  cCs0t|i|iƒ}|iii}x|iD]ú\}}|djo¸|ii d|ƒ||ii jodSn|ii |}t|tƒo|ii d|ƒdSn|io*x:|iD]}|d|||( sselfscurrentsNonesfullNamesfnswarningss setdefaultstypesappendsdetail(sselfstypesdetailsfn((s.build/bdist.linux-i686/egg/cheesecake/model.pyswarningèsccs0x)|iD]}t||ƒo|Vq q WdS(N(sselfsorderedallobjectssos isinstancescls(sselfsclsso((s.build/bdist.linux-i686/egg/cheesecake/model.pys objectsOfTypeïs cCs|iƒdS(N(sselfsrecordBasesAndSubclasses(sself((s.build/bdist.linux-i686/egg/cheesecake/model.pysfinalStateComputationsôscCsoxh|itƒD]W}xN|iD]C}|ii|ƒ}|i i |ƒ|o|i i |ƒq q WqWdS(N( sselfs objectsOfTypesClasssclssbasessnsparentsresolveDottedNamesos baseobjectssappends subclasses(sselfsnsoscls((s.build/bdist.linux-i686/egg/cheesecake/model.pysrecordBasesAndSubclasses÷s cCs|iiƒ}|d=|SdS(Ns moresystems(sselfs__dict__scopysstate(sselfsstate((s.build/bdist.linux-i686/egg/cheesecake/model.pys __getstate__ÿscCshg|_|ii|ƒxH|iD]=}x4|iiƒiƒD]\}}|i dƒo&|i|=|i ||i|dt|i|itƒ}|iii|i gƒi |ƒndS(Nis*( snodesnamess expandModnamesselfssystemsmodnamesFalsesimportstargraphs setdefaults modfullnamesappend(sselfsnodesmodname((s.build/bdist.linux-i686/egg/cheesecake/model.pys visitFrom8s(s__name__s __module__s__init__s visitFrom(((s.build/bdist.linux-i686/egg/cheesecake/model.pysImportStarFinder3s cCsw|i||ƒ}t||ƒxQ|ioF|iidƒ\}}|i ||ƒ|i |ƒ|i|ƒq"WdS(Ni( ssystems ModuleVistorsnamesmvswalksasts morenodesspopsobjsnodespushsvisit(sastsnamessystemsnodesobjsmv((s.build/bdist.linux-i686/egg/cheesecake/model.pysprocessModuleAst>s   scCs`|tjo tƒ}n|}tt|ƒ||ƒ|tjo|iƒn|i dSdS(Ni( ssystemsNonesSystems_systemsprocessModuleAstsparsessrcsmodnamesfinalStateComputationss rootobjects(ssrcsmodnamessystems_system((s.build/bdist.linux-i686/egg/cheesecake/model.pysfromTextHs   cCsT|iddgjpt‚tii|ƒo"|itii|ƒtƒ}nt}x×ti |ƒD]Æ}tii ||ƒ}tii|ƒo,tiitii |dƒƒo |djot||ƒqh|idƒoHtii|ƒd}|i|tƒ}||_t|_|iƒqhqhW|o|iƒnd|_dS(Nsblankspreparses __init__.pystests.pyi(ssystemsstatesAssertionErrorsosspathsbasenamesdirpaths pushPackagesNonespackageslistdirsfnamesjoinsfullnamesisdirsexistsspreprocessDirectorysendswithssplitextsmodnames pushModulesmodsfilepathsFalses processeds popModules popPackage(ssystemsdirpathspackagesmodnamesfnamesfullnamesmod((s.build/bdist.linux-i686/egg/cheesecake/model.pyspreprocessDirectorySs$"B  cCsÑ|idgjpt‚t|itƒƒ}x’|D]Š}|i|i ƒt ||i ƒƒ}yt |iƒ}Wn,ttfj o|id|iƒnXt||ƒ|i|i ƒq6Wd|_dS(Nspreparses cannot parses importstarred(ssystemsstatesAssertionErrorslists objectsOfTypesModulesmodlistsmodspushsparentsImportStarFindersfullNamesisfs parseFilesfilepathsasts SyntaxErrors ValueErrorswarningswalkspop(ssystemsmodlistsastsisfsmod((s.build/bdist.linux-i686/egg/cheesecake/model.pysfindImportStarsgs cCs|iddgjpt‚t|itƒƒ}tgi}|D]}||i ƒƒqC~|i ƒ}x™|D]‘}|i|}|i|iƒyt|iƒ}Wn,ttfj o|id|iƒnXt||i|ƒt|_|i|iƒqrWd|_dS(Nspreparses importstarreds cannot parsesparsed(ssystemsstatesAssertionErrorslists objectsOfTypesModulesmodliststoposortsappends_[1]smsfullNamesimportstargraphsnewlistsmods allobjectsspushsparents parseFilesfilepathsasts SyntaxErrors ValueErrorswarningsprocessModuleAstsnamesTrues processedspop(ssystemsmodlistsastsnewlists_[1]smsmod((s.build/bdist.linux-i686/egg/cheesecake/model.pysextractDocstringsus9  cCs1|idgjpt‚|iƒd|_dS(Nsparseds finalized(ssystemsstatesAssertionErrorsfinalStateComputations(ssystem((s.build/bdist.linux-i686/egg/cheesecake/model.pysfinalStateComputations‡s cCs/t||ƒt|ƒt|ƒt|ƒdS(N(spreprocessDirectoryssystemsdirpathsfindImportStarssextractDocstringssfinalStateComputations(ssystemsdirpath((s.build/bdist.linux-i686/egg/cheesecake/model.pysprocessDirectoryŒs   csUg‰tiˆƒ‰‡‡‡‡d†‰x ˆoˆˆiƒdƒq-WˆSdS(NcsPx<ˆi|gƒD](}|ˆjoˆ|=ˆ|ƒqqWˆi|ƒdS(N(sedgessgetsisjsinputspsoutputsappend(sisj(spsedgessoutputsinput(s.build/bdist.linux-i686/egg/cheesecake/model.pysp–s  i(soutputsdictsfromkeyssinputspspopitem(sinputsedgesspsoutput((sinputsedgessoutputsps.build/bdist.linux-i686/egg/cheesecake/model.pystoposort’scCsd|jo™|idƒt|ƒdjpt‚|ƒ}t||dƒti|t ddƒti ƒHdGHxŒ|i i ƒD]\}}|Gt|ƒGHqƒWn]|ƒ}xF|D]>}tiitii|ƒƒd}tt|ƒ||ƒq¶W|iƒdS(Ns-riisda.outswbswarning summary:(sargvsremoveslensAssertionErrors systemclsssystemsprocessDirectoryspicklesdumpsopensHIGHEST_PROTOCOLswarningss iteritemssksvsfnamesosspathssplitextsbasenamesmodnamesprocessModuleAsts parseFilesreport(s systemclssargvsmodnameskssystemsfnamesv((s.build/bdist.linux-i686/egg/cheesecake/model.pysmain¡s"     "s__main__i()s__doc__scompilersastssyssosscPicklespickles __builtin__ssetsscompiler.transformersparses parseFilescompiler.visitorswalksast_pps get_call_namesget_function_callssobjects DocumentablesPackagesModulesClasssFunctions ModuleVistorsstatessSystemsTrues expandModnamesImportStarFindersprocessModuleAstsNonesfromTextspreprocessDirectorysfindImportStarssextractDocstringssfinalStateComputationssprocessDirectorystoposortsmains__name__sargv(sprocessDirectorysImportStarFinders get_call_namesSystems __builtin__swalksparsesFunctionsfindImportStarssPackagesast_ppspreprocessDirectorysmains ModuleVistors expandModnamestoposortsget_function_callssfromTextsastssyss parseFilesextractDocstringssprocessModuleAsts DocumentablesstatesspicklesfinalStateComputationssModulesClassssetssos((s.build/bdist.linux-i686/egg/cheesecake/model.pys? s@          t   Æ          PKçI6»>V¸:¸:cheesecake/ast_pp.pyc;ò ËËEc@s¤dkZdklZdklZdklZlZdefd„ƒYZd„Zd„Z e djo5e e d ƒi ƒZe eƒ\ZZeGHeGHndS( N(sStringIO(spprint(sparseswalks SourceWritercBsvtZdZd„Zd„Zd„Zd„Zd„Zd„Zd„Z d „Z d „Z d „Z d „Z d „Zd„Zd„Zd„Zd„Zd„Zd„Zd„Zd„Zd„Zd„Zd„Zd„Zd„Zd„Zd„Zd„Zd„Zd„Z d „Z!d!„Z"d"„Z#d#„Z$d$„Z%d%„Z&d&„Z'd'„Z(d(„Z)d)„Z*RS(*NicCstƒ|_dS(N(sStringIOsselfss(sself((s/build/bdist.linux-i686/egg/cheesecake/ast_pp.pys__init__ scCs|ii|ƒdS(N(sselfssswrite(sselfss((s/build/bdist.linux-i686/egg/cheesecake/ast_pp.pyswscCs/|iidƒ|iidd|iƒdS(Ns s i(sselfssswrites_i(sself((s/build/bdist.linux-i686/egg/cheesecake/ast_pp.pysnlscCs|id7_|iƒdS(Ni(sselfs_isnl(sself((s/build/bdist.linux-i686/egg/cheesecake/ast_pp.pysindentscCs|id8_|iƒdS(Ni(sselfs_isnl(sself((s/build/bdist.linux-i686/egg/cheesecake/ast_pp.pysdedentscCs>|itj o|it|iƒƒnt|i|ƒdS(N(snodesdocsNonesselfswlsreprswalk(sselfsnode((s/build/bdist.linux-i686/egg/cheesecake/ast_pp.pys visitModulescCs(x!|iƒD]}t||ƒq WdS(N(snodes getChildrensnswalksself(sselfsnodesn((s/build/bdist.linux-i686/egg/cheesecake/ast_pp.pys visitStmt"s c Cs d} |io´t|iƒ}t|iƒ}|i|| }di|i| ƒ}||jo^t |i||iƒ}|ddigi }|D]}|di|ƒƒq–~ƒ}qÖndi|iƒ}|i| |i|fƒ|iƒzt|i|ƒWd|iƒXdS(Ns def %s(%s):s, s=(sfmtsnodesdefaultsslensargnamessnargssndefss noDefaultssjoinssszipsargdefssappends_[1]sxsselfswsnamesindentswalkscodesdedent( sselfsnodes noDefaultssargdefssnargss_[1]sssndefssxsfmt((s/build/bdist.linux-i686/egg/cheesecake/ast_pp.pys visitFunction&s   I cCs?t|id|ƒ|idƒt|i|ƒ|iƒdS(Nis = (swalksnodesnodessselfswsexprsnl(sselfsnode((s/build/bdist.linux-i686/egg/cheesecake/ast_pp.pys visitAssign9s cCs|i|iƒdS(N(sselfswsnodesname(sselfsnode((s/build/bdist.linux-i686/egg/cheesecake/ast_pp.pys visitAssName?scCs…t|i|ƒ|idƒx/|id D] }t||ƒ|idƒq+Wx"|idD]}t||ƒq]W|idƒdS(Ns(iÿÿÿÿs, s)(swalksnodesselfswsargssa(sselfsnodesa((s/build/bdist.linux-i686/egg/cheesecake/ast_pp.pys visitCallFuncBs  cCsO|idƒt|i|ƒx|iD]}t||ƒq'W|idƒdS(Ns[s](sselfswswalksnodesexprsqualssq(sselfsnodesq((s/build/bdist.linux-i686/egg/cheesecake/ast_pp.pys visitListCompLs   cCsl|idƒt|i|ƒ|idƒt|i|ƒx+|iD] }|idƒt||ƒqDWdS(Ns for s in s if (sselfswswalksnodesassignslistsifssexpr(sselfsnodesexpr((s/build/bdist.linux-i686/egg/cheesecake/ast_pp.pysvisitListCompForSs    cCs|i|iƒdS(N(sselfswsnodesname(sselfsnode((s/build/bdist.linux-i686/egg/cheesecake/ast_pp.pys visitName\scCst|i|ƒ|iƒdS(N(swalksnodesexprsselfsnl(sselfsnode((s/build/bdist.linux-i686/egg/cheesecake/ast_pp.pys visitDiscard_scCst|idƒ|io.|idƒt|i|ƒ|idƒnx|iD]}t||ƒqOW|iƒdS(Nsprint s>>s, (sselfswsnodesdestswalksnodessesnl(sselfsnodese((s/build/bdist.linux-i686/egg/cheesecake/ast_pp.pys visitPrintnlcs    cCs1t|i|ƒ|idƒ|i|iƒdS(Ns.(swalksnodesexprsselfswsattrname(sselfsnode((s/build/bdist.linux-i686/egg/cheesecake/ast_pp.pys visitGetattrms cCsz|idƒx\|iD]Q\}}|i|ƒ|tj o|idƒ|i|ƒn|idƒqW|iƒdS(Nsimport s as s, (sselfswsnodesnamessmodsas_wordsNonesnl(sselfsnodesas_wordsmod((s/build/bdist.linux-i686/egg/cheesecake/ast_pp.pys visitImportrs     cCs—|idƒ|i|iƒ|idƒx\|iD]Q\}}|i|ƒ|tj o|idƒ|i|ƒn|idƒq4W|iƒdS(Nsfrom s import s as s, ( sselfswsnodesmodnamesnamessmodsas_wordsNonesnl(sselfsnodesas_wordsmod((s/build/bdist.linux-i686/egg/cheesecake/ast_pp.pys visitFrom|s      cCs|it|iƒƒdS(N(sselfswsreprsnodesvalue(sselfsnode((s/build/bdist.linux-i686/egg/cheesecake/ast_pp.pys visitConstˆscCs+|idƒt|i|ƒ|iƒdS(Nsreturn (sselfswswalksnodesvaluesnl(sselfsnode((s/build/bdist.linux-i686/egg/cheesecake/ast_pp.pys visitReturn‹s cCsÍ|idƒ|i|iƒ|ioL|idƒx+|iD] }t||ƒ|idƒq>W|idƒn|iƒz>|it j o|it |iƒƒnt|i |ƒWd|i ƒXdS(Nsclass s(s, s):( sselfswsnodesnamesbasessbswalksindentsdocsNonesreprscodesdedent(sselfsnodesb((s/build/bdist.linux-i686/egg/cheesecake/ast_pp.pys visitClasss       cCs1t|i|ƒ|idƒ|i|iƒdS(Ns.(swalksnodesexprsselfswsattrname(sselfsnode((s/build/bdist.linux-i686/egg/cheesecake/ast_pp.pys visitAssAttr¡s cCs1t|i|ƒ|idƒt|i|ƒdS(Ns * (swalksnodesleftsselfswsright(sselfsnode((s/build/bdist.linux-i686/egg/cheesecake/ast_pp.pysvisitMul¦s cCs1t|i|ƒ|idƒt|i|ƒdS(Ns - (swalksnodesleftsselfswsright(sselfsnode((s/build/bdist.linux-i686/egg/cheesecake/ast_pp.pysvisitSub«s cCs1t|i|ƒ|idƒt|i|ƒdS(Ns + (swalksnodesleftsselfswsright(sselfsnode((s/build/bdist.linux-i686/egg/cheesecake/ast_pp.pysvisitAdd°s cCs1t|i|ƒ|idƒt|i|ƒdS(Ns % (swalksnodesleftsselfswsright(sselfsnode((s/build/bdist.linux-i686/egg/cheesecake/ast_pp.pysvisitModµs cCsXt|i|ƒ|idƒ|i|iƒ|idƒt|i|ƒ|iƒdS(Ns (swalksnodesselfswsopsexprsnl(sselfsnode((s/build/bdist.linux-i686/egg/cheesecake/ast_pp.pysvisitAugAssignºs   cCsÎd}xz|iD]o\}}|i|ƒ|idƒt||ƒ|idƒ|iƒzt||ƒWd|i ƒXd}qW|i o=|idƒ|iƒzt|i |ƒWd|i ƒXndS(Nsifs s:selifselse:( skeywordsnodestestsscondsbodysselfswswalksindentsdedentselse_(sselfsnodesbodyskeywordscond((s/build/bdist.linux-i686/egg/cheesecake/ast_pp.pysvisitIfÂs(           cCsbt|i|ƒxK|iD]@\}}|idƒ|i|ƒ|idƒt||ƒqWdS(Ns (swalksnodesexprsselfsopssopsargsw(sselfsnodesopsarg((s/build/bdist.linux-i686/egg/cheesecake/ast_pp.pys visitCompare×s    cCs¾|idƒt|i|ƒ|idƒt|i|ƒ|idƒ|iƒzt|i|ƒWd|iƒX|i o=|idƒ|iƒzt|i |ƒWd|iƒXndS(Nsfor s in s:selse:( sselfswswalksnodesassignslistsindentsbodysdedentselse_(sselfsnode((s/build/bdist.linux-i686/egg/cheesecake/ast_pp.pysvisitForßs"        cCswt|i|ƒ|idƒ|iot|i|ƒn|idƒ|iot|i|ƒn|idƒdS(Ns[s:s](swalksnodesexprsselfswslowersupper(sselfsnode((s/build/bdist.linux-i686/egg/cheesecake/ast_pp.pys visitSliceòs    cCs¹|idƒt|iƒdjon‚t|iƒdjo%t|id|ƒ|idƒnGx/|id D] }t||ƒ|idƒqpWt|id|ƒ|idƒdS(Ns(iis,iÿÿÿÿs, s)(sselfswslensnodesnodesswalksexpr(sselfsnodesexpr((s/build/bdist.linux-i686/egg/cheesecake/ast_pp.pys visitTupleüs  cCsv|idƒ|iƒzt|i|ƒWd|iƒX|idƒ|iƒzt|i|ƒWd|iƒXdS(Nstry:sfinally:(sselfswsindentswalksnodesbodysdedentsfinal(sselfsnode((s/build/bdist.linux-i686/egg/cheesecake/ast_pp.pysvisitTryFinally s     cCsBt|i|ƒ|idƒt|id|ƒ|idƒdS(Ns[is](swalksnodesexprsselfswssubs(sselfsnode((s/build/bdist.linux-i686/egg/cheesecake/ast_pp.pysvisitSubscripts cCs!|idƒt|i|ƒdS(Ns-(sselfswswalksnodesexpr(sselfsnode((s/build/bdist.linux-i686/egg/cheesecake/ast_pp.pys visitUnarySubs cCsL|idƒx+|iD] }t||ƒ|idƒqW|idƒdS(Ns(s, s)(sselfswsnodesnodessexprswalk(sselfsnodesexpr((s/build/bdist.linux-i686/egg/cheesecake/ast_pp.pys visitAssTuple"s    cCs|idƒt|i|ƒ|ioL|idƒt|i|ƒ|io!|idƒt|i|ƒqsn|iƒdS(Nsraise s, (sselfswswalksnodesexpr1sexpr2sexpr3snl(sselfsnode((s/build/bdist.linux-i686/egg/cheesecake/ast_pp.pys visitRaise)s     cCsl|idƒxK|iD]@\}}t||ƒ|idƒt||ƒ|idƒqW|idƒdS(Ns{s:s,s}(sselfswsnodesitemssksvswalk(sselfsnodesksv((s/build/bdist.linux-i686/egg/cheesecake/ast_pp.pys visitDict4s     cCs|iiƒSdS(N(sselfsssgetvalue(sself((s/build/bdist.linux-i686/egg/cheesecake/ast_pp.pys__str__=s(+s__name__s __module__s_is__init__swsnlsindentsdedents visitModules visitStmts visitFunctions visitAssigns visitAssNames visitCallFuncs visitListCompsvisitListCompFors visitNames visitDiscards visitPrintnls visitGetattrs visitImports visitFroms visitConsts visitReturns visitClasss visitAssAttrsvisitMulsvisitSubsvisitAddsvisitModsvisitAugAssignsvisitIfs visitComparesvisitFors visitSlices visitTuplesvisitTryFinallysvisitSubscripts visitUnarySubs visitAssTuples visitRaises visitDicts__str__(((s/build/bdist.linux-i686/egg/cheesecake/ast_pp.pys SourceWritersR                                cCs'tƒ}t||ƒ|iiƒSdS(N(s SourceWritersswswalksastsssgetvalue(sastssw((s/build/bdist.linux-i686/egg/cheesecake/ast_pp.pyspp@s  cCs0t|ƒ}tƒ}t||ƒ||fSdS(N(sparsesssasts SourceWritersswswalk(sssastssw((s/build/bdist.linux-i686/egg/cheesecake/ast_pp.pysmagicEs   s__main__sr(ssyssStringIOspprintscompilersparseswalksobjects SourceWritersppsmagics__name__sfiles__file__sreadsfsastssw( sparses SourceWritersmagicsfsStringIOspprintsswsppsastswalkssys((s/build/bdist.linux-i686/egg/cheesecake/ast_pp.pys?s   ÿ9   PKçI6¬ÿ|TÞ Þ cheesecake/codeparser.pyc;ò ËËEc@s¸dkZdkZdkZdkZdklZlZlZlZl Z l Z e ede ƒoei ƒiZn eiZed„Zeed„Zed„Zhdedƒedƒed ƒed d hd d <dd<ƒeddƒedƒeddƒeddƒeddƒg <deidƒeddƒeddƒeddƒg<deidƒeddƒeideiƒg|tjo |}ntdhd|<d|<|ƒSdS(Nsj(START %(start)s ALPHA %(end)s END) | (START %(start)s ALPHA WORD* ALPHA %(end)s END)sstartsend(sendsNonesstarts compile_regexsmapping(sstartsendsmapping((s3build/bdist.linux-i686/egg/cheesecake/codeparser.pys inline_markup's  cCs2t||dhdd<dd<dd<ƒSdS(NsmappingsALPHAs [-.,?!\s\w]sSTARTs (\n|^)[\ \t]*sENDs(s inline_markupsstartsend(sstartsend((s3build/bdist.linux-i686/egg/cheesecake/codeparser.pys line_markup.ssreSTs\*s\*\*s``s\(s_\)sALPHAs\wsWORDs[-.\w]s\(`s`_\)s:s[*+-]ss((\d+) | ([a-zA-Z]+) [.\)])s\( ((\d+) | ([a-zA-Z]+)) \)sepytexts[BCEGILMSUX]\{.*\}s@[a-z]+([\ \t][a-zA-Z]+)?:s-s \d+(\.\d+)*sjavadocs<[a-zA-z]+[^>]*>s@[a-z][a-zA-Z]*\ssI{@ ((docRoot) | (inheritDoc) | (link) | (linkplain) | (value)) [^}]* }cCs8x-t|D]!}ti||ƒotSq q WtSdS(s‹Return True if text includes given documentation format and False otherwise. See supported_formats for list of known formats. N(ssupported_formatssformatspatternsressearchstextsTruesFalse(stextsformatspattern((s3build/bdist.linux-i686/egg/cheesecake/codeparser.pys use_formatTs   s CodeParsercBsJtZdZed„Zd„Zd„Zd„Zd„Ze eƒZ RS(s¶Information about the structure of a Python module. * Collects modules, classes, methods, functions and associated docstrings * Based on mwh's docextractor.model module cCsÎ|o|i|_ntii|_g|_g|_g|_g|_g|_ g|_ h|_ d|_ d|_ d|_xtD]} g|i | >> << += -= *= /= %= ^= &= |= == <= >= >>= <<= != <> : in is or not and cCst|ƒidƒ}| odSnd|jo|d}n|d}||d>> expand_indent(' ') 4 >>> expand_indent('\t') 8 >>> expand_indent(' \t') 8 >>> expand_indent(' \t') 8 >>> expand_indent(' \t') 16 is is iN(sresultslineschar(slinescharsresult((s-build/bdist.linux-i686/egg/cheesecake/pep8.pys expand_indentPs  cCs |GHdS(sPrint a message.N(stext(stext((s-build/bdist.linux-i686/egg/cheesecake/pep8.pysmessagepscCs¯g}ttƒ}xˆtƒiƒD]w\}}t|ƒ|joXti |ƒd}t |ƒdjo|di |ƒo|i|||fƒq™q"q"W|iƒ|SdS(sj Find all globally visible functions where the first argument name starts with argument_name. iiN(schecksstypes find_checkss function_typesglobalss iteritemssnamesfunctionsinspects getargspecsargsslens startswiths argument_namesappendssort(s argument_namesfunctionsnamesargss function_typeschecks((s-build/bdist.linux-i686/egg/cheesecake/pep8.pys find_checksws  '" cCs¼d}t|ƒd}|idƒo||idƒ7}n(|idƒo||idƒ7}n|idƒp |idƒo|d7}|d8}n|| d||||SdS( sÇ Replace contents with 'xxx' to prevent syntax matching. >>> mute_string('"abc"') '"xxx"' >>> mute_string("'''abc'''") "'''xxx'''" >>> mute_string("r'abc'") "r'xxx'" is"s's"""s'''isxN(sstartslenstextsendsendswithsindex(stextsendsstart((s-build/bdist.linux-i686/egg/cheesecake/pep8.pys mute_string‡s   sCheckercBs_tZdZd„Zd„Zd„Zd„Zd„Zd„Zd„Z d„Z d „Z RS( sE Load a Python source file, tokenize it, check coding style. cCsi||_t|ƒiƒ|_tdƒ|_tdƒ|_ti i ddƒt |iƒti d Run all physical checks on a raw input line. N(slinesselfs physical_linesphysical_checkssnameschecksargument_namess run_checksresultsNonesoffsetstexts report_errors line_number(sselfslinesnamestextsargument_namessresultsoffsetscheck((s-build/bdist.linux-i686/egg/cheesecake/pep8.pyscheck_physicalÈs    c Cs g|_g}d}t} xl|iD]a}|dd!\}}|t i t i t i t it ifjoq%n|t ijot|ƒ}n| o¶| d\} }|d\} }| | jo?|i| d|ddjo|idƒ|d7}qIqM||jo9|i| d||!}|i|ƒ|t|ƒ7}qMn|ii||fƒ|i|ƒ|t|ƒ7}|} q%Wdi|ƒ|_dS( s3 Build a logical line from tokens. iiiis{[(s sN(sselfsmappingslogicalslengthsNonespreviousstokensstokens token_typestextstokenizesCOMMENTsNLsINDENTsDEDENTsNEWLINEsSTRINGs mute_stringsend_linesends start_linesstartslinessappendsfillslensjoins logical_line( sselfsendsfillstextslengthslogicals token_typesstartstokensend_lines start_linesprevious((s-build/bdist.linux-i686/egg/cheesecake/pep8.pysbuild_tokens_lineÓs8  +       c Cs•tiiddƒdtid<|iƒ|i|iddddd} | |idddd }t |ƒ|_ ti djo|i d i ƒGHnxî|iD]ã\}}}ti djo dG|GHn|i||ƒ}|tj o˜|\}}t|ƒtjo|\} } nPxL|iD]A\} }|| jo(|dd} |dd|| } q.q.W|i| | ||ƒqªqªWdS( sL Build a line from tokens and run all logical checks on it. s logical linesiiiiPis N(soptionsscounterssgetsselfsbuild_tokens_lineslinessmappings first_linesindents expand_indents indent_levelsverboses logical_linesrstripslogical_checkssnameschecksargument_namess run_checksresultsNonesoffsetstextstypestuplesoriginal_numbersoriginal_offsets token_offsetstokens report_error( sselfsindentsnamestextsargument_namesscheckstokensresultsoffsetsoriginal_numbers first_lines token_offsetsoriginal_offset((s-build/bdist.linux-i686/egg/cheesecake/pep8.pys check_logicalôs0  $       cCsVd|_d|_hdd<|_g|_d}xti|iƒD]}|ii |ƒ|dd!\}}|ti jo |djo|d7}n|ti jo |djo|d8}n|tijo| o$|iƒd|id}|tijo(dti|||ti|fGHq(q(WdS( s" Print benchmark numbers. s %-7.2f %ssseconds elapseds directoriessfiless logical linessphysical liness%-7d %s per second (%d total)N(selapsedskeysskeysoptionsscounters(selapsedskeysskey((s-build/bdist.linux-i686/egg/cheesecake/pep8.pysprint_benchmark®sc Cs”d}t|ƒ}|idddddddd ƒ|id d dddddd ƒ|id dddtddtƒ|idddddƒ|idddddddƒ|idddddƒ|idddddƒ|idddddƒ|idddddƒ|id dddd!ƒ|id"dd#dd$ƒ|id%dddd&ƒ|i|ƒ\aati oti ti ƒnt tƒdjo|i d'ƒnt iitidƒt_tiid(ƒt_x:tt tiƒƒD]#}ti|id)ƒti|„>¤Ècheesecake/cheesecake_index.pycPKçI6^zsãü€ü€¤Ácheesecake/subprocess.pycPKçI65@uàÀ%À%¤ô‡cheesecake/util.pycPKçI6˜`n­±±¤å­cheesecake/__init__.pycPKçI6ÌÃ&ç{{¤Ë®cheesecake/logger.pycPKçI6¼ÒJïhzhz¤yËcheesecake/model.pycPKçI6»>V¸:¸:¤Fcheesecake/ast_pp.pycPKçI6¬ÿ|TÞ Þ ¤þ€cheesecake/codeparser.pycPKçI6Øùʨltlt¤¢cheesecake/pep8.pycPKçI6û^$››¤°EGG-INFO/PKG-INFOPKçI6¸K𚚤zEGG-INFO/SOURCES.txtPKçI6“×2¤FEGG-INFO/dependency_links.txtPKçI6Áo‡²GG¤‚EGG-INFO/entry_points.txtPKçI6üôŠ ¤EGG-INFO/top_level.txtPKçI6“×2¤?EGG-INFO/not-zip-safePKçI6]ˆ´ïKK!ísEGG-INFO/scripts/cheesecake_indexPK´ý