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
Channel of Instrument does not use overwritten Instrument methods #784
Comments
Channels and Instrument both use Normally all communication problems can be handled in read/write, such that it is not necessary to overload Why did you change |
What I am trying to achieve is that My instrument is sending numbers (integers) binary encoded. So for certain values the For example communication messages see the test file I do not see how this works without overloading
|
Thanks for providing the example communication (the tests are great to have). I have to look at the code and think how to solve it best. I don't know, whether you can deactivate the split method. |
I just looked at the instrument code and it seems very reasonable. I agree that values is not written for bytes communication. |
You could also add the following method to your
This is possibly an indication that |
If values redirects to the instrument one, we bypass the channel write method. You can "import" values from instrument as you @msmttchr suggest, but you cannot call it directly. |
Yes, you are right In this specific case, you would have: In class
In
If this works, a similar split can be implemented in the default |
I like that idea. |
Thanks for all the feedback. I tested all suggestions. The first one of @msmttchr indeed would bypass Regarding TC38D: thanks for this hint: I looked into it, but it seems to me I can not do this easily. My reply messages do not identify themself to which write command they correspond. So inside I think the solution suggested above is what I was looking for. I updated the new device branch on my fork and the minimal example with a working version. For me all tests of the package are passing if the split method is put into CommonBase. |
@dkriegner could you try the following, please: def values(self, parameters):
# here is all the values stuff: ask and the content of _format_values
class SomeChannel(Channel):
values = values
class CXN(Instrument):
values = values I think, that you could have a single function for both objects. It is important, that you assign them at class level (as here) and that the function contains @bilderbuchi, could you please provide your opinion: For an example see #800 I don't like it, as values will be just two calls: |
This pattern also works. I tested in in the minimal example as well as in the code of the device in #800 (not commited yet). I guess this last suggestion is a bit cleaner if you look for a solution for the device in #800 only, but it should be somewhere documented how |
Thanks for testing. @dkriegner @bilderbuchi another idea: As ask returns (as default) a str, we could get rid of the str cast in def values(self, command, separator=',', cast=float, preprocess_reply=lambda s: s.strip(), maxsplit=-1):
"""Write a command to the instrument and return a list of formatted
values from the result.
:param command: SCPI command to be sent to the instrument
:param separator: A separator character to split the string into a list
:param cast: A type to cast the result
:param preprocess_reply: optional callable used to preprocess values
received from the instrument. The callable returns the processed
string. Set to `None` for deactivation.
:param maxsplit: At most `maxsplit` splits are done. -1 (default) indicates no limit.
:returns: A list of the desired type, or strings where the casting fails
"""
results = self.ask(command)
if callable(preprocess_reply):
results = preprocess_reply(results)
results = results.split(separator, maxsplit=maxsplit)
for i, result in enumerate(results):
try:
if cast == bool:
# Need to cast to float first since results are usually
# strings and bool of a non-empty string is always True
results[i] = bool(float(result))
else:
results[i] = cast(result)
except Exception:
pass # Keep as string
return results At least the first change (getting rid of str in |
I opened a pull request, getting rid of the str conversion (#803 ). (N.B: you have to set the separator to some bytes object or to None) |
I like the suggestion of improving
I guess |
Moving strip (and possibly split) into preprocess_reply is a larger change, as some instruments might require the strip and use their own preprocess_reply.
You could make a def values(self, preprocess_reply=lambda v: v*5, ...):
return super().values(preprocess_reply=preprocess_reply, ...) For #800 I suggest, you use one of the previously mentioned methods (splitting values into two or having an "external" values method) and we continue the discussion in this issue until we find a good solution (I'd like to get feedback from other maintainers as well). |
The Instrument and Channel can like this use the same value method. Suggested in pymeasure#784
Sorry I mistyped. Of course I meant Overall I think we could close this issue since the solutions suggested above provide good workarounds for the problems with overloading values in connection with Channels (which I guess is not so common in the codebase anyways)! |
Thanks for your thoughts. I looked at the code of the example and the tc038 and noticed, that we have the conversion to Str and back to numbers. This instrument is a good candidate for #779, a list of solutions to different problems. |
Thanks for the ping, I'll try to weigh in here over the Christmas break. |
The way that Splitting out the formatting into a separate method that then becomes overridable/replaceable as needed seems to me a solid idea that would allow flexible use. I agree, though, that the now quite slim The approach with Moving the Yet another potential approach to improve the separation would be to add an argument to |
@bmoneke Concerning the potential sensitivity to whitespace-stripping of binary protocols, should we add a test that fails if the What about this:
|
Thanks @bilderbuchi. I don't understand, what you try to achieve with that test. Regarding separation (to log an idea): we could rename values to "extract_values" (or similar) and remove the messaging part (a deprecated "values" will remain). Finally "Control" will call ask and that formatting method. |
I was thinking that we make sure we cannot inadvertently introduce a change that would change the behaviour when parsing binary messages because a whitespace character like
I considered that, too. However, |
As we talk in another issue about the reworking, I close this issue. |
I am implementing another device driver based on pymeasure's
Instrument
and run into an issue.The device uses messages based on binary code for communication. I have overwritten
Instrument.read/write/values
to work with binary messages. This all works great. For a set of properties, it seemed useful to use theChannel
framework.Using
Channel
s, however, seems to not use all the overwritten methods. In particular my customvalues
method is not used.I have prepared a minimal working example where the test framework nicely illustrates the problem.
The Instrument code and test file can be found at
https://gist.github.com/dkriegner/7af08dc78fdd1461125e079670675bcf
The test_prop succeeds as expected, while testing the same property via a channel fails because
CommonBase.values
seems to be used (the string conversion causes the problem).Is it wrong to expect that with
Channel
s I can still overwrite thevalues
method?My WIP code for the real device can be found in my fork, but its not ready and lots of other things issue the problem there.
The text was updated successfully, but these errors were encountered: