Skip to content

Commit

Permalink
Fix Windows build and runtime on Python 3.11.4 (#312)
Browse files Browse the repository at this point in the history
* Fix Windows build and runtime on Python 3.11.4

Fixes:
- Runtime on Python 3.11
- Setuptools, tested with 3.11.4
- Missing pywin32 dependency
- Lock file mishandling on Windows
- Fix a mistake in version handling code
  • Loading branch information
AstralStorm authored Jan 16, 2024
1 parent 29d5256 commit 2132e21
Show file tree
Hide file tree
Showing 7 changed files with 65 additions and 63 deletions.
2 changes: 0 additions & 2 deletions DisplayCAL/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -2226,7 +2226,5 @@ def writecfg(which="user", worker=None, module=None, options=(), cfg=cfg):
if not cafile:
# Use our bundled CA file
cafile = get_data_path("cacert.pem")
if cafile:
cafile = cafile.encode(fs_enc, "replace")
if cafile:
os.environ["SSL_CERT_FILE"] = cafile
47 changes: 24 additions & 23 deletions DisplayCAL/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@
from DisplayCAL.util_os import FileLock, LockingError, UnlockingError

if sys.platform == "win32":
from util_win import win_ver
from DisplayCAL.util_win import win_ver
import ctypes


Expand Down Expand Up @@ -392,8 +392,9 @@ def _main(module, name, app_lock_file_name, probe_ports=True):
handle_error(lang.getstr("app.otherinstance", name))
# Exit
return
lock.unlock()
# Use exclusive lock during app startup
with lock:
with AppLock(app_lock_file_name, "a+", True, True) as lock:
# Create listening socket
appsocket = AppSocket()
if appsocket:
Expand Down Expand Up @@ -513,27 +514,27 @@ def _main(module, name, app_lock_file_name, probe_ports=True):
% ";".join(script).encode(fs_enc),
]
)
# Initialize & run
if module == "3DLUT-maker":
from DisplayCAL.wxLUT3DFrame import main
elif module == "curve-viewer":
from DisplayCAL.wxLUTViewer import main
elif module == "profile-info":
from DisplayCAL.wxProfileInfo import main
elif module == "scripting-client":
from DisplayCAL.wxScriptingClient import main
elif module == "synthprofile":
from DisplayCAL.wxSynthICCFrame import main
elif module == "testchart-editor":
from DisplayCAL.wxTestchartEditor import main
elif module == "VRML-to-X3D-converter":
from DisplayCAL.wxVRML2X3D import main
elif module == "apply-profiles":
from DisplayCAL.profile_loader import main
else:
from DisplayCAL.display_cal import main
# Run main after releasing lock
main()
# Initialize & run
if module == "3DLUT-maker":
from DisplayCAL.wxLUT3DFrame import main
elif module == "curve-viewer":
from DisplayCAL.wxLUTViewer import main
elif module == "profile-info":
from DisplayCAL.wxProfileInfo import main
elif module == "scripting-client":
from DisplayCAL.wxScriptingClient import main
elif module == "synthprofile":
from DisplayCAL.wxSynthICCFrame import main
elif module == "testchart-editor":
from DisplayCAL.wxTestchartEditor import main
elif module == "VRML-to-X3D-converter":
from DisplayCAL.wxVRML2X3D import main
elif module == "apply-profiles":
from DisplayCAL.profile_loader import main
else:
from DisplayCAL.display_cal import main
# Run main after releasing lock
main()


def main(module=None):
Expand Down
2 changes: 1 addition & 1 deletion DisplayCAL/postinstall.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ def file_created(path):
installed_files.extend(line.rstrip("\n") for line in recordfile)
recordfile.close()
try:
path.decode("ASCII")
path.encode("ASCII")
except (UnicodeDecodeError, UnicodeEncodeError):
# the contents of the record file used by distutils
# must be ASCII GetShortPathName allows us to avoid
Expand Down
8 changes: 5 additions & 3 deletions DisplayCAL/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -197,9 +197,9 @@ def add_lib_excludes(key, excludebits):
config["excludes"][key].extend([f"{name}.lib{exclude}", f"lib{exclude}"])

