How to properly call a coroutine from a coroutine in a subclass - python-3.6

I am new to Python's async, so bear with me please...
So, I am trying to extend the functionality of a class, let's say it's defined as such:
class OrigClass:
...
async def another_method(self, *args):
# Some code irrelevant to that I want to do
...
async def a_method(self, *args):
# Some heavyweight logic which I have no desire to copy
...
# After all that logic, it 'passes the torch' to yet another
await self.another_method(*args)
I want to add some checks to a_method through subclassing, like this:
class SubClass(OrigClass):
...
#asyncio.coroutine
def a_method(self, *args):
# Some checking / mangling of args here
...
# No 'heavyweight logic' done here;
# heavyweight logic is done in OrigClass.a_method
yield from super().a_method(*mangled_args)
Is this the proper way to implement what I want to do?

Related

How to override slot from native Qt class (QStatusBar) so that the overridden implementations get called by other methods?

I am trying to override the clearMessage slot/method from QStatusBar in PySide2.
I have a custom class inheriting from QStatusBar, which re-implements showMessage and clearMessage methods.
class MyStatus(QtWidgets.QStatusBar):
def showMessage(self, *args, **kwargs):
super(MyStatus, self).showMessage(*args, **kwargs)
print('Showing message')
def clearMessage(self, *args, **kwargs):
super(MyStatus, self).clearMessage(*args, **kwargs)
print('Clearing message')
According to the c++ source code I could find for the QStatusBar, when calling showMessage with a timeout argument, the clearMessage slot should be called when the timer expires:
void QStatusBar::showMessage(const QString &message, int timeout)
{
Q_D(QStatusBar);
if (timeout > 0) {
if (!d->timer) {
d->timer = new QTimer(this);
connect(d->timer, SIGNAL(timeout()), this, SLOT(clearMessage()));
}
d->timer->start(timeout);
} else if (d->timer) {
delete d->timer;
d->timer = nullptr;
}
if (d->tempItem == message)
return;
d->tempItem = message;
hideOrShow();
}
While the message does clear at the end of the timer, the print line I added in the method is not being printed, which makes me believe that either:
it's still executing the base class's clearMessage method
maybe the source code I found is for a different version of Qt, and PySide2 5.12.6 doesn't call the method at all
I need to make sure my custom clearMessage is being called any time the message gets cleared, whether it's manually(currently fine) or via a timer or other reason.
I could re-implement my own Qtimer and make sure I'm catching any other method which might call clearMessage, but I'm wondering if I'm missing something obvious which is preventing me from overriding the method properly.
clearMessage() is not listed as virtual, which means that overriding has no effect in the "internal" behavior, and it would only work when explicitly called from your code.
Since clearMessage() is actually called from Qt only from the QTimer created in showMessage(), then a possible workaround is to check for the latest QTimer child object created after calling the base implementation, disconnect its timeout signal and connect it again to your slot:
class MyStatusBar(QStatusBar):
def showMessage(self, message, timeout=0):
super().showMessage(message, timeout)
if timeout:
timer = self.findChildren(QTimer)[-1]
timer.timeout.disconnect()
timer.timeout.connect(self.clearMessage)
def clearMessage(self):
super().clearMessage()
print('my clearMessage')
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setStatusBar(MyStatusBar(self))
Note that the above code will only work properly if you never use other timers created as children of your subclass. If you do that, you may involuntarily reconnect them instead. Take this case:
def showMessage(self, message, timeout=0):
super().showMessage(message, timeout)
if timeout:
timer = self.findChildren(QTimer)[-1]
timer.timeout.disconnect()
timer.timeout.connect(self.clearMessage)
anotherTimer = QTimer(self, interval=3000,
timeout=self.myFunction)
anotherTimer.start()
def myFunction(self):
print('my custom function')
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setStatusBar(MyStatusBar(self))
self.statusBar().showMessage('Hello 1', 5000)
QTimer.singleShot(2000,
lambda: self.statusBar().showMessage('Hello 2', 5000))
The above will result in the following sequence:
show a message for 5 seconds;
start a timer that will timeout after 3 seconds;
myFunction() is called;
2 seconds after startup, a new showMessage() is called;
the override finds the last timer (which is the new anotherTimer), disconnects it, and connects it to clearMessage() instead;
While the case above obviously doesn't make a lot of sense, it's better to consider the possibility of other timers created arbitrarily; the solution is quite simple: set an object name for the internal timer and check for it before calling the base implementation.
showMessage() always creates a new timer if a previous d->timer doesn't exist, otherwise it just renews it keeping existing connections intact, so if there was no previous timer with our object name set, we set it, so that we can find it whenever showMessage() is called before its timeout and don't reconnect any timer again.
Note that I also added the Qt.FindDirectChildrenOnly flag to avoid the possibility of finding QTimers coming from other objects (like when using addWidget() or addPermanentWidget()).
def showMessage(self, message, timeout=0):
if timeout:
oldTimer = self.findChild(QTimer, 'clearMessageTimer',
Qt.FindDirectChildrenOnly)
super().showMessage(message, timeout)
if timeout and not oldTimer:
# there was no previously set timer
timer = self.findChildren(
QTimer, Qt.FindDirectChildrenOnly)[-1]
timer.setObjectName('clearMessageTimer')
timer.timeout.disconnect()
timer.timeout.connect(self.clearMessage)
For obvious reasons, this is based on the assumption that the base implementation of clearMessage() is always called in its override.

