Re: Is there a nice way to switch between 2 different packages providing the same APIs?

2018-07-05 Thread Mark via Python-list
On Thursday, July 5, 2018 at 6:24:09 PM UTC+1, Tim Williams wrote:
> On Thu, Jul 5, 2018 at 9:02 AM Mark Summerfield via Python-list <
> python-list@python.org> wrote:
> 
> > For GUI programming I often use Python bindings for Qt.
> >
> > There are two competing bindings, PySide and PyQt.
> >
> > Ideally I like to have applications that can use either. This way, if I
> > get a problem I can try with the other bindings: if I still get the
> > problem, then it is probably me; but if I don't it may be an issue with the
> > bindings.
> >
> > But working with both means that my imports are very messy. Here's a tiny
> > example:
> >
> > if PYSIDE: # bool True -> Use PySide; False -> Use PyQt5
> > from PySide2.QtCore import Qt
> > from PySide2.QtGui import QIcon
> > from PySide2.QtWidgets import (
> > QDialog, QFrame, QGridLayout, QLabel, QLineEdit, QPushButton,
> > QVBoxLayout)
> > else:
> > from PyQt5.QtCore import Qt
> > from PyQt5.QtGui import QIcon
> > from PyQt5.QtWidgets import (
> > QDialog, QFrame, QGridLayout, QLabel, QLineEdit, QPushButton,
> > QVBoxLayout)
> >
> > The PYSIDE constant is imported from another module and is used for all
> > .py files in a given project so that just by changing PYSIDE's value I can
> > run an entire application with PySide2 or with PyQt5.
> >
> > But I'd really rather just have one lot of imports per file.
> >
> > One obvious solution is to create a 'Qt.py' module that imports everything
> > depending on the PYSIDE switch and that I then use in all the other .py
> > files, something like this:
> >
> > from Qt.QtCore import Qt
> > from Qt.QtGui import QIcon
> > ... etc.
> >
> > But I'm just wondering if there's a nicer way to do all this?
> > --
> > https://mail.python.org/mailman/listinfo/python-list
> 
> 
> Check out pyqtgraph 
> 
> It tries to use  PyQt5/PyQt4/PySide depending on which if these packages
> were imported before importing pyqtgraph.

I looked at the source for this and it is v. similar to what I'm doing myself 
right down to having an isObjectAlive() function done exactly as I'm doing it.

The thing I'm not keen on is that the imports are like this:

from .Qt import QtCore

and then used as:

p = QtCore.QPoint(0, 0)

whereas I want to do something like this (incorrect & maybe not possible):

from .Qt.QtCore import QPoint, QRect

p = QPoint(0, 0)
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Is there a nice way to switch between 2 different packages providing the same APIs?

2018-07-06 Thread Mark via Python-list
In the end I changed to a completely different approach.

I now have two parallel directories, one with PySide-based code and the other 
with auto-generated PyQt-based code. And I created a tiny script to copy the 
PySide code to the PyQt directory & do the necessary changes. (I can post the 
script if anyone's interested.)

This means that there are no import hacks and no (manual) duplication, while 
still being easy to test using either binding library.
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Is there a nice way to switch between 2 different packages providing the same APIs?

2018-07-06 Thread Mark via Python-list
On Friday, July 6, 2018 at 1:22:46 PM UTC+1, Bev in TX wrote:
> > On Jul 6, 2018, at 3:14 AM, Mark via Python-list  
> > wrote:
> > 
> > In the end I changed to a completely different approach.
> > 
> > I now have two parallel directories, one with PySide-based code and the 
> > other with auto-generated PyQt-based code. And I created a tiny script to 
> > copy the PySide code to the PyQt directory & do the necessary changes. (I 
> > can post the script if anyone's interested.)
> 
> I am interested.
> > 
> > This means that there are no import hacks and no (manual) duplication, 
> > while still being easy to test using either binding library.
> > -- 
> > https://mail.python.org/mailman/listinfo/python-list
> 
> Bev in TX

OK, here're the details. Note that the paths are hard-coded (but could easily 
be configurable using argparse).

I assume: (1) the source dir is 'app'; (2) the dest dir is 'app-pyqt'; (3) 
there is a file called app/Uniform.py with this content:

#!/usr/bin/env python3
# Uniform.py
import PySide2.QtCore
from PySide2.shiboken2 import isValid as isObjectAlive
VERSION_STR = (f'PySide2 {PySide2.__version__} / '
   f'Qt {PySide2.QtCore.__version__}')


I then run pyside2pyqt.py in the dir *above* app and app-pyqt:

#!/usr/bin/env python3

import contextlib
import os
import shutil

SRC = 'app'
DST = 'app-pyqt'
UNIFORM_FILE = 'Uniform.py'

def main():
with contextlib.suppress(FileNotFoundError):
shutil.rmtree(DST)
shutil.copytree(SRC, DST, ignore=shutil.ignore_patterns(
'__pycache__', UNIFORM_FILE))
for root, _, files in os.walk(DST):
for name in files:
if name.endswith(('.py', '.pyw')):
filename = os.path.join(root, name)
with open(filename, 'rt', encoding='utf-8') as file:
text = file.read().replace('PySide2', 'PyQt5')
with open(filename, 'wt', encoding='utf-8') as file:
for line in text.splitlines():
if 'pyside2pyqt: DELETE' not in line:
print(line, file=file)
with open(os.path.join(DST, UNIFORM_FILE), 'wt',
  encoding='utf-8') as file:
file.write(UNIFORM)

UNIFORM = '''#!/usr/bin/env python3
import PyQt5.QtCore
import PyQt5.sip
VERSION_STR = (f'PyQt5 {PyQt5.QtCore.PYQT_VERSION_STR} / '
   f'Qt {PyQt5.QtCore.QT_VERSION_STR}')
def isObjectAlive(obj):
return not PyQt5.sip.isdeleted(obj)
'''

if __name__ == '__main__':
main()

The reaons for being able to delete lines is that the APIs aren't identical. 
For example, PySide2's QStyleHints has a setCursorFlashTime() method; but 
PyQt5's doesn't. So for any lines you don't want copied just add the comment, 
e.g.:

style_hints = self.styleHints()   # pyside2pyqt: DELETE
style_hints.setCursorFlashTime(0) # pyside2pyqt: DELETE

I'm sure someone could come up with a more generalized script, but this is 
sufficient for my needs.
-- 
https://mail.python.org/mailman/listinfo/python-list