for exclude in ("32", "64"):
for pycompat in ("38", "39", "310"):
for pycompat in ("38", "39", "310", "311"):
if key == "win32" and (
pycompat == sys.version[0] + sys.version[2] or exclude == excludebits[0]
pycompat == str(sys.version_info[0]) + str(sys.version_info[1]) or exclude == excludebits[0]
):
continue
config["excludes"][key].extend(
Expand Down Expand Up @@ -955,7 +955,7 @@ def findall(
packages = [name, f"{name}.lib", f"{name}.lib.agw"]
if sdist:
# For source distributions we want all libraries
for pycompat in ("38", "39", "310"):
for pycompat in ("38", "39", "310", "311"):
packages.extend(
[
f"{name}.lib{bits}",
Expand Down Expand Up @@ -1265,6 +1265,8 @@ def copy_package_data(self, package, target_dir):
"mswsock.dll",
"urlmon.dll",
"w9xpopen.exe",
"gdiplus.dll",
"mfc90.dll",
],
"excludes": config["excludes"]["all"] + config["excludes"]["win32"],
"bundle_files": 3 if wx.VERSION >= (2, 8, 10, 1) else 1,
Expand Down
60 changes: 30 additions & 30 deletions DisplayCAL/util_os.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,95 +104,95 @@ def open(path, *args, **kwargs):

_access = os.access

def access(path, mode):
return _access(make_win32_compatible_long_path(path), mode)
def access(path, mode, *args, **kwargs):
return _access(make_win32_compatible_long_path(path), mode, *args, **kwargs)

os.access = access

_exists = os.path.exists

def exists(path):
return _exists(make_win32_compatible_long_path(path))
def exists(path, *args, **kwargs):
return _exists(make_win32_compatible_long_path(path), *args, **kwargs)

os.path.exists = exists

_isdir = os.path.isdir

def isdir(path):
return _isdir(make_win32_compatible_long_path(path))
def isdir(path, *args, **kwargs):
return _isdir(make_win32_compatible_long_path(path), *args, **kwargs)

os.path.isdir = isdir

_isfile = os.path.isfile

def isfile(path):
return _isfile(make_win32_compatible_long_path(path))
def isfile(path, *args, **kwargs):
return _isfile(make_win32_compatible_long_path(path), *args, **kwargs)

os.path.isfile = isfile

def listdir(path):
return _listdir(make_win32_compatible_long_path(path))
def listdir(path, *args, **kwargs):
return _listdir(make_win32_compatible_long_path(path), *args, **kwargs)

_lstat = os.lstat

def lstat(path):
return _lstat(make_win32_compatible_long_path(path))
def lstat(path, *args, **kwargs):
return _lstat(make_win32_compatible_long_path(path), *args, **kwargs)

os.lstat = lstat

_mkdir = os.mkdir

def mkdir(path, mode=0o777):
return _mkdir(make_win32_compatible_long_path(path, 247), mode)
def mkdir(path, mode=0o777, *args, **kwargs):
return _mkdir(make_win32_compatible_long_path(path, 247), mode, *args, **kwargs)

os.mkdir = mkdir

_makedirs = os.makedirs

def makedirs(path, mode=0o777):
return _makedirs(make_win32_compatible_long_path(path, 247), mode)
def makedirs(path, mode=0o777, *args, **kwargs):
return _makedirs(make_win32_compatible_long_path(path, 247), mode, *args, **kwargs)

os.makedirs = makedirs

_remove = os.remove

def remove(path):
return _remove(make_win32_compatible_long_path(path))
def remove(path, *args, **kwargs):
return _remove(make_win32_compatible_long_path(path), *args, **kwargs)

os.remove = retry_sharing_violation_factory(remove)

_rename = os.rename

def rename(src, dst):
def rename(src, dst, *args, **kwargs):
src, dst = [make_win32_compatible_long_path(path) for path in (src, dst)]
return _rename(src, dst)
return _rename(src, dst, *args, **kwargs)

os.rename = retry_sharing_violation_factory(rename)

_stat = os.stat

def stat(path):
return _stat(make_win32_compatible_long_path(path))
def stat(path, *args, **kwargs):
return _stat(make_win32_compatible_long_path(path), *args, **kwargs)

os.stat = stat

_unlink = os.unlink

def unlink(path):
return _unlink(make_win32_compatible_long_path(path))
def unlink(path, *args, **kwargs):
return _unlink(make_win32_compatible_long_path(path), *args, **kwargs)

os.unlink = retry_sharing_violation_factory(unlink)

_GetShortPathName = win32api.GetShortPathName

def GetShortPathName(path):
return _GetShortPathName(make_win32_compatible_long_path(path))
def GetShortPathName(path, *args, **kwargs):
return _GetShortPathName(make_win32_compatible_long_path(path), *args, **kwargs)

win32api.GetShortPathName = GetShortPathName
else:

def listdir(path):
paths = _listdir(path)
def listdir(path, *args, **kwargs):
paths = _listdir(path, *args, **kwargs)
if isinstance(path, str):
# Undecodable filenames will still be string objects. Ignore them.
paths = [path for path in paths if isinstance(path, str)]
Expand Down Expand Up @@ -465,9 +465,9 @@ def listdir_re(path, rex=None):
def make_win32_compatible_long_path(path, maxpath=259):
if (
sys.platform == "win32"
and len(path) > maxpath
and len(str(path)) > maxpath
and os.path.isabs(path)
and not path.startswith("\\\\?\\")
and not str(path).startswith("\\\\?\\")
):
path = "\\\\?\\" + path
return path
Expand Down
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
[build-system]
requires = ["setuptools"]
requires = ["setuptools",
'pywin32; platform_system=="Windows"']
build-backend = "setuptools.build_meta"
6 changes: 3 additions & 3 deletions util/winmanifest.py
Original file line number Diff line number Diff line change
Expand Up @@ -990,9 +990,9 @@ def toprettyxml(self, indent=" ", newl=os.linesep, encoding="UTF-8"):
xmlstr = domtree.toprettyxml(indent, newl, encoding)
else:
xmlstr = domtree.toprettyxml(indent, newl)
xmlstr = xmlstr.strip(os.linesep).replace(
'<?xml version="1.0" encoding="%s"?>' % encoding,
'<?xml version="1.0" encoding="%s" standalone="yes"?>' % encoding,
xmlstr = xmlstr.strip(os.linesep.encode('utf-8')).replace(
('<?xml version="1.0" encoding="%s"?>' % encoding).encode('utf-8'),
('<?xml version="1.0" encoding="%s" standalone="yes"?>' % encoding).encode('utf-8'),
)
domtree.unlink()
return xmlstr
Expand Down

0 comments on commit 2132e21

Please sign in to comment.