From ea649894de07c28eb7a076f987d8af61bf312320 Mon Sep 17 00:00:00 2001 From: Tarek Ziade Date: Thu, 19 May 2011 13:07:25 +0200 Subject: initial import of the packaging package in the standard library --- Lib/packaging/command/build_py.py | 410 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 410 insertions(+) create mode 100644 Lib/packaging/command/build_py.py (limited to 'Lib/packaging/command/build_py.py') diff --git a/Lib/packaging/command/build_py.py b/Lib/packaging/command/build_py.py new file mode 100644 index 0000000000..360f4c96ad --- /dev/null +++ b/Lib/packaging/command/build_py.py @@ -0,0 +1,410 @@ +"""Build pure Python modules (just copy to build directory).""" + +import os +import sys +from glob import glob + +from packaging import logger +from packaging.command.cmd import Command +from packaging.errors import PackagingOptionError, PackagingFileError +from packaging.util import convert_path +from packaging.compat import Mixin2to3 + +# marking public APIs +__all__ = ['build_py'] + +class build_py(Command, Mixin2to3): + + description = "build pure Python modules (copy to build directory)" + + user_options = [ + ('build-lib=', 'd', "directory to build (copy) to"), + ('compile', 'c', "compile .py to .pyc"), + ('no-compile', None, "don't compile .py files [default]"), + ('optimize=', 'O', + "also compile with optimization: -O1 for \"python -O\", " + "-O2 for \"python -OO\", and -O0 to disable [default: -O0]"), + ('force', 'f', "forcibly build everything (ignore file timestamps)"), + ('use-2to3', None, + "use 2to3 to make source python 3.x compatible"), + ('convert-2to3-doctests', None, + "use 2to3 to convert doctests in seperate text files"), + ('use-2to3-fixers', None, + "list additional fixers opted for during 2to3 conversion"), + ] + + boolean_options = ['compile', 'force'] + negative_opt = {'no-compile' : 'compile'} + + def initialize_options(self): + self.build_lib = None + self.py_modules = None + self.package = None + self.package_data = None + self.package_dir = None + self.compile = False + self.optimize = 0 + self.force = None + self._updated_files = [] + self._doctests_2to3 = [] + self.use_2to3 = False + self.convert_2to3_doctests = None + self.use_2to3_fixers = None + + def finalize_options(self): + self.set_undefined_options('build', + 'use_2to3', 'use_2to3_fixers', + 'convert_2to3_doctests', 'build_lib', + 'force') + + # Get the distribution options that are aliases for build_py + # options -- list of packages and list of modules. + self.packages = self.distribution.packages + self.py_modules = self.distribution.py_modules + self.package_data = self.distribution.package_data + self.package_dir = None + if self.distribution.package_dir is not None: + self.package_dir = convert_path(self.distribution.package_dir) + self.data_files = self.get_data_files() + + # Ick, copied straight from install_lib.py (fancy_getopt needs a + # type system! Hell, *everything* needs a type system!!!) + if not isinstance(self.optimize, int): + try: + self.optimize = int(self.optimize) + assert 0 <= self.optimize <= 2 + except (ValueError, AssertionError): + raise PackagingOptionError("optimize must be 0, 1, or 2") + + def run(self): + # XXX copy_file by default preserves atime and mtime. IMHO this is + # the right thing to do, but perhaps it should be an option -- in + # particular, a site administrator might want installed files to + # reflect the time of installation rather than the last + # modification time before the installed release. + + # XXX copy_file by default preserves mode, which appears to be the + # wrong thing to do: if a file is read-only in the working + # directory, we want it to be installed read/write so that the next + # installation of the same module distribution can overwrite it + # without problems. (This might be a Unix-specific issue.) Thus + # we turn off 'preserve_mode' when copying to the build directory, + # since the build directory is supposed to be exactly what the + # installation will look like (ie. we preserve mode when + # installing). + + # Two options control which modules will be installed: 'packages' + # and 'py_modules'. The former lets us work with whole packages, not + # specifying individual modules at all; the latter is for + # specifying modules one-at-a-time. + + if self.py_modules: + self.build_modules() + if self.packages: + self.build_packages() + self.build_package_data() + + if self.use_2to3 and self._updated_files: + self.run_2to3(self._updated_files, self._doctests_2to3, + self.use_2to3_fixers) + + self.byte_compile(self.get_outputs(include_bytecode=False)) + + # -- Top-level worker functions ------------------------------------ + + def get_data_files(self): + """Generate list of '(package,src_dir,build_dir,filenames)' tuples. + + Helper function for `finalize_options()`. + """ + data = [] + if not self.packages: + return data + for package in self.packages: + # Locate package source directory + src_dir = self.get_package_dir(package) + + # Compute package build directory + build_dir = os.path.join(*([self.build_lib] + package.split('.'))) + + # Length of path to strip from found files + plen = 0 + if src_dir: + plen = len(src_dir)+1 + + # Strip directory from globbed filenames + filenames = [ + file[plen:] for file in self.find_data_files(package, src_dir) + ] + data.append((package, src_dir, build_dir, filenames)) + return data + + def find_data_files(self, package, src_dir): + """Return filenames for package's data files in 'src_dir'. + + Helper function for `get_data_files()`. + """ + globs = (self.package_data.get('', []) + + self.package_data.get(package, [])) + files = [] + for pattern in globs: + # Each pattern has to be converted to a platform-specific path + filelist = glob(os.path.join(src_dir, convert_path(pattern))) + # Files that match more than one pattern are only added once + files.extend(fn for fn in filelist if fn not in files) + return files + + def build_package_data(self): + """Copy data files into build directory. + + Helper function for `run()`. + """ + # FIXME add tests for this method + for package, src_dir, build_dir, filenames in self.data_files: + for filename in filenames: + target = os.path.join(build_dir, filename) + srcfile = os.path.join(src_dir, filename) + self.mkpath(os.path.dirname(target)) + outf, copied = self.copy_file(srcfile, + target, preserve_mode=False) + if copied and srcfile in self.distribution.convert_2to3.doctests: + self._doctests_2to3.append(outf) + + # XXX - this should be moved to the Distribution class as it is not + # only needed for build_py. It also has no dependencies on this class. + def get_package_dir(self, package): + """Return the directory, relative to the top of the source + distribution, where package 'package' should be found + (at least according to the 'package_dir' option, if any).""" + + path = package.split('.') + if self.package_dir is not None: + path.insert(0, self.package_dir) + + if len(path) > 0: + return os.path.join(*path) + + return '' + + def check_package(self, package, package_dir): + """Helper function for `find_package_modules()` and `find_modules()'. + """ + # Empty dir name means current directory, which we can probably + # assume exists. Also, os.path.exists and isdir don't know about + # my "empty string means current dir" convention, so we have to + # circumvent them. + if package_dir != "": + if not os.path.exists(package_dir): + raise PackagingFileError( + "package directory '%s' does not exist" % package_dir) + if not os.path.isdir(package_dir): + raise PackagingFileError( + "supposed package directory '%s' exists, " + "but is not a directory" % package_dir) + + # Require __init__.py for all but the "root package" + if package: + init_py = os.path.join(package_dir, "__init__.py") + if os.path.isfile(init_py): + return init_py + else: + logger.warning(("package init file '%s' not found " + + "(or not a regular file)"), init_py) + + # Either not in a package at all (__init__.py not expected), or + # __init__.py doesn't exist -- so don't return the filename. + return None + + def check_module(self, module, module_file): + if not os.path.isfile(module_file): + logger.warning("file %s (for module %s) not found", + module_file, module) + return False + else: + return True + + def find_package_modules(self, package, package_dir): + self.check_package(package, package_dir) + module_files = glob(os.path.join(package_dir, "*.py")) + modules = [] + if self.distribution.script_name is not None: + setup_script = os.path.abspath(self.distribution.script_name) + else: + setup_script = None + + for f in module_files: + abs_f = os.path.abspath(f) + if abs_f != setup_script: + module = os.path.splitext(os.path.basename(f))[0] + modules.append((package, module, f)) + else: + logger.debug("excluding %s", setup_script) + return modules + + def find_modules(self): + """Finds individually-specified Python modules, ie. those listed by + module name in 'self.py_modules'. Returns a list of tuples (package, + module_base, filename): 'package' is a tuple of the path through + package-space to the module; 'module_base' is the bare (no + packages, no dots) module name, and 'filename' is the path to the + ".py" file (relative to the distribution root) that implements the + module. + """ + # Map package names to tuples of useful info about the package: + # (package_dir, checked) + # package_dir - the directory where we'll find source files for + # this package + # checked - true if we have checked that the package directory + # is valid (exists, contains __init__.py, ... ?) + packages = {} + + # List of (package, module, filename) tuples to return + modules = [] + + # We treat modules-in-packages almost the same as toplevel modules, + # just the "package" for a toplevel is empty (either an empty + # string or empty list, depending on context). Differences: + # - don't check for __init__.py in directory for empty package + for module in self.py_modules: + path = module.split('.') + package = '.'.join(path[0:-1]) + module_base = path[-1] + + try: + package_dir, checked = packages[package] + except KeyError: + package_dir = self.get_package_dir(package) + checked = False + + if not checked: + init_py = self.check_package(package, package_dir) + packages[package] = (package_dir, 1) + if init_py: + modules.append((package, "__init__", init_py)) + + # XXX perhaps we should also check for just .pyc files + # (so greedy closed-source bastards can distribute Python + # modules too) + module_file = os.path.join(package_dir, module_base + ".py") + if not self.check_module(module, module_file): + continue + + modules.append((package, module_base, module_file)) + + return modules + + def find_all_modules(self): + """Compute the list of all modules that will be built, whether + they are specified one-module-at-a-time ('self.py_modules') or + by whole packages ('self.packages'). Return a list of tuples + (package, module, module_file), just like 'find_modules()' and + 'find_package_modules()' do.""" + modules = [] + if self.py_modules: + modules.extend(self.find_modules()) + if self.packages: + for package in self.packages: + package_dir = self.get_package_dir(package) + m = self.find_package_modules(package, package_dir) + modules.extend(m) + return modules + + def get_source_files(self): + sources = [module[-1] for module in self.find_all_modules()] + sources += [ + os.path.join(src_dir, filename) + for package, src_dir, build_dir, filenames in self.data_files + for filename in filenames] + return sources + + def get_module_outfile(self, build_dir, package, module): + outfile_path = [build_dir] + list(package) + [module + ".py"] + return os.path.join(*outfile_path) + + def get_outputs(self, include_bytecode=True): + modules = self.find_all_modules() + outputs = [] + for package, module, module_file in modules: + package = package.split('.') + filename = self.get_module_outfile(self.build_lib, package, module) + outputs.append(filename) + if include_bytecode: + if self.compile: + outputs.append(filename + "c") + if self.optimize > 0: + outputs.append(filename + "o") + + outputs += [ + os.path.join(build_dir, filename) + for package, src_dir, build_dir, filenames in self.data_files + for filename in filenames] + + return outputs + + def build_module(self, module, module_file, package): + if isinstance(package, str): + package = package.split('.') + elif not isinstance(package, (list, tuple)): + raise TypeError( + "'package' must be a string (dot-separated), list, or tuple") + + # Now put the module source file into the "build" area -- this is + # easy, we just copy it somewhere under self.build_lib (the build + # directory for Python source). + outfile = self.get_module_outfile(self.build_lib, package, module) + dir = os.path.dirname(outfile) + self.mkpath(dir) + return self.copy_file(module_file, outfile, preserve_mode=False) + + def build_modules(self): + modules = self.find_modules() + for package, module, module_file in modules: + + # Now "build" the module -- ie. copy the source file to + # self.build_lib (the build directory for Python source). + # (Actually, it gets copied to the directory for this package + # under self.build_lib.) + self.build_module(module, module_file, package) + + def build_packages(self): + for package in self.packages: + + # Get list of (package, module, module_file) tuples based on + # scanning the package directory. 'package' is only included + # in the tuple so that 'find_modules()' and + # 'find_package_tuples()' have a consistent interface; it's + # ignored here (apart from a sanity check). Also, 'module' is + # the *unqualified* module name (ie. no dots, no package -- we + # already know its package!), and 'module_file' is the path to + # the .py file, relative to the current directory + # (ie. including 'package_dir'). + package_dir = self.get_package_dir(package) + modules = self.find_package_modules(package, package_dir) + + # Now loop over the modules we found, "building" each one (just + # copy it to self.build_lib). + for package_, module, module_file in modules: + assert package == package_ + self.build_module(module, module_file, package) + + def byte_compile(self, files): + if hasattr(sys, 'dont_write_bytecode') and sys.dont_write_bytecode: + logger.warning('%s: byte-compiling is disabled, skipping.', + self.get_command_name()) + return + + from packaging.util import byte_compile + prefix = self.build_lib + if prefix[-1] != os.sep: + prefix = prefix + os.sep + + # XXX this code is essentially the same as the 'byte_compile() + # method of the "install_lib" command, except for the determination + # of the 'prefix' string. Hmmm. + + if self.compile: + byte_compile(files, optimize=0, + force=self.force, prefix=prefix, dry_run=self.dry_run) + if self.optimize > 0: + byte_compile(files, optimize=self.optimize, + force=self.force, prefix=prefix, dry_run=self.dry_run) -- cgit v1.2.1 From 1bbddaf95a3e3c81a2024496a3db6b81811d48a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Araujo?= Date: Thu, 1 Sep 2011 05:11:29 +0200 Subject: Clean up packaging.util: add __all__, remove some unused functions. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This huge module is the heir of six distutils modules, and contains a number of miscellaneous functions. I have attempted to help readers of the source code with an annoted __all__. Removed or deprecated functions have been removed from the documentation; I’m working on another patch to document the remaining public functions. For the curious: The unzip_file and untar_file were used by (or intended to be used by) “pysetup install path/to/archive.tar.gz”, but the code presently used shutil.unpack_archive and an helper function, so I just deleted them. They’re still in the repository if we need them in the future. The find_packages function is not used anymore but I want to discuss module and package auto-discovery (in “pysetup create”) again before removing it. subst_vars now lives in sysconfig; rfc822_escape is inlined in packaging.metadata. Other functions are for internal use only, or deprecated; I have left them out of __all__ and sprinkled TODO notes for future cleanups. --- Lib/packaging/command/build_py.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Lib/packaging/command/build_py.py') diff --git a/Lib/packaging/command/build_py.py b/Lib/packaging/command/build_py.py index 360f4c96ad..7baa6e46a0 100644 --- a/Lib/packaging/command/build_py.py +++ b/Lib/packaging/command/build_py.py @@ -393,7 +393,7 @@ class build_py(Command, Mixin2to3): self.get_command_name()) return - from packaging.util import byte_compile + from packaging.util import byte_compile # FIXME use compileall prefix = self.build_lib if prefix[-1] != os.sep: prefix = prefix + os.sep -- cgit v1.2.1 From cf94d362a3726b4a636210a6a250214eab4969e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Araujo?= Date: Sat, 17 Sep 2011 03:31:51 +0200 Subject: Packaging cleanup: remove conditionals for < 2.6 support. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PEP 370 features and sys.dont_write_bytecode are always available in 3.3; the distutils2 backport still has the conditionals. I also renamed an internal misnamed method and fixed a few things (“packaging2” name, stray print, unused import, fd leak). --- Lib/packaging/command/build_py.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Lib/packaging/command/build_py.py') diff --git a/Lib/packaging/command/build_py.py b/Lib/packaging/command/build_py.py index 7baa6e46a0..0eafffa3ae 100644 --- a/Lib/packaging/command/build_py.py +++ b/Lib/packaging/command/build_py.py @@ -388,7 +388,7 @@ class build_py(Command, Mixin2to3): self.build_module(module, module_file, package) def byte_compile(self, files): - if hasattr(sys, 'dont_write_bytecode') and sys.dont_write_bytecode: + if sys.dont_write_bytecode: logger.warning('%s: byte-compiling is disabled, skipping.', self.get_command_name()) return -- cgit v1.2.1 From 60dbff8a0e3234a078a2c2c2882608bb9c47a68c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Araujo?= Date: Wed, 19 Oct 2011 08:18:05 +0200 Subject: More fixes for PEP 3147 compliance in packaging (#11254) --- Lib/packaging/command/build_py.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'Lib/packaging/command/build_py.py') diff --git a/Lib/packaging/command/build_py.py b/Lib/packaging/command/build_py.py index 0eafffa3ae..e5b10b0048 100644 --- a/Lib/packaging/command/build_py.py +++ b/Lib/packaging/command/build_py.py @@ -1,6 +1,7 @@ """Build pure Python modules (just copy to build directory).""" import os +import imp import sys from glob import glob @@ -330,9 +331,10 @@ class build_py(Command, Mixin2to3): outputs.append(filename) if include_bytecode: if self.compile: - outputs.append(filename + "c") + outputs.append(imp.cache_from_source(filename)) if self.optimize > 0: - outputs.append(filename + "o") + outputs.append(imp.cache_from_source(filename, + debug_override=False)) outputs += [ os.path.join(build_dir, filename) -- cgit v1.2.1 From 0d58ff9f2bbacc3207c141d188fcb955ef1c0fb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Araujo?= Date: Thu, 3 Nov 2011 00:13:05 +0100 Subject: =?UTF-8?q?Fix=20typo=20=E2=80=9Cseperate=E2=80=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Lib/packaging/command/build_py.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Lib/packaging/command/build_py.py') diff --git a/Lib/packaging/command/build_py.py b/Lib/packaging/command/build_py.py index e5b10b0048..02482134d0 100644 --- a/Lib/packaging/command/build_py.py +++ b/Lib/packaging/command/build_py.py @@ -29,7 +29,7 @@ class build_py(Command, Mixin2to3): ('use-2to3', None, "use 2to3 to make source python 3.x compatible"), ('convert-2to3-doctests', None, - "use 2to3 to convert doctests in seperate text files"), + "use 2to3 to convert doctests in separate text files"), ('use-2to3-fixers', None, "list additional fixers opted for during 2to3 conversion"), ] -- cgit v1.2.1 From 15375554c6034cf5120d254403c43c62f1f7a670 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Araujo?= Date: Thu, 3 Nov 2011 05:08:28 +0100 Subject: Improve byte-compilation in packaging to be independent of -O or -B. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The code I fixed to comply with PEP 3147 still had one bug: When run under python -O, some paths for pyc files would be pyo, because I called imp.cache_from_source without explicit debug_override argument in some places, and under -O that would return .pyo (this is well explained in the imp docs). Now all code (util.byte_compile, build_py, install_lib) can create .pyo files according to options given by users, without interference from the calling Python’s own optimize mode. On a related topic, I also removed the code that prevented byte compilation under python -B. The rationale is that packaging gives control over the creation of pyc files to the user with its own explicit option, and the behavior should not be changed if the calling Python happens to run with -B for whatever reason. I will argue that this is a bug fix and ask to be allowed to backport this change to distutils. Finally, I moved one nugget of information about the --compile and --optimize options from the source into the doc. It clears up a misunderstanding that I (and maybe other people) had. --- Lib/packaging/command/build_py.py | 47 ++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 25 deletions(-) (limited to 'Lib/packaging/command/build_py.py') diff --git a/Lib/packaging/command/build_py.py b/Lib/packaging/command/build_py.py index 02482134d0..5faae39f51 100644 --- a/Lib/packaging/command/build_py.py +++ b/Lib/packaging/command/build_py.py @@ -2,7 +2,6 @@ import os import imp -import sys from glob import glob from packaging import logger @@ -14,10 +13,14 @@ from packaging.compat import Mixin2to3 # marking public APIs __all__ = ['build_py'] + class build_py(Command, Mixin2to3): description = "build pure Python modules (copy to build directory)" + # The options for controlling byte compilations are two independent sets; + # more info in install_lib or the reST docs + user_options = [ ('build-lib=', 'd', "directory to build (copy) to"), ('compile', 'c', "compile .py to .pyc"), @@ -35,7 +38,8 @@ class build_py(Command, Mixin2to3): ] boolean_options = ['compile', 'force'] - negative_opt = {'no-compile' : 'compile'} + + negative_opt = {'no-compile': 'compile'} def initialize_options(self): self.build_lib = None @@ -116,7 +120,7 @@ class build_py(Command, Mixin2to3): def get_data_files(self): """Generate list of '(package,src_dir,build_dir,filenames)' tuples. - Helper function for `finalize_options()`. + Helper function for finalize_options. """ data = [] if not self.packages: @@ -131,7 +135,7 @@ class build_py(Command, Mixin2to3): # Length of path to strip from found files plen = 0 if src_dir: - plen = len(src_dir)+1 + plen = len(src_dir) + 1 # Strip directory from globbed filenames filenames = [ @@ -143,7 +147,7 @@ class build_py(Command, Mixin2to3): def find_data_files(self, package, src_dir): """Return filenames for package's data files in 'src_dir'. - Helper function for `get_data_files()`. + Helper function for get_data_files. """ globs = (self.package_data.get('', []) + self.package_data.get(package, [])) @@ -158,7 +162,7 @@ class build_py(Command, Mixin2to3): def build_package_data(self): """Copy data files into build directory. - Helper function for `run()`. + Helper function for run. """ # FIXME add tests for this method for package, src_dir, build_dir, filenames in self.data_files: @@ -168,16 +172,17 @@ class build_py(Command, Mixin2to3): self.mkpath(os.path.dirname(target)) outf, copied = self.copy_file(srcfile, target, preserve_mode=False) - if copied and srcfile in self.distribution.convert_2to3.doctests: + doctests = self.distribution.convert_2to3_doctests + if copied and srcfile in doctests: self._doctests_2to3.append(outf) # XXX - this should be moved to the Distribution class as it is not # only needed for build_py. It also has no dependencies on this class. def get_package_dir(self, package): """Return the directory, relative to the top of the source - distribution, where package 'package' should be found - (at least according to the 'package_dir' option, if any).""" - + distribution, where package 'package' should be found + (at least according to the 'package_dir' option, if any). + """ path = package.split('.') if self.package_dir is not None: path.insert(0, self.package_dir) @@ -188,8 +193,7 @@ class build_py(Command, Mixin2to3): return '' def check_package(self, package, package_dir): - """Helper function for `find_package_modules()` and `find_modules()'. - """ + """Helper function for find_package_modules and find_modules.""" # Empty dir name means current directory, which we can probably # assume exists. Also, os.path.exists and isdir don't know about # my "empty string means current dir" convention, so we have to @@ -209,8 +213,8 @@ class build_py(Command, Mixin2to3): if os.path.isfile(init_py): return init_py else: - logger.warning(("package init file '%s' not found " + - "(or not a regular file)"), init_py) + logger.warning("package init file %r not found " + "(or not a regular file)", init_py) # Either not in a package at all (__init__.py not expected), or # __init__.py doesn't exist -- so don't return the filename. @@ -218,7 +222,7 @@ class build_py(Command, Mixin2to3): def check_module(self, module, module_file): if not os.path.isfile(module_file): - logger.warning("file %s (for module %s) not found", + logger.warning("file %r (for module %r) not found", module_file, module) return False else: @@ -239,7 +243,7 @@ class build_py(Command, Mixin2to3): module = os.path.splitext(os.path.basename(f))[0] modules.append((package, module, f)) else: - logger.debug("excluding %s", setup_script) + logger.debug("excluding %r", setup_script) return modules def find_modules(self): @@ -331,7 +335,8 @@ class build_py(Command, Mixin2to3): outputs.append(filename) if include_bytecode: if self.compile: - outputs.append(imp.cache_from_source(filename)) + outputs.append(imp.cache_from_source(filename, + debug_override=True)) if self.optimize > 0: outputs.append(imp.cache_from_source(filename, debug_override=False)) @@ -361,7 +366,6 @@ class build_py(Command, Mixin2to3): def build_modules(self): modules = self.find_modules() for package, module, module_file in modules: - # Now "build" the module -- ie. copy the source file to # self.build_lib (the build directory for Python source). # (Actually, it gets copied to the directory for this package @@ -370,7 +374,6 @@ class build_py(Command, Mixin2to3): def build_packages(self): for package in self.packages: - # Get list of (package, module, module_file) tuples based on # scanning the package directory. 'package' is only included # in the tuple so that 'find_modules()' and @@ -390,11 +393,6 @@ class build_py(Command, Mixin2to3): self.build_module(module, module_file, package) def byte_compile(self, files): - if sys.dont_write_bytecode: - logger.warning('%s: byte-compiling is disabled, skipping.', - self.get_command_name()) - return - from packaging.util import byte_compile # FIXME use compileall prefix = self.build_lib if prefix[-1] != os.sep: @@ -403,7 +401,6 @@ class build_py(Command, Mixin2to3): # XXX this code is essentially the same as the 'byte_compile() # method of the "install_lib" command, except for the determination # of the 'prefix' string. Hmmm. - if self.compile: byte_compile(files, optimize=0, force=self.force, prefix=prefix, dry_run=self.dry_run) -- cgit v1.2.1 From 8e92ee0e28ca442e05defef631b5f158b07498e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Araujo?= Date: Mon, 14 Nov 2011 18:10:19 +0100 Subject: Clean up byte-compilation code in packaging (#11254 followup). MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Don't use keyword arguments for debug_override; I find it more readable to have a comment explaining that True makes pyc and False pyo than to write out the non-obvious (when you haven’t read the doc) argument name - Move duplicate code from build_py and install_lib into cmd - Remove obsolete verbose argument of util.byte_compile - Remove obsolete passing of -O/-OO to the Python process spawned by util.byte_compile (I’ll remove the whole spawning later, after I write more tests to check the contents of pyc and pyo files; now that byte_compile does not depend on the value of __debug__ in the calling Python, we can call py_compile or compileall directly) --- Lib/packaging/command/build_py.py | 29 ++++++----------------------- 1 file changed, 6 insertions(+), 23 deletions(-) (limited to 'Lib/packaging/command/build_py.py') diff --git a/Lib/packaging/command/build_py.py b/Lib/packaging/command/build_py.py index 5faae39f51..00621400da 100644 --- a/Lib/packaging/command/build_py.py +++ b/Lib/packaging/command/build_py.py @@ -18,7 +18,7 @@ class build_py(Command, Mixin2to3): description = "build pure Python modules (copy to build directory)" - # The options for controlling byte compilations are two independent sets; + # The options for controlling byte compilation are two independent sets; # more info in install_lib or the reST docs user_options = [ @@ -113,7 +113,8 @@ class build_py(Command, Mixin2to3): self.run_2to3(self._updated_files, self._doctests_2to3, self.use_2to3_fixers) - self.byte_compile(self.get_outputs(include_bytecode=False)) + self.byte_compile(self.get_outputs(include_bytecode=False), + prefix=self.build_lib) # -- Top-level worker functions ------------------------------------ @@ -335,11 +336,9 @@ class build_py(Command, Mixin2to3): outputs.append(filename) if include_bytecode: if self.compile: - outputs.append(imp.cache_from_source(filename, - debug_override=True)) - if self.optimize > 0: - outputs.append(imp.cache_from_source(filename, - debug_override=False)) + outputs.append(imp.cache_from_source(filename, True)) + if self.optimize: + outputs.append(imp.cache_from_source(filename, False)) outputs += [ os.path.join(build_dir, filename) @@ -391,19 +390,3 @@ class build_py(Command, Mixin2to3): for package_, module, module_file in modules: assert package == package_ self.build_module(module, module_file, package) - - def byte_compile(self, files): - from packaging.util import byte_compile # FIXME use compileall - prefix = self.build_lib - if prefix[-1] != os.sep: - prefix = prefix + os.sep - - # XXX this code is essentially the same as the 'byte_compile() - # method of the "install_lib" command, except for the determination - # of the 'prefix' string. Hmmm. - if self.compile: - byte_compile(files, optimize=0, - force=self.force, prefix=prefix, dry_run=self.dry_run) - if self.optimize > 0: - byte_compile(files, optimize=self.optimize, - force=self.force, prefix=prefix, dry_run=self.dry_run) -- cgit v1.2.1