Last active
June 1, 2024 04:07
-
-
Save Meatplowz/1e99b987ee8caac4bafe6ec298dc6203 to your computer and use it in GitHub Desktop.
Convert a designer .UI file to .Py file and insert into an existing .Py tool file
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import os | |
from shutil import copyfile | |
try: | |
# Pyside | |
from pysideuic import compileUi | |
except: | |
# Pyside2 | |
from pyside2uic import compileUi | |
def update_py_ui(ui_py, tool_py): | |
""" | |
Inject the modified .ui/.py code and inject into the actual python tool | |
*Arguments:* | |
* ``ui_py`` The .py file converted from .ui | |
* ``tool_py`` The .py file that will we inject the updated ui code into | |
*Keyword Arguments:* | |
* ``None`` | |
*Returns:* | |
* ``None`` | |
*Author:* | |
* randall.hess, [email protected], 09/02/2018 3:41:59 PM | |
""" | |
# open the ui_py file | |
try: | |
ui_file = open(ui_py, 'r') | |
except: | |
return | |
ui_all_lines = ui_file.readlines() | |
ui_file.close() | |
# scan to the line after class.startswith | |
ui_lines = None | |
for index in range(len(ui_all_lines)): | |
line = ui_all_lines[index].lstrip() | |
if line.startswith('class'): | |
ui_lines = ui_all_lines[index+1:] | |
break | |
# make sure we have ui lines | |
if not ui_lines: | |
return | |
# remove any from/import lines | |
# when promoting to external classes from/import lines are added | |
ui_lines = [line for line in ui_lines if not 'from' in line and not 'import' in line] | |
# open the tool_py file | |
try: | |
tool_file = open(tool_py, 'r') | |
except: | |
# file does not exist to read | |
return | |
tool_all_lines = tool_file.readlines() | |
tool_file.close() | |
# backup the tool file | |
name_split = os.path.basename(tool_py).split(os.path.extsep) | |
backup_name = name_split[0] + '_bak' + os.path.extsep + name_split[1] | |
backup_tool_py = os.path.join(os.path.dirname(tool_py), backup_name) | |
# remove def setupUI() lines through end of def retranslateUI() > def/class = 2 empty new lines | |
start_replace_index = None | |
end_replace_index = None | |
end_replace_scan = False | |
empty_line_range = 2 # Following PEP8 2 empty lines | |
empty_line_count = 0 | |
for index in range(len(tool_all_lines)): | |
line = tool_all_lines[index].lstrip() | |
if start_replace_index is None: | |
if line.startswith('def setupUi'): | |
start_replace_index = index | |
continue | |
else: | |
if not end_replace_scan: | |
# start scanning for the end of this def | |
if line.startswith('def retranslateUi'): | |
end_replace_scan = True | |
continue | |
else: | |
# scan for a new def/class line or stop after two empty lines | |
strip_line = line.rstrip() | |
if not strip_line: | |
empty_line_count += 1 | |
# exit end scan if we hit too many empty lines | |
if empty_line_count == empty_line_range: | |
end_replace_index = index | |
break | |
else: | |
# reset empty count if we continue to find text in subsequent lines | |
empty_line_count = 0 | |
# exit if the next def line is found | |
if strip_line.startswith('def'): | |
end_replace_index = index-1 | |
break | |
# exit if the new class line is found | |
elif strip_line.startswith('class'): | |
end_replace_index = index-1 | |
break | |
# make sure we have both indices | |
if not start_replace_index is None and not end_replace_index is None: | |
# lines that we keep up until we replace | |
start_lines = tool_all_lines[0:start_replace_index] | |
# lines that we keep after we are replacing | |
end_lines = tool_all_lines[end_replace_index:] | |
# create new tool lines | |
new_tool_lines = start_lines | |
new_tool_lines.extend(ui_lines) | |
new_tool_lines.extend(end_lines) | |
updated_file = False | |
with open(backup_tool_py, "w") as backup_tool_file: | |
backup_tool_file.writelines(new_tool_lines) | |
updated_file = True | |
# make sure the file was written properly | |
if updated_file: | |
# make sure file is writable and copy over it | |
try: | |
os.chmod(tool_py, 0777) | |
copyfile(backup_tool_py, tool_py) | |
except: | |
pass | |
def convert_qt_py(ui_py_file): | |
""" | |
Manual conversion of the python ui file to work with Qt.py | |
A couple search and replace strings have done the trick so far. | |
# Alternatively, you can use the conversion for Qt.py specifically | |
https://github.com/mottosso/Qt.py/issues/131 | |
*Arguments:* | |
* ``ui_py_file`` The .py file that was converted from the .ui | |
*Keyword Arguments:* | |
* ``None`` | |
*Returns:* | |
* ``None`` | |
*Author:* | |
* randall.hess, [email protected], 09/02/2018 3:41:59 PM | |
""" | |
# need to replace strings in this order | |
replace_strings = { 1: ['QtGui.QApplication','QtWidgets.QApplication'] | |
,2: ['QtGui','QtWidgets'] | |
,3: ['QtWidgets.QFont','QtGui.QFont'] | |
} | |
# ignore lines with any of these strings found in them | |
ignore_line_strings = ['import'] | |
if os.path.exists( ui_py_file ): | |
lines = None | |
try: | |
file_ = open( ui_py_file, 'r' ) | |
lines = file_.readlines() | |
file_.close() | |
except: | |
cmds.warning('Could not open the ui python file!') | |
return | |
if lines: | |
new_lines = [] | |
for line in lines: | |
new_line = line | |
# check for lines to ignore | |
if not any([x in new_line for x in ignore_line_strings]): | |
# see if there are strings to replace in this line | |
for index, replace_tuple in sorted(replace_strings.iteritems()): | |
old_str, new_str = replace_tuple | |
if old_str in new_line: | |
while old_str in new_line: | |
new_line = new_line.replace(old_str, new_str) | |
# add the modified/unmodified line | |
new_lines.append(new_line) | |
else: | |
new_lines.append(new_line) | |
# write all the new lines to the same file | |
with open(ui_py_file, 'w') as _file: | |
_file.writelines(new_lines) | |
def convert_ui_to_py( ui_file, tool_file): | |
""" | |
Main method to convert a ui file to python | |
Update the actual python tool file with new code | |
*Arguments:* | |
* ``ui_file`` The .ui file we are converting | |
* ``tool_file`` The .py file that will we inject the updated ui code into | |
*Keyword Arguments:* | |
* ``None`` | |
*Returns:* | |
* ``None`` | |
*Author:* | |
* randall.hess, [email protected], 09/02/2018 3:41:59 PM | |
""" | |
# check the incoming files | |
files = [ui_file, tool_file] | |
for _file in files: | |
if _file is None: | |
return | |
if not os.path.lexists(_file): | |
return | |
# python file and ui file should be named the same | |
py_filename = ui_file.replace('.ui','.py') | |
# create a temp .py file that we convert the .ui file into | |
py_file = open(py_filename, 'w') | |
# convert the .ui file to the .py file | |
compileUi(ui_file, py_file, False, 4, False) | |
py_file.close() | |
# handle conversion for Qt.py | |
# This is optional only if you intend to run ui code with Qt.py | |
convert_qt_py(py_filename) | |
# update the actual python tool | |
update_py_ui(py_filename, tool_file) | |
# Example | |
ui_file = r'D:\temp.ui' | |
tool_file = r'D:\test_dialog.py' | |
convert_ui_to_py(ui_file, tool_file) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment