From 14068984402f5004104506815c7d76067fd2e0ae Mon Sep 17 00:00:00 2001 From: Evgenii Kliuchnikov Date: Thu, 25 Sep 2025 07:59:41 -0700 Subject: [PATCH] Build and test with PY2.7 PiperOrigin-RevId: 811352084 --- .gitattributes | 1 + .github/workflows/build_test.yml | 44 ++++++++++++++++++++----------- CMakeLists.txt | 17 +++++++----- python/_brotli.c | 24 ++++++++--------- python/tests/_test_utils.py | 7 +++-- python/tests/compressor_test.py | 10 +++---- python/tests/decompressor_test.py | 8 +++--- setup.py | 4 +-- 8 files changed, 68 insertions(+), 47 deletions(-) diff --git a/.gitattributes b/.gitattributes index bbe7293..de14a00 100644 --- a/.gitattributes +++ b/.gitattributes @@ -51,3 +51,4 @@ tests/testdata/empty !export-ignore tests/testdata/empty.compressed !export-ignore tests/testdata/ukkonooa !export-ignore tests/testdata/ukkonooa.compressed !export-ignore +tests/testdata/zerosukkanooa.compressed !export-ignore diff --git a/.github/workflows/build_test.yml b/.github/workflows/build_test.yml index 81c5ecb..330579f 100644 --- a/.github/workflows/build_test.yml +++ b/.github/workflows/build_test.yml @@ -18,7 +18,7 @@ concurrency: cancel-in-progress: ${{ github.event_name == 'pull_request' }} jobs: - ubuntu_build: + build_test: name: Build and test ${{ matrix.name }} runs-on: ${{ matrix.os || 'ubuntu-latest' }} defaults: @@ -188,13 +188,6 @@ jobs: submodules: false fetch-depth: 1 - #- name: Checkout VC9 for Python - # if: ${{ runner.os == 'Windows' && matrix.build_system == 'python' && matrix.python_version == '2.7' }} - # uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 - # with: - # repository: reider-roque/sulley-win-installer - # path: third_party/VCForPython27 - - name: Configure / Build / Test with CMake if: ${{ matrix.build_system == 'cmake' }} run: | @@ -294,17 +287,36 @@ jobs: with: python-version: ${{ matrix.python_version }} - # TODO: investigate, why msiexec hangs - #- name: Install VC9 for Python - # if: ${{ runner.os == 'Windows' && matrix.build_system == 'python' && matrix.python_version == '2.7' }} - # run: | - # echo "070474db76a2e625513a5835df4595df9324d820f9cc97eab2a596dcbc2f5cbf third_party/VCForPython27/VCForPython27.msi" | sha256sum --check --status - # msiexec ALLUSERS=1 /qn /norestart /i third_party/VCForPython27/VCForPython27.msi /l*v ${RUNNER_TEMP}/msiexec.log - # cat ${RUNNER_TEMP}/msiexec.log - - name: Build / Test with Python if: ${{ matrix.build_system == 'python' }} run: | python -VV python -c "import sys; sys.exit('Invalid python version') if '.'.join(map(str,sys.version_info[0:2])) != '${{ matrix.python_version }}' else True" python setup.py ${{ matrix.py_setuptools_cmd || 'test'}} + + build_test_py27: + name: Build and test with Python 2.7 + runs-on: ubuntu-latest + container: + image: ubuntu:22.04 + steps: + + - name: Install deps + run: | + apt update + apt install -y curl gcc python2.7 python2.7-dev + curl https://bootstrap.pypa.io/pip/2.7/get-pip.py --output get-pip.py + python2.7 get-pip.py + python2.7 -m pip install distutils-pytest==0.1 + + - name: Checkout the source + uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 + with: + submodules: false + fetch-depth: 1 + + - name: Build / Test + run: | + python2.7 -VV + python2.7 -c "import sys; sys.exit('Invalid python version') if '.'.join(map(str,sys.version_info[0:2])) != '2.7' else True" + python2.7 setup.py test diff --git a/CMakeLists.txt b/CMakeLists.txt index 74e08df..1dfac68 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -255,13 +255,16 @@ if(NOT BROTLI_DISABLE_TESTS AND BROTLI_BUILD_TOOLS) tests/testdata/*.compressed*) foreach(INPUT ${COMPATIBILITY_INPUTS}) - add_test(NAME "${BROTLI_TEST_PREFIX}compatibility/${INPUT}" - COMMAND "${CMAKE_COMMAND}" - -DBROTLI_WRAPPER=${BROTLI_WRAPPER} - -DBROTLI_WRAPPER_LD_PREFIX=${BROTLI_WRAPPER_LD_PREFIX} - -DBROTLI_CLI=$ - -DINPUT=${CMAKE_CURRENT_SOURCE_DIR}/${INPUT} - -P ${CMAKE_CURRENT_SOURCE_DIR}/tests/run-compatibility-test.cmake) + string(REGEX REPLACE "([a-zA-Z0-9\\.]+)\\.compressed(\\.[0-9]+)?$" "\\1" UNCOMPRESSED_INPUT "${INPUT}") + if (EXISTS ${UNCOMPRESSED_INPUT}) + add_test(NAME "${BROTLI_TEST_PREFIX}compatibility/${INPUT}" + COMMAND "${CMAKE_COMMAND}" + -DBROTLI_WRAPPER=${BROTLI_WRAPPER} + -DBROTLI_WRAPPER_LD_PREFIX=${BROTLI_WRAPPER_LD_PREFIX} + -DBROTLI_CLI=$ + -DINPUT=${CMAKE_CURRENT_SOURCE_DIR}/${INPUT} + -P ${CMAKE_CURRENT_SOURCE_DIR}/tests/run-compatibility-test.cmake) + endif() endforeach() endif() # BROTLI_DISABLE_TESTS diff --git a/python/_brotli.c b/python/_brotli.c index 137ec68..1f9150e 100644 --- a/python/_brotli.c +++ b/python/_brotli.c @@ -854,18 +854,6 @@ static PyMethodDef brotli_methods[] = { brotli_decompress__doc__}, {NULL, NULL, 0, NULL}}; -static struct PyModuleDef brotli_module = { - PyModuleDef_HEAD_INIT, - "_brotli", /* m_name */ - brotli_doc, /* m_doc */ - 0, /* m_size */ - brotli_methods, /* m_methods */ - NULL, /* m_reload */ - NULL, /* m_traverse */ - NULL, /* m_clear */ - NULL /* m_free */ -}; - static PyMethodDef brotli_Compressor_methods[] = { {"process", (PyCFunction)brotli_Compressor_process, METH_VARARGS, brotli_Compressor_process_doc}, @@ -889,6 +877,18 @@ static PyMethodDef brotli_Decompressor_methods[] = { #if PY_MAJOR_VERSION >= 3 +static struct PyModuleDef brotli_module = { + PyModuleDef_HEAD_INIT, + "_brotli", /* m_name */ + brotli_doc, /* m_doc */ + 0, /* m_size */ + brotli_methods, /* m_methods */ + NULL, /* m_reload */ + NULL, /* m_traverse */ + NULL, /* m_clear */ + NULL /* m_free */ +}; + static PyType_Slot brotli_Compressor_slots[] = { {Py_tp_dealloc, (destructor)brotli_Compressor_dealloc}, {Py_tp_doc, (void*)brotli_Compressor_doc}, diff --git a/python/tests/_test_utils.py b/python/tests/_test_utils.py index 713738a..36102b8 100644 --- a/python/tests/_test_utils.py +++ b/python/tests/_test_utils.py @@ -97,7 +97,10 @@ def generate_test_methods( generate a separate test method. """ if for_decompression: - paths = TESTDATA_PATHS_FOR_DECOMPRESSION + paths = [ + path for path in TESTDATA_PATHS_FOR_DECOMPRESSION + if os.path.exists(path.replace('.compressed', '')) + ] else: paths = TESTDATA_PATHS opts = [] @@ -141,7 +144,7 @@ class TestCase(unittest.TestCase): os.unlink(get_temp_uncompressed_name(f)) except OSError: pass - super().tearDown() + # super().tearDown() # Requires Py3+ def assert_files_match(self, first, second): self.assertTrue( diff --git a/python/tests/compressor_test.py b/python/tests/compressor_test.py index 2c08f8f..8f92405 100644 --- a/python/tests/compressor_test.py +++ b/python/tests/compressor_test.py @@ -20,7 +20,7 @@ class _TestCompressor(object): def tearDown(self): self.compressor = None - super().tearDown() + # super().tearDown() # Requires Py3+ def _check_decompression(self, test_data): # Write decompression to temp file and verify it matches the original. @@ -71,28 +71,28 @@ _test_utils.generate_test_methods(_TestCompressor) class TestCompressorQuality1(_TestCompressor, _test_utils.TestCase): def setUp(self): - super().setUp() + # super().setUp() # Requires Py3+ self.compressor = brotli.Compressor(quality=1) class TestCompressorQuality6(_TestCompressor, _test_utils.TestCase): def setUp(self): - super().setUp() + # super().setUp() # Requires Py3+ self.compressor = brotli.Compressor(quality=6) class TestCompressorQuality9(_TestCompressor, _test_utils.TestCase): def setUp(self): - super().setUp() + # super().setUp() # Requires Py3+ self.compressor = brotli.Compressor(quality=9) class TestCompressorQuality11(_TestCompressor, _test_utils.TestCase): def setUp(self): - super().setUp() + # super().setUp() # Requires Py3+ self.compressor = brotli.Compressor(quality=11) diff --git a/python/tests/decompressor_test.py b/python/tests/decompressor_test.py index 362c682..67844b3 100644 --- a/python/tests/decompressor_test.py +++ b/python/tests/decompressor_test.py @@ -22,12 +22,12 @@ class TestDecompressor(_test_utils.TestCase): MIN_OUTPUT_BUFFER_SIZE = 32768 # Actually, several bytes less. def setUp(self): - super().setUp() + # super().setUp() # Requires Py3+ self.decompressor = brotli.Decompressor() def tearDown(self): self.decompressor = None - super().tearDown() + # super().tearDown() # Requires Py3+ def _check_decompression(self, test_data): # Verify decompression matches the original. @@ -86,6 +86,7 @@ class TestDecompressor(_test_utils.TestCase): test_data = os.path.join( _test_utils.TESTDATA_DIR, 'zerosukkanooa.compressed' ) + check_output = os.path.exists(test_data.replace('.compressed', '')) temp_uncompressed = _test_utils.get_temp_uncompressed_name(test_data) with open(temp_uncompressed, 'wb') as out_file: with open(test_data, 'rb') as in_file: @@ -98,7 +99,8 @@ class TestDecompressor(_test_utils.TestCase): while not self.decompressor.can_accept_more_data(): out_file.write(self.decompressor.process(b'')) out_file.write(self.decompressor.process(compressed[-1:])) - self._check_decompression(test_data) + if check_output: + self._check_decompression(test_data) def test_garbage_appended(self): with self.assertRaises(brotli.error): diff --git a/setup.py b/setup.py index c44d8c5..88ca7c2 100644 --- a/setup.py +++ b/setup.py @@ -24,7 +24,7 @@ from distutils import log CURR_DIR = os.path.abspath(os.path.dirname(os.path.realpath(__file__))) -def bool_from_environ(key: str): +def bool_from_environ(key): value = os.environ.get(key) if not value: return False @@ -32,7 +32,7 @@ def bool_from_environ(key: str): return True if value == "0": return False - raise ValueError(f"Environment variable {key} has invalid value {value}. Please set it to 1, 0 or an empty string") + raise ValueError("Environment variable {} has invalid value {}. Please set it to 1, 0 or an empty string".format(key, value)) def read_define(path, macro):