pyqt-distutils-0.7.3/0000755000175000001440000000000013121460610015015 5ustar colinusers00000000000000pyqt-distutils-0.7.3/pyqt_distutils/0000755000175000001440000000000013121460610020116 5ustar colinusers00000000000000pyqt-distutils-0.7.3/pyqt_distutils/__init__.py0000644000175000001440000000022313121457723022237 0ustar colinusers00000000000000""" A set of PyQt distutils extensions for build qt ui files in a pythonic way: - build_ui: build qt ui/qrc files """ __version__ = '0.7.3' pyqt-distutils-0.7.3/pyqt_distutils/build_ui.py0000644000175000001440000001037313121457425022302 0ustar colinusers00000000000000# -*- coding: utf-8 -*- """ Distutils extension for PyQt/PySide applications """ import glob import os import subprocess import sys from setuptools import Command from .config import Config from .hooks import load_hooks from .utils import build_args, write_message class build_ui(Command): """ Builds the Qt ui files as described in pyuic.json (or pyuic.cfg). """ user_options = [ ('force', None, 'Force flag, will force recompilation of every ui/qrc file'), ] def initialize_options(self): self.force = False self._hooks = load_hooks() def finalize_options(self): try: self.cfg = Config() self.cfg.load() except (IOError, OSError): write_message('cannot open pyuic.json (or pyuic.cfg)', 'red') self.cfg = None def is_outdated(self, src, dst, ui): if src.endswith('.qrc') or self.force: return True outdated = (not os.path.exists(dst) or (os.path.getmtime(src) > os.path.getmtime(dst))) if not outdated and not ui: # for qrc files, we need to check each individual resources. # If one of them is newer than the dst file, the qrc file must be # considered as outdated # file paths are relative to the qrc file path qrc_dirname = os.path.dirname(src) with open(src, 'r') as f: lines = f.read().splitlines() lines = [l for l in lines if '' in l] cwd = os.getcwd() os.chdir(qrc_dirname) for line in lines: filename = line.replace('', '').replace( '', '').strip() filename = os.path.abspath(filename) if os.path.getmtime(filename) > os.path.getmtime(dst): outdated = True break os.chdir(cwd) return outdated def run(self): if not self.cfg: return for glob_exp, dest in self.cfg.files: for src in glob.glob(glob_exp): if not os.path.exists(src): write_message('skipping target %s, file not found' % src, 'yellow') continue src = os.path.join(os.getcwd(), src) dst = os.path.join(os.getcwd(), dest) ui = True if src.endswith('.ui'): ext = '_ui.py' cmd = self.cfg.uic_command() elif src.endswith('.qrc'): ui = False ext = '_rc.py' cmd = self.cfg.rcc_command() else: continue filename = os.path.split(src)[1] filename = os.path.splitext(filename)[0] dst = os.path.join(dst, filename + ext) try: os.makedirs(os.path.split(dst)[0]) except OSError: pass if self.is_outdated(src, dst, ui): try: cmd = build_args(cmd, src, dst) subprocess.check_call(cmd) cmd = ' '.join(cmd) except subprocess.CalledProcessError as e: if e.output: write_message(cmd, 'yellow') write_message(e.output.decode(sys.stdout.encoding), 'red') else: write_message(cmd, 'red') except OSError as e: write_message(cmd, 'yellow') write_message(str(e), 'red') else: write_message(cmd, 'green') for hookname in self.cfg.hooks: try: hook = self._hooks[hookname] except KeyError: write_message('warning, unknonw hook: %r' % hookname, 'yellow') else: write_message('running hook %r' % hookname, 'blue') hook(dst) else: write_message('skipping %s, up to date' % src) pyqt-distutils-0.7.3/pyqt_distutils/config.py0000644000175000001440000000511013121455364021744 0ustar colinusers00000000000000""" Contains the config class (pyuic.cfg or pyuic.json) """ import json from .utils import write_message class QtApi: pyqt4 = 0 pyqt5 = 1 pyside = 2 class Config: def __init__(self): self.files = [] self.pyuic = '' self.pyuic_options = '' self.pyrcc = '' self.pyrcc_options = '' self.hooks = [] def uic_command(self): return self.pyuic + ' ' + self.pyuic_options + ' %s -o %s' def rcc_command(self): return self.pyrcc + ' ' + self.pyrcc_options + ' %s -o %s' def load(self): for ext in ['.cfg', '.json']: try: with open('pyuic' + ext, 'r') as f: self.__dict__ = json.load(f) except (IOError, OSError): pass else: break else: write_message('failed to open configuration file', 'yellow') if not hasattr(self, 'hooks'): self.hooks = [] def save(self): with open('pyuic.json', 'w') as f: json.dump(self.__dict__, f, indent=4, sort_keys=True) def generate(self, api): if api == QtApi.pyqt4: self.pyrcc = 'pyrcc4' self.pyrcc_options = '-py3' self.pyuic = 'pyuic4' self.pyuic_options = '--from-import' self.files[:] = [] elif api == QtApi.pyqt5: self.pyrcc = 'pyrcc5' self.pyrcc_options = '' self.pyuic = 'pyuic5' self.pyuic_options = '--from-import' self.files[:] = [] elif api == QtApi.pyside: self.pyrcc = 'pyside-rcc' self.pyrcc_options = '-py3' self.pyuic = 'pyside-uic' self.pyuic_options = '--from-import' self.files[:] = [] self.save() write_message('pyuic.json generated', 'green') def add(self, src, dst): self.load() for fn, _ in self.files: if fn == src: write_message('ui file already added: %s' % src) return self.files.append((src, dst)) self.save() write_message('file added to pyuic.json: %s -> %s' % (src, dst), 'green') def remove(self, filename): self.load() to_remove = None for i, files in enumerate(self.files): src, dest = files if filename == src: to_remove = i break if to_remove is not None: self.files.pop(to_remove) self.save() write_message('file removed from pyuic.json: %s' % filename, 'green') pyqt-distutils-0.7.3/pyqt_distutils/hooks.py0000644000175000001440000000245413121455364021632 0ustar colinusers00000000000000""" This module contains the hooks load and our builtin hooks. """ import re import pkg_resources from .utils import write_message #: Name of the entrypoint to use in setup.py ENTRYPOINT = 'pyqt_distutils_hooks' def load_hooks(): """ Load the exposed hooks. Returns a dict of hooks where the keys are the name of the hook and the values are the actual hook functions. """ hooks = {} for entrypoint in pkg_resources.iter_entry_points(ENTRYPOINT): name = str(entrypoint).split('=')[0].strip() try: hook = entrypoint.load() except Exception as e: write_message('failed to load entry-point %r (error="%s")' % (name, e), 'yellow') else: hooks[name] = hook return hooks def hook(ui_file_path): """ This is the prototype of a hook function. """ pass def gettext(ui_file_path): """ Let you use gettext instead of the Qt tools for l18n """ with open(ui_file_path, 'r') as fin: content = fin.read() # replace ``_translate("context", `` by ``_(`` content = re.sub(r'_translate\(".*",\s', '_(', content) content = content.replace( ' _translate = QtCore.QCoreApplication.translate', '') with open(ui_file_path, 'w') as fout: fout.write(content) pyqt-distutils-0.7.3/pyqt_distutils/pyuicfg.py0000644000175000001440000000336413121455364022156 0ustar colinusers00000000000000"""Help you manage your pyuic.json file (pyqt-distutils) Usage: pyuicfg -g pyuicfg -g --pyqt5 pyuicfg -g --pyside pyuicfg -a SOURCE_FILE DESTINATION_PACKAGE pyuicfg -r SOURCE_FILE pyuicfg (-h | --help) pyuicfg --version Options: -h, --help Show help --version Show version -g Generate pyuic.json -a SOURCE_FILE DESTINATION_PACKAGE Add file to pyuic.json -r SOURCE_FILE Remove file from pyuic.json --pyqt5 Generate a pyuic.json file for PyQt5 instead of PyQt4 --pyside Generate a pyuic.json file for PySide instead of PyQt4 """ import os from docopt import docopt from pyqt_distutils import __version__ from pyqt_distutils.config import Config, QtApi def qt_api_from_args(arguments): if arguments['--pyqt5']: return QtApi.pyqt5 elif arguments['--pyside']: return QtApi.pyside return QtApi.pyqt4 def main(): arguments = docopt(__doc__, version=__version__) generate = arguments['-g'] file_to_add = arguments['-a'] destination_package = arguments['DESTINATION_PACKAGE'] file_to_remove = arguments['-r'] api = qt_api_from_args(arguments) cfg = Config() if generate: if os.path.exists('pyuic.json'): choice = input('pyuic.json already exists. Do you want to replace ' 'it? (y/N) ').lower() if choice != 'y': return cfg.generate(api) elif file_to_add: cfg.add(file_to_add, destination_package) elif file_to_remove: cfg.remove(file_to_remove) if __name__ == '__main__': main()pyqt-distutils-0.7.3/pyqt_distutils/utils.py0000644000175000001440000000214213121457425021641 0ustar colinusers00000000000000try: import colorama except ImportError: has_colorama = False else: has_colorama = True import shlex try: # Python 3 from shlex import quote except ImportError: # Python 2 from pipes import quote def build_args(cmd, src, dst): """ Build arguments list for passing to subprocess.call_check :param cmd str: Command string to interpolate src and dst filepaths into. Typically the output of `config.Config.uic_command` or `config.Config.rcc_command`. :param src str: Source filepath. :param dst str: Destination filepath. """ cmd = cmd % (quote(src), quote(dst)) args = shlex.split(cmd) return [arg for arg in args if arg] def write_message(text, color=None): if has_colorama: colors = { 'red': colorama.Fore.RED, 'green': colorama.Fore.GREEN, 'yellow': colorama.Fore.YELLOW, 'blue': colorama.Fore.BLUE } try: print(colors[color] + text + colorama.Fore.RESET) except KeyError: print(text) else: print(text) pyqt-distutils-0.7.3/pyqt_distutils.egg-info/0000755000175000001440000000000013121460610021610 5ustar colinusers00000000000000pyqt-distutils-0.7.3/pyqt_distutils.egg-info/PKG-INFO0000644000175000001440000000177313121460610022715 0ustar colinusers00000000000000Metadata-Version: 1.1 Name: pyqt-distutils Version: 0.7.3 Summary: A set of distutils extension for building Qt ui files Home-page: https://github.com/ColinDuquesnoy/pyqt_distutils Author: Colin Duquesnoy Author-email: colin.duquesnoy@gmail.com License: MIT Description: UNKNOWN Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable Classifier: Framework :: Setuptools Plugin Classifier: Environment :: Console Classifier: Environment :: X11 Applications :: Qt Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: MIT License Classifier: Natural Language :: English Classifier: Operating System :: Microsoft Classifier: Operating System :: MacOS Classifier: Operating System :: POSIX Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 2 Classifier: Topic :: Software Development :: Build Tools Classifier: Topic :: System :: Software Distribution Classifier: Topic :: Text Editors :: Integrated Development Environments (IDE) pyqt-distutils-0.7.3/pyqt_distutils.egg-info/SOURCES.txt0000644000175000001440000000063413121460610023477 0ustar colinusers00000000000000README.rst setup.cfg setup.py pyqt_distutils/__init__.py pyqt_distutils/build_ui.py pyqt_distutils/config.py pyqt_distutils/hooks.py pyqt_distutils/pyuicfg.py pyqt_distutils/utils.py pyqt_distutils.egg-info/PKG-INFO pyqt_distutils.egg-info/SOURCES.txt pyqt_distutils.egg-info/dependency_links.txt pyqt_distutils.egg-info/entry_points.txt pyqt_distutils.egg-info/requires.txt pyqt_distutils.egg-info/top_level.txtpyqt-distutils-0.7.3/pyqt_distutils.egg-info/dependency_links.txt0000644000175000001440000000000113121460610025656 0ustar colinusers00000000000000 pyqt-distutils-0.7.3/pyqt_distutils.egg-info/entry_points.txt0000644000175000001440000000017013121460610025104 0ustar colinusers00000000000000[console_scripts] pyuicfg = pyqt_distutils.pyuicfg:main [pyqt_distutils_hooks] gettext = pyqt_distutils.hooks:gettext pyqt-distutils-0.7.3/pyqt_distutils.egg-info/requires.txt0000644000175000001440000000000713121460610024205 0ustar colinusers00000000000000docopt pyqt-distutils-0.7.3/pyqt_distutils.egg-info/top_level.txt0000644000175000001440000000001713121460610024340 0ustar colinusers00000000000000pyqt_distutils pyqt-distutils-0.7.3/README.rst0000644000175000001440000001574713121460126016524 0ustar colinusers00000000000000PyQt Distutils ============== .. image:: https://img.shields.io/pypi/v/pyqt-distutils.svg :target: https://pypi.python.org/pypi/pyqt-distutils/ :alt: Latest PyPI version .. image:: https://img.shields.io/pypi/dm/pyqt-distutils.svg :target: https://pypi.python.org/pypi/pyqt-distutils/ :alt: Number of PyPI downloads A set of distutils extension to work with PyQt applications and UI files. The goal of this tiny library is to help you write PyQt application in a pythonic way, using setup.py to build the Qt designer Ui files. This works with PyQt4, PyQt5 and PySide (tested with python3 only). Usage ----- Add the following lines to your setup.py: .. code-block:: python # import build_ui try: from pyqt_distutils.build_ui import build_ui cmdclass = {'build_ui': build_ui} except ImportError: build_ui = None # user won't have pyqt_distutils when deploying cmdclass = {} ... setup(..., cmdclass=cmdclass) To build the ui/qrc files, run:: python setup.py build_ui To forcibly rebuilt every files, use the ``--force`` option:: python setup.py build_ui --force If you want to require the user to have ``pyqt-distutils`` installed, and always have the ``build_ui`` command run as part of the ``build_py`` command (and all dependent commands), you can do so with a custom command class: .. code-block:: python from setuptools import setup from setuptools.command.build_py import build_py from pyqt_distutils.build_ui import build_ui class custom_build_py(build_py): def run(self): self.run_command('build_ui') build_py.run(self) setup(..., cmdclass={ 'build_ui': build_ui, 'build_py': custom_build_py, } ) UI Files -------- The compilation of ui files is driven by a pyuic.json file, which is a plain json file with the following format: .. code-block:: json { "files": [ [ "forms/main_window.ui", "package/forms" ] ], "pyrcc": "pyrcc5", "pyrcc_options": "", "pyuic": "pyuic5", "pyuic_options": "--from-imports" } Here is a brief description of the fields: - files: list of file pairs made up of the source ui file and the destination package - pyrcc: the name of the pyrcc tool to use (e.g: 'pyrcc4' or 'pyside-rcc') - pyrcc_options: pyrcc options (optional) - pyuic: the name of the pyuic tool to use (e.g: 'pyrcc4' or 'pyside-rcc') Starting from version 3.0, you can use a *glob expression* instead of a file path. E.g., to compile all ui files under the ``forms`` directory in ``package/forms``, you could write the following pyuic.json: .. code-block:: json { "files": [ [ "forms/*.ui", "package/forms" ] ], "pyrcc": "pyrcc5", "pyrcc_options": "", "pyuic": "pyuic5", "pyuic_options": "--from-imports" } Hooks ----- A pyqt-distutils hook is a python function that is called after the compilation of a ui/rc script to let you customise its content. E.g. you might want to write a hook to change the translate function used or replace the PyQt imports by your owns if you're using a shim,... The hook function is a simple python function which must take a single argument: the path to the generated python script. Hooks are exposed as setuptools entrypoint using ``pyqt_distutils_hooks`` as the entrypoint key. Add the following code to your setup.py to register your onw hooks: .. code-block:: python setup( ..., entry_points={ 'pyqt_distutils_hooks': [ 'hook_name = package_name.module_name:function_name'] }, ...) To actually use the hook, you must add a "hooks" key to your pyuic.json. This property lists the name of the hooks you'd like to run. E.g: .. code-block:: json { "files": [ ["forms/*.ui", "foo_gui/forms/"], ["resources/*.qrc", "foo_gui/forms/"] ], "pyrcc": "pyrcc5", "pyrcc_options": "", "pyuic": "pyuic5", "pyuic_options": "--from-imports", "hooks": ["gettext", "spam", "eggs"] } At the moment, we provide one builtin hook: **gettext**. This hook let you use a ``gettext.gettext`` wrapper instead of ``QCoreApplication.translate``. Command line tool ----------------- Starting from version 0.2, you can use the ``pyuicfg`` command line tool to manage your ``pyuic.json`` file: .. code-block:: bash # generate pyuic.json in the current directory, for use with PyQt4 pyuicfg -g # generate pyuic.json in the current directory, for use with PyQt5 pyuicfg -g --pyqt5 # generate pyuic.json in the current directory, for use with PySide pyuicfg -g --pyside # add files pyuicfg -a forms/main_window.ui foo_package/forms pyuicfg -a resources/foo.qrc foo_package/forms # remove file pyuicfg -r resources/foo.qrc Requirements ------------ The following packages are required: - docopt Install ------- You can either install from pypi:: (sudo) pip install pyqt-distutils Or from source:: pip install . License ------- This project is licensed under the MIT license. Changelog --------- 0.7.3 +++++ Handle path with spaces (thanks @amacd31 and @benoit-pierre see PR `9`_) .. _9: https://github.com/ColinDuquesnoy/pyqt_distutils/pull/9 0.7.2 +++++ Fix unhandled exception: TypeError when there is a CalledProcessError (see issue `7`_) .. _7: https://github.com/ColinDuquesnoy/pyqt_distutils/issues/7 0.7.1 +++++ Improve subprocess command handling: write failing commands in yellow and their error message in red. 0.7.0 +++++ Add optional support for colorama. If colorama can be imported, the build_ui output will be colored as follow: - pyuic/pyrcc commands in GREEN - skipped targets with the DEFAULT FORE COLOR - warning message in YELLOW - error messages in RED 0.6.2 +++++ - gettext hook: don't replace ``_`` function. Now the hook works well for translating ``*.ui`` files with gettext or babel. 0.6.1 +++++ - improbe gettext hook implementation to work with xgettext and babel 0.6.0 +++++ - add support for running custom hooks 0.5.2 +++++ - remove enum34 dependency and make the wheel truly universal 0.5.1 +++++ - fix installation issue on python 3.5 0.5.0 +++++ - allow the use of .json extension instead of .cfg (both are supported, .json become the default extension) 0.4.2 ++++++ - fix python 2 compatibility (#2) 0.4.1 +++++ - remove useless and confusing print statement 0.4.0 +++++ - add a ``--force`` flag - always force compilation ``*.qrc`` files 0.3.0 +++++ - allow glob expression in files lists. 0.2.1 +++++ - fix missing install requirements (docopt and enum34). 0.2.0 +++++ - add ``pyuicfg`` command line tool to administrate your ``pyuic.cfg`` file. 0.1.2 +++++ - Improve readme 0.1.1 +++++ - Fix description and examples when pyqt-distutils has not been installed. 0.1.0 +++++ - Initial release pyqt-distutils-0.7.3/setup.cfg0000644000175000001440000000007513121460610016640 0ustar colinusers00000000000000[wheel] universal = 1 [egg_info] tag_build = tag_date = 0 pyqt-distutils-0.7.3/setup.py0000644000175000001440000000252113121455364016541 0ustar colinusers00000000000000#!/usr/bin/env python from setuptools import setup, find_packages from pyqt_distutils import __version__ setup( name='pyqt-distutils', version=__version__, packages=find_packages(), url='https://github.com/ColinDuquesnoy/pyqt_distutils', license='MIT', author='Colin Duquesnoy', author_email='colin.duquesnoy@gmail.com', description='A set of distutils extension for building Qt ui files', install_requires=['docopt'], classifiers=[ 'Development Status :: 5 - Production/Stable', 'Framework :: Setuptools Plugin', 'Environment :: Console', 'Environment :: X11 Applications :: Qt', 'Intended Audience :: Developers', 'License :: OSI Approved :: MIT License', 'Natural Language :: English', 'Operating System :: Microsoft', 'Operating System :: MacOS', 'Operating System :: POSIX', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 2', 'Topic :: Software Development :: Build Tools', 'Topic :: System :: Software Distribution', 'Topic :: Text Editors :: Integrated Development Environments (IDE)' ], entry_points={ 'console_scripts': ['pyuicfg = pyqt_distutils.pyuicfg:main'], 'pyqt_distutils_hooks': ['gettext = pyqt_distutils.hooks:gettext'] } ) pyqt-distutils-0.7.3/PKG-INFO0000644000175000001440000000177313121460610016122 0ustar colinusers00000000000000Metadata-Version: 1.1 Name: pyqt-distutils Version: 0.7.3 Summary: A set of distutils extension for building Qt ui files Home-page: https://github.com/ColinDuquesnoy/pyqt_distutils Author: Colin Duquesnoy Author-email: colin.duquesnoy@gmail.com License: MIT Description: UNKNOWN Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable Classifier: Framework :: Setuptools Plugin Classifier: Environment :: Console Classifier: Environment :: X11 Applications :: Qt Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: MIT License Classifier: Natural Language :: English Classifier: Operating System :: Microsoft Classifier: Operating System :: MacOS Classifier: Operating System :: POSIX Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 2 Classifier: Topic :: Software Development :: Build Tools Classifier: Topic :: System :: Software Distribution Classifier: Topic :: Text Editors :: Integrated Development Environments (IDE)