Changeset 44
- Timestamp:
- 06/08/06 12:54:49 (6 years ago)
- Files:
-
- branches/mk/cheesecake/_util.py (modified) (2 diffs)
- branches/mk/cheesecake/cheesecake_index.py (modified) (16 diffs)
- branches/mk/cheesecake/codeparser.py (modified) (2 diffs)
- branches/mk/tests/test_index_install.py (modified) (1 diff)
- branches/mk/tests/test_index_installability.py (modified) (1 diff)
- branches/mk/tests/test_index_unpack.py (modified) (3 diffs)
- branches/mk/tests/test_index_unpack_dir.py (modified) (1 diff)
- branches/mk/tests/test_index_url_download.py (modified) (4 diffs)
- branches/mk/tests/test_init_cleanup.py (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
branches/mk/cheesecake/_util.py
r42 r44 1 #!/usr/bin/env python 2 """ 3 Cheesecake: How tasty is your code? 1 import os 2 import sys 3 import tarfile 4 import zipfile 4 5 5 The idea of the Cheesecake project is to rank Python packages6 based on various empiric "kwalitee" factors, such as:7 8 * whether the package can be downloaded9 * whether the package can be unpacked10 * whether the package can be installed into an alternate directory11 * existence of certain files such as README, INSTALL, LICENSE, setup.py etc.12 * existence of certain directories such as doc, test, demo, examples13 * percentage of modules/functions/classes/methods with docstrings14 * percentage of functions/methods that are unit tested15 * average pylint score for all non-test and non-demo modules16 * whether the package can be unpacked17 * whether the package can be installed into an alternate directory18 """19 20 import os, sys21 6 from subprocess import call, ProcessError, Popen, PIPE, STDOUT 22 7 … … 109 94 msg = char * (PAD_TEXT + PAD_VALUE + 1) 110 95 return msg 96 97 def unzip_package(package, destination): 98 """Unzip given `package` to the `destination` directory. 99 100 Return name of unpacked directory or None on error. 101 """ 102 try: 103 z = zipfile.ZipFile(package) 104 except zipfile.error: 105 return None 106 107 # Get directory structure from zip and create it in destination directory. 108 for name in z.namelist(): 109 (dir, file) = os.path.split(name) 110 unpack_dir = dir 111 target_dir = os.path.join(destination, dir) 112 if not os.path.exists(target_dir): 113 os.makedirs(target_dir) 114 115 # Extract files to directory structure 116 for i, name in enumerate(z.namelist()): 117 if not name.endswith('/'): 118 outfile = open(os.path.join(destination, name), 'wb') 119 outfile.write(z.read(name)) 120 outfile.flush() 121 outfile.close() 122 123 return unpack_dir.split(os.sep)[0] 124 125 def untar_package(package, destination): 126 """Untar given `package` to the `destination` directory. 127 128 Return name of unpacked directory or None on error. 129 """ 130 try: 131 t = tarfile.open(package) 132 except tarfile.ReadError, e: 133 return None 134 135 for member in t.getmembers(): 136 t.extract(member, destination) 137 138 tarinfo = t.members[0] 139 return tarinfo.name.split(os.sep)[0] branches/mk/cheesecake/cheesecake_index.py
r43 r44 19 19 20 20 import os, sys, re, shutil 21 import tarfile, zipfile22 21 import tempfile 23 22 from optparse import OptionParser … … 26 25 from math import ceil 27 26 28 from _util import run_cmd, pad_with_dots, pad_left_spaces, pad_msg, pad_line, command_successful 27 from _util import pad_with_dots, pad_left_spaces, pad_msg, pad_line 28 from _util import run_cmd, command_successful 29 from _util import unzip_package, untar_package 29 30 from _util import StdoutRedirector 30 31 import logger … … 43 44 44 45 def isiterable(obj): 45 return hasattr(obj, '__iter__') 46 """Check whether object is iterable. 47 48 >>> isiterable([1,2,3]) 49 True 50 >>> isiterable("string") 51 True 52 >>> isiterable(object) 53 False 54 """ 55 return hasattr(obj, '__iter__') or isinstance(obj, basestring) 46 56 47 57 def has_extension(filename, ext): … … 571 581 572 582 def reset_rules(self, rules): 573 if isiterable(rules): 583 if isinstance(rules, basestring): 584 pass 585 elif isiterable(rules): 574 586 for rule in rules: 575 587 self.reset_rules(rule) … … 785 797 self.quiet = quiet 786 798 787 self.package_types = ["tar.gz", "tgz", "zip"] 799 self.package_types = { 800 "tar.gz": untar_package, 801 "tgz": untar_package, 802 "zip": unzip_package, 803 } 804 788 805 self.sandbox_pkg_file = "" 789 806 self.sandbox_pkg_dir = "" … … 810 827 Don't use logging, since it can be called before logging has been setup. 811 828 """ 812 self.cleanup() 813 os.unlink(os.path.join(self.sandbox, self.logfile)) 829 self.cleanup(remove_log_file=False) 814 830 815 831 msg += "\n" + pad_msg("CHEESECAKE INDEX", 0) 832 msg += "\nDetailed info available in log file %s" % self.logfile 833 816 834 raise CheesecakeError(msg) 817 818 def cleanup(self ):835 836 def cleanup(self, remove_log_file=True): 819 837 """Delete temporary directories and files that were created 820 838 in the sandbox. At the end delete the sandbox itself. … … 831 849 832 850 delete_dir(self.sandbox) 851 852 if remove_log_file: 853 os.unlink(os.path.join(self.sandbox, self.logfile)) 833 854 834 855 def set_defaults(self): … … 873 894 """Default settings for logging. 874 895 875 If verbose, log goes to console, else it goes to logfile 876 log.debug goes to logfile 877 log.info goes to console 878 log.warn and log.error go to both logfile and stdout 896 If verbose, log goes to console, else it goes to logfile. 897 log.debug and log.info goes to logfile. 898 log.warn and log.error go to both logfile and stdout. 879 899 """ 880 900 if logfile: … … 891 911 else: 892 912 self.log = logger.MultipleProducer('cheesecake logfile') 893 if self.quiet: 894 self.log.info = logger.MultipleProducer('cheesecake logfile') 895 else: 896 self.log.info = logger.MultipleProducer('cheesecake console') 913 914 self.log.info = logger.MultipleProducer('cheesecake logfile') 897 915 self.log.debug = logger.MultipleProducer('cheesecake logfile') 898 916 self.log.warn = logger.MultipleProducer('cheesecake console') 899 917 self.log.error = logger.MultipleProducer('cheesecake console') 900 901 self.log.debug("package = ", self.short_pkg_name)902 918 903 919 def retrieve_pkg(self): … … 908 924 else: 909 925 self.copy_pkg() 910 911 def get_package_from_url(self):912 """Use ``urlparse`` to obtain package path from URL.913 """914 (scheme,location,path,param,query,fragment_id) = urlparse(self.url)915 return self.get_package_from_path(path)916 917 def get_package_from_path(self, path):918 """Get package name as file portion of path.919 """920 dir, file = os.path.split(path)921 self.short_pkg_name = file922 for package_type in self.package_types:923 s = re.search("(.+)\.%s" % package_type, file)924 if s:925 self.short_pkg_name = s.group(1)926 break927 return file928 926 929 927 def get_pkg_from_pypi(self): … … 1002 1000 #self.log("Downloaded package %s to %s" % (self.package, downloaded_filename)) 1003 1001 1004 if re.search("Content-Type: details/html", str(headers)):1002 if headers.gettype() in ["text/html"]: 1005 1003 f = open(downloaded_filename) 1006 1004 if re.search("404 Not Found", "".join(f.readlines())): … … 1022 1020 def unpack_pkg(self): 1023 1021 """Unpack the package in the sandbox directory. 1024 1025 Currently supported archive types: 1026 1027 * .tar.gz (handled with ``tarfile`` module) 1028 * .zip (handled with ``zipfile`` module) 1022 1023 Check `package_types` attribute for list of currently supported 1024 archive types. 1029 1025 1030 1026 :Ivariables: … … 1033 1029 self.package_type = "" 1034 1030 1035 for type in self.package_types :1031 for type in self.package_types.keys(): 1036 1032 s = re.search(r"(.+)\.%s" % type, self.package) 1037 1033 if s: … … 1051 1047 shutil.rmtree(self.sandbox_pkg_dir) 1052 1048 1053 if self.package_type in ["tar.gz", "tgz"]: 1054 self.untar_pkg() 1055 elif self.package_type == "zip": 1056 self.unzip_pkg() 1049 # Call appropriate function to unpack the package. 1050 unpack = self.package_types[self.package_type] 1051 self.unpack_dir = unpack(self.sandbox_pkg_file, self.sandbox) 1052 1053 if self.unpack_dir is None: 1054 self.raise_exception("Could not unpack package %s ... exiting" % \ 1055 self.sandbox_pkg_file) 1056 1057 self.unpacked = True 1057 1058 1058 1059 if self.unpack_dir != self.package_name: 1059 1060 self.original_package_name = self.package_name 1060 1061 self.package_name = self.unpack_dir 1061 1062 if not self.quiet:1063 self.log.info("Detailed info available in log file %s" % self.logfile)1064 1065 def untar_pkg(self):1066 """Untar the package in the sandbox directory.1067 1068 Uses tarfile module.1069 """1070 try:1071 t = tarfile.open(self.sandbox_pkg_file)1072 except tarfile.ReadError, e:1073 self.raise_exception("Could not read tar file %s ... exiting" % self.sandbox_pkg_file)1074 1075 for member in t.getmembers():1076 t.extract(member, self.sandbox)1077 1078 tarinfo = t.members[0]1079 self.unpack_dir = tarinfo.name.split(os.sep)[0]1080 1081 self.unpacked = True1082 1083 def unzip_pkg(self):1084 """Unzip the package in the sandbox directory.1085 1086 Uses zipfile module.1087 """1088 try:1089 z = zipfile.ZipFile(self.sandbox_pkg_file)1090 except zipfile.error:1091 self.raise_exception("Error unzipping file %s ... exiting" % self.sandbox_pkg_file)1092 1093 # Get directory structure from zip and create it in sandbox1094 for name in z.namelist():1095 (dir, file) = os.path.split(name)1096 unpack_dir = dir1097 target_dir = os.path.join(self.sandbox, dir)1098 if not os.path.exists(target_dir):1099 os.makedirs(target_dir)1100 1101 # Extract files to directory structure1102 for i, name in enumerate(z.namelist()):1103 if not name.endswith('/'):1104 outfile = open(os.path.join(self.sandbox, name), 'wb')1105 outfile.write(z.read(name))1106 outfile.flush()1107 outfile.close()1108 1109 self.unpack_dir = unpack_dir.split(os.sep)[0]1110 1111 self.unpacked = True1112 1062 1113 1063 def walk_pkg(self): … … 1202 1152 return cheesecake_index 1203 1153 1154 ################################################################################ 1155 ## Command line. 1156 ################################################################################ 1204 1157 1205 1158 def process_cmdline_args(): 1206 """ 1207 Parse command-line options 1159 """Parse command-line options. 1208 1160 """ 1209 1161 parser = OptionParser() … … 1233 1185 1234 1186 def main(): 1235 """ 1236 Display Cheesecake index for package specified via command-line options 1187 """Display Cheesecake index for package specified via command-line options. 1237 1188 """ 1238 1189 options = process_cmdline_args() branches/mk/cheesecake/codeparser.py
r39 r44 91 91 """ 92 92 def __init__(self, pyfile, log=None): 93 """ 93 """Initialize Code Parser object. 94 94 95 :Parameters: 95 96 `pyfile` : str … … 177 178 178 179 def docstring_count(self): 179 """Return number of docstrings found in this module 180 """Return number of docstrings found in this module. 180 181 """ 181 182 return len(self.docstrings) 182 183 183 184 def docstring_count_by_type(self, type): 184 """Return number of docstrings of given type found in this module 185 """Return number of docstrings of given type found in this module. 185 186 """ 186 187 return len(self.docstrings_by_format[type]) 187 188 188 189 def functions_called(self): 189 """ 190 Return list of functions called by functions/methods 191 defined in this module 190 """Return list of functions called by functions/methods 191 defined in this module. 192 192 """ 193 193 return self.system.func_called.keys() branches/mk/tests/test_index_install.py
r40 r44 14 14 return 15 15 self.cheesecake.cleanup() 16 os.unlink(self.cheesecake.logfile)17 16 18 17 def test_index_install_correct_package(self): branches/mk/tests/test_index_installability.py
r40 r44 19 19 return 20 20 self.cheesecake.cleanup() 21 os.unlink(self.cheesecake.logfile)22 21 23 22 def test_index_installability_local_path(self): branches/mk/tests/test_index_unpack.py
r40 r44 11 11 def setUp(self): 12 12 self.cheesecake = None 13 self.logfile = None 13 14 14 15 def tearDown(self): … … 16 17 return 17 18 self.cheesecake.cleanup() 18 os.unlink(self.cheesecake.logfile) 19 20 if self.logfile: 21 os.unlink(self.logfile) 19 22 20 23 def _run_valid(self, package_file): … … 37 40 self._run_valid("package1.zip") 38 41 39 def _run_invalid(self, package_file, message): 42 def _run_invalid(self, package_file): 43 self.logfile = tempfile.mktemp() 44 40 45 try: 41 46 self.cheesecake = Cheesecake(path=os.path.join(datadir, package_file), 42 sandbox=default_temp_directory) 47 sandbox=default_temp_directory, 48 logfile=self.logfile) 43 49 assert 0 # This statement should not be reached 44 50 except CheesecakeError, e: 45 msg = message % os.path.join(default_temp_directory, package_file) 46 msg += pad_msg("CHEESECAKE INDEX", 0) 51 msg = "Could not unpack package %s ... exiting" % \ 52 os.path.join(default_temp_directory, package_file) 53 msg += "\n" + pad_msg("CHEESECAKE INDEX", 0) 54 msg += "\nDetailed info available in log file %s" % self.logfile 47 55 assert str(e) == msg 48 56 57 # If run failed log file should not be deleted. 58 assert os.path.isfile(self.logfile) 59 49 60 def test_index_unpack_invalid_tar_gz(self): 50 self._run_invalid("invalid_package.tar.gz", 51 "Could not read tar file %s ... exiting\n") 61 self._run_invalid("invalid_package.tar.gz") 52 62 53 63 def test_index_unpack_invalid_tgz(self): 54 self._run_invalid("invalid_package.tgz", 55 "Could not read tar file %s ... exiting\n") 64 self._run_invalid("invalid_package.tgz") 56 65 57 66 def test_index_unpack_invalid_zip(self): 58 self._run_invalid("invalid_package.zip", 59 "Error unzipping file %s ... exiting\n") 67 self._run_invalid("invalid_package.zip") branches/mk/tests/test_index_unpack_dir.py
r40 r44 14 14 return 15 15 self.cheesecake.cleanup() 16 os.unlink(self.cheesecake.logfile)17 16 18 17 class TestIndexUnpackDirCorrectPackage(IndexUnpackDirTest): branches/mk/tests/test_index_url_download.py
r40 r44 13 13 14 14 def _run_it(self, test_fun): 15 logfile = tempfile.mktemp() 16 15 17 try: 16 test_fun( )18 test_fun(logfile) 17 19 finally: 18 20 if self.cheesecake: 19 21 self.cheesecake.cleanup() 20 os.unlink(self.cheesecake.logfile)21 22 22 23 def test_index_url_download_valid_url(self): … … 29 30 30 31 for url in urls: 31 def test_fun( ):32 def test_fun(logfile): 32 33 try: 33 self.cheesecake = Cheesecake(url=url )34 self.cheesecake = Cheesecake(url=url, logfile=logfile) 34 35 35 36 index = self.cheesecake.index["INSTALLABILITY"]["url_download"] … … 45 46 msg = "[Errno socket error] (111, 'Connection refused')\n" 46 47 msg += pad_msg("CHEESECAKE INDEX", 0) 48 msg += "\nDetailed info available in log file %s" % logfile 47 49 assert str(e) == msg 48 50 … … 50 52 51 53 def test_index_url_download_invalid_url(self): 52 def test_fun( ):54 def test_fun(logfile): 53 55 try: 54 56 self.cheesecake = Cheesecake(url="http://www.agilistas.org/cheesecake/not_there.tar.gz", 55 sandbox=default_temp_directory )57 sandbox=default_temp_directory, logfile=logfile) 56 58 assert 0 # This statement should not be reached 57 59 except CheesecakeError, e: 58 msg = " Could not read tar file %s ... exiting\n" % \59 os.path.join(default_temp_directory, 'not_there.tar.gz')60 msg += pad_msg("CHEESECAKE INDEX", 0)60 msg = "Got '404 Not Found' error while trying to download package ... exiting" 61 msg += "\n" + pad_msg("CHEESECAKE INDEX", 0) 62 msg += "\nDetailed info available in log file %s" % logfile 61 63 assert str(e) == msg 62 64 branches/mk/tests/test_init_cleanup.py
r40 r44 1 import _path_cheesecake2 from cheesecake.cheesecake_index import Cheesecake3 1 import os 4 2 import shutil 5 3 import tempfile 6 4 5 import _path_cheesecake 6 from cheesecake.cheesecake_index import Cheesecake 7 7 8 datadir = os.path.abspath(os.path.join(os.path.dirname(__file__), "data")) 8 9 9 10 class TestInitCleanup(object): 10 11 11 def tearDown(self): 12 12 if hasattr(self, 'cheesecake'): … … 32 32 assert os.path.isfile(self.logfile) 33 33 34 def test_cleanup(self):35 self.cheesecake = Cheesecake(path=os.path.join(datadir, "package1.tar.gz"))36 self.cheesecake.cleanup()37 assert not os.path.exists(self.cheesecake.sandbox_pkg_dir)38 assert not os.path.exists(self.cheesecake.sandbox_pkg_file)39 assert not os.path.exists(self.cheesecake.sandbox)40 # Log file should not have been deleted41 self.logfile = self.cheesecake.logfile42 assert os.path.isfile(self.logfile)43 44 34 def test_cleanup_after_install(self): 45 35 self.cheesecake = Cheesecake(path=os.path.join(datadir, "package1.tar.gz")) … … 49 39 assert not os.path.exists(self.cheesecake.sandbox_install_dir) 50 40 assert not os.path.exists(self.cheesecake.sandbox) 51 # Log file should not have been deleted52 41 self.logfile = self.cheesecake.logfile 53 assert os.path.isfile(self.logfile)42 assert not os.path.isfile(self.logfile)
