Skip to content

Commit 03b7c5e

Browse files
committed
Run setupext qt checks in a subprocess rather than with multiprocessing.
1 parent 912f9b6 commit 03b7c5e

File tree

1 file changed

+60
-133
lines changed

1 file changed

+60
-133
lines changed

setupext.py

Lines changed: 60 additions & 133 deletions
Original file line numberDiff line numberDiff line change
@@ -1621,155 +1621,82 @@ def get_extension(self):
16211621
return ext
16221622

16231623

1624-
class BackendQtBase(OptionalBackendPackage):
1625-
1626-
def convert_qt_version(self, version):
1627-
version = '%x' % version
1628-
temp = []
1629-
while len(version) > 0:
1630-
version, chunk = version[:-2], version[-2:]
1631-
temp.insert(0, str(int(chunk, 16)))
1632-
return '.'.join(temp)
1633-
1634-
def check_requirements(self):
1635-
"""
1636-
If PyQt4/PyQt5 is already imported, importing PyQt5/PyQt4 will fail
1637-
so we need to test in a subprocess (as for Gtk3).
1638-
"""
1639-
try:
1640-
p = multiprocessing.Pool()
1641-
1642-
except:
1643-
# Can't do multiprocessing, fall back to normal approach
1644-
# (this will fail if importing both PyQt4 and PyQt5).
1645-
try:
1646-
# Try in-process
1647-
msg = self.callback(self)
1648-
except RuntimeError:
1649-
raise CheckFailed(
1650-
"Could not import: are PyQt4 & PyQt5 both installed?")
1651-
1652-
else:
1653-
# Multiprocessing OK
1654-
try:
1655-
res = p.map_async(self.callback, [self])
1656-
msg = res.get(timeout=10)[0]
1657-
except multiprocessing.TimeoutError:
1658-
p.terminate()
1659-
# No result returned. Probably hanging, terminate the process.
1660-
raise CheckFailed("Check timed out")
1661-
except:
1662-
# Some other error.
1663-
p.close()
1664-
raise
1665-
else:
1666-
# Clean exit
1667-
p.close()
1668-
finally:
1669-
# Tidy up multiprocessing
1670-
p.join()
1671-
1672-
return msg
1673-
1674-
1675-
def backend_pyside_internal_check(self):
1676-
try:
1677-
from PySide import __version__
1678-
from PySide import QtCore
1679-
except ImportError:
1680-
raise CheckFailed("PySide not found")
1681-
else:
1682-
return ("Qt: %s, PySide: %s" %
1683-
(QtCore.__version__, __version__))
1624+
def _run_check_script(script):
1625+
"""
1626+
Run given script in a subprocess.
16841627
1628+
If the subprocess returns successfully, return the subprocess' stdout.
1629+
Otherwise, raise a `CheckFailed` with the subprocess' stderr.
16851630
1686-
def backend_pyqt4_internal_check(self):
1687-
try:
1688-
from PyQt4 import QtCore
1689-
except ImportError:
1690-
raise CheckFailed("PyQt4 not found")
1691-
1631+
The use of a subprocess is needed to avoid importing both Qt4 and Qt5 in
1632+
the same process (which causes a RuntimeError).
1633+
"""
16921634
try:
1693-
qt_version = QtCore.QT_VERSION
1694-
pyqt_version_str = QtCore.PYQT_VERSION_STR
1695-
except AttributeError:
1696-
raise CheckFailed('PyQt4 not correctly imported')
1635+
proc = subprocess.run([sys.executable, "-c", script],
1636+
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
1637+
universal_newlines=True, timeout=10)
1638+
except subprocess.TimeoutExpired:
1639+
raise CheckFailed("Check timed out")
1640+
if proc.returncode:
1641+
raise CheckFailed(proc.stderr)
16971642
else:
1698-
return ("Qt: %s, PyQt: %s" % (self.convert_qt_version(qt_version), pyqt_version_str))
1699-
1700-
1701-
def backend_qt4_internal_check(self):
1702-
successes = []
1703-
failures = []
1704-
try:
1705-
successes.append(backend_pyside_internal_check(self))
1706-
except CheckFailed as e:
1707-
failures.append(str(e))
1643+
return proc.stdout
17081644

