From 2a6b0f77f74a1f243737f6d4ad7bc91822f6a94f Mon Sep 17 00:00:00 2001 From: Emma Harper Smith Date: Tue, 15 Apr 2025 19:14:33 -0700 Subject: [PATCH 1/7] Introduce `compression` package This commit introduces the `compression` package, specified in PEP 784 to re-export the `lzma`, `bz2`, `gzip`, and `zlib` modules. Introduction of `compression.zstd` will be completed in a future commit once the `_zstd` module is merged. This commit also moves the `_compression` private module to `compression._common.streams`. --- Lib/bz2.py | 8 ++++---- .../_common/streams.py} | 2 +- Lib/compression/bz2/__init__.py | 6 ++++++ Lib/compression/gzip/__init__.py | 6 ++++++ Lib/compression/lzma/__init__.py | 6 ++++++ Lib/compression/zlib/__init__.py | 6 ++++++ Lib/gzip.py | 6 +++--- Lib/lzma.py | 6 +++--- Lib/test/test_bz2.py | 10 +++++----- Lib/test/test_lzma.py | 10 +++++----- 10 files changed, 45 insertions(+), 21 deletions(-) rename Lib/{_compression.py => compression/_common/streams.py} (98%) create mode 100644 Lib/compression/bz2/__init__.py create mode 100644 Lib/compression/gzip/__init__.py create mode 100644 Lib/compression/lzma/__init__.py create mode 100644 Lib/compression/zlib/__init__.py diff --git a/Lib/bz2.py b/Lib/bz2.py index 2420cd019069b4..8d4f365607ad7d 100644 --- a/Lib/bz2.py +++ b/Lib/bz2.py @@ -12,7 +12,7 @@ from builtins import open as _builtin_open import io import os -import _compression +from compression._common import streams from _bz2 import BZ2Compressor, BZ2Decompressor @@ -23,7 +23,7 @@ _MODE_WRITE = 3 -class BZ2File(_compression.BaseStream): +class BZ2File(streams.BaseStream): """A file object providing transparent bzip2 (de)compression. @@ -88,7 +88,7 @@ def __init__(self, filename, mode="r", *, compresslevel=9): raise TypeError("filename must be a str, bytes, file or PathLike object") if self._mode == _MODE_READ: - raw = _compression.DecompressReader(self._fp, + raw = streams.DecompressReader(self._fp, BZ2Decompressor, trailing_error=OSError) self._buffer = io.BufferedReader(raw) else: @@ -248,7 +248,7 @@ def writelines(self, seq): Line separators are not added between the written byte strings. """ - return _compression.BaseStream.writelines(self, seq) + return streams.BaseStream.writelines(self, seq) def seek(self, offset, whence=io.SEEK_SET): """Change the file position. diff --git a/Lib/_compression.py b/Lib/compression/_common/streams.py similarity index 98% rename from Lib/_compression.py rename to Lib/compression/_common/streams.py index e8b70aa0a3e680..9f367d4e30440f 100644 --- a/Lib/_compression.py +++ b/Lib/compression/_common/streams.py @@ -1,4 +1,4 @@ -"""Internal classes used by the gzip, lzma and bz2 modules""" +"""Internal classes used by compression modules""" import io import sys diff --git a/Lib/compression/bz2/__init__.py b/Lib/compression/bz2/__init__.py new file mode 100644 index 00000000000000..76c9a50baa4b17 --- /dev/null +++ b/Lib/compression/bz2/__init__.py @@ -0,0 +1,6 @@ +"""Module re-exporting contents of the bz2 module. + +Please refer to the bz2 documentation for this module's contents. +""" + +from bz2 import * diff --git a/Lib/compression/gzip/__init__.py b/Lib/compression/gzip/__init__.py new file mode 100644 index 00000000000000..7c0f559627b4dc --- /dev/null +++ b/Lib/compression/gzip/__init__.py @@ -0,0 +1,6 @@ +"""Module re-exporting contents of the gzip module. + +Please refer to the gzip documentation for this module's contents. +""" + +from gzip import * diff --git a/Lib/compression/lzma/__init__.py b/Lib/compression/lzma/__init__.py new file mode 100644 index 00000000000000..d0a24163e3fb0d --- /dev/null +++ b/Lib/compression/lzma/__init__.py @@ -0,0 +1,6 @@ +"""Module re-exporting contents of the lzma module. + +Please refer to the lzma documentation for this module's contents. +""" + +from lzma import * diff --git a/Lib/compression/zlib/__init__.py b/Lib/compression/zlib/__init__.py new file mode 100644 index 00000000000000..a4d52f2019d40f --- /dev/null +++ b/Lib/compression/zlib/__init__.py @@ -0,0 +1,6 @@ +"""Module re-exporting contents of the zlib module. + +Please refer to the bz2 documentation for this module's contents. +""" + +from zlib import * diff --git a/Lib/gzip.py b/Lib/gzip.py index 2a6eea1b3939b7..c362f51bd888f9 100644 --- a/Lib/gzip.py +++ b/Lib/gzip.py @@ -5,7 +5,6 @@ # based on Andrew Kuchling's minigzip.py distributed with the zlib module -import _compression import builtins import io import os @@ -14,6 +13,7 @@ import time import weakref import zlib +from compression._common import streams __all__ = ["BadGzipFile", "GzipFile", "open", "compress", "decompress"] @@ -144,7 +144,7 @@ def writable(self): return True -class GzipFile(_compression.BaseStream): +class GzipFile(streams.BaseStream): """The GzipFile class simulates most of the methods of a file object with the exception of the truncate() method. @@ -523,7 +523,7 @@ def _read_gzip_header(fp): return last_mtime -class _GzipReader(_compression.DecompressReader): +class _GzipReader(streams.DecompressReader): def __init__(self, fp): super().__init__(_PaddedFile(fp), zlib._ZlibDecompressor, wbits=-zlib.MAX_WBITS) diff --git a/Lib/lzma.py b/Lib/lzma.py index 946066aa0fba56..7fe93c4d9a06d8 100644 --- a/Lib/lzma.py +++ b/Lib/lzma.py @@ -26,7 +26,7 @@ import os from _lzma import * from _lzma import _encode_filter_properties, _decode_filter_properties # noqa: F401 -import _compression +from compression._common import streams # Value 0 no longer used @@ -35,7 +35,7 @@ _MODE_WRITE = 3 -class LZMAFile(_compression.BaseStream): +class LZMAFile(streams.BaseStream): """A file object providing transparent LZMA (de)compression. @@ -127,7 +127,7 @@ def __init__(self, filename=None, mode="r", *, raise TypeError("filename must be a str, bytes, file or PathLike object") if self._mode == _MODE_READ: - raw = _compression.DecompressReader(self._fp, LZMADecompressor, + raw = streams.DecompressReader(self._fp, LZMADecompressor, trailing_error=LZMAError, format=format, filters=filters) self._buffer = io.BufferedReader(raw) diff --git a/Lib/test/test_bz2.py b/Lib/test/test_bz2.py index 7d786be1d25b1c..cdb8a859ae1d10 100644 --- a/Lib/test/test_bz2.py +++ b/Lib/test/test_bz2.py @@ -16,7 +16,7 @@ from test.support import import_helper from test.support import threading_helper from test.support.os_helper import unlink, FakePath -import _compression +from compression._common import streams import sys @@ -126,15 +126,15 @@ def testReadMultiStream(self): def testReadMonkeyMultiStream(self): # Test BZ2File.read() on a multi-stream archive where a stream # boundary coincides with the end of the raw read buffer. - buffer_size = _compression.BUFFER_SIZE - _compression.BUFFER_SIZE = len(self.DATA) + buffer_size = streams.BUFFER_SIZE + streams.BUFFER_SIZE = len(self.DATA) try: self.createTempFile(streams=5) with BZ2File(self.filename) as bz2f: self.assertRaises(TypeError, bz2f.read, float()) self.assertEqual(bz2f.read(), self.TEXT * 5) finally: - _compression.BUFFER_SIZE = buffer_size + streams.BUFFER_SIZE = buffer_size def testReadTrailingJunk(self): self.createTempFile(suffix=self.BAD_DATA) @@ -742,7 +742,7 @@ def testOpenPathLikeFilename(self): def testDecompressLimited(self): """Decompressed data buffering should be limited""" bomb = bz2.compress(b'\0' * int(2e6), compresslevel=9) - self.assertLess(len(bomb), _compression.BUFFER_SIZE) + self.assertLess(len(bomb), streams.BUFFER_SIZE) decomp = BZ2File(BytesIO(bomb)) self.assertEqual(decomp.read(1), b'\0') diff --git a/Lib/test/test_lzma.py b/Lib/test/test_lzma.py index 4dd10faf71360a..267c06cfbb8e78 100644 --- a/Lib/test/test_lzma.py +++ b/Lib/test/test_lzma.py @@ -1,4 +1,3 @@ -import _compression import array from io import BytesIO, UnsupportedOperation, DEFAULT_BUFFER_SIZE import os @@ -7,6 +6,7 @@ import sys from test import support import unittest +from compression._common import streams from test.support import _4G, bigmemtest from test.support.import_helper import import_module @@ -861,13 +861,13 @@ def test_read_multistream(self): def test_read_multistream_buffer_size_aligned(self): # Test the case where a stream boundary coincides with the end # of the raw read buffer. - saved_buffer_size = _compression.BUFFER_SIZE - _compression.BUFFER_SIZE = len(COMPRESSED_XZ) + saved_buffer_size = streams.BUFFER_SIZE + streams.BUFFER_SIZE = len(COMPRESSED_XZ) try: with LZMAFile(BytesIO(COMPRESSED_XZ * 5)) as f: self.assertEqual(f.read(), INPUT * 5) finally: - _compression.BUFFER_SIZE = saved_buffer_size + streams.BUFFER_SIZE = saved_buffer_size def test_read_trailing_junk(self): with LZMAFile(BytesIO(COMPRESSED_XZ + COMPRESSED_BOGUS)) as f: @@ -1066,7 +1066,7 @@ def test_readlines(self): def test_decompress_limited(self): """Decompressed data buffering should be limited""" bomb = lzma.compress(b'\0' * int(2e6), preset=6) - self.assertLess(len(bomb), _compression.BUFFER_SIZE) + self.assertLess(len(bomb), streams.BUFFER_SIZE) decomp = LZMAFile(BytesIO(bomb)) self.assertEqual(decomp.read(1), b'\0') From 0d7e1db155f3ce57069c41c71143ab748a50438c Mon Sep 17 00:00:00 2001 From: Emma Harper Smith Date: Sat, 26 Apr 2025 11:27:30 -0700 Subject: [PATCH 2/7] Update stdlib modules list Also update `generate_stdlib_module_names.py` to collect `compression`, a namespace package. --- Python/stdlib_module_names.h | 2 +- Tools/build/generate_stdlib_module_names.py | 12 ++++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/Python/stdlib_module_names.h b/Python/stdlib_module_names.h index 26f6272ae9cfbc..fcef7419bd397b 100644 --- a/Python/stdlib_module_names.h +++ b/Python/stdlib_module_names.h @@ -24,7 +24,6 @@ static const char* _Py_stdlib_module_names[] = { "_collections_abc", "_colorize", "_compat_pickle", -"_compression", "_contextvars", "_csv", "_ctypes", @@ -128,6 +127,7 @@ static const char* _Py_stdlib_module_names[] = { "collections", "colorsys", "compileall", +"compression", "concurrent", "configparser", "contextlib", diff --git a/Tools/build/generate_stdlib_module_names.py b/Tools/build/generate_stdlib_module_names.py index 9873890837fa8e..0e3ba35d867e2c 100644 --- a/Tools/build/generate_stdlib_module_names.py +++ b/Tools/build/generate_stdlib_module_names.py @@ -70,8 +70,16 @@ def list_packages(names): package_path = os.path.join(STDLIB_PATH, name) if not os.path.isdir(package_path): continue - if any(package_file.endswith(".py") - for package_file in os.listdir(package_path)): + # Walk the package directory to check if the package is a namespace + has_py_files = False + for root, _dirs, files in os.walk(package_path): + for file in files: + if file.endswith(".py"): + has_py_files = True + break + if has_py_files: + break + if has_py_files: names.add(name) From 095abfee34df9d3176030d8456fdefa46cbe2f97 Mon Sep 17 00:00:00 2001 From: Emma Harper Smith Date: Sat, 26 Apr 2025 11:31:33 -0700 Subject: [PATCH 3/7] Sort lzma import in alphabetical order --- Lib/lzma.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/lzma.py b/Lib/lzma.py index 7fe93c4d9a06d8..94e83538e4035e 100644 --- a/Lib/lzma.py +++ b/Lib/lzma.py @@ -24,9 +24,9 @@ import builtins import io import os +from compression._common import streams from _lzma import * from _lzma import _encode_filter_properties, _decode_filter_properties # noqa: F401 -from compression._common import streams # Value 0 no longer used From 073113033a9d3842416b7d58e8dc57a64ede3c57 Mon Sep 17 00:00:00 2001 From: Emma Harper Smith Date: Sat, 26 Apr 2025 12:07:51 -0700 Subject: [PATCH 4/7] More import sorting --- Lib/bz2.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/bz2.py b/Lib/bz2.py index 8d4f365607ad7d..ddd9f9645975f3 100644 --- a/Lib/bz2.py +++ b/Lib/bz2.py @@ -10,9 +10,9 @@ __author__ = "Nadeem Vawda " from builtins import open as _builtin_open +from compression._common import streams import io import os -from compression._common import streams from _bz2 import BZ2Compressor, BZ2Decompressor From c8201ba9e058e3fad060fe13e91800a5017f037c Mon Sep 17 00:00:00 2001 From: Emma Harper Smith Date: Sat, 26 Apr 2025 14:44:56 -0700 Subject: [PATCH 5/7] Rename compression._common.streams to compression._common._streams --- Lib/bz2.py | 8 ++++---- Lib/compression/_common/{streams.py => _streams.py} | 0 Lib/gzip.py | 6 +++--- Lib/lzma.py | 6 +++--- Lib/test/test_bz2.py | 10 +++++----- Lib/test/test_lzma.py | 10 +++++----- 6 files changed, 20 insertions(+), 20 deletions(-) rename Lib/compression/_common/{streams.py => _streams.py} (100%) diff --git a/Lib/bz2.py b/Lib/bz2.py index ddd9f9645975f3..eb58f4da596ea1 100644 --- a/Lib/bz2.py +++ b/Lib/bz2.py @@ -10,7 +10,7 @@ __author__ = "Nadeem Vawda " from builtins import open as _builtin_open -from compression._common import streams +from compression._common import _streams import io import os @@ -23,7 +23,7 @@ _MODE_WRITE = 3 -class BZ2File(streams.BaseStream): +class BZ2File(_streams.BaseStream): """A file object providing transparent bzip2 (de)compression. @@ -88,7 +88,7 @@ def __init__(self, filename, mode="r", *, compresslevel=9): raise TypeError("filename must be a str, bytes, file or PathLike object") if self._mode == _MODE_READ: - raw = streams.DecompressReader(self._fp, + raw = _streams.DecompressReader(self._fp, BZ2Decompressor, trailing_error=OSError) self._buffer = io.BufferedReader(raw) else: @@ -248,7 +248,7 @@ def writelines(self, seq): Line separators are not added between the written byte strings. """ - return streams.BaseStream.writelines(self, seq) + return _streams.BaseStream.writelines(self, seq) def seek(self, offset, whence=io.SEEK_SET): """Change the file position. diff --git a/Lib/compression/_common/streams.py b/Lib/compression/_common/_streams.py similarity index 100% rename from Lib/compression/_common/streams.py rename to Lib/compression/_common/_streams.py diff --git a/Lib/gzip.py b/Lib/gzip.py index c362f51bd888f9..b7375b2547314f 100644 --- a/Lib/gzip.py +++ b/Lib/gzip.py @@ -13,7 +13,7 @@ import time import weakref import zlib -from compression._common import streams +from compression._common import _streams __all__ = ["BadGzipFile", "GzipFile", "open", "compress", "decompress"] @@ -144,7 +144,7 @@ def writable(self): return True -class GzipFile(streams.BaseStream): +class GzipFile(_streams.BaseStream): """The GzipFile class simulates most of the methods of a file object with the exception of the truncate() method. @@ -523,7 +523,7 @@ def _read_gzip_header(fp): return last_mtime -class _GzipReader(streams.DecompressReader): +class _GzipReader(_streams.DecompressReader): def __init__(self, fp): super().__init__(_PaddedFile(fp), zlib._ZlibDecompressor, wbits=-zlib.MAX_WBITS) diff --git a/Lib/lzma.py b/Lib/lzma.py index 94e83538e4035e..316066d024ea02 100644 --- a/Lib/lzma.py +++ b/Lib/lzma.py @@ -24,7 +24,7 @@ import builtins import io import os -from compression._common import streams +from compression._common import _streams from _lzma import * from _lzma import _encode_filter_properties, _decode_filter_properties # noqa: F401 @@ -35,7 +35,7 @@ _MODE_WRITE = 3 -class LZMAFile(streams.BaseStream): +class LZMAFile(_streams.BaseStream): """A file object providing transparent LZMA (de)compression. @@ -127,7 +127,7 @@ def __init__(self, filename=None, mode="r", *, raise TypeError("filename must be a str, bytes, file or PathLike object") if self._mode == _MODE_READ: - raw = streams.DecompressReader(self._fp, LZMADecompressor, + raw = _streams.DecompressReader(self._fp, LZMADecompressor, trailing_error=LZMAError, format=format, filters=filters) self._buffer = io.BufferedReader(raw) diff --git a/Lib/test/test_bz2.py b/Lib/test/test_bz2.py index cdb8a859ae1d10..f32b24b39bad00 100644 --- a/Lib/test/test_bz2.py +++ b/Lib/test/test_bz2.py @@ -16,7 +16,7 @@ from test.support import import_helper from test.support import threading_helper from test.support.os_helper import unlink, FakePath -from compression._common import streams +from compression._common import _streams import sys @@ -126,15 +126,15 @@ def testReadMultiStream(self): def testReadMonkeyMultiStream(self): # Test BZ2File.read() on a multi-stream archive where a stream # boundary coincides with the end of the raw read buffer. - buffer_size = streams.BUFFER_SIZE - streams.BUFFER_SIZE = len(self.DATA) + buffer_size = _streams.BUFFER_SIZE + _streams.BUFFER_SIZE = len(self.DATA) try: self.createTempFile(streams=5) with BZ2File(self.filename) as bz2f: self.assertRaises(TypeError, bz2f.read, float()) self.assertEqual(bz2f.read(), self.TEXT * 5) finally: - streams.BUFFER_SIZE = buffer_size + _streams.BUFFER_SIZE = buffer_size def testReadTrailingJunk(self): self.createTempFile(suffix=self.BAD_DATA) @@ -742,7 +742,7 @@ def testOpenPathLikeFilename(self): def testDecompressLimited(self): """Decompressed data buffering should be limited""" bomb = bz2.compress(b'\0' * int(2e6), compresslevel=9) - self.assertLess(len(bomb), streams.BUFFER_SIZE) + self.assertLess(len(bomb), _streams.BUFFER_SIZE) decomp = BZ2File(BytesIO(bomb)) self.assertEqual(decomp.read(1), b'\0') diff --git a/Lib/test/test_lzma.py b/Lib/test/test_lzma.py index 267c06cfbb8e78..d7e8327cfee18a 100644 --- a/Lib/test/test_lzma.py +++ b/Lib/test/test_lzma.py @@ -6,7 +6,7 @@ import sys from test import support import unittest -from compression._common import streams +from compression._common import _streams from test.support import _4G, bigmemtest from test.support.import_helper import import_module @@ -861,13 +861,13 @@ def test_read_multistream(self): def test_read_multistream_buffer_size_aligned(self): # Test the case where a stream boundary coincides with the end # of the raw read buffer. - saved_buffer_size = streams.BUFFER_SIZE - streams.BUFFER_SIZE = len(COMPRESSED_XZ) + saved_buffer_size = _streams.BUFFER_SIZE + _streams.BUFFER_SIZE = len(COMPRESSED_XZ) try: with LZMAFile(BytesIO(COMPRESSED_XZ * 5)) as f: self.assertEqual(f.read(), INPUT * 5) finally: - streams.BUFFER_SIZE = saved_buffer_size + _streams.BUFFER_SIZE = saved_buffer_size def test_read_trailing_junk(self): with LZMAFile(BytesIO(COMPRESSED_XZ + COMPRESSED_BOGUS)) as f: @@ -1066,7 +1066,7 @@ def test_readlines(self): def test_decompress_limited(self): """Decompressed data buffering should be limited""" bomb = lzma.compress(b'\0' * int(2e6), preset=6) - self.assertLess(len(bomb), streams.BUFFER_SIZE) + self.assertLess(len(bomb), _streams.BUFFER_SIZE) decomp = LZMAFile(BytesIO(bomb)) self.assertEqual(decomp.read(1), b'\0') From e7fed14b44ab4e3ad77379af6bbf90b41d2348f4 Mon Sep 17 00:00:00 2001 From: Emma Harper Smith Date: Sat, 26 Apr 2025 14:45:47 -0700 Subject: [PATCH 6/7] Re-export existing module docstrings --- Lib/compression/bz2/__init__.py | 7 +++---- Lib/compression/gzip/__init__.py | 7 +++---- Lib/compression/lzma/__init__.py | 7 +++---- Lib/compression/zlib/__init__.py | 7 +++---- 4 files changed, 12 insertions(+), 16 deletions(-) diff --git a/Lib/compression/bz2/__init__.py b/Lib/compression/bz2/__init__.py index 76c9a50baa4b17..16815d6cd20e5b 100644 --- a/Lib/compression/bz2/__init__.py +++ b/Lib/compression/bz2/__init__.py @@ -1,6 +1,5 @@ -"""Module re-exporting contents of the bz2 module. - -Please refer to the bz2 documentation for this module's contents. -""" +import bz2 +__doc__ = bz2.__doc__ +del bz2 from bz2 import * diff --git a/Lib/compression/gzip/__init__.py b/Lib/compression/gzip/__init__.py index 7c0f559627b4dc..552f48f948ae47 100644 --- a/Lib/compression/gzip/__init__.py +++ b/Lib/compression/gzip/__init__.py @@ -1,6 +1,5 @@ -"""Module re-exporting contents of the gzip module. - -Please refer to the gzip documentation for this module's contents. -""" +import gzip +__doc__ = gzip.__doc__ +del gzip from gzip import * diff --git a/Lib/compression/lzma/__init__.py b/Lib/compression/lzma/__init__.py index d0a24163e3fb0d..b4bc7ccb1db3cf 100644 --- a/Lib/compression/lzma/__init__.py +++ b/Lib/compression/lzma/__init__.py @@ -1,6 +1,5 @@ -"""Module re-exporting contents of the lzma module. - -Please refer to the lzma documentation for this module's contents. -""" +import lzma +__doc__ = lzma.__doc__ +del lzma from lzma import * diff --git a/Lib/compression/zlib/__init__.py b/Lib/compression/zlib/__init__.py index a4d52f2019d40f..3aa7e2db90e862 100644 --- a/Lib/compression/zlib/__init__.py +++ b/Lib/compression/zlib/__init__.py @@ -1,6 +1,5 @@ -"""Module re-exporting contents of the zlib module. - -Please refer to the bz2 documentation for this module's contents. -""" +import zlib +__doc__ = zlib.__doc__ +del zlib from zlib import * From 2e1b2a8ddc718c603aef13969c6bbfa2bdef0f8f Mon Sep 17 00:00:00 2001 From: Emma Harper Smith Date: Sat, 26 Apr 2025 16:34:49 -0700 Subject: [PATCH 7/7] Add compression/__init__.py and revert tooling change --- Lib/compression/__init__.py | 0 Tools/build/generate_stdlib_module_names.py | 12 ++---------- 2 files changed, 2 insertions(+), 10 deletions(-) create mode 100644 Lib/compression/__init__.py diff --git a/Lib/compression/__init__.py b/Lib/compression/__init__.py new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/Tools/build/generate_stdlib_module_names.py b/Tools/build/generate_stdlib_module_names.py index 0e3ba35d867e2c..9873890837fa8e 100644 --- a/Tools/build/generate_stdlib_module_names.py +++ b/Tools/build/generate_stdlib_module_names.py @@ -70,16 +70,8 @@ def list_packages(names): package_path = os.path.join(STDLIB_PATH, name) if not os.path.isdir(package_path): continue - # Walk the package directory to check if the package is a namespace - has_py_files = False - for root, _dirs, files in os.walk(package_path): - for file in files: - if file.endswith(".py"): - has_py_files = True - break - if has_py_files: - break - if has_py_files: + if any(package_file.endswith(".py") + for package_file in os.listdir(package_path)): names.add(name) pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy