From f82195bf001f5f75ffb27735ecf6e98941ce4405 Mon Sep 17 00:00:00 2001 From: Roman Lacko Date: Mon, 4 Jun 2012 16:13:58 +0200 Subject: Initial commit (copy of lck/pyside-dist repo) --- .gitignore | 11 + .gitmodules | 12 + MANIFEST.in | 41 ++++ README.txt | 235 +++++++++++++++++++ popenasync.py | 311 +++++++++++++++++++++++++ pyside_postinstall.py | 174 ++++++++++++++ qtinfo.py | 51 ++++ setup.py | 609 ++++++++++++++++++++++++++++++++++++++++++++++++ sources/pyside | 1 + sources/pyside-examples | 1 + sources/pyside-tools | 1 + sources/shiboken | 1 + utils.py | 177 ++++++++++++++ 13 files changed, 1625 insertions(+) create mode 100644 .gitignore create mode 100644 .gitmodules create mode 100644 MANIFEST.in create mode 100644 README.txt create mode 100644 popenasync.py create mode 100644 pyside_postinstall.py create mode 100644 qtinfo.py create mode 100644 setup.py create mode 160000 sources/pyside create mode 160000 sources/pyside-examples create mode 160000 sources/pyside-tools create mode 160000 sources/shiboken create mode 100644 utils.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..80f86bc3b --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ +/build +/dist +/pyside_build +/pyside_install +/PySide +/PySide-*.*.* +/SciTE.* +/pysideuic +*.egg-info +*.pyc +patchelf diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..2cb2d59e1 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,12 @@ +[submodule "sources/shiboken"] + path = sources/shiboken + url = https://git.gitorious.org/pyside/shiboken.git +[submodule "sources/pyside"] + path = sources/pyside + url = https://git.gitorious.org/pyside/pyside.git +[submodule "sources/pyside-tools"] + path = sources/pyside-tools + url = https://git.gitorious.org/pyside/pyside-tools.git +[submodule "sources/pyside-examples"] + path = sources/pyside-examples + url = https://git.gitorious.org/pyside/pyside-examples.git diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 000000000..95f5ed0c7 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,41 @@ +# +# MANIFEST.in +# +# Manifest template for creating the PySide source distribution. + +include MANIFEST.in +include setup.py +include pyside_postinstall.py +include popenasync.py +include qtinfo.py +include utils.py + +# sources +recursive-include sources/patchelf ** +recursive-include sources/shiboken ** +recursive-include sources/pyside ** +recursive-include sources/pyside-tools ** +recursive-include sources/pyside-examples ** +recursive-exclude sources/pyside-examples/examples/hyperui ** +recursive-exclude sources/pyside-examples/mobility ** +# ignore .git +recursive-exclude sources/shiboken/.git ** +recursive-exclude sources/pyside/.git ** +recursive-exclude sources/pyside-tools/.git ** +recursive-exclude sources/pyside-examples/.git ** + +# PySide package +recursive-include PySide ** +recursive-include PySide/plugins ** +recursive-include PySide/imports ** +recursive-include PySide/translations ** +recursive-include PySide/include ** +recursive-include PySide/typesystems ** +recursive-include PySide/examples ** + +# pysideuic package +recursive-include pysideuic/ ** +recursive-include pysideuic/Compiler ** +recursive-include pysideuic/port_v2 ** +recursive-include pysideuic/port_v3 ** +recursive-include pysideuic/widget-plugins ** diff --git a/README.txt b/README.txt new file mode 100644 index 000000000..2527401b5 --- /dev/null +++ b/README.txt @@ -0,0 +1,235 @@ +============ +About PySide +============ + +PySide is the Python Qt bindings project, providing access the complete Qt 4.8 framework +as well as to generator tools for rapidly generating bindings for any C++ libraries. + +The PySide project is developed in the open, with all facilities you'd expect +from any modern OSS project such as all code in a git repository [1], an open +Bugzilla [2] for reporting bugs, and an open design process [3]. We welcome +any contribution without requiring a transfer of copyright. + +======= +Changes +======= + +1.1.1 (2012-04-19) +================== + +Major changes +------------- + +- Unified toolchain! No more GeneratorRunner and ApiExtractor, now you just need Shiboken to compile PySide. + +Bug fixes +--------- + +- 1105 Spyder fails with HEAD +- 1126 Segfault when exception is raised in signalInstanceDisconnect +- 1135 SIGSEGV when loading custom widget using QUiLoader when overriding createWidget() +- 1041 QAbstractItemModel has wrong ownership policy for selectionModel() +- 1086 generatorrunner segfault processing #include +- 1110 Concurrency error causes GC heap corruption +- 1113 Instantiating QObject in user-defined QML element's constructor crashes if instantiated from QML +- 1129 Segmentation fault on close by QStandardItem/QStandardItemModel +- 1104 QSettings has problems with long integers +- 1108 tests/QtGui/pyside_reload_test.py fails when bytecode writing is disabled +- 1138 Subclassing of QUiLoader leads to "Internal C++ object already deleted" exception (again) +- 1124 QPainter.drawPixmapFragments should take a list as first argument +- 1065 Invalid example in QFileDialog documentation +- 1092 shiboken names itself a 'generator' +- 1094 shiboken doesn't complain about invalid options +- 1044 Incorrect call to parent constructor in example +- 1139 Crash at exit due to thread state (tstate) being NULL +- PYSIDE-41 QModelIndex unhashable + +1.1.0 (2012-01-02) +================== + +Major changes +------------- + +- New type converter scheme + +Bug fixes +--------- + +- 1010 Shiboken Cygwin patch +- 1034 Error compiling PySide with Python 3.2.2 32bit on Windows +- 1040 pyside-uic overwriting attributes before they are being used +- 1053 pyside-lupdate used with .pro files can't handle Windows paths that contain spaces +- 1060 Subclassing of QUiLoader leads to "Internal C++ object already deleted" exception +- 1063 Bug writing to files using "QTextStream + QFile + QTextEdit" on Linux +- 1069 QtCore.QDataStream silently fails on writing Python string +- 1077 Application exit crash when call QSyntaxHighlighter.document() +- 1082 OSX binary links are broken +- 1083 winId returns a PyCObject making it impossible to compare two winIds +- 1084 Crash (segfault) when writing unicode string on socket +- 1091 PixmapFragment and drawPixmapFragments are not bound +- 1095 No examples for shiboken tutorial +- 1097 QtGui.QShortcut.setKey requires QKeySequence +- 1101 Report invalid function signatures in typesystem +- 902 Expose Shiboken functionality through a Python module +- 969 viewOptions of QAbstractItemView error + +1.0.9 (2011-11-29) +================== + +Bug fixes +--------- + +- 1058 Strange code in PySide/QtUiTools/glue/plugins.h +- 1057 valgrind detected "Conditional jump or move depends on uninitialised value" +- 1052 PySideConfig.cmake contains an infinite loop due to missing default for SHIBOKEN_PYTHON_SUFFIX +- 1048 QGridLayout.itemAtPosition() crashes when it should return None +- 1037 shiboken fails to build against python 3.2 (both normal and -dbg) on i386 (and others) +- 1036 Qt.KeyboardModifiers always evaluates to zero +- 1033 QDialog.DialogCode instances and return value from QDialog.exec_ hash to different values +- 1031 QState.parentState() or QState.machine() causes python crash at exit +- 1029 qmlRegisterType Fails to Increase the Ref Count +- 1028 QWidget winId missing +- 1016 Calling of Q_INVOKABLE method returning not QVariant is impossible... +- 1013 connect to QSqlTableModel.primeInsert() causes crash +- 1012 FTBFS with hardening flags enabled +- 1011 PySide Cygwin patch +- 1010 Shiboken Cygwin patch +- 1009 GeneratorRunner Cygwin patch +- 1008 ApiExtractor Cygwin patch +- 891 ApiExtractor doesn't support doxygen as backend to doc generation. + +1.0.8 (2011-10-21) +================== + +Major changes +------------- + +- Experimental Python3.2 support +- Qt4.8 beta support +- Bug Fixes + +Bug fixes +--------- + +- 1022 RuntimeError: maximum recursion depth exceeded while getting the str of an object +- 1019 Overriding QWidget.show or QWidget.hide do not work +- 944 Segfault on QIcon(None).pixmap() + +1.0.7 (2011-09-21) +================== + +Bug fixes +--------- + +- 996 Missing dependencies for QtWebKit in buildscripts for Fedora +- 986 Documentation links +- 985 Provide versioned pyside-docs zip file to help packagers +- 981 QSettings docs should empathize the behavior changes of value() on different platforms +- 902 Expose Shiboken functionality through a Python module +- 997 QDeclarativePropertyMap doesn't work. +- 994 QIODevice.readData must use qmemcpy instead of qstrncpy +- 989 Pickling QColor fails +- 987 Disconnecting a signal that has not been connected +- 973 shouldInterruptJavaScript slot override is never called +- 966 QX11Info.display() missing +- 959 can't pass QVariant to the QtWebkit bridge +- 1006 Segfault in QLabel init +- 1002 Segmentation fault on PySide/Spyder exit +- 998 Segfault with Spyder after switching to another app +- 995 QDeclarativeView.itemAt returns faulty reference. (leading to SEGFAULT) +- 990 Segfault when trying to disconnect a signal that is not connected +- 975 Possible memory leak +- 991 The __repr__ of various types is broken +- 988 The type supplied with currentChanged signal in QTabWidget has changed in 1.0.6 + +1.0.6 (2011-08-22) +================== + +Major changes +------------- + +- New documentation layout; +- Fixed some regressions from the last release (1.0.5); +- Optimizations during anonymous connection; + +Bug fixes +--------- + +- 972 anchorlayout.py of graphicsview example raised a unwriteable memory exception when exits +- 953 Segfault when QObject is garbage collected after QTimer.singeShot +- 951 ComponentComplete not called on QDeclarativeItem subclass +- 965 Segfault in QtUiTools.QUiLoader.load +- 958 Segmentation fault with resource files +- 944 Segfault on QIcon(None).pixmap() +- 941 Signals with QtCore.Qt types as arguments has invalid signatures +- 964 QAbstractItemView.moveCursor() method is missing +- 963 What's This not displaying QTableWidget column header information as in Qt Designer +- 961 QColor.__repr__/__str__ should be more pythonic +- 960 QColor.__reduce__ is incorrect for HSL colors +- 950 implement Q_INVOKABLE +- 940 setAttributeArray/setUniformValueArray do not take arrays +- 931 isinstance() fails with Signal instances +- 928 100's of QGraphicItems with signal connections causes slowdown +- 930 Documentation mixes signals and functions. +- 923 Make QScriptValue (or QScriptValueIterator) implement the Python iterator protocol +- 922 QScriptValue's repr() should give some information about its data +- 900 QtCore.Property as decorator +- 895 jQuery version is outdated, distribution code de-duplication breaks documentation search +- 731 Can't specify more than a single 'since' argument +- 983 copy.deepcopy raises SystemError with QColor +- 947 NETWORK_ERR during interaction QtWebKit window with server +- 873 Deprecated methods could emit DeprecationWarning +- 831 PySide docs would have a "Inherited by" list for each class + +1.0.5 (2011-07-22) +================== + +Major changes +------------- + +- Widgets present on "ui" files are exported in the root widget, check PySide ML thread for more information[1]; +- pyside-uic generate menubars without parent on MacOS plataform; +- Signal connection optimizations; + +Bug fixes +--------- + +- 892 Segfault when destructing QWidget and QApplication has event filter installed +- 407 Crash while multiple inheriting with QObject and native python class +- 939 Shiboken::importModule must verify if PyImport_ImportModule succeeds +- 937 missing pid method in QProcess +- 927 Segfault on QThread code. +- 925 Segfault when passing a QScriptValue as QObject or when using .toVariant() on a QScriptValue +- 905 QtGui.QHBoxLayout.setMargin function call is created by pyside-uic, but this is not available in the pyside bindings +- 904 Repeatedly opening a QDialog with Qt.WA_DeleteOnClose set crashes PySide +- 899 Segfault with 'QVariantList' Property. +- 893 Shiboken leak reference in the parent control +- 878 Shiboken may generate incompatible modules if a new class is added. +- 938 QTemporaryFile JPEG problem +- 934 A __getitem__ of QByteArray behaves strange +- 929 pkg-config files do not know about Python version tags +- 926 qmlRegisterType does not work with QObject +- 924 Allow QScriptValue to be accessed via [] +- 921 Signals not automatically disconnected on object destruction +- 920 Cannot use same slot for two signals +- 919 Default arguments on QStyle methods not working +- 915 QDeclarativeView.scene().addItem(x) make the x object invalid +- 913 Widgets inside QTabWidget are not exported as members of the containing widget +- 910 installEventFilter() increments reference count on target object +- 907 pyside-uic adds MainWindow.setMenuBar(self.menubar) to the generated code under OS X +- 903 eventFilter in ItemDelegate +- 897 QObject.property() and QObject.setProperty() methods fails for user-defined properties +- 896 QObject.staticMetaObject() is missing +- 916 Missing info about when is possible to use keyword arguments in docs [was: QListWidgetItem's constructor ignores text parameter] +- 890 Add signal connection example for valueChanged(int) on QSpinBox to the docs +- 821 Mapping interface for QPixmapCache +- 909 Deletion of QMainWindow/QApplication leads to segmentation fault + +========== +References +========== + +- [1] http://qt.gitorious.org/pyside +- [2] http://bugs.openbossa.org/ +- [3] http://www.pyside.org/docs/pseps/psep-0001.html +- [4] http://developer.qt.nokia.com/wiki/PySideDownloads diff --git a/popenasync.py b/popenasync.py new file mode 100644 index 000000000..df4944ee7 --- /dev/null +++ b/popenasync.py @@ -0,0 +1,311 @@ +################################################################################ +""" + +Modification of http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/440554 + +""" + +#################################### IMPORTS ################################### + +import os +import subprocess +import errno +import time +import sys +import unittest +import tempfile + +def geterror (): + return sys.exc_info()[1] + +if sys.version_info >= (3,): + null_byte = '\x00'.encode('ascii') +else: + null_byte = '\x00' + +if subprocess.mswindows: + if sys.version_info >= (3,): + # Test date should be in ascii. + def encode(s): + return s.encode('ascii') + + def decode(b): + return b.decode('ascii') + else: + # Strings only; do nothing + def encode(s): + return s + + def decode(b): + return b + + try: + import ctypes + from ctypes.wintypes import DWORD + kernel32 = ctypes.windll.kernel32 + TerminateProcess = ctypes.windll.kernel32.TerminateProcess + def WriteFile(handle, data, ol = None): + c_written = DWORD() + success = ctypes.windll.kernel32.WriteFile(handle, ctypes.create_string_buffer(encode(data)), len(data), ctypes.byref(c_written), ol) + return ctypes.windll.kernel32.GetLastError(), c_written.value + def ReadFile(handle, desired_bytes, ol = None): + c_read = DWORD() + buffer = ctypes.create_string_buffer(desired_bytes+1) + success = ctypes.windll.kernel32.ReadFile(handle, buffer, desired_bytes, ctypes.byref(c_read), ol) + buffer[c_read.value] = null_byte + return ctypes.windll.kernel32.GetLastError(), decode(buffer.value) + def PeekNamedPipe(handle, desired_bytes): + c_avail = DWORD() + c_message = DWORD() + if desired_bytes > 0: + c_read = DWORD() + buffer = ctypes.create_string_buffer(desired_bytes+1) + success = ctypes.windll.kernel32.PeekNamedPipe(handle, buffer, desired_bytes, ctypes.byref(c_read), ctypes.byref(c_avail), ctypes.byref(c_message)) + buffer[c_read.value] = null_byte + return decode(buffer.value), c_avail.value, c_message.value + else: + success = ctypes.windll.kernel32.PeekNamedPipe(handle, None, desired_bytes, None, ctypes.byref(c_avail), ctypes.byref(c_message)) + return "", c_avail.value, c_message.value + + except ImportError: + from win32file import ReadFile, WriteFile + from win32pipe import PeekNamedPipe + from win32api import TerminateProcess + import msvcrt + +else: + from signal import SIGINT, SIGTERM, SIGKILL + import select + import fcntl + +################################### CONSTANTS ################################## + +PIPE = subprocess.PIPE + +################################################################################ + +class Popen(subprocess.Popen): + def __init__(self, *args, **kwargs): + subprocess.Popen.__init__(self, *args, **kwargs) + + def recv(self, maxsize=None): + return self._recv('stdout', maxsize) + + def recv_err(self, maxsize=None): + return self._recv('stderr', maxsize) + + def send_recv(self, input='', maxsize=None): + return self.send(input), self.recv(maxsize), self.recv_err(maxsize) + + def read_async(self, wait=.1, e=1, tr=5, stderr=0): + if tr < 1: + tr = 1 + x = time.time()+ wait + y = [] + r = '' + pr = self.recv + if stderr: + pr = self.recv_err + while time.time() < x or r: + r = pr() + if r is None: + if e: + raise Exception("Other end disconnected!") + else: + break + elif r: + y.append(r) + else: + time.sleep(max((x-time.time())/tr, 0)) + return ''.join(y) + + def send_all(self, data): + while len(data): + sent = self.send(data) + if sent is None: + raise Exception("Other end disconnected!") + data = buffer(data, sent) + + def get_conn_maxsize(self, which, maxsize): + if maxsize is None: + maxsize = 1024 + elif maxsize < 1: + maxsize = 1 + return getattr(self, which), maxsize + + def _close(self, which): + conn = getattr(self, which) + flags = fcntl.fcntl(conn, fcntl.F_GETFL) + if not conn.closed: + fcntl.fcntl(conn, fcntl.F_SETFL, flags & ~os.O_NONBLOCK) + assert conn.read() == '' + getattr(self, which).close() + setattr(self, which, None) + + if subprocess.mswindows: + def kill(self): + # Recipes + #http://me.in-berlin.de/doc/python/faq/windows.html#how-do-i-emulate-os-kill-in-windows + #http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/347462 + + """kill function for Win32""" + TerminateProcess(int(self._handle), 0) # returns None + + def send(self, input): + if not self.stdin: + return None + + try: + x = msvcrt.get_osfhandle(self.stdin.fileno()) + (errCode, written) = WriteFile(x, input) + except ValueError: + return self._close('stdin') + except (subprocess.pywintypes.error, Exception): + if geterror()[0] in (109, errno.ESHUTDOWN): + return self._close('stdin') + raise + + return written + + def _recv(self, which, maxsize): + conn, maxsize = self.get_conn_maxsize(which, maxsize) + if conn is None: + return None + + try: + x = msvcrt.get_osfhandle(conn.fileno()) + (read, nAvail, nMessage) = PeekNamedPipe(x, 0) + if maxsize < nAvail: + nAvail = maxsize + if nAvail > 0: + (errCode, read) = ReadFile(x, nAvail, None) + except ValueError: + return self._close(which) + except (subprocess.pywintypes.error, Exception): + if geterror()[0] in (109, errno.ESHUTDOWN): + return self._close(which) + raise + + if self.universal_newlines: + # Translate newlines. For Python 3.x assume read is text. + # If bytes then another solution is needed. + read = read.replace("\r\n", "\n").replace("\r", "\n") + return read + + else: + def kill(self): + for i, sig in enumerate([SIGTERM, SIGKILL] * 2): + if i % 2 == 0: os.kill(self.pid, sig) + time.sleep((i * (i % 2) / 5.0) + 0.01) + + killed_pid, stat = os.waitpid(self.pid, os.WNOHANG) + if killed_pid != 0: return + + def send(self, input): + if not self.stdin: + return None + + if not select.select([], [self.stdin], [], 0)[1]: + return 0 + + try: + written = os.write(self.stdin.fileno(), input) + except OSError: + if geterror()[0] == errno.EPIPE: #broken pipe + return self._close('stdin') + raise + + return written + + def _recv(self, which, maxsize): + conn, maxsize = self.get_conn_maxsize(which, maxsize) + if conn is None: + return None + + flags = fcntl.fcntl(conn, fcntl.F_GETFL) + if not conn.closed: + fcntl.fcntl(conn, fcntl.F_SETFL, flags| os.O_NONBLOCK) + + try: + if not select.select([conn], [], [], 0)[0]: + return '' + + try: + r = conn.read(maxsize) + except IOError as e: + if e.errno == errno.EAGAIN: + return '' + raise + if not r: + return self._close(which) + + if self.universal_newlines: + r = r.replace("\r\n", "\n").replace("\r", "\n") + return r + finally: + if not conn.closed: + fcntl.fcntl(conn, fcntl.F_SETFL, flags) + +################################################################################ + +def proc_in_time_or_kill(cmd, time_out, wd = None, env = None): + proc = Popen ( + cmd, cwd = wd, env = env, + stdin = subprocess.PIPE, stdout = subprocess.PIPE, + stderr = subprocess.STDOUT, universal_newlines = 1 + ) + + ret_code = None + response = [] + + t = time.time() + while ret_code is None and ((time.time() -t) < time_out): + ret_code = proc.poll() + response += [proc.read_async(wait=0.1, e=0)] + + if ret_code is None: + ret_code = '"Process timed out (time_out = %s secs) ' % time_out + try: + proc.kill() + ret_code += 'and was successfully terminated"' + except Exception: + ret_code += ('and termination failed (exception: %s)"' % + (geterror(),)) + + return ret_code, ''.join(response) + +################################################################################ + +class AsyncTest(unittest.TestCase): + def test_proc_in_time_or_kill(self): + ret_code, response = proc_in_time_or_kill( + [sys.executable, '-c', 'while 1: pass'], time_out = 1 + ) + + self.assert_( 'rocess timed out' in ret_code ) + self.assert_( 'successfully terminated' in ret_code ) + +################################################################################ + +def _example(): + if sys.platform == 'win32': + shell, commands, tail = ('cmd', ('echo "hello"', 'echo "HELLO WORLD"'), '\r\n') + else: + shell, commands, tail = ('sh', ('ls', 'echo HELLO WORLD'), '\n') + + a = Popen(shell, stdin=PIPE, stdout=PIPE) + sys.stdout.write(a.read_async()) + sys.stdout.write(" ") + for cmd in commands: + a.send_all(cmd + tail) + sys.stdout.write(a.read_async()) + sys.stdout.write(" ") + a.send_all('exit' + tail) + print (a.read_async(e=0)) + a.wait() + +################################################################################ + +if __name__ == '__main__': + if 1: unittest.main() + else: _example() diff --git a/pyside_postinstall.py b/pyside_postinstall.py new file mode 100644 index 000000000..95d875138 --- /dev/null +++ b/pyside_postinstall.py @@ -0,0 +1,174 @@ +# Postinstall script for PySide +# +# Generates the qt.conf file +# +# This file is based on pywin32_postinstall.py file from pywin32 project + +import os, sys, traceback, shutil, fnmatch, stat + +try: + # When this script is run from inside the bdist_wininst installer, + # file_created() and directory_created() are additional builtin + # functions which write lines to Python23\pyside-install.log. This is + # a list of actions for the uninstaller, the format is inspired by what + # the Wise installer also creates. + file_created + is_bdist_wininst = True +except NameError: + is_bdist_wininst = False # we know what it is not - but not what it is :) + def file_created(file): + pass + +def install(): + if sys.platform == "win32": + install_win32() + else: + install_linux() + +def filter_match(name, patterns): + for pattern in patterns: + if pattern is None: + continue + if fnmatch.fnmatch(name, pattern): + return True + return False + +def set_exec(name): + mode = os.stat(name).st_mode + new_mode = mode + if new_mode & stat.S_IRUSR: + new_mode = new_mode | stat.S_IXUSR + if new_mode & stat.S_IRGRP: + new_mode = new_mode | stat.S_IXGRP + if new_mode & stat.S_IROTH: + new_mode = new_mode | stat.S_IXOTH + if (mode != new_mode): + print("Setting exec for '%s' (mode %o => %o)" % (name, mode, new_mode)) + os.chmod(name, new_mode) + +def install_linux(): + # Try to find PySide package + try: + import PySide + except ImportError: + print("The PySide package not found: %s" % traceback.print_exception(*sys.exc_info())) + return + pyside_path = os.path.abspath(os.path.dirname(PySide.__file__)) + print("PySide package found in %s..." % pyside_path) + + # Set exec mode on executables + for elf in ["patchelf", "shiboken"]: + elfpath = os.path.join(pyside_path, elf) + set_exec(elfpath) + + # Update rpath in PySide libs + from distutils.spawn import spawn + patchelf_path = os.path.join(pyside_path, "patchelf") + for srcname in os.listdir(pyside_path): + if os.path.isdir(srcname): + continue + if not filter_match(srcname, ["Qt*.so", "phonon.so", "shiboken"]): + continue + srcpath = os.path.join(pyside_path, srcname) + cmd = [ + patchelf_path, + "--set-rpath", + pyside_path, + srcpath, + ] + spawn(cmd, search_path=0, verbose=1) + print("Patched rpath in %s to %s." % (srcpath, pyside_path)) + + # Check PySide installation status + try: + from PySide import QtCore + print("PySide package successfully installed in %s..." % \ + os.path.abspath(os.path.dirname(QtCore.__file__))) + except ImportError: + print("The PySide package not installed: %s" % traceback.print_exception(*sys.exc_info())) + +def install_win32(): + # Try to find PySide package + try: + from PySide import QtCore + except ImportError: + print("The PySide package not found: %s" % traceback.print_exception(*sys.exc_info())) + return + pyside_path = os.path.dirname(QtCore.__file__) + pyside_path = pyside_path.replace("\\", "/") + pyside_path = pyside_path.replace("lib/site-packages", "Lib/site-packages") + print("PySide package found in %s..." % pyside_path) + + if is_bdist_wininst: + # Run from inside the bdist_wininst installer + import distutils.sysconfig + exec_prefix = distutils.sysconfig.get_config_var("exec_prefix") + else: + # Run manually + exec_prefix = os.path.dirname(sys.executable) + + # Generate qt.conf + qtconf_path = os.path.join(exec_prefix, "qt.conf") + print("Generating file %s..." % qtconf_path) + f = open(qtconf_path, 'wt') + file_created(qtconf_path) + f.write("""[Paths] +Prefix = %(pyside_prefix)s +Binaries = %(pyside_prefix)s +Plugins = %(pyside_prefix)s/plugins +Translations = %(pyside_prefix)s/translations +""" % { "pyside_prefix": pyside_path }) + print("The PySide extensions were successfully installed.") + + # Install OpenSSL libs + for dll in ["libeay32.dll", "ssleay32.dll"]: + dest_path = os.path.join(exec_prefix, dll) + src_path = os.path.join(pyside_path, dll) + if not os.path.exists(dest_path) and os.path.exists(src_path): + shutil.copy(src_path, dest_path) + file_created(dest_path) + print("Installed %s to %s." % (dll, exec_prefix)) + +def uninstall(): + print("The PySide extensions were successfully uninstalled.") + +def usage(): + msg = \ +"""%s: A post-install script for the PySide extensions. + +This should be run automatically after installation, but if it fails you +can run it again with a '-install' parameter, to ensure the environment +is setup correctly. +""" + print(msg.strip() % os.path.basename(sys.argv[0])) + +# NOTE: If this script is run from inside the bdist_wininst created +# binary installer or uninstaller, the command line args are either +# '-install' or '-remove'. + +# Important: From inside the binary installer this script MUST NOT +# call sys.exit() or raise SystemExit, otherwise not only this script +# but also the installer will terminate! (Is there a way to prevent +# this from the bdist_wininst C code?) + +if __name__ == '__main__': + if len(sys.argv)==1: + usage() + sys.exit(1) + + arg_index = 1 + while arg_index < len(sys.argv): + arg = sys.argv[arg_index] + if arg == "-install": + install() + elif arg == "-remove": + # bdist_msi calls us before uninstall, so we can undo what we + # previously did. Sadly, bdist_wininst calls us *after*, so + # we can't do much at all. + if not is_bdist_wininst: + uninstall() + else: + print("Unknown option: %s" % arg) + usage() + sys.exit(0) + arg_index += 1 diff --git a/qtinfo.py b/qtinfo.py new file mode 100644 index 000000000..1369bff6d --- /dev/null +++ b/qtinfo.py @@ -0,0 +1,51 @@ +import subprocess +from distutils.spawn import find_executable +from popenasync import Popen + +class QtInfo(object): + def __init__(self, qmake_path=None): + if qmake_path: + self._qmake_path = qmake_path + else: + self._qmake_path = find_executable("qmake") + + def getQMakePath(self): + return self._qmake_path + + def getVersion(self): + return self.getProperty("QT_VERSION") + + def getBinsPath(self): + return self.getProperty("QT_INSTALL_BINS") + + def getPluginsPath(self): + return self.getProperty("QT_INSTALL_PLUGINS") + + def getImportsPath(self): + return self.getProperty("QT_INSTALL_IMPORTS") + + def getTranslationsPath(self): + return self.getProperty("QT_INSTALL_TRANSLATIONS") + + def getProperty(self, prop_name): + cmd = [self._qmake_path, "-query", prop_name] + proc = Popen(cmd, + stdin = subprocess.PIPE, + stdout = subprocess.PIPE, + stderr = subprocess.STDOUT, + universal_newlines = 1, + shell=False) + prop = '' + while proc.poll() is None: + prop += proc.read_async(wait=0.1, e=0) + proc.wait() + if proc.returncode != 0: + return None + return prop.strip() + + version = property(getVersion) + bins_dir = property(getBinsPath) + plugins_dir = property(getPluginsPath) + qmake_path = property(getQMakePath) + imports_dir = property(getImportsPath) + translations_dir = property(getTranslationsPath) diff --git a/setup.py b/setup.py new file mode 100644 index 000000000..94d74fb3e --- /dev/null +++ b/setup.py @@ -0,0 +1,609 @@ +"""This is a distutils setup-script for the PySide project + +To build the PySide, simply execute: + python setup.py build --qmake= [--cmake=] [--opnessl=] +or + python setup.py install --qmake= [--cmake=] [--opnessl=] +to build and install into your current Python installation. + +You can use special option --only-package, if you want to create more binary packages (bdist_egg, bdist_wininst, ...) +without rebuilding entire PySide every time. + +Examples: + # First time we create bdist_winist with full PySide build + python setup.py bdist_winist --qmake=c:\Qt\4.7.4\bin\qmake.exe --cmake=c:\tools\cmake\bin\cmake.exe --opnessl=c:\libs\OpenSSL32bit\bin + + # Then we crate bdist_egg reusing PySide build with option --only-package + python setup.py bdist_egg --only-package --qmake=c:\Qt\4.7.4\bin\qmake.exe --cmake=c:\tools\cmake\bin\cmake.exe --opnessl=c:\libs\OpenSSL32bit\bin + +REQUIREMENTS: +- Python: 2.6, 2.7 and 3.2 is supported +- Distribute: http://pypi.python.org/pypi/distribute +- Cmake: Specify the path to cmake with --cmake option or add cmake to the system path. + +OPTIONAL: +OpenSSL: You can specify the location of OpenSSL DLLs with option --opnessl=. + You can download OpenSSL for windows here: http://slproweb.com/products/Win32OpenSSL.html + +NOTES: +On Windows You need to execute this script from Visual Studio 2008 Command Prompt. +Building 64bit version is not supported with Visual Studio 2008 Express Edition. +""" + +__version__ = "1.1.1" + +import os +import sys +import platform + +from distutils import log +from distutils.errors import DistutilsOptionError +from distutils.errors import DistutilsSetupError +from distutils.sysconfig import get_config_var +from distutils.spawn import find_executable +from distutils.command.build import build as _build + +from setuptools import setup +from setuptools import find_packages +from setuptools.command.install import install as _install +from setuptools.command.bdist_egg import bdist_egg as _bdist_egg + +from qtinfo import QtInfo +from utils import rmtree +from utils import makefile +from utils import copyfile +from utils import copydir +from utils import run_process + +# Change the cwd to our source dir +try: + this_file = __file__ +except NameError: + this_file = sys.argv[0] +this_file = os.path.abspath(this_file) +if os.path.dirname(this_file): + os.chdir(os.path.dirname(this_file)) + +# Clean temp build folders +script_dir = os.getcwd() +for n in ["build", "PySide.egg-info", "PySide-%s" % __version__, + "PySide", "pysideuic"]: + d = os.path.join(script_dir, n) + if os.path.isdir(d): + print("Removing %s" % d) + rmtree(d) + +# Create empty package folders +for pkg in ["PySide", "pysideuic"]: + pkg_dir = os.path.join(script_dir, pkg) + os.makedirs(pkg_dir) + +def has_option(name): + try: + sys.argv.remove('--%s' % name) + return True + except ValueError: + pass + # allow passing all cmd line options also as environment variables + env_val = os.getenv(name.upper().replace('-', '_'), 'false').lower() + if env_val == "true": + return True + return False + +def option_value(name): + for index, option in enumerate(sys.argv): + if option == '--' + name: + if index+1 >= len(sys.argv): + raise DistutilsOptionError( + 'The option %s requires a value' % option) + value = sys.argv[index+1] + sys.argv[index:index+2] = [] + return value + if option.startswith('--' + name + '='): + value = option[len(name)+3:] + sys.argv[index:index+1] = [] + return value + env_val = os.getenv(name.upper().replace('-', '_')) + return env_val + +OPTION_DEBUG = has_option("debug") +OPTION_QMAKE = option_value("qmake") +OPTION_CMAKE = option_value("cmake") +OPTION_OPENSSL = option_value("openssl") +OPTION_ONLYPACKAGE = has_option("only-package") + +if OPTION_QMAKE is None: + OPTION_QMAKE = find_executable("qmake") +if OPTION_CMAKE is None: + OPTION_CMAKE = find_executable("cmake") + +class pyside_install(_install): + def run(self): + _install.run(self) + # Custom script we run at the end of installing - this is the same script + # run by bdist_wininst + # If self.root has a value, it means we are being "installed" into + # some other directory than Python itself (eg, into a temp directory + # for bdist_wininst to use) - in which case we must *not* run our + # installer + if not self.dry_run and not self.root: + if sys.platform == "win32": + filename = os.path.join(self.prefix, "Scripts", "pyside_postinstall.py") + else: + filename = os.path.join(self.prefix, "bin", "pyside_postinstall.py") + if not os.path.isfile(filename): + raise RuntimeError("Can't find '%s'" % (filename,)) + print("Executing post install script '%s'..." % filename) + cmd = [ + os.path.abspath(sys.executable), + filename, + "-install" + ] + run_process(cmd) + +class pyside_bdist_egg(_bdist_egg): + + def __init__(self, *args, **kwargs): + _bdist_egg.__init__(self, *args, **kwargs) + + def run(self): + self.run_command("build") + _bdist_egg.run(self) + +class pyside_build(_build): + + def __init__(self, *args, **kwargs): + _build.__init__(self, *args, **kwargs) + + def initialize_options(self): + _build.initialize_options(self) + self.debug = False + self.script_dir = None + self.sources_dir = None + self.build_dir = None + self.install_dir = None + self.qmake_path = None + self.py_executable = None + self.py_include_dir = None + self.py_library = None + self.py_version = None + self.build_type = "Release" + self.qtinfo = None + + def run(self): + # Check env + if not OPTION_ONLYPACKAGE: + make_name = sys.platform == "win32" and "nmake" or "make" + make_path = find_executable(make_name) + if make_path is None or not os.path.exists(make_path): + raise DistutilsSetupError( + "You need the program \"%s\" on your system path to compile PySide." \ + % make_name) + + if OPTION_CMAKE is None or not os.path.exists(OPTION_CMAKE): + raise DistutilsSetupError( + "Failed to find cmake." + " Please specify the path to cmake with --cmake parameter.") + + if OPTION_QMAKE is None or not os.path.exists(OPTION_QMAKE): + raise DistutilsSetupError( + "Failed to find qmake." + " Please specify the path to qmake with --qmake parameter.") + + # Prepare parameters + build_type = OPTION_DEBUG and "Debug" or "Release" + + py_version = "%s.%s" % (sys.version_info[0], sys.version_info[1]) + py_include_dir = get_config_var("INCLUDEPY") + py_libdir = get_config_var("LIBDIR") + py_executable = sys.executable + dbgPostfix = "" + if build_type == "Debug": + dbgPostfix = "_d" + py_executable = py_executable[:-4] + "_d.exe" + if sys.platform == "win32": + py_library = os.path.join(py_libdir, "python%s%s.lib" % \ + (py_version.replace(".", ""), dbgPostfix)) + else: + py_library = os.path.join(py_libdir, "libpython%s%s.so" % \ + (py_version, dbgPostfix)) + if not os.path.exists(py_library): + raise DistutilsSetupError( + "Failed to locate the Python library %s" % py_library) + + qtinfo = QtInfo(OPTION_QMAKE) + + # Update os.path + paths = os.environ['PATH'].lower().split(os.pathsep) + def updatepath(path): + if not path.lower() in paths: + log.info("Adding path \"%s\" to environment" % path) + paths.append(path) + qt_dir = os.path.dirname(OPTION_QMAKE) + updatepath(qt_dir) + os.environ['PATH'] = os.pathsep.join(paths) + + qt_version = qtinfo.version + if not qt_version: + log.error("Failed to query the Qt version with qmake %s" % qtinfo.qmake_path) + sys.exit(1) + + build_name = "py%s-qt%s-%s-%s" % \ + (py_version, qt_version, platform.architecture()[0], build_type.lower()) + + script_dir = os.getcwd() + sources_dir = os.path.join(script_dir, "sources") + build_dir = os.path.join(script_dir, os.path.join("pyside_build", "%s" % build_name)) + install_dir = os.path.join(script_dir, os.path.join("pyside_install", "%s" % build_name)) + + self.debug = OPTION_DEBUG + self.script_dir = script_dir + self.sources_dir = sources_dir + self.build_dir = build_dir + self.install_dir = install_dir + self.qmake_path = OPTION_QMAKE + self.py_executable = py_executable + self.py_include_dir = py_include_dir + self.py_library = py_library + self.py_version = py_version + self.build_type = build_type + self.qtinfo = qtinfo + + log.info("=" * 30) + log.info("Build type: %s" % self.build_type) + log.info("Package version: %s" % __version__) + log.info("-" * 3) + log.info("Script directory: %s" % self.script_dir) + log.info("Sources directory: %s" % self.sources_dir) + log.info("Build directory: %s" % self.build_dir) + log.info("Install directory: %s" % self.install_dir) + log.info("-" * 3) + log.info("Python executable: %s" % self.py_executable) + log.info("Python includes: %s" % self.py_include_dir) + log.info("Python library: %s" % self.py_library) + log.info("-" * 3) + log.info("Qt qmake: %s" % self.qmake_path) + log.info("Qt bins: %s" % qtinfo.bins_dir) + log.info("Qt plugins: %s" % qtinfo.plugins_dir) + log.info("-" * 3) + log.info("OpenSSL libs: %s" % OPTION_OPENSSL) + log.info("=" * 30) + + # Prepare folders + if not os.path.exists(self.sources_dir): + log.info("Creating sources folder %s..." % self.sources_dir) + os.makedirs(self.sources_dir) + if not os.path.exists(self.build_dir): + log.info("Creating build folder %s..." % self.build_dir) + os.makedirs(self.build_dir) + if not os.path.exists(self.install_dir): + log.info("Creating install folder %s..." % self.install_dir) + os.makedirs(self.install_dir) + + if not OPTION_ONLYPACKAGE: + # Build extensions + for ext in ['shiboken', 'pyside', 'pyside-tools']: + self.build_extension(ext) + + # Build patchelf + self.build_patchelf() + + # Prepare packages + self.prepare_packages() + + # Build packages + _build.run(self) + + def build_patchelf(self): + if sys.platform != "linux2": + return + + log.info("Building patchelf...") + + module_src_dir = os.path.join(self.sources_dir, "patchelf") + + build_cmd = [ + "g++", + "%s/patchelf.cc" % (module_src_dir), + "-o", + "patchelf", + ] + + if run_process(build_cmd, log) != 0: + raise DistutilsSetupError("Error building patchelf") + + def build_extension(self, extension): + log.info("Building module %s..." % extension) + + # Prepare folders + os.chdir(self.build_dir) + module_build_dir = os.path.join(self.build_dir, extension) + if os.path.exists(module_build_dir): + log.info("Deleting module build folder %s..." % module_build_dir) + rmtree(module_build_dir) + log.info("Creating module build folder %s..." % module_build_dir) + os.mkdir(module_build_dir) + os.chdir(module_build_dir) + + module_src_dir = os.path.join(self.sources_dir, extension) + + # Build module + if sys.platform == "win32": + cmake_generator = "NMake Makefiles" + make_cmd = "nmake" + else: + cmake_generator = "Unix Makefiles" + make_cmd = "make" + cmake_cmd = [ + "cmake", + "-G", cmake_generator, + "-DQT_QMAKE_EXECUTABLE=%s" % self.qmake_path, + "-DBUILD_TESTS=False", + "-DDISABLE_DOCSTRINGS=True", + "-DCMAKE_BUILD_TYPE=%s" % self.build_type, + "-DCMAKE_INSTALL_PREFIX=%s" % self.install_dir, + module_src_dir + ] + if sys.version_info[0] > 2: + cmake_cmd.append("-DPYTHON3_EXECUTABLE=%s" % self.py_executable) + cmake_cmd.append("-DPYTHON3_INCLUDE_DIR=%s" % self.py_include_dir) + cmake_cmd.append("-DPYTHON3_LIBRARY=%s" % self.py_library) + if self.build_type.lower() == 'debug': + cmake_cmd.append("-DPYTHON3_DBG_EXECUTABLE=%s" % self.py_executable) + cmake_cmd.append("-DPYTHON3_DEBUG_LIBRARY=%s" % self.py_library) + else: + cmake_cmd.append("-DPYTHON_EXECUTABLE=%s" % self.py_executable) + cmake_cmd.append("-DPYTHON_INCLUDE_DIR=%s" % self.py_include_dir) + cmake_cmd.append("-DPYTHON_LIBRARIES=%s" % self.py_library) + if self.build_type.lower() == 'debug': + cmake_cmd.append("-DPYTHON_DEBUG_LIBRARY=%s" % self.py_library) + if extension.lower() == "shiboken": + cmake_cmd.append("-DCMAKE_INSTALL_RPATH_USE_LINK_PATH=yes") + if sys.version_info[0] > 2: + cmake_cmd.append("-DUSE_PYTHON3=ON") + + log.info("Configuring module %s (%s)..." % (extension, module_src_dir)) + if run_process(cmake_cmd, log) != 0: + raise DistutilsSetupError("Error configuring " + extension) + + log.info("Compiling module %s..." % extension) + if run_process(make_cmd, log) != 0: + raise DistutilsSetupError("Error compiling " + extension) + + log.info("Installing module %s..." % extension) + if run_process([make_cmd, "install/fast"], log) != 0: + raise DistutilsSetupError("Error pseudo installing " + extension) + + os.chdir(self.script_dir) + + def prepare_packages(self): + log.info("Preparing packages...") + version_str = "%sqt%s%s" % (__version__, self.qtinfo.version.replace(".", "")[0:3], + self.debug and "dbg" or "") + vars = { + "sources_dir": self.sources_dir, + "install_dir": self.install_dir, + "build_dir": self.build_dir, + "setup_dir": self.script_dir, + "ssl_libs_dir": OPTION_OPENSSL, + "py_version": self.py_version, + "qt_bin_dir": self.qtinfo.bins_dir, + "qt_plugins_dir": self.qtinfo.plugins_dir, + "qt_imports_dir": self.qtinfo.imports_dir, + "qt_translations_dir": self.qtinfo.translations_dir, + "version": version_str, + } + os.chdir(self.script_dir) + if sys.platform == "win32": + return self.prepare_packages_win32(vars) + return self.prepare_packages_linux(vars) + + def prepare_packages_linux(self, vars): + # patchelf -> PySide/patchelf + copyfile( + "${setup_dir}/patchelf", + "${setup_dir}/PySide/patchelf", + logger=log, vars=vars) + # /lib/site-packages/PySide/* -> /PySide + copydir( + "${install_dir}/lib/python${py_version}/site-packages/PySide", + "${setup_dir}/PySide", + logger=log, vars=vars) + # /lib/site-packages/pysideuic/* -> /pysideuic + copydir( + "${install_dir}/lib/python${py_version}/site-packages/pysideuic", + "${setup_dir}/pysideuic", + force=False, logger=log, vars=vars) + # /bin/pyside-uic -> PySide/scripts/uic.py + makefile( + "${setup_dir}/PySide/scripts/__init__.py", + logger=log, vars=vars) + copyfile( + "${install_dir}/bin/pyside-uic", + "${setup_dir}/PySide/scripts/uic.py", + force=False, logger=log, vars=vars) + # /bin/* -> PySide/ + copydir( + "${install_dir}/bin/", + "${setup_dir}/PySide", + filter=[ + "pyside-lupdate", + "pyside-rcc", + "shiboken", + ], + recursive=False, logger=log, vars=vars) + # /lib/lib* -> PySide/ + copydir( + "${install_dir}/lib/", + "${setup_dir}/PySide", + filter=[ + "libpyside*", + "libshiboken*", + ], + recursive=False, logger=log, vars=vars) + # /share/PySide/typesystems/* -> /PySide/typesystems + copydir( + "${install_dir}/share/PySide/typesystems", + "${setup_dir}/PySide/typesystems", + logger=log, vars=vars) + # /include/* -> /PySide/include + copydir( + "${install_dir}/include", + "${setup_dir}/PySide/include", + logger=log, vars=vars) + # /pyside-examples/examples/* -> /PySide/examples + copydir( + "${sources_dir}/pyside-examples/examples", + "${setup_dir}/PySide/examples", + force=False, logger=log, vars=vars) + + def prepare_packages_win32(self, vars): + # /lib/site-packages/PySide/* -> /PySide + copydir( + "${install_dir}/lib/site-packages/PySide", + "${setup_dir}/PySide", + logger=log, vars=vars) + if self.debug: + # /pyside/PySide/*.pdb -> /PySide + copydir( + "${build_dir}/pyside/PySide", + "${setup_dir}/PySide", + filter=["*.pdb"], + recursive=False, logger=log, vars=vars) + # /lib/site-packages/pysideuic/* -> /pysideuic + copydir( + "${install_dir}/lib/site-packages/pysideuic", + "${setup_dir}/pysideuic", + force=False, logger=log, vars=vars) + # /bin/pyside-uic -> PySide/scripts/uic.py + makefile( + "${setup_dir}/PySide/scripts/__init__.py", + logger=log, vars=vars) + copyfile( + "${install_dir}/bin/pyside-uic", + "${setup_dir}/PySide/scripts/uic.py", + force=False, logger=log, vars=vars) + # /bin/*.exe,*.dll -> PySide/ + copydir( + "${install_dir}/bin/", + "${setup_dir}/PySide", + filter=["*.exe", "*.dll"], + recursive=False, logger=log, vars=vars) + # /lib/*.lib -> PySide/ + copydir( + "${install_dir}/lib/", + "${setup_dir}/PySide", + filter=["*.lib"], + recursive=False, logger=log, vars=vars) + # /share/PySide/typesystems/* -> /PySide/typesystems + copydir( + "${install_dir}/share/PySide/typesystems", + "${setup_dir}/PySide/typesystems", + logger=log, vars=vars) + # /include/* -> /PySide/include + copydir( + "${install_dir}/include", + "${setup_dir}/PySide/include", + logger=log, vars=vars) + # /* -> /PySide/ + copydir("${ssl_libs_dir}", "${setup_dir}/PySide", + filter=[ + "libeay32.dll", + "ssleay32.dll"], + force=False, logger=log, vars=vars) + # /bin/*.dll -> /PySide + copydir("${qt_bin_dir}", "${setup_dir}/PySide", + filter=[ + "*.dll", + "designer.exe", + "linguist.exe", + "lrelease.exe", + "lupdate.exe", + "lconvert.exe"], + ignore=["*d4.dll"], + recursive=False, logger=log, vars=vars) + if self.debug: + # /bin/*d4.dll -> /PySide + copydir("${qt_bin_dir}", "${setup_dir}/PySide", + filter=["*d4.dll"], + recursive=False, logger=log, vars=vars) + # /plugins/* -> /PySide/plugins + copydir("${qt_plugins_dir}", "${setup_dir}/PySide/plugins", + filter=["*.dll"], + logger=log, vars=vars) + # /imports/* -> /PySide/imports + copydir("${qt_imports_dir}", "${setup_dir}/PySide/imports", + filter=["qmldir", "*.dll"], + logger=log, vars=vars) + # /translations/* -> /PySide/translations + copydir("${qt_translations_dir}", "${setup_dir}/PySide/translations", + filter=["*.ts"], + logger=log, vars=vars) + # /pyside-examples/examples/* -> /PySide/examples + copydir( + "${sources_dir}/pyside-examples/examples", + "${setup_dir}/PySide/examples", + force=False, logger=log, vars=vars) + +def read(fname): + return open(os.path.join(os.path.dirname(__file__), fname)).read() + +setup( + name = "PySide", + version = __version__, + description = ("Python bindings for the Qt cross-platform application and UI framework"), + long_description = read('README.txt'), + options = { + "bdist_wininst": { + "install_script": "pyside_postinstall.py", + }, + "bdist_msi": { + "install_script": "pyside_postinstall.py", + }, + }, + scripts = [ + "pyside_postinstall.py" + ], + classifiers = [ + 'Development Status :: 5 - Production/Stable', + 'Environment :: Console', + 'Environment :: MacOS X', + 'Environment :: X11 Applications :: Qt', + 'Intended Audience :: Developers', + 'License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)', + 'Operating System :: MacOS :: MacOS X', + 'Operating System :: POSIX', + 'Operating System :: POSIX :: Linux', + 'Programming Language :: C++', + 'Programming Language :: Python', + 'Programming Language :: Python :: 2', + 'Programming Language :: Python :: 2.6', + 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.2', + 'Topic :: Database', + 'Topic :: Software Development', + 'Topic :: Software Development :: Code Generators', + 'Topic :: Software Development :: Libraries :: Application Frameworks', + 'Topic :: Software Development :: User Interfaces', + 'Topic :: Software Development :: Widget Sets', + ], + keywords = 'Qt', + author = 'PySide Team', + author_email = 'contact@pyside.org', + url = 'http://www.pyside.org', + license = 'LGPL', + packages = ['PySide', 'pysideuic'], + include_package_data = True, + zip_safe = False, + entry_points = { + 'console_scripts': [ + 'pyside-uic = PySide.scripts.uic:main', + ] + }, + cmdclass = { + 'build': pyside_build, + 'bdist_egg': pyside_bdist_egg, + 'install': pyside_install, + }, +) diff --git a/sources/pyside b/sources/pyside new file mode 160000 index 000000000..ee95e8819 --- /dev/null +++ b/sources/pyside @@ -0,0 +1 @@ +Subproject commit ee95e881929b3b51e535ad9024025cc7ac91d57c diff --git a/sources/pyside-examples b/sources/pyside-examples new file mode 160000 index 000000000..060dca8e4 --- /dev/null +++ b/sources/pyside-examples @@ -0,0 +1 @@ +Subproject commit 060dca8e4b82f301dfb33a7182767eaf8ad3d024 diff --git a/sources/pyside-tools b/sources/pyside-tools new file mode 160000 index 000000000..92062bcf8 --- /dev/null +++ b/sources/pyside-tools @@ -0,0 +1 @@ +Subproject commit 92062bcf842814328a9f4a89f10c115bfcace0b3 diff --git a/sources/shiboken b/sources/shiboken new file mode 160000 index 000000000..54cce10fa --- /dev/null +++ b/sources/shiboken @@ -0,0 +1 @@ +Subproject commit 54cce10fa8a9942450c9e1a9d9a9d2a1b688f243 diff --git a/utils.py b/utils.py new file mode 100644 index 000000000..59cb50d44 --- /dev/null +++ b/utils.py @@ -0,0 +1,177 @@ +import sys +import os +import stat +import errno +import time +import shutil +import subprocess +import popenasync +import fnmatch + + +def filter_match(name, patterns): + for pattern in patterns: + if pattern is None: + continue + if fnmatch.fnmatch(name, pattern): + return True + return False + + +def subst_vars(input, **vars): + if vars is not None: + for key in vars: + input = input.replace("${%s}" % key, str(vars[key])) + return input + + +def copyfile(src, dst, logger=None, force=True, vars=None, subst_content=False): + if vars is not None: + src = subst_vars(src, **vars) + dst = subst_vars(dst, **vars) + + if not os.path.exists(src) and not force: + if logger is not None: + logger.info("**Skiping copy file %s to %s. Source does not exists." % (src, dst)) + return + + if logger is not None: + logger.info("Copying file %s to %s." % (src, dst)) + + if vars is None or not subst_content: + shutil.copy2(src, dst) + return + + print ("copyfile " + src) + f = open(src, "rt") + content = f.read() + f.close() + content = subst_vars(content, **vars) + f = open(dst, "wt") + f.write(content) + f.close() + + +def makefile(dst, content=None, logger=None, vars=None): + if vars is not None: + if content is not None: + content = subst_vars(content, **vars) + dst = subst_vars(dst, **vars) + + if logger is not None: + logger.info("Making file %s." % (dst)) + + dstdir = os.path.dirname(dst) + if not os.path.exists(dstdir): + os.makedirs(dstdir) + + f = open(dst, "wt") + if content is not None: + f.write(content) + f.close() + + +def copydir(src, dst, logger=None, filter=None, ignore=None, force=True, + recursive=True, vars=None, subst_files_content=False): + + if vars is not None: + src = subst_vars(src, **vars) + dst = subst_vars(dst, **vars) + + if not os.path.exists(src) and not force: + if logger is not None: + logger.info("**Skiping copy tree %s to %s. Source does not exists. filter=%s. ignore=%s." % \ + (src, dst, filter, ignore)) + return + + if logger is not None: + logger.info("Copying tree %s to %s. filter=%s. ignore=%s." % \ + (src, dst, filter, ignore)) + + names = os.listdir(src) + + if not os.path.exists(dst): + os.makedirs(dst) + + errors = [] + for name in names: + srcname = os.path.join(src, name) + dstname = os.path.join(dst, name) + try: + if os.path.isdir(srcname): + if recursive: + copydir(srcname, dstname, logger, filter, ignore, force, recursive, + vars, subst_files_content) + else: + if (filter is not None and not filter_match(name, filter)) or \ + (ignore is not None and filter_match(name, ignore)): + continue + copyfile(srcname, dstname, logger, True, vars, subst_files_content) + # catch the Error from the recursive copytree so that we can + # continue with other files + except shutil.Error as err: + errors.extend(err.args[0]) + except EnvironmentError as why: + errors.append((srcname, dstname, str(why))) + try: + shutil.copystat(src, dst) + except OSError as why: + if WindowsError is not None and isinstance(why, WindowsError): + # Copying file access times may fail on Windows + pass + else: + errors.extend((src, dst, str(why))) + if errors: + raise EnvironmentError(errors) + + +def rmtree(dirname): + def handleRemoveReadonly(func, path, exc): + excvalue = exc[1] + if func in (os.rmdir, os.remove) and excvalue.errno == errno.EACCES: + os.chmod(path, stat.S_IRWXU| stat.S_IRWXG| stat.S_IRWXO) # 0777 + func(path) + else: + raise + shutil.rmtree(dirname, ignore_errors=False, onerror=handleRemoveReadonly) + + +def run_process(args, logger=None): + def log(buffer, checkNewLine): + endsWithNewLine = False + if buffer.endswith('\n'): + endsWithNewLine = True + if checkNewLine and buffer.find('\n') == -1: + return buffer + lines = buffer.splitlines() + buffer = '' + if checkNewLine and not endsWithNewLine: + buffer = lines[-1] + lines = lines[:-1] + for line in lines: + if not logger is None: + logger.info(line.rstrip('\r')) + else: + print(line.rstrip('\r')) + return buffer + + shell = False + if sys.platform == "win32": + shell = True + + proc = popenasync.Popen(args, + stdin = subprocess.PIPE, + stdout = subprocess.PIPE, + stderr = subprocess.STDOUT, + universal_newlines = 1, + shell = shell, + env = os.environ) + + log_buffer = None; + while proc.poll() is None: + log_buffer = log(proc.read_async(wait=0.1, e=0), False) + if log_buffer: + log(log_buffer, False) + + proc.wait() + return proc.returncode -- cgit v1.2.3