1709-
try:
1710-
successes.append(backend_pyqt4_internal_check(self))
1711-
except CheckFailed as e:
1712-
failures.append(str(e))
1713-
1714-
if len(successes) == 0:
1715-
raise CheckFailed('; '.join(failures))
1716-
return '; '.join(successes + failures)
17171645

1718-
1719-
class BackendQt4(BackendQtBase):
1646+
class BackendQt4(OptionalBackendPackage):
17201647
name = "qt4agg"
17211648

1722-
def __init__(self, *args, **kwargs):
1723-
BackendQtBase.__init__(self, *args, **kwargs)
1724-
self.callback = backend_qt4_internal_check
1649+
def check_requirements(self):
1650+
return _run_check_script("""\
1651+
found = []
17251652
1726-
def backend_pyside2_internal_check(self):
1727-
try:
1728-
from PySide2 import __version__
1729-
from PySide2 import QtCore
1730-
except ImportError:
1731-
raise CheckFailed("PySide2 not found")
1732-
else:
1733-
return ("Qt: %s, PySide2: %s" %
1734-
(QtCore.__version__, __version__))
1653+
try:
1654+
from PyQt4.QtCore import QT_VERSION_STR, PYQT_VERSION_STR
1655+
except ImportError:
1656+
pass
1657+
else:
1658+
found.append("Qt: {}, PyQt: {}".format(QT_VERSION_STR, PYQT_VERSION_STR))
17351659
1736-
def backend_pyqt5_internal_check(self):
1737-
try:
1738-
from PyQt5 import QtCore
1739-
except ImportError:
1740-
raise CheckFailed("PyQt5 not found")
1660+
try:
1661+
from PySide import __version__, QtCore
1662+
except ImportError:
1663+
pass
1664+
else:
1665+
found.append("Qt: {}, PySide: {}".format(QtCore.__version__, __version__))
17411666
1742-
try:
1743-
qt_version = QtCore.QT_VERSION
1744-
pyqt_version_str = QtCore.PYQT_VERSION_STR
1745-
except AttributeError:
1746-
raise CheckFailed('PyQt5 not correctly imported')
1747-
else:
1748-
return ("Qt: %s, PyQt: %s" % (self.convert_qt_version(qt_version), pyqt_version_str))
1667+
if found:
1668+
print("; ".join(found), end="")
1669+
else:
1670+
sys.exit("Found neither PyQt4 nor PySide.")
1671+
""")
17491672

1750-
def backend_qt5_internal_check(self):
1751-
successes = []
1752-
failures = []
1753-
try:
1754-
successes.append(backend_pyside2_internal_check(self))
1755-
except CheckFailed as e:
1756-
failures.append(str(e))
17571673

1758-
try:
1759-
successes.append(backend_pyqt5_internal_check(self))
1760-
except CheckFailed as e:
1761-
failures.append(str(e))
1674+
class BackendQt5(OptionalBackendPackage):
1675+
name = "qt5agg"
17621676

1763-
if len(successes) == 0:
1764-
raise CheckFailed('; '.join(failures))
1765-
return '; '.join(successes + failures)
1677+
def check_requirements(self):
1678+
return _run_check_script("""\
1679+
found = []
17661680
1767-
class BackendQt5(BackendQtBase):
1768-
name = "qt5agg"
1681+
try:
1682+
from PyQt5.QtCore import QT_VERSION_STR, PYQT_VERSION_STR
1683+
except ImportError:
1684+
pass
1685+
else:
1686+
found.append("Qt: {}, PyQt: {}".format(QT_VERSION_STR, PYQT_VERSION_STR))
17691687
1770-
def __init__(self, *args, **kwargs):
1771-
BackendQtBase.__init__(self, *args, **kwargs)
1772-
self.callback = backend_qt5_internal_check
1688+
try:
1689+
from PySide2 import __version__, QtCore
1690+
except ImportError:
1691+
pass
1692+
else:
1693+
found.append("Qt: {}, PySide: {}".format(QtCore.__version__, __version__))
1694+
1695+
if found:
1696+
print("; ".join(found), end="")
1697+
else:
1698+
sys.exit("Found neither PyQt5 nor PySide2.")
1699+
""")
17731700

17741701

17751702
class BackendCairo(OptionalBackendPackage):

0 commit comments

Comments
 (0)