aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitmodules24
-rw-r--r--README.rst22
-rw-r--r--checklibs.py318
-rw-r--r--qtinfo.py4
-rw-r--r--setup.py37
m---------sources/pyside-examples0
m---------sources/pyside-examples20
m---------sources/pyside-tools20
m---------sources/pyside213
m---------sources/shiboken210
10 files changed, 387 insertions, 41 deletions
diff --git a/.gitmodules b/.gitmodules
index e5567f5ab..f23e1853b 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,12 +1,12 @@
-[submodule "sources/shiboken"]
- path = sources/shiboken
- url = https://github.com/PySide/shiboken.git
-[submodule "sources/pyside"]
- path = sources/pyside
- url = https://github.com/PySide/pyside.git
-[submodule "sources/pyside-tools"]
- path = sources/pyside-tools
- url = https://github.com/PySide/Tools.git
-[submodule "sources/pyside-examples"]
- path = sources/pyside-examples
- url = https://github.com/PySide/Examples.git
+[submodule "sources/pyside2"]
+ path = sources/pyside2
+ url=https://github.com/PySide/pyside2.git
+[submodule "sources/shiboken2"]
+ path = sources/shiboken2
+ url=https://github.com/PySide/shiboken2.git
+[submodule "sources/pyside-tools2"]
+ path = sources/pyside-tools2
+ url=https://github.com/PySide/pyside-tools2.git
+[submodule "sources/pyside-examples2"]
+ path = sources/pyside-examples2
+ url=https://github.com/PySide/pyside-examples2.git
diff --git a/README.rst b/README.rst
index 809354c7f..26ab178e8 100644
--- a/README.rst
+++ b/README.rst
@@ -1,20 +1,20 @@
-======
-PySide
-======
+=======
+PySide2
+=======
-.. image:: https://pypip.in/wheel/PySide/badge.png
+.. image:: https://img.shields.io/pypi/wheel/pyside.svg
:target: https://pypi.python.org/pypi/PySide/
:alt: Wheel Status
-.. image:: https://pypip.in/download/PySide/badge.png
+.. image:: https://img.shields.io/pypi/dm/pyside.svg
:target: https://pypi.python.org/pypi/PySide/
:alt: Downloads
-.. image:: https://pypip.in/version/PySide/badge.png
+.. image:: https://img.shields.io/pypi/v/pyside.svg
:target: https://pypi.python.org/pypi/PySide/
:alt: Latest Version
-.. image:: https://pypip.in/license/PySide/badge.png
+.. image:: https://binstar.org/asmeurer/pyside/badges/license.svg
:target: https://pypi.python.org/pypi/PySide/
:alt: License
@@ -27,6 +27,12 @@ PySide
Introduction
============
+.. note::
+
+ This text is mostly from PySide 1.2.X. We need to update it when
+ PySide2 for Qt5 is more ready.
+
+
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.
@@ -45,7 +51,7 @@ PySide requires Python 2.6 or later and Qt 4.6 or better.
.. note::
- Qt 5.x is currently not supported.
+ Qt 5.x is currently in the works.
Installation
============
diff --git a/checklibs.py b/checklibs.py
new file mode 100644
index 000000000..ff4d51ae8
--- /dev/null
+++ b/checklibs.py
@@ -0,0 +1,318 @@
+#!/usr/bin/env python
+#
+# checklibs.py
+#
+# Check Mach-O dependencies.
+#
+# See http://www.entropy.ch/blog/Developer/2011/03/05/2011-Update-to-checklibs-Script-for-dynamic-library-dependencies.html
+#
+# Written by Marc Liyanage <http://www.entropy.ch>
+#
+#
+
+import subprocess, sys, re, os.path, optparse, collections
+from pprint import pprint
+
+
+class MachOFile:
+
+ def __init__(self, image_path, arch, parent = None):
+ self.image_path = image_path
+ self._dependencies = []
+ self._cache = dict(paths = {}, order = [])
+ self.arch = arch
+ self.parent = parent
+ self.header_info = {}
+ self.load_info()
+ self.add_to_cache()
+
+ def load_info(self):
+ if not self.image_path.exists():
+ return
+ self.load_header()
+ self.load_rpaths()
+
+ def load_header(self):
+ # Get the mach-o header info, we're interested in the file type (executable, dylib)
+ cmd = 'otool -arch {0} -h "{1}"'
+ output = self.shell(cmd, [self.arch, self.image_path.resolved_path], fatal = True)
+ if not output:
+ print >> sys.stderr, 'Unable to load mach header for {0} ({1}), architecture mismatch? Use --arch option to pick architecture'.format(self.image_path.resolved_path, self.arch)
+ exit()
+ (keys, values) = output.splitlines()[2:]
+ self.header_info = dict(zip(keys.split(), values.split()))
+
+ def load_rpaths(self):
+ output = self.shell('otool -arch {0} -l "{1}"', [self.arch, self.image_path.resolved_path], fatal = True)
+ load_commands = re.split('Load command (\d+)', output)[1:] # skip file name on first line
+ self._rpaths = []
+ load_commands = collections.deque(load_commands)
+ while load_commands:
+ load_commands.popleft() # command index
+ command = load_commands.popleft().strip().splitlines()
+ if command[0].find('LC_RPATH') == -1:
+ continue
+
+ path = re.findall('path (.+) \(offset \d+\)$', command[2])[0]
+ image_path = self.image_path_for_recorded_path(path)
+ image_path.rpath_source = self
+ self._rpaths.append(image_path)
+
+ def ancestors(self):
+ ancestors = []
+ parent = self.parent
+ while parent:
+ ancestors.append(parent)
+ parent = parent.parent
+
+ return ancestors
+
+ def self_and_ancestors(self):
+ return [self] + self.ancestors()
+
+ def rpaths(self):
+ return self._rpaths
+
+ def all_rpaths(self):
+ rpaths = []
+ for image in self.self_and_ancestors():
+ rpaths.extend(image.rpaths())
+ return rpaths
+
+ def root(self):
+ if not self.parent:
+ return self
+ return self.ancestors()[-1]
+
+ def executable_path(self):
+ root = self.root()
+ if root.is_executable():
+ return root.image_path
+ return None
+
+ def filetype(self):
+ return long(self.header_info.get('filetype', 0))
+
+ def is_dylib(self):
+ return self.filetype() == MachOFile.MH_DYLIB
+
+ def is_executable(self):
+ return self.filetype() == MachOFile.MH_EXECUTE
+
+ def all_dependencies(self):
+ self.walk_dependencies()
+ return self.cache()['order']
+
+ def walk_dependencies(self, known = {}):
+ if known.get(self.image_path.resolved_path):
+ return
+
+ known[self.image_path.resolved_path] = self
+
+ for item in self.dependencies():
+ item.walk_dependencies(known)
+
+ def dependencies(self):
+ if not self.image_path.exists():
+ return []
+
+ if self._dependencies:
+ return self._dependencies
+
+ output = self.shell('otool -arch {0} -L "{1}"', [self.arch, self.image_path.resolved_path], fatal = True)
+ output = [line.strip() for line in output.splitlines()]
+ del(output[0])
+ if self.is_dylib():
+ del(output[0]) # In the case of dylibs, the first line is the id line
+
+ self._dependencies = []
+ for line in output:
+ match = re.match('^(.+)\s+(\(.+)\)$', line)
+ if not match:
+ continue
+ recorded_path = match.group(1)
+ image_path = self.image_path_for_recorded_path(recorded_path)
+ image = self.lookup_or_make_item(image_path)
+ self._dependencies.append(image)
+
+ return self._dependencies
+
+ # The root item holds the cache, all lower-level requests bubble up the parent chain
+ def cache(self):
+ if self.parent:
+ return self.parent.cache()
+ return self._cache
+
+ def add_to_cache(self):
+ cache = self.cache()
+ cache['paths'][self.image_path.resolved_path] = self
+ cache['order'].append(self)
+
+ def cached_item_for_path(self, path):
+ if not path:
+ return None
+ return self.cache()['paths'].get(path)
+
+ def lookup_or_make_item(self, image_path):
+ image = self.cached_item_for_path(image_path.resolved_path)
+ if not image: # cache miss
+ image = MachOFile(image_path, self.arch, parent = self)
+ return image
+
+ def image_path_for_recorded_path(self, recorded_path):
+ path = ImagePath(None, recorded_path)
+
+ # handle @executable_path
+ if recorded_path.startswith(ImagePath.EXECUTABLE_PATH_TOKEN):
+ executable_image_path = self.executable_path()
+ if executable_image_path:
+ path.resolved_path = os.path.normpath(recorded_path.replace(ImagePath.EXECUTABLE_PATH_TOKEN, os.path.dirname(executable_image_path.resolved_path)))
+
+ # handle @loader_path
+ elif recorded_path.startswith(ImagePath.LOADER_PATH_TOKEN):
+ path.resolved_path = os.path.normpath(recorded_path.replace(ImagePath.LOADER_PATH_TOKEN, os.path.dirname(self.image_path.resolved_path)))
+
+ # handle @rpath
+ elif recorded_path.startswith(ImagePath.RPATH_TOKEN):
+ for rpath in self.all_rpaths():
+ resolved_path = os.path.normpath(recorded_path.replace(ImagePath.RPATH_TOKEN, rpath.resolved_path))
+ if os.path.exists(resolved_path):
+ path.resolved_path = resolved_path
+ path.rpath_source = rpath.rpath_source
+ break
+
+ # handle absolute path
+ elif recorded_path.startswith('/'):
+ path.resolved_path = recorded_path
+
+ return path
+
+ def __repr__(self):
+ return str(self.image_path)
+
+ def dump(self):
+ print self.image_path
+ for dependency in self.dependencies():
+ print '\t{0}'.format(dependency)
+
+ @staticmethod
+ def shell(cmd_format, args, fatal = False):
+ cmd = cmd_format.format(*args)
+ popen = subprocess.Popen(cmd, shell = True, stdout = subprocess.PIPE)
+ output = popen.communicate()[0]
+ if popen.returncode and fatal:
+ print >> sys.stderr, 'Nonzero exit status for shell command "{0}"'.format(cmd)
+ sys.exit(1)
+
+ return output
+
+ @classmethod
+ def architectures_for_image_at_path(cls, path):
+ output = cls.shell('file "{}"', [path])
+ file_architectures = re.findall(r' executable (\w+)', output)
+ ordering = 'x86_64 i386'.split()
+ file_architectures = sorted(file_architectures, lambda a, b: cmp(ordering.index(a), ordering.index(b)))
+ return file_architectures
+
+ MH_EXECUTE = 0x2
+ MH_DYLIB = 0x6
+ MH_BUNDLE = 0x8
+
+
+# ANSI terminal coloring sequences
+class Color:
+ HEADER = '\033[95m'
+ BLUE = '\033[94m'
+ GREEN = '\033[92m'
+ RED = '\033[91m'
+ ENDC = '\033[0m'
+
+ @staticmethod
+ def red(string):
+ return Color.wrap(string, Color.RED)
+
+ @staticmethod
+ def blue(string):
+ return Color.wrap(string, Color.BLUE)
+
+ @staticmethod
+ def wrap(string, color):
+ return Color.HEADER + color + string + Color.ENDC
+
+
+# This class holds path information for a mach-0 image file. It holds the path as it was recorded
+# in the loading binary as well as the effective, resolved file system path.
+# The former can contain @-replacement tokens.
+# In the case where the recorded path contains an @rpath token that was resolved successfully, we also
+# capture the path of the binary that supplied the rpath value that was used.
+# That path itself can contain replacement tokens such as @loader_path.
+class ImagePath:
+
+ def __init__(self, resolved_path, recorded_path = None):
+ self.recorded_path = recorded_path
+ self.resolved_path = resolved_path
+ self.rpath_source = None
+
+ def __repr__(self):
+ description = None
+
+ if self.resolved_equals_recorded() or self.recorded_path == None:
+ description = self.resolved_path
+ else:
+ description = '{0} ({1})'.format(self.resolved_path, self.recorded_path)
+
+ if (not self.is_system_location()) and (not self.uses_dyld_token()):
+ description = Color.blue(description)
+
+ if self.rpath_source:
+ description += ' (rpath source: {0})'.format(self.rpath_source.image_path.resolved_path)
+
+ if not self.exists():
+ description += Color.red(' (missing)')
+
+ return description
+
+ def exists(self):
+ return self.resolved_path and os.path.exists(self.resolved_path)
+
+ def resolved_equals_recorded(self):
+ return self.resolved_path and self.recorded_path and self.resolved_path == self.recorded_path
+
+ def uses_dyld_token(self):
+ return self.recorded_path and self.recorded_path.startswith('@')
+
+ def is_system_location(self):
+ system_prefixes = ['/System/Library', '/usr/lib']
+ for prefix in system_prefixes:
+ if self.resolved_path and self.resolved_path.startswith(prefix):
+ return True
+
+ EXECUTABLE_PATH_TOKEN = '@executable_path'
+ LOADER_PATH_TOKEN = '@loader_path'
+ RPATH_TOKEN = '@rpath'
+
+
+# Command line driver
+parser = optparse.OptionParser(usage = "Usage: %prog [options] path_to_mach_o_file")
+parser.add_option("--arch", dest = "arch", help = "architecture", metavar = "ARCH")
+parser.add_option("--all", dest = "include_system_libraries", help = "Include system frameworks and libraries", action="store_true")
+(options, args) = parser.parse_args()
+
+if len(args) < 1:
+ parser.print_help()
+ sys.exit(1)
+
+archs = MachOFile.architectures_for_image_at_path(args[0])
+if archs and not options.arch:
+ print >> sys.stderr, 'Analyzing architecture {}, override with --arch if needed'.format(archs[0])
+ options.arch = archs[0]
+
+toplevel_image = MachOFile(ImagePath(args[0]), options.arch)
+
+for dependency in toplevel_image.all_dependencies():
+ if dependency.image_path.exists() and (not options.include_system_libraries) and dependency.image_path.is_system_location():
+ continue
+
+ dependency.dump()
+ print
+
diff --git a/qtinfo.py b/qtinfo.py
index 631adb667..7c4cde76b 100644
--- a/qtinfo.py
+++ b/qtinfo.py
@@ -33,6 +33,9 @@ class QtInfo(object):
def getHeadersPath(self):
return self.getProperty("QT_INSTALL_HEADERS")
+ def getDocsPath(self):
+ return self.getProperty("QT_INSTALL_DOCS")
+
def getProperty(self, prop_name):
cmd = [self._qmake_path, "-query", prop_name]
proc = subprocess.Popen(cmd, stdout = subprocess.PIPE, shell=False)
@@ -52,3 +55,4 @@ class QtInfo(object):
imports_dir = property(getImportsPath)
translations_dir = property(getTranslationsPath)
headers_dir = property(getHeadersPath)
+ docs_dir = property(getDocsPath)
diff --git a/setup.py b/setup.py
index b2798e243..7bb2d7af9 100644
--- a/setup.py
+++ b/setup.py
@@ -33,7 +33,7 @@ submodules = {
["shiboken2", "qt5"],
["pyside2", "qt5"],
["pyside-tools2", "qt5"],
- ["pyside-examples", "master"],
+ ["pyside-examples2", "qt5"],
],
'1.3.0dev': [
["shiboken", "master"],
@@ -113,6 +113,12 @@ from utils import regenerate_qt_resources
from utils import filter_match
from utils import osx_localize_libpaths
+# guess a close folder name for extensions
+def get_extension_folder(ext):
+ maybe = list(map(lambda x:x[0], submodules[__version__]))
+ folder = difflib.get_close_matches(ext, maybe)[0]
+ return folder
+
# Declare options
OPTION_DEBUG = has_option("debug")
OPTION_RELWITHDEBINFO = has_option('relwithdebinfo')
@@ -203,7 +209,7 @@ Use --list-versions option to get list of available versions""" % OPTION_VERSION
if OPTION_NOEXAMPLES:
# remove pyside-exampes from submodules so they will not be included
for idx, item in enumerate(submodules[__version__]):
- if item[0] == 'pyside-examples':
+ if item[0].startswith('pyside-examples'):
del submodules[__version__][idx]
@@ -236,7 +242,11 @@ for n in ["pyside_package", "build", "PySide-%s" % __version__]:
d = os.path.join(script_dir, n)
if os.path.isdir(d):
print("Removing %s" % d)
- rmtree(d)
+ try:
+ rmtree(d)
+ except Exception as e:
+ print('***** problem removing "{}"'.format(d))
+ print('ignored error: {}'.format(e))
# Prepare package folders
for pkg in ["pyside_package/PySide", "pyside_package/pysideuic"]:
@@ -490,6 +500,7 @@ class pyside_build(_build):
log.info("Qt qmake: %s" % self.qmake_path)
log.info("Qt version: %s" % qtinfo.version)
log.info("Qt bins: %s" % qtinfo.bins_dir)
+ log.info("Qt docs: %s" % qtinfo.docs_dir)
log.info("Qt plugins: %s" % qtinfo.plugins_dir)
log.info("-" * 3)
log.info("OpenSSL libs: %s" % OPTION_OPENSSL)
@@ -536,8 +547,7 @@ class pyside_build(_build):
def build_extension(self, extension):
# calculate the subrepos folder name
- maybe = list(map(lambda x:x[0], submodules[__version__]))
- folder = difflib.get_close_matches(extension, maybe)[0]
+ folder = get_extension_folder(extension)
log.info("Building module %s..." % extension)
@@ -550,9 +560,14 @@ class pyside_build(_build):
return
if os.path.exists(module_build_dir):
log.info("Deleting module build folder %s..." % module_build_dir)
- rmtree(module_build_dir)
+ try:
+ rmtree(module_build_dir)
+ except Exception as e:
+ print('***** problem removing "{}"'.format(module_build_dir))
+ print('ignored error: {}'.format(e))
log.info("Creating module build folder %s..." % module_build_dir)
- os.makedirs(module_build_dir)
+ if not os.path.exists(module_build_dir):
+ os.makedirs(module_build_dir)
os.chdir(module_build_dir)
module_src_dir = os.path.join(self.sources_dir, folder)
@@ -564,6 +579,7 @@ class pyside_build(_build):
"-DQT_QMAKE_EXECUTABLE=%s" % self.qmake_path,
"-DBUILD_TESTS=%s" % self.build_tests,
"-DDISABLE_DOCSTRINGS=True",
+ "-DQt5Help_DIR=%s" % self.qtinfo.docs_dir,
"-DCMAKE_BUILD_TYPE=%s" % self.build_type,
"-DCMAKE_INSTALL_PREFIX=%s" % self.install_dir,
module_src_dir
@@ -634,6 +650,7 @@ class pyside_build(_build):
"py_version": self.py_version,
"qt_version": self.qtinfo.version,
"qt_bin_dir": self.qtinfo.bins_dir,
+ "qt_doc_dir": self.qtinfo.docs_dir,
"qt_lib_dir": self.qtinfo.libs_dir,
"qt_plugins_dir": self.qtinfo.plugins_dir,
"qt_imports_dir": self.qtinfo.imports_dir,
@@ -717,8 +734,9 @@ class pyside_build(_build):
vars=vars)
if not OPTION_NOEXAMPLES:
# <sources>/pyside-examples/examples/* -> <setup>/PySide/examples
+ folder = get_extension_folder('pyside-examples')
copydir(
- "{sources_dir}/pyside-examples/examples",
+ "{sources_dir}/%s/examples" % folder,
"{dist_dir}/PySide/examples",
force=False, vars=vars)
# Re-generate examples Qt resource files for Python 3 compatibility
@@ -836,8 +854,9 @@ class pyside_build(_build):
vars=vars)
if not OPTION_NOEXAMPLES:
# <sources>/pyside-examples/examples/* -> <setup>/PySide/examples
+ folder = get_extension_folder('pyside-examples')
copydir(
- "{sources_dir}/pyside-examples/examples",
+ "{sources_dir}/%s/examples" % folder,
"{dist_dir}/PySide/examples",
force=False, vars=vars)
# Re-generate examples Qt resource files for Python 3 compatibility
diff --git a/sources/pyside-examples b/sources/pyside-examples
deleted file mode 160000
-Subproject df4f44b6aeb08f27da270392f5d9dc2e2f28e3a
diff --git a/sources/pyside-examples2 b/sources/pyside-examples2
new file mode 160000
+Subproject 0d814764dd2d34553b4f4d8f34a0641457a21a7
diff --git a/sources/pyside-tools2 b/sources/pyside-tools2
-Subproject d7f2a9bc3d228884235f19e1e73d132e7db39de
+Subproject f69bcb12713ca10752f0175f64ae5bcb3125fed
diff --git a/sources/pyside2 b/sources/pyside2
-Subproject cd0f27e7219c64fe6a4a079892f75d1a6af726b
+Subproject b8473ad41057eefa3f48faf02a9bad360200ad6
diff --git a/sources/shiboken2 b/sources/shiboken2
-Subproject af111f1634bbaea5e7685fc89ae14dc2c293337
+Subproject bfb1186f639d7ccd71e1f2baaf7bd342df4837e