Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-cx_Freeze for openSUSE:Factory checked in at 2024-02-21 17:58:51 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-cx_Freeze (Old) and /work/SRC/openSUSE:Factory/.python-cx_Freeze.new.1706 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-cx_Freeze" Wed Feb 21 17:58:51 2024 rev:14 rq:1148496 version:6.15.15 Changes: -------- --- /work/SRC/openSUSE:Factory/python-cx_Freeze/python-cx_Freeze.changes 2024-01-30 18:27:04.889549164 +0100 +++ /work/SRC/openSUSE:Factory/.python-cx_Freeze.new.1706/python-cx_Freeze.changes 2024-02-21 17:58:55.624750570 +0100 @@ -1,0 +2,7 @@ +Wed Feb 21 08:52:26 UTC 2024 - Daniel Garcia <daniel.gar...@suse.com> + +- Add python312.patch, gh#marcelotduarte/cx_Freeze#1925 +- update to 6.15.15: + * **Full Changelog**: https://github.com/marcelotduarte/cx_Freeze/compare/6.15.13...6.15.15 + +------------------------------------------------------------------- Old: ---- 6.15.13.tar.gz New: ---- 6.15.15.tar.gz python312.patch BETA DEBUG BEGIN: New: - Add python312.patch, gh#marcelotduarte/cx_Freeze#1925 - update to 6.15.15: BETA DEBUG END: ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-cx_Freeze.spec ++++++ --- /var/tmp/diff_new_pack.pbogsF/_old 2024-02-21 17:58:56.224772267 +0100 +++ /var/tmp/diff_new_pack.pbogsF/_new 2024-02-21 17:58:56.224772267 +0100 @@ -18,12 +18,14 @@ %define oldpython python Name: python-cx_Freeze -Version: 6.15.13 +Version: 6.15.15 Release: 0 Summary: Scripts to create standalone executables from Python scripts License: Python-2.0 URL: https://github.com/anthony-tuininga/cx_Freeze Source: https://github.com/anthony-tuininga/cx_Freeze/archive/%{version}.tar.gz +# PATCH-FIX-UPSTREAM python312.patch gh#marcelotduarte/cx_Freeze#1925 +Patch1: python312.patch BuildRequires: %{python_module base >= 3.7} BuildRequires: %{python_module devel} BuildRequires: %{python_module hatchling} ++++++ 6.15.13.tar.gz -> 6.15.15.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cx_Freeze-6.15.13/.github/workflows/ci.yml new/cx_Freeze-6.15.15/.github/workflows/ci.yml --- old/cx_Freeze-6.15.13/.github/workflows/ci.yml 2024-01-24 09:02:55.000000000 +0100 +++ new/cx_Freeze-6.15.15/.github/workflows/ci.yml 2024-02-10 10:18:02.000000000 +0100 @@ -25,9 +25,9 @@ pip install -v -e .[dev,doc] - name: Run pre-commit - uses: pre-commit/action@v3.0.0 - with: - extra_args: --all-files --hook-stage=manual + run: >- + pre-commit run --show-diff-on-failure --color=always + --all-files --hook-stage manual tests: runs-on: ${{ matrix.os }} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cx_Freeze-6.15.13/Makefile new/cx_Freeze-6.15.15/Makefile --- old/cx_Freeze-6.15.13/Makefile 2024-01-24 09:02:55.000000000 +0100 +++ new/cx_Freeze-6.15.15/Makefile 2024-02-10 10:18:02.000000000 +0100 @@ -7,18 +7,18 @@ .PHONY: pre-commit pre-commit: install - @SKIP=pylint pre-commit run -a --hook-stage manual || true + @SKIP=pylint pre-commit run --show-diff-on-failure --color=always --all-files --hook-stage manual || true @pre-commit gc .PHONY: pre-commit-all pre-commit-all: install - @pre-commit run -a --hook-stage manual || true + @pre-commit run --show-diff-on-failure --color=always --all-files --hook-stage manual || true @pre-commit gc .PHONY: pylint pylint: pip install --upgrade pylint - @pre-commit run pylint -a -v --hook-stage manual + @pre-commit run pylint --show-diff-on-failure --color=always --all-files --hook-stage manual .PHONY: clean clean: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cx_Freeze-6.15.13/cx_Freeze/__init__.py new/cx_Freeze-6.15.15/cx_Freeze/__init__.py --- old/cx_Freeze-6.15.13/cx_Freeze/__init__.py 2024-01-24 09:02:55.000000000 +0100 +++ new/cx_Freeze-6.15.15/cx_Freeze/__init__.py 2024-02-10 10:18:02.000000000 +0100 @@ -42,7 +42,7 @@ __all__.append(bdist_rpm.__name__) -__version__ = "6.15.13" +__version__ = "6.15.15" def setup(**attrs): # noqa: D103 @@ -69,9 +69,9 @@ if getattr(dist, "executables", None) is None: return - # Fix package discovery (setuptools >= 61) - if getattr(dist, "py_modules", None) is None: - dist.py_modules = [] + # Disable package discovery (setuptools >= 61) and/or misuse of packages + dist.py_modules = [] + dist.packages = [] # Add/update commands (provisional) cmdclass = dist.cmdclass diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cx_Freeze-6.15.13/cx_Freeze/command/build_exe.py new/cx_Freeze-6.15.15/cx_Freeze/command/build_exe.py --- old/cx_Freeze-6.15.13/cx_Freeze/command/build_exe.py 2024-01-24 09:02:55.000000000 +0100 +++ new/cx_Freeze-6.15.15/cx_Freeze/command/build_exe.py 2024-02-10 10:18:02.000000000 +0100 @@ -223,25 +223,7 @@ # the degree of silencing, set from either the silent or silent-level # option, as appropriate - self.silent_setting = 0 - if self.silent is not None and self.silent: - self.silent_setting = 1 - - if self.silent_level is None: - pass - elif self.silent_level is False: - self.silent_setting = 0 - elif self.silent_level is True: - self.silent_setting = 1 - elif isinstance(self.silent_level, int): - self.silent_setting = self.silent_level - elif isinstance(self.silent_level, str): - try: - self.silent_setting = int(self.silent_level) - except ValueError: - self.silent_setting = 1 - else: - self.silent_setting = 1 + self.silent = int(self.silent or self.silent_level or 0) # if self.include_msvcr is None: @@ -276,7 +258,7 @@ zip_includes=self.zip_includes, zip_include_packages=self.zip_include_packages, zip_exclude_packages=self.zip_exclude_packages, - silent=self.silent_setting, + silent=self.silent, metadata=metadata, include_msvcr=self.include_msvcr, ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cx_Freeze-6.15.13/cx_Freeze/command/install.py new/cx_Freeze-6.15.15/cx_Freeze/command/install.py --- old/cx_Freeze-6.15.13/cx_Freeze/command/install.py 2024-01-24 09:02:55.000000000 +0100 +++ new/cx_Freeze-6.15.15/cx_Freeze/command/install.py 2024-02-10 10:18:02.000000000 +0100 @@ -52,7 +52,7 @@ ) prefix = str(winreg.QueryValueEx(key, "ProgramFilesDir")[0]) metadata = self.distribution.metadata - self.prefix = f"{prefix}\\{metadata.name}" + self.prefix = f"{prefix}\\{metadata.get_name()}" super().finalize_options() self.convert_paths("exe") if self.root is not None: @@ -65,7 +65,7 @@ self.install_exe = "$base" else: metadata = self.distribution.metadata - dir_name = f"{metadata.name}-{metadata.version}" + dir_name = f"{metadata.get_name()}-{metadata.get_version()}" self.install_exe = f"$base/lib/{dir_name}" def run(self): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cx_Freeze-6.15.13/cx_Freeze/command/install_exe.py new/cx_Freeze-6.15.15/cx_Freeze/command/install_exe.py --- old/cx_Freeze-6.15.13/cx_Freeze/command/install_exe.py 2024-01-24 09:02:55.000000000 +0100 +++ new/cx_Freeze-6.15.15/cx_Freeze/command/install_exe.py 2024-02-10 10:18:02.000000000 +0100 @@ -1,8 +1,9 @@ """Implements the 'install_exe' command.""" from __future__ import annotations +import os +import shutil import sys -from pathlib import Path from setuptools import Command @@ -26,6 +27,7 @@ self.force = 0 self.build_dir = None self.skip_build = None + self.outfiles = None def finalize_options(self): self.set_undefined_options("build_exe", ("build_exe", "build_dir")) @@ -39,22 +41,31 @@ def run(self): if not self.skip_build: self.run_command("build_exe") + + self.mkpath(self.install_dir) self.outfiles = self.copy_tree(self.build_dir, self.install_dir) - if sys.platform != "win32": - install_dir = Path(self.install_dir) - base_dir = install_dir.parent.parent - bin_dir: Path = base_dir / "bin" - if not bin_dir.exists(): - bin_dir.mkdir(parents=True) - source_dir = ".." / install_dir.relative_to(base_dir) - for executable in self.distribution.executables: - name = executable.target_name - source = source_dir / name - target = bin_dir / name - if target.exists(): - target.unlink() - target.symlink_to(source) - self.outfiles.append(target.as_posix()) + + if sys.platform == "win32": + return + + # in posix, make symlinks to the executables + install_dir = self.install_dir + bin_dir = os.path.join( + os.path.dirname(os.path.dirname(install_dir)), "bin" + ) + self.execute(shutil.rmtree, (bin_dir, True), msg=f"removing {bin_dir}") + self.mkpath(bin_dir) + for executable in self.get_inputs(): + name = executable.target_name + target = os.path.join(install_dir, name) + origin = os.path.join(bin_dir, name) + relative_reference = os.path.relpath(target, bin_dir) + self.execute( + os.symlink, + (relative_reference, origin, True), + msg=f"linking {origin} -> {relative_reference}", + ) + self.outfiles.append(origin) def get_inputs(self): return self.distribution.executables or [] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cx_Freeze-6.15.13/cx_Freeze/freezer.py new/cx_Freeze-6.15.15/cx_Freeze/freezer.py --- old/cx_Freeze-6.15.13/cx_Freeze/freezer.py 2024-01-24 09:02:55.000000000 +0100 +++ new/cx_Freeze-6.15.15/cx_Freeze/freezer.py 2024-02-10 10:18:02.000000000 +0100 @@ -103,13 +103,7 @@ self.zip_includes: InternalIncludesList = process_path_specs( zip_includes ) - if isinstance(silent, bool): - if silent: - self.silent = 1 - else: - self.silent = 0 - else: - self.silent = silent + self.silent = int(silent) self.metadata: Any = metadata self.zip_exclude_packages: set[str] = {"*"} @@ -527,10 +521,11 @@ name.partition(".")[0] for name in zip_exclude_packages } # check invalid usage - invalid = ", ".join(zip_include_packages & zip_exclude_packages) + invalid = sorted(zip_include_packages & zip_exclude_packages) if invalid: raise OptionError( - f"package{'s' if len(invalid)>1 else ''} {invalid!r} " + f"package{'s' if len(invalid)>1 else ''} " + f"{', '.join(invalid)!r} " "cannot be both included and excluded from zip file" ) # populate @@ -909,11 +904,10 @@ def _default_bin_includes(self) -> list[str]: python_shared_libs: list[str] = [] - if IS_MINGW: + name = sysconfig.get_config_var("INSTSONAME") + if name: # MSYS2 python returns a static library. - name = sysconfig.get_config_var("INSTSONAME") - if name: - python_shared_libs.append(name.replace(".dll.a", ".dll")) + python_shared_libs.append(name.replace(".dll.a", ".dll")) else: python_shared_libs += [ f"python{sys.version_info[0]}.dll", diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cx_Freeze-6.15.13/cx_Freeze/hooks/cv2.py new/cx_Freeze-6.15.15/cx_Freeze/hooks/cv2.py --- old/cx_Freeze-6.15.13/cx_Freeze/hooks/cv2.py 2024-01-24 09:02:55.000000000 +0100 +++ new/cx_Freeze-6.15.15/cx_Freeze/hooks/cv2.py 2024-02-10 10:18:02.000000000 +0100 @@ -62,7 +62,7 @@ finder.exclude_module("cv2.load_config_py2") module.exclude_names.add("load_config_py2") # include files config.py (empty) and config-3.py (original) - source = finder.cache_path / "cv2-config.py" + source = temp_path.path / "cv2-config.py" source.touch() finder.include_files(source, target_dir / "config.py") finder.include_files( diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cx_Freeze-6.15.13/cx_Freeze/winversioninfo.py new/cx_Freeze-6.15.15/cx_Freeze/winversioninfo.py --- old/cx_Freeze-6.15.13/cx_Freeze/winversioninfo.py 2024-01-24 09:02:55.000000000 +0100 +++ new/cx_Freeze-6.15.15/cx_Freeze/winversioninfo.py 2024-02-10 10:18:02.000000000 +0100 @@ -13,16 +13,16 @@ __all__ = ["Version", "VersionInfo"] +# types +CHAR = "c" +WCHAR = "ss" +WORD = "=H" +DWORD = "=L" + # constants RT_VERSION = 16 ID_VERSION = 1 -# types -CHAR = "c" -DWORD = "L" -WCHAR = "H" -WORD = "H" - VS_FFI_SIGNATURE = 0xFEEF04BD VS_FFI_STRUCVERSION = 0x00010000 VS_FFI_FILEFLAGSMASK = 0x0000003F @@ -33,6 +33,8 @@ KEY_STRING_TABLE = "040904E4" KEY_VAR_FILE_INFO = "VarFileInfo" +COMMENTS_MAX_LEN = (64 - 2) * 1024 // calcsize(WCHAR) + # To disable the experimental feature in Windows: # set CX_FREEZE_STAMP=pywin32 # pip install -U pywin32 @@ -83,7 +85,7 @@ data = data.to_buffer() elif isinstance(data, str): data = data.encode("utf-16le") - elif isinstance(fmt, str): + elif isinstance(data, int): data = pack(fmt, data) buffer += data return buffer @@ -143,7 +145,9 @@ value_len = value.wLength fields.append(("Value", type(value))) elif isinstance(value, Structure): - value_len = calcsize("".join([f[1] for f in value._fields])) + value_len = 0 + for field in value._fields: + value_len += calcsize(field[1]) value_type = 0 fields.append(("Value", type(value))) @@ -200,7 +204,8 @@ self.valid_version: Version = valid_version self.internal_name: str | None = internal_name self.original_filename: str | None = original_filename - self.comments: str | None = comments + # comments length must be limited to 31kb + self.comments: str = comments[:COMMENTS_MAX_LEN] if comments else None self.company: str | None = company self.description: str | None = description self.copyright: str | None = copyright @@ -222,6 +227,8 @@ version_stamp = import_module("win32verstamp").stamp except ImportError as exc: raise RuntimeError("install pywin32 extension first") from exc + # comments length must be limited to 15kb (uses WORD='h') + self.comments = (self.comments or "")[: COMMENTS_MAX_LEN // 2] version_stamp(os.fspath(path), self) return @@ -264,17 +271,18 @@ elif len(self.valid_version.release) >= 4: build = self.valid_version.release[3] + # use the data in the order shown in 'pepper' data = { - "Comments": self.comments or "", - "CompanyName": self.company or "", "FileDescription": self.description or "", "FileVersion": self.version, "InternalName": self.internal_name or path.name, + "CompanyName": self.company or "", "LegalCopyright": self.copyright or "", "LegalTrademarks": self.trademarks or "", "OriginalFilename": self.original_filename or path.name, "ProductName": self.product or "", "ProductVersion": str(self.valid_version), + "Comments": self.comments or "", } is_dll = self.dll if is_dll is None: @@ -312,6 +320,7 @@ string_version_info = String(KEY_VERSION_INFO, fixed_file_info) string_version_info.children(string_file_info) string_version_info.children(var_file_info) + return string_version_info diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cx_Freeze-6.15.13/doc/src/conf.py new/cx_Freeze-6.15.15/doc/src/conf.py --- old/cx_Freeze-6.15.13/doc/src/conf.py 2024-01-24 09:02:55.000000000 +0100 +++ new/cx_Freeze-6.15.15/doc/src/conf.py 2024-02-10 10:18:02.000000000 +0100 @@ -43,7 +43,7 @@ # General information about the project. project = "cx_Freeze" copyright = "2024, Marcelo Duarte" # noqa: A001 -__version__ = "6.15.13" +__version__ = "6.15.15" # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cx_Freeze-6.15.13/pyproject.toml new/cx_Freeze-6.15.15/pyproject.toml --- old/cx_Freeze-6.15.13/pyproject.toml 2024-01-24 09:02:55.000000000 +0100 +++ new/cx_Freeze-6.15.15/pyproject.toml 2024-02-10 10:18:02.000000000 +0100 @@ -116,7 +116,7 @@ [tool.bumpversion] commit = true -current_version = "6.15.13" +current_version = "6.15.15" message = "Bump version: {current_version} â {new_version} [ci skip]" parse = "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)(\\-(?P<release>[a-z]+)(?P<build>\\d+))?" serialize = [ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cx_Freeze-6.15.13/tests/test___main__.py new/cx_Freeze-6.15.15/tests/test___main__.py --- old/cx_Freeze-6.15.13/tests/test___main__.py 1970-01-01 01:00:00.000000000 +0100 +++ new/cx_Freeze-6.15.15/tests/test___main__.py 2024-02-10 10:18:02.000000000 +0100 @@ -0,0 +1,28 @@ +"""Tests for 'python -m cx_Freeze'.""" +from __future__ import annotations + +import sys +from pathlib import Path + +from generate_samples import create_package, run_command + +SUFFIX = ".exe" if sys.platform == "win32" else "" + +SOURCE = """ +test.py + print("Hello from cx_Freeze") +command + python -m cx_Freeze test.py --target-dir=dist --excludes=tkinter +""" + + +def test___main__(tmp_path: Path): + """Test __main__.""" + create_package(tmp_path, SOURCE) + output = run_command(tmp_path) + + file_created = tmp_path / "dist" / f"test{SUFFIX}" + assert file_created.is_file(), f"file not found: {file_created}" + + output = run_command(tmp_path, file_created, timeout=10) + assert output.startswith("Hello from cx_Freeze") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cx_Freeze-6.15.13/tests/test_cli.py new/cx_Freeze-6.15.15/tests/test_cli.py --- old/cx_Freeze-6.15.13/tests/test_cli.py 1970-01-01 01:00:00.000000000 +0100 +++ new/cx_Freeze-6.15.15/tests/test_cli.py 2024-02-10 10:18:02.000000000 +0100 @@ -0,0 +1,37 @@ +"""Tests for 'cxfreeze'.""" +from __future__ import annotations + +import sys +from pathlib import Path +from subprocess import CalledProcessError + +import pytest +from generate_samples import create_package, run_command + +SUFFIX = ".exe" if sys.platform == "win32" else "" + +SOURCE = """ +test.py + print("Hello from cx_Freeze") +command + cxfreeze test.py --target-dir=dist --excludes=tkinter +""" + + +def test_cxfreeze(tmp_path: Path): + """Test cxfreeze.""" + create_package(tmp_path, SOURCE) + output = run_command(tmp_path) + + file_created = tmp_path / "dist" / f"test{SUFFIX}" + assert file_created.is_file(), f"file not found: {file_created}" + + output = run_command(tmp_path, file_created, timeout=10) + assert output.startswith("Hello from cx_Freeze") + + +def test_cxfreeze_without_options(tmp_path: Path): + """Test cxfreeze without options.""" + create_package(tmp_path, SOURCE) + with pytest.raises(CalledProcessError): + run_command(tmp_path, "cxfreeze") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cx_Freeze-6.15.13/tests/test_command_bdist_msi.py new/cx_Freeze-6.15.15/tests/test_command_bdist_msi.py --- old/cx_Freeze-6.15.13/tests/test_command_bdist_msi.py 2024-01-24 09:02:55.000000000 +0100 +++ new/cx_Freeze-6.15.15/tests/test_command_bdist_msi.py 2024-02-10 10:18:02.000000000 +0100 @@ -5,7 +5,7 @@ from sysconfig import get_platform import pytest -from generate_samples import run_command +from generate_samples import create_package, run_command from setuptools import Distribution bdist_msi = pytest.importorskip( @@ -21,15 +21,6 @@ SAMPLES_DIR = Path(__file__).resolve().parent.parent / "samples" -@pytest.mark.datafiles(SAMPLES_DIR / "msi_binary_data") -def test_bdist_msi(datafiles: Path): - """Test the msi_binary_data sample.""" - run_command(datafiles, "python setup.py bdist_msi") - platform = get_platform().replace("win-amd64", "win64") - file_created = datafiles / "dist" / f"hello-0.1-{platform}.msi" - assert file_created.is_file() - - def test_bdist_msi_target_name(): """Test the bdist_msi with extra target_name option.""" dist = Distribution(DIST_ATTRS) @@ -52,6 +43,15 @@ @pytest.mark.datafiles(SAMPLES_DIR / "msi_binary_data") +def test_bdist_msi_default(datafiles: Path): + """Test the msi_binary_data sample.""" + run_command(datafiles, "python setup.py bdist_msi") + platform = get_platform().replace("win-amd64", "win64") + file_created = datafiles / "dist" / f"hello-0.1-{platform}.msi" + assert file_created.is_file() + + +@pytest.mark.datafiles(SAMPLES_DIR / "msi_binary_data") def test_bdist_msi_target_name_with_extension(datafiles: Path): """Test the msi_binary_data sample, with a specified target_name that includes an ".msi" extension. @@ -62,3 +62,65 @@ ) file_created = datafiles / "dist" / msi_name assert file_created.is_file() + + +@pytest.mark.datafiles(SAMPLES_DIR / "advanced") +def test_bdist_msi_advanced(datafiles: Path): + """Test the advanced sample.""" + msi_name = "output.msi" + run_command( + datafiles, f"python setup.py bdist_msi --target-name {msi_name}" + ) + file_created = datafiles / "dist" / msi_name + assert file_created.is_file() + + +@pytest.mark.datafiles(SAMPLES_DIR / "asmodule") +def test_bdist_msi_asmodule(datafiles: Path): + """Test the asmodule sample.""" + msi_name = "output.msi" + run_command( + datafiles, f"python setup.py bdist_msi --target-name {msi_name}" + ) + file_created = datafiles / "dist" / msi_name + assert file_created.is_file() + + +@pytest.mark.datafiles(SAMPLES_DIR / "sqlite") +def test_bdist_msi_sqlite(datafiles: Path): + """Test the sqlite sample.""" + msi_name = "output.msi" + run_command( + datafiles, f"python setup.py bdist_msi --target-name {msi_name}" + ) + file_created = datafiles / "dist" / msi_name + assert file_created.is_file() + + +SOURCE_HELLO = """ +hello.py + import pkg.hi + print("Hello from cx_Freeze") +setup.py + from cx_Freeze import Executable, setup + + setup( + name="hello", + version="0.1.2.3", + description="Sample cx_Freeze script", + executables=[Executable("hello.py")], + ) +pkg/hi.py + print("Hi!") +""" + + +def test_bdist_msi_advanced2(tmp_path: Path): + """Test the executables option.""" + create_package(tmp_path, SOURCE_HELLO) + msi_name = "output.msi" + run_command( + tmp_path, f"python setup.py bdist_msi --target-name {msi_name}" + ) + file_created = tmp_path / "dist" / msi_name + assert file_created.is_file() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cx_Freeze-6.15.13/tests/test_command_build.py new/cx_Freeze-6.15.15/tests/test_command_build.py --- old/cx_Freeze-6.15.13/tests/test_command_build.py 2024-01-24 09:02:55.000000000 +0100 +++ new/cx_Freeze-6.15.15/tests/test_command_build.py 2024-02-10 10:18:02.000000000 +0100 @@ -5,21 +5,53 @@ from pathlib import Path from sysconfig import get_platform, get_python_version -import pytest -from generate_samples import run_command +from generate_samples import create_package, run_command PLATFORM = get_platform() PYTHON_VERSION = get_python_version() BUILD_EXE_DIR = f"build/exe.{PLATFORM}-{PYTHON_VERSION}" -SAMPLES_DIR = Path(__file__).resolve().parent.parent / "samples" -IS_WINDOWS = sys.platform == "win32" -SUFFIX = ".exe" if IS_WINDOWS else "" +SUFFIX = ".exe" if sys.platform == "win32" else "" +SOURCE = """ +test.py + print("Hello from cx_Freeze") +setup.py + from cx_Freeze import setup, Executable -@pytest.mark.datafiles(SAMPLES_DIR / "simple") -def test_build(datafiles: Path): - """Test the simple sample.""" - run_command(datafiles) - file_created = datafiles / BUILD_EXE_DIR / f"hello{SUFFIX}" - assert file_created.is_file() + setup(executables=[Executable("test.py")]) +command + python setup.py build +""" + + +def test_build(tmp_path: Path): + """Test a simple build.""" + create_package(tmp_path, SOURCE) + + # first run, count the files + output = run_command(tmp_path) + + build_exe_dir = tmp_path / BUILD_EXE_DIR + + file_created = build_exe_dir / f"test{SUFFIX}" + assert file_created.is_file(), f"file not found: {file_created}" + + output = run_command(tmp_path, file_created, timeout=10) + assert output.startswith("Hello from cx_Freeze") + + files1 = list(build_exe_dir.rglob("*")) + + # second run to test target_dir "starts in a clean directory" + output = run_command(tmp_path) + + file_created = build_exe_dir / f"test{SUFFIX}" + assert file_created.is_file(), f"file not found: {file_created}" + + output = run_command(tmp_path, file_created, timeout=10) + assert output.startswith("Hello from cx_Freeze") + + files2 = list(build_exe_dir.rglob("*")) + + # compare + assert files1 == files2 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cx_Freeze-6.15.13/tests/test_command_build_exe.py new/cx_Freeze-6.15.15/tests/test_command_build_exe.py --- old/cx_Freeze-6.15.13/tests/test_command_build_exe.py 2024-01-24 09:02:55.000000000 +0100 +++ new/cx_Freeze-6.15.15/tests/test_command_build_exe.py 2024-02-10 10:18:02.000000000 +0100 @@ -1,6 +1,7 @@ """Tests for cx_Freeze.command.build_exe.""" from __future__ import annotations +import os import sys from pathlib import Path from sysconfig import get_platform, get_python_version @@ -14,7 +15,7 @@ PLATFORM = get_platform() PYTHON_VERSION = get_python_version() -BUILD_EXE_DIR = f"build/exe.{PLATFORM}-{PYTHON_VERSION}" +BUILD_EXE_DIR = os.path.normpath(f"build/exe.{PLATFORM}-{PYTHON_VERSION}") SAMPLES_DIR = Path(__file__).resolve().parent.parent / "samples" BUILD_EXE_CMD = "python setup.py build_exe --silent --excludes=tkinter" @@ -35,37 +36,69 @@ @pytest.mark.parametrize( - ("option", "value"), + ("kwargs", "option", "result"), [ + pytest.param( + {"build_exe": None}, + "build_exe", + BUILD_EXE_DIR, + id="build-exe=none", + ), # build_exe directory is the same as the build_base - ("build_exe", "build") + pytest.param( + {"build_exe": "build"}, + "build_exe", + None, + id="build-exe=build", + marks=pytest.mark.xfail(raises=SetupError), + ), + pytest.param( + {"build_exe": "dist"}, "build_exe", "dist", id="build-exe=dist" + ), + pytest.param( + {"include_msvcr": None}, + "include_msvcr", + False, + id="include-msvcr=none", + marks=pytest.mark.skipif(not IS_WINDOWS, reason="Windows tests"), + ), + pytest.param( + {"include_msvcr": False}, + "include_msvcr", + False, + id="include-msvcr=false", + marks=pytest.mark.skipif(not IS_WINDOWS, reason="Windows tests"), + ), + pytest.param( + {"include_msvcr": True}, + "include_msvcr", + True, + id="include-msvcr=true", + marks=pytest.mark.skipif(not IS_WINDOWS, reason="Windows tests"), + ), + pytest.param({"silent": None}, "silent", 0, id="silent=none->0"), + pytest.param({"silent": False}, "silent", 0, id="silent=false->0"), + pytest.param({"silent": True}, "silent", 1, id="silent=true->1"), + pytest.param( + {"silent_level": None}, "silent", 0, id="silent-level=none->0" + ), + pytest.param({"silent_level": 0}, "silent", 0, id="silent-level=0->0"), + pytest.param({"silent_level": 1}, "silent", 1, id="silent-level=1->1"), + pytest.param({"silent_level": 2}, "silent", 2, id="silent-level=2->2"), + pytest.param( + {"silent_level": "3"}, "silent", 3, id="silent-level=3->3" + ), ], ) -def test_build_exe_invalid_options(option, value): - """Test the build_exe with invalid options.""" +def test_build_exe_finalize_options( + kwargs: dict[str, ...], option: str, result +): + """Test the build_exe finalize_options.""" dist = Distribution(DIST_ATTRS) - cmd = build_exe(dist, **{option: value}) - with pytest.raises(SetupError): - cmd.finalize_options() - - -@pytest.mark.skipif(sys.platform != "win32", reason="Windows tests") -@pytest.mark.parametrize( - ("option", "value", "result"), - [ - ("include_msvcr", True, True), - ("include_msvcr", None, False), - ("include_msvcr", False, False), - ], - ids=["yes", "none", "no"], -) -def test_build_exe_with_include_msvcr_option(option, value, result): - """Test the build_exe with include_msvcr option.""" - dist = Distribution(DIST_ATTRS) - cmd = build_exe(dist, **{option: value}) + cmd = build_exe(dist, **kwargs) cmd.finalize_options() cmd.ensure_finalized() - assert cmd.include_msvcr == result + assert getattr(cmd, option) == result @pytest.mark.datafiles(SAMPLES_DIR / "advanced") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cx_Freeze-6.15.13/tests/test_command_install.py new/cx_Freeze-6.15.15/tests/test_command_install.py --- old/cx_Freeze-6.15.13/tests/test_command_install.py 1970-01-01 01:00:00.000000000 +0100 +++ new/cx_Freeze-6.15.15/tests/test_command_install.py 2024-02-10 10:18:02.000000000 +0100 @@ -0,0 +1,47 @@ +"""Tests for cx_Freeze.command.install.""" + +from __future__ import annotations + +import os +import sys +from pathlib import Path +from sysconfig import get_platform, get_python_version + +from generate_samples import create_package, run_command + +PLATFORM = get_platform() +PYTHON_VERSION = get_python_version() +BUILD_EXE_DIR = f"build/exe.{PLATFORM}-{PYTHON_VERSION}" + +SUFFIX = ".exe" if sys.platform == "win32" else "" + +SOURCE = """ +test.py + print("Hello from cx_Freeze") +setup.py + from cx_Freeze import setup, Executable + + setup(name="hello", executables=[Executable("test.py")]) +command + python setup.py install --prefix=base --root=root +""" + + +def test_install(tmp_path: Path): + """Test a simple install.""" + create_package(tmp_path, SOURCE) + + if sys.platform == "win32": + run_command(tmp_path, "python setup.py install --root=root") + program_files = Path(os.getenv("PROGRAMFILES")) + prefix = program_files.relative_to(program_files.anchor) / "hello" + else: + run_command(tmp_path) + prefix = "base/lib/hello-0.0.0" + install_dir = tmp_path / "root" / prefix + + file_created = install_dir / f"test{SUFFIX}" + assert file_created.is_file(), f"file not found: {file_created}" + + output = run_command(tmp_path, file_created, timeout=10) + assert output.startswith("Hello from cx_Freeze") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cx_Freeze-6.15.13/tests/test_command_install_exe.py new/cx_Freeze-6.15.15/tests/test_command_install_exe.py --- old/cx_Freeze-6.15.13/tests/test_command_install_exe.py 1970-01-01 01:00:00.000000000 +0100 +++ new/cx_Freeze-6.15.15/tests/test_command_install_exe.py 2024-02-10 10:18:02.000000000 +0100 @@ -0,0 +1,55 @@ +"""Tests for cx_Freeze.command.install_exe.""" + +from __future__ import annotations + +import os +import sys +from pathlib import Path +from sysconfig import get_config_var + +import pytest +from setuptools import Distribution + +from cx_Freeze import Executable +from cx_Freeze.command.install_exe import InstallEXE as install_exe + +DIST_ATTRS = { + "name": "foo", + "version": "0.0", + "executables": [Executable("hello.py")], + "script_name": "setup.py", +} + + +@pytest.mark.parametrize( + ("kwargs", "option", "result"), + [ + pytest.param( + {"install_dir": None}, + "install_dir", + os.fspath( + Path(os.getenv("PROGRAMFILES"), "foo") + if sys.platform == "win32" + else Path(get_config_var("base"), "lib/foo-0.0") + ), + id="install-dir=none", + ), + pytest.param( + {"install_dir": "dist"}, + "install_dir", + "dist", + id="install-dir=dist", + ), + ], +) +def test_install_exe_finalize_options( + kwargs: dict[str, ...], option: str, result +): + """Test the install_exe finalize_options.""" + dist = Distribution(DIST_ATTRS) + cmd = install_exe(dist, **kwargs) + cmd.finalize_options() + cmd.ensure_finalized() + assert getattr(cmd, option) == result + assert len(cmd.get_inputs()) > 0 + assert cmd.get_outputs() == [] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cx_Freeze-6.15.13/tests/test_freezer.py new/cx_Freeze-6.15.15/tests/test_freezer.py --- old/cx_Freeze-6.15.13/tests/test_freezer.py 1970-01-01 01:00:00.000000000 +0100 +++ new/cx_Freeze-6.15.15/tests/test_freezer.py 2024-02-10 10:18:02.000000000 +0100 @@ -0,0 +1,181 @@ +"""Tests for cx_Freeze.freezer.""" + +from __future__ import annotations + +import sys +from pathlib import Path +from sysconfig import get_config_vars, get_platform, get_python_version + +import pytest +from generate_samples import create_package + +from cx_Freeze import Executable, Freezer +from cx_Freeze.exception import OptionError + +PLATFORM = get_platform() +IS_LINUX = PLATFORM.startswith("linux") +IS_MACOS = PLATFORM.startswith("macos") +IS_WINDOWS = PLATFORM.startswith("win") +PYTHON_VERSION = get_python_version() +BUILD_EXE_DIR = f"build/exe.{PLATFORM}-{PYTHON_VERSION}" + +SOURCE = """ +hello.py + print("Hello from cx_Freeze") +""" + + +def test_freezer_target_dir_empty(tmp_path: Path, monkeypatch): + """Test freezer target_dir empty.""" + create_package(tmp_path, SOURCE) + monkeypatch.chdir(tmp_path) + + freezer = Freezer(executables=[Executable("hello.py")]) + target_dir = tmp_path / BUILD_EXE_DIR + assert freezer.target_dir.absolute() == target_dir + + +def test_freezer_target_dir_in_path(tmp_path: Path, monkeypatch): + """Test freezer target_dir in path.""" + create_package(tmp_path, SOURCE) + monkeypatch.chdir(tmp_path) + + target_dir = tmp_path / BUILD_EXE_DIR + target_dir.mkdir(parents=True) + with pytest.raises( + OptionError, + match="the build_exe directory cannot be used as search path", + ): + Freezer( + executables=[Executable("hello.py")], path=[*sys.path, target_dir] + ) + + +def test_freezer_target_dir_locked(tmp_path: Path, monkeypatch): + """Test freezer target_dir locked.""" + create_package(tmp_path, SOURCE) + monkeypatch.chdir(tmp_path) + + def t_rmtree(path, _ignore_errors=False, _onerror=None): + raise OSError(f"cannot clean {path}") + + monkeypatch.setattr("shutil.rmtree", t_rmtree) + + target_dir = tmp_path / BUILD_EXE_DIR + target_dir.mkdir(parents=True) + with pytest.raises( + OptionError, match="the build_exe directory cannot be cleaned" + ): + Freezer(executables=[Executable("hello.py")], target_dir=target_dir) + + +def test_freezer_default_bin_includes(tmp_path: Path, monkeypatch): + """Test freezer _default_bin_includes.""" + create_package(tmp_path, SOURCE) + monkeypatch.chdir(tmp_path) + + freezer = Freezer(executables=[Executable("hello.py")]) + if IS_WINDOWS: + expected = f"python{PYTHON_VERSION.replace('.','')}.dll" + elif IS_MACOS: + if sys.version_info[:2] <= (3, 10): + expected = f"libpython{PYTHON_VERSION}.dylib" + else: + expected = f"Python.framework/Versions/{PYTHON_VERSION}/Python" + else: + expected = f"libpython{PYTHON_VERSION}.so" + assert expected in freezer.bin_includes + + +def test_freezer_default_bin_includes_emulated(tmp_path: Path, monkeypatch): + """Test freezer _default_bin_includes in conda/mingw environments.""" + create_package(tmp_path, SOURCE) + monkeypatch.chdir(tmp_path) + + def t_get_config_var(name): + if name == "INSTSONAME": + # emulate conda and/or mingw + soname = f"libpython{PYTHON_VERSION}.a" + if IS_WINDOWS: # emulate mingw + soname = soname.replace(".a", ".dll.a") + return soname + return get_config_vars().get(name) + + monkeypatch.setattr("sysconfig.get_config_var", t_get_config_var) + + freezer = Freezer(executables=[Executable("hello.py")]) + if IS_WINDOWS: + expected = f"libpython{PYTHON_VERSION}.dll" + elif IS_MACOS: + expected = f"libpython{PYTHON_VERSION}.dylib" + else: + expected = f"libpython{PYTHON_VERSION}.so" + assert expected in freezer.bin_includes + + +def test_freezer_populate_zip_options(tmp_path: Path, monkeypatch): + """Test freezer _populate_zip_options.""" + create_package(tmp_path, SOURCE) + monkeypatch.chdir(tmp_path) + + # zip_include_packages and zip_exclude_packages are None (default) + freezer = Freezer(executables=[Executable("hello.py")]) + assert freezer.zip_include_packages == set() + assert freezer.zip_exclude_packages == set("*") + assert freezer.zip_include_all_packages is False + + # zip_include_packages=* + freezer = Freezer( + executables=[Executable("hello.py")], + zip_include_packages=["*"], + zip_exclude_packages=[], + ) + assert freezer.zip_include_packages == set("*") + assert freezer.zip_exclude_packages == set() + assert freezer.zip_include_all_packages is True + + # zip_exclude_packages=* + freezer = Freezer( + executables=[Executable("hello.py")], + zip_include_packages=[], + zip_exclude_packages=["*"], + ) + assert freezer.zip_include_packages == set() + assert freezer.zip_exclude_packages == set("*") + assert freezer.zip_include_all_packages is False + + # zip_include_packages and zip_exclude_packages are "*" + with pytest.raises( + OptionError, match="all packages cannot be included and excluded " + ): + freezer = Freezer( + executables=[Executable("hello.py")], + zip_include_packages=["*"], + zip_exclude_packages=["*"], + ) + + # zip_include_packages and zip_exclude_packages has the same package + with pytest.raises(OptionError, match="package 'tkinter' cannot be both"): + freezer = Freezer( + executables=[Executable("hello.py")], + zip_include_packages=["tkinter"], + zip_exclude_packages=["tkinter"], + ) + with pytest.raises( + OptionError, match="packages 'tkinter, unittest' cannot be both" + ): + freezer = Freezer( + executables=[Executable("hello.py")], + zip_include_packages=["tkinter", "unittest"], + zip_exclude_packages=["tkinter", "unittest", "codeop"], + ) + + # zip_include_packages and zip_exclude_packages are namespace packages + freezer = Freezer( + executables=[Executable("hello.py")], + zip_include_packages=["namespace.test"], + zip_exclude_packages=["zope.event", "zope.interface"], + ) + assert freezer.zip_include_packages == {"namespace"} + assert freezer.zip_exclude_packages == {"zope"} + assert freezer.zip_include_all_packages is False diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cx_Freeze-6.15.13/tests/test_winversioninfo.py new/cx_Freeze-6.15.15/tests/test_winversioninfo.py --- old/cx_Freeze-6.15.13/tests/test_winversioninfo.py 2024-01-24 09:02:55.000000000 +0100 +++ new/cx_Freeze-6.15.15/tests/test_winversioninfo.py 2024-02-10 10:18:02.000000000 +0100 @@ -9,7 +9,12 @@ import pytest from generate_samples import create_package, run_command -from cx_Freeze.winversioninfo import Version, VersionInfo, main_test +from cx_Freeze.winversioninfo import ( + COMMENTS_MAX_LEN, + Version, + VersionInfo, + main_test, +) PLATFORM = get_platform() PYTHON_VERSION = get_python_version() @@ -97,6 +102,14 @@ assert version_instance.debug is input_debug assert version_instance.verbose is input_verbose + def test_big_comment(self): + """Tests a big comment value for the VersionInfo class.""" + input_version = "9.9.9.9" + input_comments = "TestComment" + "=" * COMMENTS_MAX_LEN + version_instance = VersionInfo(input_version, comments=input_comments) + assert version_instance.version == "9.9.9.9" + assert version_instance.comments == input_comments[:COMMENTS_MAX_LEN] + @pytest.mark.parametrize( ("input_version", "version"), [ ++++++ python312.patch ++++++ Index: cx_Freeze-6.15.15/cx_Freeze/finder.py =================================================================== --- cx_Freeze-6.15.15.orig/cx_Freeze/finder.py +++ cx_Freeze-6.15.15/cx_Freeze/finder.py @@ -30,7 +30,10 @@ EXTENDED_ARG = opcode.opmap["EXTENDED_AR LOAD_CONST = opcode.opmap["LOAD_CONST"] IMPORT_NAME = opcode.opmap["IMPORT_NAME"] IMPORT_FROM = opcode.opmap["IMPORT_FROM"] -IMPORT_STAR = opcode.opmap["IMPORT_STAR"] +# Python 3.12+ uses CALL_INTRINSIC_1 with argument 2 +IMPORT_STAR = ( + opcode.opmap.get("IMPORT_STAR") or opcode.opmap["CALL_INTRINSIC_1"] +) STORE_FAST = opcode.opmap["STORE_FAST"] STORE_NAME = opcode.opmap["STORE_NAME"] STORE_GLOBAL = opcode.opmap["STORE_GLOBAL"] @@ -637,6 +640,7 @@ class ModuleFinder: # import * statement: copy all global names elif ( opc == IMPORT_STAR + and (arg == 2 if opc > HAVE_ARGUMENT else None) and top_level and imported_module is not None ): Index: cx_Freeze-6.15.15/pyproject.toml =================================================================== --- cx_Freeze-6.15.15.orig/pyproject.toml +++ cx_Freeze-6.15.15/pyproject.toml @@ -31,6 +31,7 @@ classifiers = [ "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", "Topic :: Software Development :: Build Tools", "Topic :: Software Development :: Libraries :: Python Modules", "Topic :: System :: Software Distribution",