Python unittest Mock an object to not have an attribute

I have a function that runs some code if the object has a certain attribute, and in rare cases if if the object does not have the attribute, it runs different code. It is hard for me to create the object without the attribute for testing. I tried del instance.attribute but got an error. The attribute is actually a #property under the hood.
I have an object instance that has foo attribute. How does one mock it so that when one tries to access instance.foo it raises an AttributeError as usual if there is no attribute?
I tried mock.Mock(side_effect=AttributeError('Boom!')) but it only works with methods.
You could try to use a PropertyMock for the property, and generally you shall be able to set the respective side effect. Here is a simple working example:
from unittest import mock
import pytest
class Foo:
#property
def bar(self):
return "bar"
def test_no_foo():
bar_mock = mock.PropertyMock()
with mock.patch(f"{__name__}.Foo.bar", bar_mock):
bar_mock.side_effect = AttributeError('Boom!')
foo = Foo()
with pytest.raises(AttributeError):
foo.bar
As you patch the property in the class, not in the object, you can can also do this using patch.object if you have access to the object by accessing the class of the object:
def test_no_foo():
bar_mock = mock.PropertyMock()
foo = Foo()
with mock.patch.object(foo.__class__, "bar", bar_mock):
bar_mock.side_effect = AttributeError('Boom!')
with pytest.raises(AttributeError):
foo.bar

fastapi using bool in route paths

Is it possible to use bool parameters in route paths?
#app.get("/allprojects")
#app.get("/allprojects/{reload}")
async def GetAllProjects(reload:typing.Optional[bool]=False):
work using /allprojects?reload=true, but not /allprojects/reload=true nor /allprojects/reload will work, they both return:
{"detail":[{"loc":["path","reload"],"msg":"value could not be parsed to a boolean","type":"type_error.bool"}]}
I know I can create a separate route with reload as a str but would be nice to use bool parameters.
Thanks to #astrochun, that hinted the solution, the 2nd line was actually a str which is not allowed in the function, so using a typing.Union[bool,str] and handling the str incident solves it:
#app.get("/allprojects", response_class=HTMLResponse)
#app.get("/allprojects/{reload}", response_class=HTMLResponse)
async def GetAllProjects(request:Request, reload:typing.Optional[typing.Union[bool, str]]=False):
""" get all projects from cache, reload=True will reread projects taking 3minutes """
if isinstance(reload, str):
reload:bool = True
allprojects = gitlab.allprojects(reload=reload)
so now /allprojects/reload and /allprojects?reload=true reread, while /allprojects reads from database in 15ms

Using dexterity behaviors to provide a method

I've been using a schema behavior with no problem, but I want to also have a method that provides some logic. Right now I have
class IMyFoo(form.Schema):
requester = schema.TextLine(title=_(u"Requestor"),
required=False,
)
def foo(self):
""" foo """
alsoProvides(IMyFoo, IFormFieldProvider)
And in the zcml
<plone:behavior
title="My behavior"
description="Some desc"
provides=".behaviors.IMyFoo"
for=".interfaces.ISomeInterface"
/>
I included IMyFoo in the behaviors section of a content type in portal_types. This gives me the schema but not that foo() method. So I tried to add a factory for it from reading http://plone-training.readthedocs.org/en/latest/behaviors2.html with the following code
class MyFoo(object):
def foo(self):
return 'bar'
And in the zcml
<plone:behavior
title="My behavior"
description="Some desc"
provides=".behaviors.IMyFoo"
factory=".behaviors.MyFoo"
for=".interfaces.ISomeInterface"
/>
But this didn't seem to make a difference, or at least, I don't know how to access that method. The closest I've been able to come is the following:
class IMyFoo(Interface):
""" Marker """
class MyFoo(object):
def __init__(self, context):
self.context = context
def foo(self):
return 'bar'
<adapter for=".interfaces.ISomeInterface"
factory=".behaviors.MyFoo"
provides=".behaviors.IMyFoo" />
I put IMyFoo in the behaviors attribute in the fti, and then call it by walking through all behaviors with something like
behavior = resolveDottedName(context.portal_types.getTypeInfo(context.portal_type).behaviors[-1]))
behavior(self).myfoo()
Surely going through the FTI like that is not the proper way to do it. But I'm at a loss at this point. In Archetypes I would just make a mixin class and inherit it with any content type I wanted to use it. I could do the same here, but my understanding is that behaviors are supposed to be a replacement for them, so I'd like to figure out how to use this preferred method.
As you've discovered, the schema class really is just an interface. It can't provide any methods. To provide more functionality, you need to connect your behavior interface to a factory class that adapts a dexterity object to provide your interface.
So, if your behaviors.py looks like this:
# your imports plus:
from plone.dexterity.interfaces import IDexterityContent
from zope.component import adapts
from zope.interface import implements
class IMyFoo(form.Schema):
requester = schema.TextLine(
title=_(u"Requestor"),
required=False,
)
def foo(self):
""" foo """
alsoProvides(IMyFoo, IFormFieldProvider)
class MyFoo(object):
implements(IMyFoo)
adapts(IDexterityContent)
def __init__(self, context):
self.context = context
def foo(self):
return 'bar'
Then your one-and-only zcml declaration would be:
<plone:behavior
title="My behavior name"
description="Behavior description"
provides=".behavior.IMyFoo"
factory=".behavior.MyFoo"
for="plone.dexterity.interfaces.IDexterityContent"
/>
And, you would reach your method with code like:
IMyFoo(myFooishObject).foo()
Note the use of IDexterityContent. You're creating a behavior that could be applied to any Dexterity content. So, the behavior adapter should be for that very general interface.

