Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

"In the face of ambiguity refuse the temptation to guess" -- Tim Peters #29

Open
wants to merge 13 commits into
base: master
Choose a base branch
from

Conversation

harvimt
Copy link
Owner

@harvimt harvimt commented Jan 19, 2015

the dependency injection stuff. This branch is quite a bit cleaner than the depinject branch (I made a depinject4realz branch and then started over again with a depinject5realz branch)

So I'm asking for comments/review of this code to see if it seems to hackish or a suitably elegant solution befitting a pull request with a Zen of Python quote as it's title.

see #16

_easycallback is hard to use indirectly to create signals at runtime,
_make_signaller is more flexible & designed specifically to creat
signals at runtime.

_windows used it's own signal creation mechanism, and now it uses the
same one as _call_soon_threadsafe.
QtModule was imported but unused.
Using import module is cleaner than __import__ in some situations.

This code is much easier to read.
Also eliminates the QtModule variable.
QtCore is only referenced directly by the tests, never in code except in
the initializer for the loop, but everyone else receives a copy of
QtCore from the loop, and never receives it at compile time.
This is a big commit, but any smaller changes would put the project into
a non-working state where everything fails and things crumble and it's
all terrible.

The big change is QtCore, and QApplication are no longer imported by
quamash at import time. Instead, the type of the app parameter to
QEventLoop determines which module is imported (PySide, PyQt4, or
PyQt5). This is fairly robust and should support PySide with Qt5 when
(and if) it is released.

QThreadExecutor now takes in a parameter that should reference
QtCore.QThread.

Changes to tests and CI configuration to use a --qtimpl parameter
instead of the QUAMASH_QTIMPL environment variable.

a new fixture called qtcore was also created so tests (mostly those that
test QThreadExecutor) could access a reference to the QtCore module.

TODO update README
try:
signal = qtimpl_qtcore.Signal(*args)
except AttributeError:
signal = qtimpl_qtcore.pyqtSignal(*args)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(minor) To avoid shadowing errors in an implementation, I’d suggest:

    try:
        signal_cls = qtimpl_qtcore.Signal
    except AttributeError:
        signal_cls = qtimpl_qtcore.pyqtSignal
    signal = signal_cls(*args)

Or just going straight away with hasattr(), which seems to be the preferred way in ducktyping terms from the python code I have seen.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with your suggested code @horazont. I don't think we should go with hasattr though, after all it's easier to ask for forgiveness than permission, which is a typical rule of thumb in Python (at least this is what I learnt many years ago).

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I went a slightly different route style-wise, (I like to reduce indentations, even if it means more lines, and I like to spell out variables in words instead of weird abbreviations), but it's been pushed. see: abb907a

@horazont
Copy link
Contributor

I made a few comments in the diff. The hack of using the module attribute of the application type is quite nice, as long as it works with all (supported) Qt wrappers. I would maybe factor that out into a separate function (this is quite some magic happening where you would not expect it and it is not immediately obvious what and why this is happening; a function would allow for a matching docstring), but this is just personal taste.

... f = executor.submit(lambda x: 2 + x, 2)
... r = f.result()
... assert r == 4
"""

def __init__(self, max_workers=10, parent=None):
super().__init__(parent)
def __init__(self, qthread_class, max_workers=10):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't look right to me to make clients of Quamash have to specify the thread class, considering QThreadExecutor is public API.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, but I'm not sure what the alternative is.

One of the ideas floated around was some sort of quamash.set_qt(PyQt5/PyQt4/PySide) type thing.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I think there should be a single way of saying which Qt implementation Quamash is to use. quamash.set_qt still looks good to me, since we then don't have to infer which Qt package to use. It's logically analogous to Qt widgets' refusal to be constructed unless there's a QApplication running; the complication in our case being that we don't know the type of QApplication until someone points us to the containing package.

@harvimt
Copy link
Owner Author

harvimt commented Jan 19, 2015

Note that the failing appveyor tests (kinda) pass. py.test is returning an exit status that isn't zero, but the console output shows all tests pass. I'm able to replicate this on my end, so it's probably something that can be fixed, but I'm not entirely sure it's a problem with qumash or a problem with py.test.

harvimt and others added 6 commits January 19, 2015 12:17
Before sending in an app value of None was allowed (and the default),
but now that's not allowed, so we should guard against it.

More guards would be against duck-typing.

Wow. There were TWO self.__app is not None assertions.
This way if signal_class() raises AttributeError it won't be caught.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants