+++ /dev/null
-"""Routine to "compile" a .py file to a .pyc (or .pyo) file.\r
-\r
-This module has intimate knowledge of the format of .pyc files.\r
-"""\r
-\r
-import __builtin__\r
-import imp\r
-import marshal\r
-import os\r
-import sys\r
-import traceback\r
-\r
-MAGIC = imp.get_magic()\r
-\r
-__all__ = ["compile", "main", "PyCompileError"]\r
-\r
-\r
-class PyCompileError(Exception):\r
- """Exception raised when an error occurs while attempting to\r
- compile the file.\r
-\r
- To raise this exception, use\r
-\r
- raise PyCompileError(exc_type,exc_value,file[,msg])\r
-\r
- where\r
-\r
- exc_type: exception type to be used in error message\r
- type name can be accesses as class variable\r
- 'exc_type_name'\r
-\r
- exc_value: exception value to be used in error message\r
- can be accesses as class variable 'exc_value'\r
-\r
- file: name of file being compiled to be used in error message\r
- can be accesses as class variable 'file'\r
-\r
- msg: string message to be written as error message\r
- If no value is given, a default exception message will be given,\r
- consistent with 'standard' py_compile output.\r
- message (or default) can be accesses as class variable 'msg'\r
-\r
- """\r
-\r
- def __init__(self, exc_type, exc_value, file, msg=''):\r
- exc_type_name = exc_type.__name__\r
- if exc_type is SyntaxError:\r
- tbtext = ''.join(traceback.format_exception_only(exc_type, exc_value))\r
- errmsg = tbtext.replace('File "<string>"', 'File "%s"' % file)\r
- else:\r
- errmsg = "Sorry: %s: %s" % (exc_type_name,exc_value)\r
-\r
- Exception.__init__(self,msg or errmsg,exc_type_name,exc_value,file)\r
-\r
- self.exc_type_name = exc_type_name\r
- self.exc_value = exc_value\r
- self.file = file\r
- self.msg = msg or errmsg\r
-\r
- def __str__(self):\r
- return self.msg\r
-\r
-\r
-def wr_long(f, x):\r
- """Internal; write a 32-bit int to a file in little-endian order."""\r
- f.write(chr( x & 0xff))\r
- f.write(chr((x >> 8) & 0xff))\r
- f.write(chr((x >> 16) & 0xff))\r
- f.write(chr((x >> 24) & 0xff))\r
-\r
-def compile(file, cfile=None, dfile=None, doraise=False):\r
- """Byte-compile one Python source file to Python bytecode.\r
-\r
- Arguments:\r
-\r
- file: source filename\r
- cfile: target filename; defaults to source with 'c' or 'o' appended\r
- ('c' normally, 'o' in optimizing mode, giving .pyc or .pyo)\r
- dfile: purported filename; defaults to source (this is the filename\r
- that will show up in error messages)\r
- doraise: flag indicating whether or not an exception should be\r
- raised when a compile error is found. If an exception\r
- occurs and this flag is set to False, a string\r
- indicating the nature of the exception will be printed,\r
- and the function will return to the caller. If an\r
- exception occurs and this flag is set to True, a\r
- PyCompileError exception will be raised.\r
-\r
- Note that it isn't necessary to byte-compile Python modules for\r
- execution efficiency -- Python itself byte-compiles a module when\r
- it is loaded, and if it can, writes out the bytecode to the\r
- corresponding .pyc (or .pyo) file.\r
-\r
- However, if a Python installation is shared between users, it is a\r
- good idea to byte-compile all modules upon installation, since\r
- other users may not be able to write in the source directories,\r
- and thus they won't be able to write the .pyc/.pyo file, and then\r
- they would be byte-compiling every module each time it is loaded.\r
- This can slow down program start-up considerably.\r
-\r
- See compileall.py for a script/module that uses this module to\r
- byte-compile all installed files (or all files in selected\r
- directories).\r
-\r
- """\r
- with open(file, 'U') as f:\r
- try:\r
- timestamp = long(os.fstat(f.fileno()).st_mtime)\r
- except AttributeError:\r
- timestamp = long(os.stat(file).st_mtime)\r
- codestring = f.read()\r
- try:\r
- codeobject = __builtin__.compile(codestring, dfile or file,'exec')\r
- except Exception,err:\r
- py_exc = PyCompileError(err.__class__,err.args,dfile or file)\r
- if doraise:\r
- raise py_exc\r
- else:\r
- sys.stderr.write(py_exc.msg + '\n')\r
- return\r
- if cfile is None:\r
- cfile = file + (__debug__ and 'c' or 'o')\r
- with open(cfile, 'wb') as fc:\r
- fc.write('\0\0\0\0')\r
- wr_long(fc, timestamp)\r
- marshal.dump(codeobject, fc)\r
- fc.flush()\r
- fc.seek(0, 0)\r
- fc.write(MAGIC)\r
-\r
-def main(args=None):\r
- """Compile several source files.\r
-\r
- The files named in 'args' (or on the command line, if 'args' is\r
- not specified) are compiled and the resulting bytecode is cached\r
- in the normal manner. This function does not search a directory\r
- structure to locate source files; it only compiles files named\r
- explicitly. If '-' is the only parameter in args, the list of\r
- files is taken from standard input.\r
-\r
- """\r
- if args is None:\r
- args = sys.argv[1:]\r
- rv = 0\r
- if args == ['-']:\r
- while True:\r
- filename = sys.stdin.readline()\r
- if not filename:\r
- break\r
- filename = filename.rstrip('\n')\r
- try:\r
- compile(filename, doraise=True)\r
- except PyCompileError as error:\r
- rv = 1\r
- sys.stderr.write("%s\n" % error.msg)\r
- except IOError as error:\r
- rv = 1\r
- sys.stderr.write("%s\n" % error)\r
- else:\r
- for filename in args:\r
- try:\r
- compile(filename, doraise=True)\r
- except PyCompileError as error:\r
- # return value to indicate at least one failure\r
- rv = 1\r
- sys.stderr.write(error.msg)\r
- return rv\r
-\r
-if __name__ == "__main__":\r
- sys.exit(main())\r