diff --git a/CAVEATS.md b/CAVEATS.md
index 4ebdc2a8..3c4ec0e6 100644
--- a/CAVEATS.md
+++ b/CAVEATS.md
@@ -216,3 +216,49 @@ Traceback (most recent call last):
...
TypeError: ...
```
+
+
+#### QtWidgets.QHeaderView.setResizeMode
+
+`setResizeMode` was [renamed](http://doc.qt.io/qt-5/qheaderview.html#setSectionResizeMode) `setSectionResizeMode` in Qt 5.
+
+```python
+# PySide2
+>>> from Qt import QtWidgets
+>>> app = QtWidgets.QApplication(sys.argv)
+>>> view = QtWidgets.QTreeWidget()
+>>> header = view.header()
+>>> header.setResizeMode(QtWidgets.QHeaderView.Fixed)
+Traceback (most recent call last):
+...
+AttributeError: 'PySide2.QtWidgets.QHeaderView' object has no attribute 'setResizeMode'
+```
+
+```python
+# PySide
+>>> from Qt import QtWidgets
+>>> app = QtWidgets.QApplication(sys.argv)
+>>> view = QtWidgets.QTreeWidget()
+>>> header = view.header()
+>>> header.setSectionResizeMode(QtWidgets.QHeaderView.Fixed)
+Traceback (most recent call last):
+...
+AttributeError: 'PySide.QtGui.QHeaderView' object has no attribute 'setSectionResizeMode'
+```
+
+##### Workaround
+
+Use a conditional.
+
+```python
+# PySide2
+>>> from Qt import QtWidgets, __binding__
+>>> app = QtWidgets.QApplication(sys.argv)
+>>> view = QtWidgets.QTreeWidget()
+>>> header = view.header()
+>>> if __binding__ in ("PyQt4", "PySide"):
+... header.setResizeMode(QtWidgets.QHeaderView.Fixed)
+... else:
+... header.setSectionResizeMode(QtWidgets.QHeaderView.Fixed)
+```
+
diff --git a/Dockerfile-py2.7 b/Dockerfile-py2.7
index 28f242a6..a8e59fda 100644
--- a/Dockerfile-py2.7
+++ b/Dockerfile-py2.7
@@ -11,7 +11,8 @@ RUN apt-get update && \
python-qt4 \
python-pyqt5 \
python-pyside \
- python-pyside2
+ python-pyside2 \
+ xvfb
# Nose is the Python test-runner
RUN pip install nose nosepipe
@@ -19,9 +20,14 @@ RUN pip install nose nosepipe
# Enable additional output from Qt.py
ENV QT_VERBOSE true
+# Xvfb
+ENV DISPLAY :99
+
WORKDIR /workspace/Qt.py
ENTRYPOINT cp -r /Qt.py /workspace && \
python build_caveats_tests.py && \
+ Xvfb :99 -screen 0 1024x768x16 2>/dev/null & \
+ sleep 3 && \
nosetests \
--verbose \
--with-process-isolation \
diff --git a/Dockerfile-py3.5 b/Dockerfile-py3.5
index e064e349..89bedfa4 100644
--- a/Dockerfile-py3.5
+++ b/Dockerfile-py3.5
@@ -11,7 +11,8 @@ RUN apt-get update && \
python3-pyqt4 \
python3-pyqt5 \
python3-pyside \
- python3-pyside2
+ python3-pyside2 \
+ xvfb
# Nose is the Python test-runner
RUN pip3 install nose nosepipe
@@ -19,9 +20,14 @@ RUN pip3 install nose nosepipe
# Enable additional output from Qt.py
ENV QT_VERBOSE true
+# Xvfb
+ENV DISPLAY :99
+
WORKDIR /workspace/Qt.py
ENTRYPOINT cp -r /Qt.py /workspace && \
python3 build_caveats_tests.py && \
+ Xvfb :99 -screen 0 1024x768x16 2>/dev/null & \
+ sleep 3 && \
nosetests \
--verbose \
--with-process-isolation \
diff --git a/README.md b/README.md
index d6312612..d541defd 100644
--- a/README.md
+++ b/README.md
@@ -4,6 +4,30 @@
Qt.py enables you to write software that dynamically chooses the most desireable bindings based on what's available, including PySide2, PyQt5, PySide and PyQt4; in that (configurable) order (see below).
+
+
+**Table of contents**
+
+- [Install](#install)
+- [Usage](#usage)
+- [Documentation](#documentation)
+- [Rules](#rules)
+- [How it works](#how-it-works)
+- [Known problems](#known-problems)
+- [Who's using Qt.py?](#whos-using-qtpy)
+- [Projects using Qt.py](#projects-using-qtpy)
+- [Projects similar to Qt.py](#projects-similar-to-qtpy)
+- [Developer guide](#developer-guide)
+
+
+
+
+
+### Development goals
+
+- Simplicity. Simple to read, simple to grok, simple to maintain.
+- No bugs. What you get is what each binding provides equally and documentation of inequalities.
+
@@ -45,29 +69,86 @@ app.exec_()
-### How it works
+### Documentation
-Once you import Qt.py, Qt.py replaces itself with the most desirable binding on your platform, or throws an `ImportError` if none are available.
+All members of `Qt` stem directly from those available via PySide2, along with these additional members.
+
+| Attribute | Type | Value
+|:------------------------|:-------|:------------
+| `__binding__` | `str` | A string reference to binding currently in use
+| `__qt_version__` | `str` | Reference to version of Qt, such as Qt 5.6.1
+| `__binding_version__` | `str` | Reference to version of binding, such as PySide 1.2.6
+| `__wrapper_version__` | `str` | Version of this project
+| `load_ui()` | `func` | Minimal wrapper of PyQt4.loadUi and PySide equivalent
+
+
+
+##### Branch binding-specific code
+
+Some bindings offer features not available in others, you can use `__binding__` to capture those.
```python
->>> import Qt
->>> print(Qt)
-
+if "PySide" in Qt.__binding__:
+ do_pyside_stuff()
```
-Here's an example of how this works.
+
-**Qt.py**
+##### Override preferred choice
+
+If your system has multiple choices where one or more is preferred, you can override the preference and order in which they are tried with this environment variable.
+
+```bash
+# Windows
+$ set QT_PREFERRED_BINDING=PyQt5
+$ python -c "import Qt;print(Qt.__binding__)"
+PyQt5
+
+# Unix/OSX
+$ export QT_PREFERRED_BINDING=PyQt5
+$ python -c "import Qt;print(Qt.__binding__)"
+PyQt5
+```
+
+Constrain available choices and order of discovery by supplying multiple values.
+
+```bash
+# Try PyQt first and then PySide, but nothing else.
+$ export QT_PREFERRED_BINDING=PyQt:PySide
+```
+
+Using the OS path separator (`os.pathsep`) which is `:` on Unix systems and `;` on Windows.
+
+
+
+##### Load Qt Designer .ui files
+
+The `uic.loadUi` function of PyQt4 and PyQt5 as well as the `QtUiTools.QUiLoader().load` function of PySide/PySide2 are mapped to a convenience function `load_ui`.
```python
import sys
-import PyQt5
+import Qt
-# Replace myself PyQt5
-sys.modules["Qt"] = PyQt5
+app = QtWidgets.QApplication(sys.argv)
+ui = Qt.load_ui("my.ui")
+ui.show()
+app.exec_()
```
-Once imported, it is as though your application was importing whichever binding was chosen and Qt.py never existed.
+Please note, for maximum compatibility, only pass the argument of the filename to the `load_ui` function.
+
+
+
+##### sip API v2
+
+If you're using PyQt4, `sip` attempts to set its API to version 2 for the following:
+- `QString`
+- `QVariant`
+- `QDate`
+- `QDateTime`
+- `QTextStream`
+- `QTime`
+- `QUrl`
@@ -119,86 +200,29 @@ There are cases where Qt.py is not handling incompatibility issues. Please see [
-### Documentation
-
-All members of `Qt` stem directly from those available via PySide2, along with these additional members.
-
-```python
-import Qt
-
-# A string reference to binding currently in use
-Qt.__binding__ == 'PyQt5'
-
-# Reference to version of Qt, such as Qt 5.6.1
-Qt.__qt_version__ == '5.6.1'
-
-# Reference to version of binding, such as PySide 1.2.6
-Qt.__binding_version__ == '1.2.6'
-
-# Version of this project
-Qt.__wrapper_version__ == '1.0.0'
-```
-
-##### Branch binding-specific code
+### How it works
-Some bindings offer features not available in others, you can use `__binding__` to capture those.
+Once you import Qt.py, Qt.py replaces itself with the most desirable binding on your platform, or throws an `ImportError` if none are available.
```python
-if "PySide" in Qt.__binding__:
- do_pyside_stuff()
-```
-
-##### Override preferred choice
-
-If your system has multiple choices where one or more is preferred, you can override the preference and order in which they are tried with this environment variable.
-
-```bash
-# Windows
-$ set QT_PREFERRED_BINDING=PyQt5
-$ python -c "import Qt;print(Qt.__binding__)"
-PyQt5
-
-# Unix/OSX
-$ export QT_PREFERRED_BINDING=PyQt5
-$ python -c "import Qt;print(Qt.__binding__)"
-PyQt5
-```
-
-Constrain available choices and order of discovery by supplying multiple values.
-
-```bash
-# Try PyQt first and then PySide, but nothing else.
-$ export QT_PREFERRED_BINDING=PyQt:PySide
+>>> import Qt
+>>> print(Qt)
+
```
-Using the OS path separator (`os.pathsep`) which is `:` on Unix systems and `;` on Windows.
-
-##### Load Qt Designer .ui files
+Here's an example of how this works.
-The `uic.loadUi` function of PyQt4 and PyQt5 as well as the `QtUiTools.QUiLoader().load` function of PySide/PySide2 are mapped to a convenience function `load_ui`.
+**Qt.py**
```python
import sys
-import Qt
+import PyQt5
-app = QtWidgets.QApplication(sys.argv)
-ui = Qt.load_ui("my.ui")
-ui.show()
-app.exec_()
+# Replace myself PyQt5
+sys.modules["Qt"] = PyQt5
```
-Please note, for maximum compatibility, only pass the argument of the filename to the `load_ui` function.
-
-##### sip API v2
-
-If you're using PyQt4, `sip` attempts to set its API to version 2 for the following:
-- `QString`
-- `QVariant`
-- `QDate`
-- `QDateTime`
-- `QTextStream`
-- `QTime`
-- `QUrl`
+Once imported, it is as though your application was importing whichever binding was chosen and Qt.py never existed.
diff --git a/tests.py b/tests.py
index 887f1346..5aa45a1d 100644
--- a/tests.py
+++ b/tests.py
@@ -92,7 +92,7 @@ def test_preferred_pyside():
def test_preferred_pyside2():
- """Setting QT_PREFERRED_BINDING to PyQt5 properly forces the binding"""
+ """Setting QT_PREFERRED_BINDING to PySide2 properly forces the binding"""
with pyside2():
import Qt
assert Qt.__name__ == "PySide2", ("PySide2 should have been picked, "