Type Parameters on Scala Macro Annotations

I'm trying to use macro annotations in scala, where my macro annotation would take an argument of another type. It would then use scala reflection to look at the passed in type, and add some methods as appropriate.Eg.
trait MyTrait {
def x: Int
def y: Float
}
#MyAnnotation class MyClass //<-- somehow, this annotation should reference MyTrait
class MyAnnotation(val target: Any) extends StaticAnnotation {
def macroTransform(annottees: Any*) = macro MyAnnotationImpl.impl
}
object MyAnnotationImpl {
def impl(c: Context)(annottees: c.Expr[Any]*): c.Expr[Any] = {
// if I can get a handle on the type MyTrait in here
// then I can call .members on it, etc.
...
}
}
Basically, the same thing as Using Scala reflection in Scala macros, except using macro annotations. However, when I try to template my macro annotation with a TypeTag
class MyAnnotation[T](val target: Any) extends StaticAnnotation {
def macroTransform[T](annottees: Any*) = macro MyAnnotationImpl.impl[T]
}
object MyAnnotationImpl {
def impl[T: c.WeakTypeTag](c: Context)(annottees: c.Expr[Any]*): c.Expr[Any] = {
...
}
}
I get
[error] /Users/imran/other_projs/learn_macros/macros/src/main/scala/com/imranrashid/oleander/macros/MacrosWithReflection.scala:7: macro annotation has wrong shape:
[error] required: def macroTransform(annottees: Any*) = macro ...
[error] found : def macroTransform[T](annottees: Any*) = macro ...
[error] class MyAnnotation[T](val target: Any) extends StaticAnnotation {
[error] ^
I've also tried to make the type an argument to my annotation, so I would use it like #MyAnnotation(MyTrait) class Foo .... I can extract the name as a String with something like
val targetTrait = c.prefix.tree match {
case Apply(Select(New(Ident(_)), nme.CONSTRUCTOR), List(Ident(termName))) => termName
}
but, I'm not sure what I can do w/ that String to get back the full type. I've also tried variants like #MyAnnotation(typeOf[MyTrait]) class Foo ..., and then use c.eval on the typeOf inside my macro, but that doesn't compile either.
In macro paradise 2.0.0-SNAPSHOT we have quite a tricky way of accessing type parameters for macro annotations (the situation will improve later on when we have dedicated APIs for that, but right now it's very difficult to introduce new functionality to scala-reflect.jar in macro paradise, so the current API is a bit rough).
For now it's necessary to specify the type parameter on the annotation class and not to declare any type parameters on the macroTransform method. Then, in macro expansion, access c.macroApplication and extract the untyped tree corresponding to the passed type parameter. Afterwards, do c.typeCheck as described in Can't access Parent's Members while dealing with Macro Annotations.
As Eugene points out in his answer it is possible to match on the tree of the whole macro application. Like every Scala method, annotation macro applications can take multiple type argument lists as well as multiple value argument lists.
Consider the macro application of an annotation macro called test:
#test[A, B][C, D](a, b)(c, d) trait Foo
In the implementation of test we can inspect the macro application by
println(show(c.macroApplication))
which will result in:
new test[A, B][C, D](a, b)(c, d).macroTransform(abstract trait Foo extends scala.AnyRef)
To extract the (type/value) parameters from the tree you have to pattern match on the tree. A parser for an arbitrary amount of parameter lists can be found in this project
Using this parser retrieving the first value argument of the macro application is as easy as
val List(List(arg)) = MacroApp(c.macroApplication).termArgs

Resources