# HG changeset patch # Parent 87c102d0df39a1fdde2d0f7f2de4284121dd44a6 diff -r 87c102d0df39 Doc/library/zipapp.rst --- a/Doc/library/zipapp.rst Mon Mar 16 12:45:27 2015 -0500 +++ b/Doc/library/zipapp.rst Mon Mar 16 21:45:44 2015 +0000 @@ -104,12 +104,13 @@ Create an application archive from *source*. The source can be any of the following: - * The name of a directory, in which case a new application archive - will be created from the content of that directory. - * The name of an existing application archive file, in which case the file is - copied to the target (modifying it to reflect the value given for the - *interpreter* argument). The file name should include the ``.pyz`` - extension, if required. + * The name of a directory, or a :class:`pathlib.Path` object referring + to a directory, in which case a new application archive will be + created from the content of that directory. + * The name of an existing application archive file, or a :class:`pathlib.Path` + object referring to such a file, in which case the file is copied to + the target (modifying it to reflect the value given for the *interpreter* + argument). The file name should include the ``.pyz`` extension, if required. * A file object open for reading in bytes mode. The content of the file should be an application archive, and the file object is assumed to be positioned at the start of the archive. @@ -117,8 +118,8 @@ The *target* argument determines where the resulting archive will be written: - * If it is the name of a file, the archive will be written to that - file. + * If it is the name of a file, or a :class:`pathlb.Path` object, + the archive will be written to that file. * If it is an open file object, the archive will be written to that file object, which must be open for writing in bytes mode. * If the target is omitted (or None), the source must be a directory diff -r 87c102d0df39 Lib/test/test_zipapp.py --- a/Lib/test/test_zipapp.py Mon Mar 16 12:45:27 2015 -0500 +++ b/Lib/test/test_zipapp.py Mon Mar 16 21:45:44 2015 +0000 @@ -28,6 +28,15 @@ zipapp.create_archive(str(source), str(target)) self.assertTrue(target.is_file()) + def test_create_archive_with_pathlib(self): + # Test packing a directory using Path objects for source and target. + source = self.tmpdir / 'source' + source.mkdir() + (source / '__main__.py').touch() + target = self.tmpdir / 'source.pyz' + zipapp.create_archive(source, target) + self.assertTrue(target.is_file()) + def test_create_archive_with_subdirs(self): # Test packing a directory includes entries for subdirectories. source = self.tmpdir / 'source' diff -r 87c102d0df39 Lib/zipapp.py --- a/Lib/zipapp.py Mon Mar 16 12:45:27 2015 -0500 +++ b/Lib/zipapp.py Mon Mar 16 21:45:44 2015 +0000 @@ -36,6 +36,8 @@ @contextlib.contextmanager def _maybe_open(archive, mode): + if isinstance(archive, pathlib.Path): + archive = str(archive) if isinstance(archive, str): with open(archive, mode) as f: yield f @@ -92,12 +94,20 @@ is an error to omit MAIN if the directory has no __main__.py. """ # Are we copying an existing archive? - if not (isinstance(source, str) and os.path.isdir(source)): + source_is_file = False + if hasattr(source, 'read') and hasattr(source, 'readline'): + source_is_file = True + else: + source = pathlib.Path(source) + if source.is_file(): + source_is_file = True + + if source_is_file: _copy_archive(source, target, interpreter) return # We are creating a new archive from a directory. - has_main = os.path.exists(os.path.join(source, '__main__.py')) + has_main = (source / '__main__.py').is_file() if main and has_main: raise ZipAppError( "Cannot specify entry point if the source has __main__.py") @@ -115,7 +125,9 @@ main_py = MAIN_TEMPLATE.format(module=mod, fn=fn) if target is None: - target = source + '.pyz' + target = source.with_suffix('.pyz') + elif not hasattr(target, 'write'): + target = pathlib.Path(target) with _maybe_open(target, 'wb') as fd: _write_file_prefix(fd, interpreter) @@ -127,8 +139,8 @@ if main_py: z.writestr('__main__.py', main_py.encode('utf-8')) - if interpreter and isinstance(target, str): - os.chmod(target, os.stat(target).st_mode | stat.S_IEXEC) + if interpreter and not hasattr(target, 'write'): + target.chmod(target.stat().st_mode | stat.S_IEXEC) def get_interpreter(archive):