-
Notifications
You must be signed in to change notification settings - Fork 111
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
Add async property callback to DemoCamera #160
Conversation
Allows for more comprehensive testing of downstream libraries. It seems that it was necessary to make a follower and leader property as with only a single property there is a callback fired as soon the action returns, so added a second "Follower" property that is set to the leaders value after a (configurable) delay.
@@ -174,7 +175,9 @@ class CDemoCamera : public CCameraBase<CDemoCamera> | |||
// action interface | |||
// ---------------- | |||
int OnMaxExposure(MM::PropertyBase* pProp, MM::ActionType eAct); | |||
int OnTestProperty(MM::PropertyBase* pProp, MM::ActionType eAct, long); | |||
int OnTestProperty(MM::PropertyBase* pProp, MM::ActionType eAct, long); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is just fixing the indenting from tab to spaces in order to match the rest of the file.
Closes: #151 Thanks for the guidance @marktsuchida, especially the hint about saving the future really saved me some time. As discussed in the commit message I didn't see an obvious way to do this without introducing a second property, but if there's a better way that I'm missing happy to adjust. |
Also cc @tlambert03 as this has implications for testing threading in pymmcore+ |
I like the direction! One thing to consider: most properties are implemented in one of two styles:
The majority of useful properties use the second style (because it is the only way to do anything interesting). Sometimes it seems redundant (and definitely confusing to someone new to the interface), but that is what we've got. If you use this style, I think it is possible to have a single test property: on One reason I bring this up is that, by storing the value in a data member that you control, it becomes possible to protect access to it using a mutex. (You would acquire the mutex whenever reading or writing it, whether in the (Whether you have a single property or a leader and follower is not a huge issue per se in my opinion. Either way works for testing.) Also, just a few minor style comments: Our convention for C++ code is to start member (and non-member) function names with a capital letter (so |
Also make follower readonly.
This is very helpful thanks! A nights sleep and that explanation has it all making a lot more sense. I've updated it to use this as well as locks (I think) as you suggested.
Oh true! Though, I still went with two because I have a hunch that that may be handy in downstream testing. Three follow up questions:
I agree that this should have locks, and by the look around and copy approach I think I got it right but it'd be nice to confirm my understanding with you. In particular whats the difference between: What is the
and finally re locks: do they just get released at the end of the function when a destructor comes in because they are locally scoped? (that's my guess as to what's happening here)
|
an extra thought regarding documentation. I think you should definitely add your description in the above comment to the properties section of: https://micro-manager.org/Building_Micro-Manager_Device_Adapters it's a very helpful description, it could even point to this code as an example for extra completeness. |
The relationship between By creating the guard within a block Documenting properties: the device page would be the place. Clearly lots of undone work here.... Testing: sadly, there is none. But we can talk about it. While I am all for adding little test utilities like this to DemoCamera (as I have done myself with, e.g., the RGB color test pattern), I feel that DemoCamera is not really structured well for rigorous automated testing in general, so if we get serious about this, we might want to have a dedicated device adapter for testing. One thing that I explored in the past (more for testing MMCore and acqEngine, but potentially relevant here) was The other related topic is about testing device adapters as modules, which (to do right) requires bypassing MMCore. I started some work on this last year: https://github.com/micro-manager/mmdevicetests. So far it is little more than the beginnings of a mechanism to load a device adapter in Python without using MMCore. This is intended to become a generic test suite for any device adapter, but I suppose there is no reason why it couldn't also be used for tests that are specific to a particular device or one of its properties. |
Is there any way to couple those docs with the contents of this repo? The disconnect across repos is a bit of bummer for keeping things in sync. Like could this repo have a
very cool. One thing I was wondering about when poking around is if it was possible to directly interact with a device and I suppose that that would be the way. Perhaps that could be released as
I have a personal bias for python because I know how to use it. But maybe a quick and dirty intermediary step would be to add automated tests to the from pymmcore_plus import CMMCorePlus
mmc: CMMCorePlus = CMMCorePlus.instance()
@mmc.events.propertyChanged.connect
def cb(*args):
print('here!')
print(args)
mmc.setDeviceAdapterSearchPaths(["../micro-manager/mmCoreAndDevices/DeviceAdapters/DemoCamera/.libs/"])
mmc.loadSystemConfiguration()
print(mmc.getLoadedDevices())
# mmc.setProperty("")
print(mmc.getDevicePropertyNames("Camera"))
# mmc.setProperty("Camera", "TestProperty4", 1)
# mmc.setProperty("Camera", "Binning", 2)
# mmc.setProperty("Camera", "Binning", 4)
# mmc.setProperty("Camera", "AsyncCallbackTestProperty", 1)
mmc.setProperty("Camera", "AsyncPropertyLeader", "some new value")
mmc.setProperty("Camera", "AsyncPropertyDelayMS", 3000)
print(mmc.getProperty("Camera", "AsyncPropertyFollower"))
mmc.setProperty("Camera", "AsyncPropertyFollower", "shouldn't be allowed")
import time
time.sleep(6)
print(mmc.getProperty("Camera", "AsyncPropertyFollower"))
# from IPython import embed
# embed(colors='neutral') |
@marktsuchida is 3ba9d48 what you had in mind with the scoping of the thread guards? |
I wonder how much of C++ code the pymmcore-plus tests and napari-micromanager tests cover. Obviously they only hit the demo camera but I suspect that they're actually pretty extensive. Probably no easy way to get the actual coverage of c++ unfortunately though. |
Exactly. |
The idea of having the docs (or at least certain parts of the docs) in the same repo used to be unpopular, but might be viable now. I've always wanted that. But it doesn't make sense to use Doxygen for device adapters, which merely implement the uniform MMDevice interface; properties are not C++ constructs. I do like the idea of having a defined format (YAML? TOML? standardized Markdown?) for device property documentation (and other relevant device metadata) that lives with the device adapter code. It has to be noted that some devices dynamically generate properties, so it's not always simple. Maybe it is better for device adapters to call a Anyway, a huge topic. |
:O I never lived in that world, so I wasn't even aware. What was the argument against having them coupled? |
Independtly I think this would be a good thing! a docstring of sorts for properties. The names are often fairly descriptive, but sometimes it would be good to have more detailed descriptions, that ideally are accessible when scripting. So name: Property Name |
No, that doesn't make sense to me (I'm curious why people keep asking for this :). The tiny bit of sanity that is preserved due to MMCore being the only way to access the device adapters is extremely precious for keeping the MM device adapter collection usable. We have enough problems as such; if we end up in a situation where some devices are tested better with MMCore and others tested with something else, all hope is lost. If something other than MMCore is going to talk to device adapters (other than for testing), it should take the full responsibility of replacing and eliminating MMCore, once and for all. (But it's hard (not impossible) for Python code to play this role.) There is a lot of duplicated logic between device adapters, which a better-designed interface would have placed in MMCore. There are also useful things in device adapters that, on the surface, it looks as if MMCore obscures. But trying to access such functionality without doing the work of updating MMCore to cleanly expose it is only going to add to the chaos, imho. The story would be different if the MMDevice interface were more watertight and precisely defined. |
I'm all for using Python for tests. I wouldn't be opposed to something like this, as long as it doesn't live in the |
Yes, and tooltips in the Device Property Browser. |
@ianhi Thanks for the update. |
Thanks for the help! My understanding is that this will be included in the next nightly release? But that I don't need to update pymmcore version to get this? |
That's correct. You only need to update |
Allows for more comprehensive testing of downstream libraries.
It seems that it was necessary to make a follower and leader property
as with only a single property there is a callback fired as soon
the action returns, so added a second "Follower" property that
is set to the leaders value after a (configurable) delay.