Skip to content
Snippets Groups Projects
Commit 8a4c9f6b authored by Andreas Bolin's avatar Andreas Bolin
Browse files

RC and UI compiler is now in separate module

parent 245f737a
No related branches found
No related tags found
1 merge request!87RC and UI compiler is now in separate module
Pipeline #74906 passed
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""B-ASIC Scheduler-gui Resource and Form Compiler Module.
Compiles Qt5 resource and form files. Requires PySide2 or PyQt5 to be installed.
If no arguments is given, the compiler search for and compiles all form (.ui)
files.
"""
from qtpy import uic, API
import sys
import os
import shutil
import subprocess
import argparse
import b_asic.scheduler_gui
import b_asic.scheduler_gui.logger as logger
log = logger.getLogger()
sys.excepthook = logger.handle_exceptions
def _check_filenames(*filenames: str) -> None:
"""Check if the filename(s) exist and if not, raise 'FileNotFoundError'
exception."""
for filename in filenames:
if not os.path.exists(filename):
raise FileNotFoundError(filename)
def _check_qt_version() -> None:
"""Checks if PySide2 or PyQt5 is installed, raises AssertionError otherwise."""
assert uic.PYSIDE2 or uic.PYQT5, 'PySide2 or PyQt5 need to be installed'
def replace_qt_bindings(filename: str) -> None:
"""Raplaces qt-binding api in 'filename' from PySide2/PyQt5 to qtpy."""
with open(f'{filename}', 'r') as file:
filedata = file.read()
filedata = filedata.replace('from PyQt5', 'from qtpy')
filedata = filedata.replace('from PySide2', 'from qtpy')
with open(f'{filename}', 'w') as file:
file.write(filedata)
def compile_rc(*filenames: str) -> None:
"""Compile resource file(s) given by 'filenames'. If no arguments are given,
the compiler will search for '*.qrc' files in 'icons\' folder and compile
accordingly."""
_check_qt_version()
def compile(filename: str = None) -> None:
outfile = f'{os.path.splitext(filename)[0]}_rc.py'
os_ = sys.platform
rcc = shutil.which('pyside2-rcc')
args = f'-g python -o {outfile} {filename}'
if rcc is None:
rcc = shutil.which('rcc')
if rcc is None:
rcc = shutil.which('pyrcc5')
args = f'-o {outfile} {filename}'
assert rcc, "PySide2 compiler failed, can't find rcc"
if os_.startswith("linux"): # Linux
cmd = f'{rcc} {args}'
subprocess.call(cmd.split())
elif os_.startswith("win32"): # Windows
# TODO: implement
log.error('Windows RC compiler not implemented')
raise NotImplementedError
elif os_.startswith("darwin"): # macOS
# TODO: implement
log.error('macOS RC compiler not implemented')
raise NotImplementedError
else: # other OS
log.error(f'{os_} RC compiler not supported')
raise NotImplementedError
replace_qt_bindings(outfile) # replace qt-bindings with qtpy
if not filenames:
rc_files = [os.path.join(root, name)
for root, dirs, files in os.walk('.')
for name in files
if name.endswith(('.qrc'))]
for filename in rc_files:
compile(filename)
else:
_check_filenames(*filenames)
for filename in filenames:
compile(filename)
def compile_ui(*filenames: str) -> None:
"""Compile form file(s) given by 'filenames'. If no arguments are given,
the compiler will search for '*.ui' files and compile accordingly."""
_check_qt_version()
def compile(filename: str) -> None:
dir, file = os.path.split(filename)
file, _ = os.path.splitext(file)
dir = dir if dir else '.'
outfile = f'{dir}/ui_{file}.py'
if uic.PYSIDE2:
os_ = sys.platform
uic_ = shutil.which('pyside2-uic')
args = f'-g python -o {outfile} {filename}'
if uic_ is None:
uic_ = shutil.which('uic')
if uic_ is None:
uic_ = shutil.which('pyuic5')
args = f'-o {outfile} {filename}'
assert uic_, "PySide2 compiler failed, can't find uic"
if os_.startswith("linux"): # Linux
cmd = f'{uic_} {args}'
subprocess.call(cmd.split())
elif os_.startswith("win32"): # Windows
# TODO: implement
log.error('Windows UI compiler not implemented')
raise NotImplementedError
elif os_.startswith("darwin"): # macOS
# TODO: implement
log.error('macOS UI compiler not implemented')
raise NotImplementedError
else: # other OS
log.error(f'{os_} UI compiler not supported')
raise NotImplementedError
else: # uic.PYQT5
from qtpy.uic import compileUi
with open(outfile, 'w') as ofile:
compileUi(filename, ofile)
replace_qt_bindings(outfile) # replace qt-bindings with qtpy
if not filenames:
ui_files = [os.path.join(root, name)
for root, dirs, files in os.walk('.')
for name in files
if name.endswith(('.ui'))]
for filename in ui_files:
compile(filename)
else:
_check_filenames(*filenames)
for filename in filenames:
compile(filename)
def compile_all():
"""The compiler will search for '*.qrc* resource files in 'icons\' folder
and for '*.ui' form files and compile accordingly."""
compile_rc()
compile_ui()
if __name__ == '__main__':
ver = b_asic.scheduler_gui.__version__
descr = __doc__
parser = argparse.ArgumentParser(description=f'{descr}',
formatter_class=argparse.RawTextHelpFormatter)
parser.add_argument('-v', '--version',
action='version',
version=f'%(prog)s v{ver}')
if sys.version_info >= (3, 8):
parser.add_argument('--ui',
metavar='<file>',
action='extend',
nargs='*',
help="compile form file(s) if <file> is given, otherwise search\n"
"for all form (*.ui) files and compile them all (default)")
parser.add_argument('--rc',
metavar='<file>',
action='extend',
nargs='*',
help="compile resource file(s) if <file> is given, otherwise\n"
"search for all resource (*.ui) files and compile them all")
else:
parser.add_argument('--ui',
metavar='<file>',
action='append',
help="compile form file")
parser.add_argument('--rc',
metavar='<file>',
action='append',
help="compile resource file")
parser.add_argument('--all',
action='store_true',
help="search and compile all resource and form file(s)")
if len(sys.argv) == 1:
compile_ui()
args = parser.parse_args()
if args.ui is not None:
compile_ui(*args.ui)
if args.rc is not None:
compile_rc(*args.rc)
if args.all:
compile_all()
......@@ -47,10 +47,8 @@ from b_asic.schedule import Schedule
from b_asic.scheduler_gui.graphics_axes_item import GraphicsAxesItem
from b_asic.scheduler_gui.graphics_component_item import GraphicsComponentItem
from b_asic.scheduler_gui.graphics_graph_item import GraphicsGraphItem
# if sys.version_info >= (3, 9):
# List = list
# #Dict = dict
sys.path.insert(0, "icons/") # Needed for *.rc.py files in ui_main_window
from b_asic.scheduler_gui.ui_main_window import Ui_MainWindow
log = logger.getLogger()
sys.excepthook = logger.handle_exceptions
......@@ -78,43 +76,6 @@ if __debug__:
log.debug("PyQt version: {}".format(PYQT_VERSION_STR))
log.debug("QtPy version: {}".format(qtpy.__version__))
# Autocompile the .ui form to a python file.
try: # PyQt5, try autocompile
from qtpy.uic import compileUiDir
compileUiDir(".", map=(lambda dir, file: (dir, "ui_" + file)))
except:
try: # PySide2, try manual compile
import subprocess
os_ = sys.platform
if os_.startswith("linux"):
cmds = ["pyside2-uic -o ui_main_window.py main_window.ui"]
for cmd in cmds:
subprocess.call(cmd.split())
else:
# TODO: Implement (startswith) 'win32', 'darwin' (MacOs)
raise SystemExit
except: # Compile failed, look for pre-compiled file
try:
from b_asic.scheduler_gui.ui_main_window import Ui_MainWindow
except: # Everything failed, exit
log.exception("Could not import 'Ui_MainWindow'.")
log.exception(
"Can't autocompile under",
QT_API,
"eviroment. Try to manual compile 'main_window.ui' to"
" 'ui/main_window_ui.py'",
)
os._exit(1)
sys.path.insert(
0, "icons/"
) # Needed for the compiled '*_rc.py' files in 'ui_*.py' files
from b_asic.scheduler_gui.ui_main_window import (
Ui_MainWindow,
) # Only availible when the form (.ui) is compiled
# The following QCoreApplication values is used for QSettings among others
QCoreApplication.setOrganizationName("Linöping University")
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment